From 268225a1de1a021bac4884e7d61fe047345cc9be Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 23 Sep 2024 19:00:21 +0900 Subject: tomoyo: preparation step for building as a loadable LSM module In order to allow Makefile to generate tomoyo.ko as output, rename tomoyo.c to hooks.h and cut out LSM hook registration part that will be built into vmlinux from hooks.h to init.c . Also, update comments and relocate some variables. No behavior changes. Signed-off-by: Tetsuo Handa --- security/tomoyo/Makefile | 2 +- security/tomoyo/gc.c | 3 + security/tomoyo/hooks.h | 515 +++++++++++++++++++++++++++++++++ security/tomoyo/init.c | 104 +++++++ security/tomoyo/securityfs_if.c | 6 +- security/tomoyo/tomoyo.c | 623 ---------------------------------------- security/tomoyo/util.c | 3 - 7 files changed, 626 insertions(+), 630 deletions(-) create mode 100644 security/tomoyo/hooks.h create mode 100644 security/tomoyo/init.c delete mode 100644 security/tomoyo/tomoyo.c (limited to 'security') diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 55c67b9846a9..e573a5cad732 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tomoyo.o util.o +obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o init.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o util.o targets += builtin-policy.h diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 026e29ea3796..6eccca150839 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c @@ -9,6 +9,9 @@ #include #include +/* Lock for GC. */ +DEFINE_SRCU(tomoyo_ss); + /** * tomoyo_memory_free - Free memory for elements. * diff --git a/security/tomoyo/hooks.h b/security/tomoyo/hooks.h new file mode 100644 index 000000000000..58929bb71477 --- /dev/null +++ b/security/tomoyo/hooks.h @@ -0,0 +1,515 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * security/tomoyo/hooks.h + * + * Copyright (C) 2005-2011 NTT DATA CORPORATION + */ + +#include "common.h" + +/** + * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread. + * + * Returns pointer to "struct tomoyo_domain_info" for current thread. + */ +struct tomoyo_domain_info *tomoyo_domain(void) +{ + struct tomoyo_task *s = tomoyo_task(current); + + return s->domain_info; +} + +/** + * tomoyo_cred_prepare - Target for security_prepare_creds(). + * + * @new: Pointer to "struct cred". + * @old: Pointer to "struct cred". + * @gfp: Memory allocation flags. + * + * Returns 0. + */ +static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, + gfp_t gfp) +{ + /* Restore old_domain_info saved by previous execve() request. */ + struct tomoyo_task *s = tomoyo_task(current); + + if (s->old_domain_info && !current->in_execve) { + atomic_dec(&s->domain_info->users); + s->domain_info = s->old_domain_info; + s->old_domain_info = NULL; + } + return 0; +} + +/** + * tomoyo_bprm_committed_creds - Target for security_bprm_committed_creds(). + * + * @bprm: Pointer to "struct linux_binprm". + */ +static void tomoyo_bprm_committed_creds(const struct linux_binprm *bprm) +{ + /* Clear old_domain_info saved by execve() request. */ + struct tomoyo_task *s = tomoyo_task(current); + + atomic_dec(&s->old_domain_info->users); + s->old_domain_info = NULL; +} + +/** + * tomoyo_bprm_check_security - Target for security_bprm_check(). + * + * @bprm: Pointer to "struct linux_binprm". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_bprm_check_security(struct linux_binprm *bprm) +{ + struct tomoyo_task *s = tomoyo_task(current); + + /* + * Execute permission is checked against pathname passed to execve() + * using current domain. + */ + if (!s->old_domain_info) { + const int idx = tomoyo_read_lock(); + const int err = tomoyo_find_next_domain(bprm); + + tomoyo_read_unlock(idx); + return err; + } + /* + * Read permission is checked against interpreters using next domain. + */ + return tomoyo_check_open_permission(s->domain_info, + &bprm->file->f_path, O_RDONLY); +} + +/** + * tomoyo_inode_getattr - Target for security_inode_getattr(). + * + * @path: Pointer to "struct path". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_inode_getattr(const struct path *path) +{ + return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, path, NULL); +} + +/** + * tomoyo_path_truncate - Target for security_path_truncate(). + * + * @path: Pointer to "struct path". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_truncate(const struct path *path) +{ + return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL); +} + +/** + * tomoyo_file_truncate - Target for security_file_truncate(). + * + * @file: Pointer to "struct file". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_file_truncate(struct file *file) +{ + return tomoyo_path_truncate(&file->f_path); +} + +/** + * tomoyo_path_unlink - Target for security_path_unlink(). + * + * @parent: Pointer to "struct path". + * @dentry: Pointer to "struct dentry". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) +{ + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + + return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); +} + +/** + * tomoyo_path_mkdir - Target for security_path_mkdir(). + * + * @parent: Pointer to "struct path". + * @dentry: Pointer to "struct dentry". + * @mode: DAC permission mode. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, + umode_t mode) +{ + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + + return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, + mode & S_IALLUGO); +} + +/** + * tomoyo_path_rmdir - Target for security_path_rmdir(). + * + * @parent: Pointer to "struct path". + * @dentry: Pointer to "struct dentry". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) +{ + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + + return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); +} + +/** + * tomoyo_path_symlink - Target for security_path_symlink(). + * + * @parent: Pointer to "struct path". + * @dentry: Pointer to "struct dentry". + * @old_name: Symlink's content. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, + const char *old_name) +{ + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + + return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); +} + +/** + * tomoyo_path_mknod - Target for security_path_mknod(). + * + * @parent: Pointer to "struct path". + * @dentry: Pointer to "struct dentry". + * @mode: DAC permission mode. + * @dev: Device attributes. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry, + umode_t mode, unsigned int dev) +{ + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + int type = TOMOYO_TYPE_CREATE; + const unsigned int perm = mode & S_IALLUGO; + + switch (mode & S_IFMT) { + case S_IFCHR: + type = TOMOYO_TYPE_MKCHAR; + break; + case S_IFBLK: + type = TOMOYO_TYPE_MKBLOCK; + break; + default: + goto no_dev; + } + return tomoyo_mkdev_perm(type, &path, perm, dev); + no_dev: + switch (mode & S_IFMT) { + case S_IFIFO: + type = TOMOYO_TYPE_MKFIFO; + break; + case S_IFSOCK: + type = TOMOYO_TYPE_MKSOCK; + break; + } + return tomoyo_path_number_perm(type, &path, perm); +} + +/** + * tomoyo_path_link - Target for security_path_link(). + * + * @old_dentry: Pointer to "struct dentry". + * @new_dir: Pointer to "struct path". + * @new_dentry: Pointer to "struct dentry". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry) +{ + struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; + struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; + + return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); +} + +/** + * tomoyo_path_rename - Target for security_path_rename(). + * + * @old_parent: Pointer to "struct path". + * @old_dentry: Pointer to "struct dentry". + * @new_parent: Pointer to "struct path". + * @new_dentry: Pointer to "struct dentry". + * @flags: Rename options. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_rename(const struct path *old_parent, + struct dentry *old_dentry, + const struct path *new_parent, + struct dentry *new_dentry, + const unsigned int flags) +{ + struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; + struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; + + if (flags & RENAME_EXCHANGE) { + const int err = tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path2, + &path1); + + if (err) + return err; + } + return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); +} + +/** + * tomoyo_file_fcntl - Target for security_file_fcntl(). + * + * @file: Pointer to "struct file". + * @cmd: Command for fcntl(). + * @arg: Argument for @cmd. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))) + return 0; + return tomoyo_check_open_permission(tomoyo_domain(), &file->f_path, + O_WRONLY | (arg & O_APPEND)); +} + +/** + * tomoyo_file_open - Target for security_file_open(). + * + * @f: Pointer to "struct file". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_file_open(struct file *f) +{ + /* Don't check read permission here if called from execve(). */ + /* Illogically, FMODE_EXEC is in f_flags, not f_mode. */ + if (f->f_flags & __FMODE_EXEC) + return 0; + return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, + f->f_flags); +} + +/** + * tomoyo_file_ioctl - Target for security_file_ioctl(). + * + * @file: Pointer to "struct file". + * @cmd: Command for ioctl(). + * @arg: Argument for @cmd. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd); +} + +/** + * tomoyo_path_chmod - Target for security_path_chmod(). + * + * @path: Pointer to "struct path". + * @mode: DAC permission mode. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_chmod(const struct path *path, umode_t mode) +{ + return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, path, + mode & S_IALLUGO); +} + +/** + * tomoyo_path_chown - Target for security_path_chown(). + * + * @path: Pointer to "struct path". + * @uid: Owner ID. + * @gid: Group ID. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid) +{ + int error = 0; + + if (uid_valid(uid)) + error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, + from_kuid(&init_user_ns, uid)); + if (!error && gid_valid(gid)) + error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, + from_kgid(&init_user_ns, gid)); + return error; +} + +/** + * tomoyo_path_chroot - Target for security_path_chroot(). + * + * @path: Pointer to "struct path". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_path_chroot(const struct path *path) +{ + return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL); +} + +/** + * tomoyo_sb_mount - Target for security_sb_mount(). + * + * @dev_name: Name of device file. Maybe NULL. + * @path: Pointer to "struct path". + * @type: Name of filesystem type. Maybe NULL. + * @flags: Mount options. + * @data: Optional data. Maybe NULL. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_sb_mount(const char *dev_name, const struct path *path, + const char *type, unsigned long flags, void *data) +{ + return tomoyo_mount_permission(dev_name, path, type, flags, data); +} + +/** + * tomoyo_sb_umount - Target for security_sb_umount(). + * + * @mnt: Pointer to "struct vfsmount". + * @flags: Unmount options. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) +{ + struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; + + return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); +} + +/** + * tomoyo_sb_pivotroot - Target for security_sb_pivotroot(). + * + * @old_path: Pointer to "struct path". + * @new_path: Pointer to "struct path". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_sb_pivotroot(const struct path *old_path, const struct path *new_path) +{ + return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); +} + +/** + * tomoyo_socket_listen - Check permission for listen(). + * + * @sock: Pointer to "struct socket". + * @backlog: Backlog parameter. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_socket_listen(struct socket *sock, int backlog) +{ + return tomoyo_socket_listen_permission(sock); +} + +/** + * tomoyo_socket_connect - Check permission for connect(). + * + * @sock: Pointer to "struct socket". + * @addr: Pointer to "struct sockaddr". + * @addr_len: Size of @addr. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr, + int addr_len) +{ + return tomoyo_socket_connect_permission(sock, addr, addr_len); +} + +/** + * tomoyo_socket_bind - Check permission for bind(). + * + * @sock: Pointer to "struct socket". + * @addr: Pointer to "struct sockaddr". + * @addr_len: Size of @addr. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr, + int addr_len) +{ + return tomoyo_socket_bind_permission(sock, addr, addr_len); +} + +/** + * tomoyo_socket_sendmsg - Check permission for sendmsg(). + * + * @sock: Pointer to "struct socket". + * @msg: Pointer to "struct msghdr". + * @size: Size of message. + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, + int size) +{ + return tomoyo_socket_sendmsg_permission(sock, msg, size); +} + +/** + * tomoyo_task_alloc - Target for security_task_alloc(). + * + * @task: Pointer to "struct task_struct". + * @clone_flags: clone() flags. + * + * Returns 0. + */ +static int tomoyo_task_alloc(struct task_struct *task, + unsigned long clone_flags) +{ + struct tomoyo_task *old = tomoyo_task(current); + struct tomoyo_task *new = tomoyo_task(task); + + new->domain_info = old->domain_info; + atomic_inc(&new->domain_info->users); + new->old_domain_info = NULL; + return 0; +} + +/** + * tomoyo_task_free - Target for security_task_free(). + * + * @task: Pointer to "struct task_struct". + */ +static void tomoyo_task_free(struct task_struct *task) +{ + struct tomoyo_task *s = tomoyo_task(task); + + if (s->domain_info) { + atomic_dec(&s->domain_info->users); + s->domain_info = NULL; + } + if (s->old_domain_info) { + atomic_dec(&s->old_domain_info->users); + s->old_domain_info = NULL; + } +} diff --git a/security/tomoyo/init.c b/security/tomoyo/init.c new file mode 100644 index 000000000000..2b38dbc7a559 --- /dev/null +++ b/security/tomoyo/init.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * security/tomoyo/init.c + * + * Copyright (C) 2005-2011 NTT DATA CORPORATION + */ + +#include +#include +#include "common.h" + +#include "hooks.h" + +#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER +static int tomoyo_bprm_creds_for_exec(struct linux_binprm *bprm) +{ + /* + * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested + * for the first time. + */ + if (!tomoyo_policy_loaded) + tomoyo_load_policy(bprm->filename); + return 0; +} +#endif + +struct lsm_blob_sizes tomoyo_blob_sizes __ro_after_init = { + .lbs_task = sizeof(struct tomoyo_task), +}; + +static const struct lsm_id tomoyo_lsmid = { + .name = "tomoyo", + .id = LSM_ID_TOMOYO, +}; + +/* tomoyo_hooks is used for registering TOMOYO. */ +static struct security_hook_list tomoyo_hooks[] __ro_after_init = { + LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), + LSM_HOOK_INIT(bprm_committed_creds, tomoyo_bprm_committed_creds), + LSM_HOOK_INIT(task_alloc, tomoyo_task_alloc), + LSM_HOOK_INIT(task_free, tomoyo_task_free), +#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER + LSM_HOOK_INIT(bprm_creds_for_exec, tomoyo_bprm_creds_for_exec), +#endif + LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security), + LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl), + LSM_HOOK_INIT(file_open, tomoyo_file_open), + LSM_HOOK_INIT(file_truncate, tomoyo_file_truncate), + LSM_HOOK_INIT(path_truncate, tomoyo_path_truncate), + LSM_HOOK_INIT(path_unlink, tomoyo_path_unlink), + LSM_HOOK_INIT(path_mkdir, tomoyo_path_mkdir), + LSM_HOOK_INIT(path_rmdir, tomoyo_path_rmdir), + LSM_HOOK_INIT(path_symlink, tomoyo_path_symlink), + LSM_HOOK_INIT(path_mknod, tomoyo_path_mknod), + LSM_HOOK_INIT(path_link, tomoyo_path_link), + LSM_HOOK_INIT(path_rename, tomoyo_path_rename), + LSM_HOOK_INIT(inode_getattr, tomoyo_inode_getattr), + LSM_HOOK_INIT(file_ioctl, tomoyo_file_ioctl), + LSM_HOOK_INIT(file_ioctl_compat, tomoyo_file_ioctl), + LSM_HOOK_INIT(path_chmod, tomoyo_path_chmod), + LSM_HOOK_INIT(path_chown, tomoyo_path_chown), + LSM_HOOK_INIT(path_chroot, tomoyo_path_chroot), + LSM_HOOK_INIT(sb_mount, tomoyo_sb_mount), + LSM_HOOK_INIT(sb_umount, tomoyo_sb_umount), + LSM_HOOK_INIT(sb_pivotroot, tomoyo_sb_pivotroot), + LSM_HOOK_INIT(socket_bind, tomoyo_socket_bind), + LSM_HOOK_INIT(socket_connect, tomoyo_socket_connect), + LSM_HOOK_INIT(socket_listen, tomoyo_socket_listen), + LSM_HOOK_INIT(socket_sendmsg, tomoyo_socket_sendmsg), +}; + +int tomoyo_enabled __ro_after_init = 1; + +/* Has /sbin/init started? */ +bool tomoyo_policy_loaded; + +/** + * tomoyo_init - Register TOMOYO Linux as a LSM module. + * + * Returns 0. + */ +static int __init tomoyo_init(void) +{ + struct tomoyo_task *s = tomoyo_task(current); + + /* register ourselves with the security framework */ + security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), + &tomoyo_lsmid); + pr_info("TOMOYO Linux initialized\n"); + s->domain_info = &tomoyo_kernel_domain; + atomic_inc(&tomoyo_kernel_domain.users); + s->old_domain_info = NULL; + tomoyo_mm_init(); + + return 0; +} + +DEFINE_LSM(tomoyo) = { + .name = "tomoyo", + .enabled = &tomoyo_enabled, + .flags = LSM_FLAG_LEGACY_MAJOR, + .blobs = &tomoyo_blob_sizes, + .init = tomoyo_init, +}; diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index a2705798476f..7e69747b2f77 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -229,11 +229,11 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode, } /** - * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. + * tomoyo_interface_init - Initialize /sys/kernel/security/tomoyo/ interface. * * Returns 0. */ -static int __init tomoyo_initerface_init(void) +static int __init tomoyo_interface_init(void) { struct tomoyo_domain_info *domain; struct dentry *tomoyo_dir; @@ -270,4 +270,4 @@ static int __init tomoyo_initerface_init(void) return 0; } -fs_initcall(tomoyo_initerface_init); +fs_initcall(tomoyo_interface_init); diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c deleted file mode 100644 index 04a92c3d65d4..000000000000 --- a/security/tomoyo/tomoyo.c +++ /dev/null @@ -1,623 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * security/tomoyo/tomoyo.c - * - * Copyright (C) 2005-2011 NTT DATA CORPORATION - */ - -#include -#include -#include "common.h" - -/** - * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread. - * - * Returns pointer to "struct tomoyo_domain_info" for current thread. - */ -struct tomoyo_domain_info *tomoyo_domain(void) -{ - struct tomoyo_task *s = tomoyo_task(current); - - if (s->old_domain_info && !current->in_execve) { - atomic_dec(&s->old_domain_info->users); - s->old_domain_info = NULL; - } - return s->domain_info; -} - -/** - * tomoyo_cred_prepare - Target for security_prepare_creds(). - * - * @new: Pointer to "struct cred". - * @old: Pointer to "struct cred". - * @gfp: Memory allocation flags. - * - * Returns 0. - */ -static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, - gfp_t gfp) -{ - /* Restore old_domain_info saved by previous execve() request. */ - struct tomoyo_task *s = tomoyo_task(current); - - if (s->old_domain_info && !current->in_execve) { - atomic_dec(&s->domain_info->users); - s->domain_info = s->old_domain_info; - s->old_domain_info = NULL; - } - return 0; -} - -/** - * tomoyo_bprm_committed_creds - Target for security_bprm_committed_creds(). - * - * @bprm: Pointer to "struct linux_binprm". - */ -static void tomoyo_bprm_committed_creds(const struct linux_binprm *bprm) -{ - /* Clear old_domain_info saved by execve() request. */ - struct tomoyo_task *s = tomoyo_task(current); - - atomic_dec(&s->old_domain_info->users); - s->old_domain_info = NULL; -} - -#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER -/** - * tomoyo_bprm_creds_for_exec - Target for security_bprm_creds_for_exec(). - * - * @bprm: Pointer to "struct linux_binprm". - * - * Returns 0. - */ -static int tomoyo_bprm_creds_for_exec(struct linux_binprm *bprm) -{ - /* - * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested - * for the first time. - */ - if (!tomoyo_policy_loaded) - tomoyo_load_policy(bprm->filename); - return 0; -} -#endif - -/** - * tomoyo_bprm_check_security - Target for security_bprm_check(). - * - * @bprm: Pointer to "struct linux_binprm". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_bprm_check_security(struct linux_binprm *bprm) -{ - struct tomoyo_task *s = tomoyo_task(current); - - /* - * Execute permission is checked against pathname passed to execve() - * using current domain. - */ - if (!s->old_domain_info) { - const int idx = tomoyo_read_lock(); - const int err = tomoyo_find_next_domain(bprm); - - tomoyo_read_unlock(idx); - return err; - } - /* - * Read permission is checked against interpreters using next domain. - */ - return tomoyo_check_open_permission(s->domain_info, - &bprm->file->f_path, O_RDONLY); -} - -/** - * tomoyo_inode_getattr - Target for security_inode_getattr(). - * - * @path: Pointer to "struct path". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_inode_getattr(const struct path *path) -{ - return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, path, NULL); -} - -/** - * tomoyo_path_truncate - Target for security_path_truncate(). - * - * @path: Pointer to "struct path". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_truncate(const struct path *path) -{ - return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL); -} - -/** - * tomoyo_file_truncate - Target for security_file_truncate(). - * - * @file: Pointer to "struct file". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_file_truncate(struct file *file) -{ - return tomoyo_path_truncate(&file->f_path); -} - -/** - * tomoyo_path_unlink - Target for security_path_unlink(). - * - * @parent: Pointer to "struct path". - * @dentry: Pointer to "struct dentry". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) -{ - struct path path = { .mnt = parent->mnt, .dentry = dentry }; - - return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); -} - -/** - * tomoyo_path_mkdir - Target for security_path_mkdir(). - * - * @parent: Pointer to "struct path". - * @dentry: Pointer to "struct dentry". - * @mode: DAC permission mode. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, - umode_t mode) -{ - struct path path = { .mnt = parent->mnt, .dentry = dentry }; - - return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, - mode & S_IALLUGO); -} - -/** - * tomoyo_path_rmdir - Target for security_path_rmdir(). - * - * @parent: Pointer to "struct path". - * @dentry: Pointer to "struct dentry". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) -{ - struct path path = { .mnt = parent->mnt, .dentry = dentry }; - - return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); -} - -/** - * tomoyo_path_symlink - Target for security_path_symlink(). - * - * @parent: Pointer to "struct path". - * @dentry: Pointer to "struct dentry". - * @old_name: Symlink's content. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, - const char *old_name) -{ - struct path path = { .mnt = parent->mnt, .dentry = dentry }; - - return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); -} - -/** - * tomoyo_path_mknod - Target for security_path_mknod(). - * - * @parent: Pointer to "struct path". - * @dentry: Pointer to "struct dentry". - * @mode: DAC permission mode. - * @dev: Device attributes. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry, - umode_t mode, unsigned int dev) -{ - struct path path = { .mnt = parent->mnt, .dentry = dentry }; - int type = TOMOYO_TYPE_CREATE; - const unsigned int perm = mode & S_IALLUGO; - - switch (mode & S_IFMT) { - case S_IFCHR: - type = TOMOYO_TYPE_MKCHAR; - break; - case S_IFBLK: - type = TOMOYO_TYPE_MKBLOCK; - break; - default: - goto no_dev; - } - return tomoyo_mkdev_perm(type, &path, perm, dev); - no_dev: - switch (mode & S_IFMT) { - case S_IFIFO: - type = TOMOYO_TYPE_MKFIFO; - break; - case S_IFSOCK: - type = TOMOYO_TYPE_MKSOCK; - break; - } - return tomoyo_path_number_perm(type, &path, perm); -} - -/** - * tomoyo_path_link - Target for security_path_link(). - * - * @old_dentry: Pointer to "struct dentry". - * @new_dir: Pointer to "struct path". - * @new_dentry: Pointer to "struct dentry". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_dir, - struct dentry *new_dentry) -{ - struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; - struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; - - return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); -} - -/** - * tomoyo_path_rename - Target for security_path_rename(). - * - * @old_parent: Pointer to "struct path". - * @old_dentry: Pointer to "struct dentry". - * @new_parent: Pointer to "struct path". - * @new_dentry: Pointer to "struct dentry". - * @flags: Rename options. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_rename(const struct path *old_parent, - struct dentry *old_dentry, - const struct path *new_parent, - struct dentry *new_dentry, - const unsigned int flags) -{ - struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; - struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; - - if (flags & RENAME_EXCHANGE) { - const int err = tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path2, - &path1); - - if (err) - return err; - } - return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); -} - -/** - * tomoyo_file_fcntl - Target for security_file_fcntl(). - * - * @file: Pointer to "struct file". - * @cmd: Command for fcntl(). - * @arg: Argument for @cmd. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))) - return 0; - return tomoyo_check_open_permission(tomoyo_domain(), &file->f_path, - O_WRONLY | (arg & O_APPEND)); -} - -/** - * tomoyo_file_open - Target for security_file_open(). - * - * @f: Pointer to "struct file". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_file_open(struct file *f) -{ - /* Don't check read permission here if called from execve(). */ - /* Illogically, FMODE_EXEC is in f_flags, not f_mode. */ - if (f->f_flags & __FMODE_EXEC) - return 0; - return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, - f->f_flags); -} - -/** - * tomoyo_file_ioctl - Target for security_file_ioctl(). - * - * @file: Pointer to "struct file". - * @cmd: Command for ioctl(). - * @arg: Argument for @cmd. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd); -} - -/** - * tomoyo_path_chmod - Target for security_path_chmod(). - * - * @path: Pointer to "struct path". - * @mode: DAC permission mode. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_chmod(const struct path *path, umode_t mode) -{ - return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, path, - mode & S_IALLUGO); -} - -/** - * tomoyo_path_chown - Target for security_path_chown(). - * - * @path: Pointer to "struct path". - * @uid: Owner ID. - * @gid: Group ID. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid) -{ - int error = 0; - - if (uid_valid(uid)) - error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, - from_kuid(&init_user_ns, uid)); - if (!error && gid_valid(gid)) - error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, - from_kgid(&init_user_ns, gid)); - return error; -} - -/** - * tomoyo_path_chroot - Target for security_path_chroot(). - * - * @path: Pointer to "struct path". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_path_chroot(const struct path *path) -{ - return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL); -} - -/** - * tomoyo_sb_mount - Target for security_sb_mount(). - * - * @dev_name: Name of device file. Maybe NULL. - * @path: Pointer to "struct path". - * @type: Name of filesystem type. Maybe NULL. - * @flags: Mount options. - * @data: Optional data. Maybe NULL. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_sb_mount(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data) -{ - return tomoyo_mount_permission(dev_name, path, type, flags, data); -} - -/** - * tomoyo_sb_umount - Target for security_sb_umount(). - * - * @mnt: Pointer to "struct vfsmount". - * @flags: Unmount options. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) -{ - struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; - - return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); -} - -/** - * tomoyo_sb_pivotroot - Target for security_sb_pivotroot(). - * - * @old_path: Pointer to "struct path". - * @new_path: Pointer to "struct path". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_sb_pivotroot(const struct path *old_path, const struct path *new_path) -{ - return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); -} - -/** - * tomoyo_socket_listen - Check permission for listen(). - * - * @sock: Pointer to "struct socket". - * @backlog: Backlog parameter. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_socket_listen(struct socket *sock, int backlog) -{ - return tomoyo_socket_listen_permission(sock); -} - -/** - * tomoyo_socket_connect - Check permission for connect(). - * - * @sock: Pointer to "struct socket". - * @addr: Pointer to "struct sockaddr". - * @addr_len: Size of @addr. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr, - int addr_len) -{ - return tomoyo_socket_connect_permission(sock, addr, addr_len); -} - -/** - * tomoyo_socket_bind - Check permission for bind(). - * - * @sock: Pointer to "struct socket". - * @addr: Pointer to "struct sockaddr". - * @addr_len: Size of @addr. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr, - int addr_len) -{ - return tomoyo_socket_bind_permission(sock, addr, addr_len); -} - -/** - * tomoyo_socket_sendmsg - Check permission for sendmsg(). - * - * @sock: Pointer to "struct socket". - * @msg: Pointer to "struct msghdr". - * @size: Size of message. - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, - int size) -{ - return tomoyo_socket_sendmsg_permission(sock, msg, size); -} - -struct lsm_blob_sizes tomoyo_blob_sizes __ro_after_init = { - .lbs_task = sizeof(struct tomoyo_task), -}; - -/** - * tomoyo_task_alloc - Target for security_task_alloc(). - * - * @task: Pointer to "struct task_struct". - * @clone_flags: clone() flags. - * - * Returns 0. - */ -static int tomoyo_task_alloc(struct task_struct *task, - unsigned long clone_flags) -{ - struct tomoyo_task *old = tomoyo_task(current); - struct tomoyo_task *new = tomoyo_task(task); - - new->domain_info = old->domain_info; - atomic_inc(&new->domain_info->users); - new->old_domain_info = NULL; - return 0; -} - -/** - * tomoyo_task_free - Target for security_task_free(). - * - * @task: Pointer to "struct task_struct". - */ -static void tomoyo_task_free(struct task_struct *task) -{ - struct tomoyo_task *s = tomoyo_task(task); - - if (s->domain_info) { - atomic_dec(&s->domain_info->users); - s->domain_info = NULL; - } - if (s->old_domain_info) { - atomic_dec(&s->old_domain_info->users); - s->old_domain_info = NULL; - } -} - -static const struct lsm_id tomoyo_lsmid = { - .name = "tomoyo", - .id = LSM_ID_TOMOYO, -}; - -/* - * tomoyo_security_ops is a "struct security_operations" which is used for - * registering TOMOYO. - */ -static struct security_hook_list tomoyo_hooks[] __ro_after_init = { - LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), - LSM_HOOK_INIT(bprm_committed_creds, tomoyo_bprm_committed_creds), - LSM_HOOK_INIT(task_alloc, tomoyo_task_alloc), - LSM_HOOK_INIT(task_free, tomoyo_task_free), -#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER - LSM_HOOK_INIT(bprm_creds_for_exec, tomoyo_bprm_creds_for_exec), -#endif - LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security), - LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl), - LSM_HOOK_INIT(file_open, tomoyo_file_open), - LSM_HOOK_INIT(file_truncate, tomoyo_file_truncate), - LSM_HOOK_INIT(path_truncate, tomoyo_path_truncate), - LSM_HOOK_INIT(path_unlink, tomoyo_path_unlink), - LSM_HOOK_INIT(path_mkdir, tomoyo_path_mkdir), - LSM_HOOK_INIT(path_rmdir, tomoyo_path_rmdir), - LSM_HOOK_INIT(path_symlink, tomoyo_path_symlink), - LSM_HOOK_INIT(path_mknod, tomoyo_path_mknod), - LSM_HOOK_INIT(path_link, tomoyo_path_link), - LSM_HOOK_INIT(path_rename, tomoyo_path_rename), - LSM_HOOK_INIT(inode_getattr, tomoyo_inode_getattr), - LSM_HOOK_INIT(file_ioctl, tomoyo_file_ioctl), - LSM_HOOK_INIT(file_ioctl_compat, tomoyo_file_ioctl), - LSM_HOOK_INIT(path_chmod, tomoyo_path_chmod), - LSM_HOOK_INIT(path_chown, tomoyo_path_chown), - LSM_HOOK_INIT(path_chroot, tomoyo_path_chroot), - LSM_HOOK_INIT(sb_mount, tomoyo_sb_mount), - LSM_HOOK_INIT(sb_umount, tomoyo_sb_umount), - LSM_HOOK_INIT(sb_pivotroot, tomoyo_sb_pivotroot), - LSM_HOOK_INIT(socket_bind, tomoyo_socket_bind), - LSM_HOOK_INIT(socket_connect, tomoyo_socket_connect), - LSM_HOOK_INIT(socket_listen, tomoyo_socket_listen), - LSM_HOOK_INIT(socket_sendmsg, tomoyo_socket_sendmsg), -}; - -/* Lock for GC. */ -DEFINE_SRCU(tomoyo_ss); - -int tomoyo_enabled __ro_after_init = 1; - -/** - * tomoyo_init - Register TOMOYO Linux as a LSM module. - * - * Returns 0. - */ -static int __init tomoyo_init(void) -{ - struct tomoyo_task *s = tomoyo_task(current); - - /* register ourselves with the security framework */ - security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), - &tomoyo_lsmid); - pr_info("TOMOYO Linux initialized\n"); - s->domain_info = &tomoyo_kernel_domain; - atomic_inc(&tomoyo_kernel_domain.users); - s->old_domain_info = NULL; - tomoyo_mm_init(); - - return 0; -} - -DEFINE_LSM(tomoyo) = { - .name = "tomoyo", - .enabled = &tomoyo_enabled, - .flags = LSM_FLAG_LEGACY_MAJOR, - .blobs = &tomoyo_blob_sizes, - .init = tomoyo_init, -}; diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 6799b1122c9d..b851ff377382 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -13,9 +13,6 @@ /* Lock for protecting policy. */ DEFINE_MUTEX(tomoyo_policy_lock); -/* Has /sbin/init started? */ -bool tomoyo_policy_loaded; - /* * Mapping table from "enum tomoyo_mac_index" to * "enum tomoyo_mac_category_index". -- cgit v1.2.3 From 8b985bbfabbe46c8b9200d7d299030232c8ebd05 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 23 Sep 2024 19:55:50 +0900 Subject: tomoyo: allow building as a loadable LSM module One of concerns for enabling TOMOYO in prebuilt kernels is that distributor wants to avoid bloating kernel packages. Although boot-time kernel command line options allows selecting built-in LSMs to enable, file size increase of vmlinux and memory footprint increase of vmlinux caused by builtin-but- not-enabled LSMs remains. If it becomes possible to make LSMs dynamically appendable after boot using loadable kernel modules, these problems will go away. Another of concerns for enabling TOMOYO in prebuilt kernels is that who can provide support when distributor cannot provide support. Due to "those who compiled kernel code is expected to provide support for that kernel code" spell, TOMOYO is failing to get enabled in Fedora distribution [1]. The point of loadable kernel module is to share the workload. If it becomes possible to make LSMs dynamically appendable after boot using loadable kernel modules, as with people can use device drivers not supported by distributors but provided by third party device vendors, we can break this spell and can lower the barrier for using TOMOYO. This patch is intended for demonstrating that there is nothing difficult for supporting TOMOYO-like loadable LSM modules. For now we need to live with a mixture of built-in part and loadable part because fully loadable LSM modules are not supported since Linux 2.6.24 [2] and number of LSMs which can reserve static call slots is determined at compile time in Linux 6.12. Major changes in this patch are described below. There are no behavior changes as long as TOMOYO is built into vmlinux. Add CONFIG_SECURITY_TOMOYO_LKM as "bool" instead of changing CONFIG_SECURITY_TOMOYO from "bool" to "tristate", for something went wrong with how Makefile is evaluated if I choose "tristate". Add proxy.c for serving as a bridge between vmlinux and tomoyo.ko . Move callback functions from init.c to proxy.c when building as a loadable LSM module. init.c is built-in part and remains for reserving static call slots. proxy.c contains module's init function and tells init.c location of callback functions, making it possible to use static call for tomoyo.ko . By deferring initialization of "struct tomoyo_task" until tomoyo.ko is loaded, threads created between init.c reserved LSM hooks and proxy.c updates LSM hooks will have NULL "struct tomoyo_task" instances. Assuming that tomoyo.ko is loaded by the moment when the global init process starts, initialize "struct tomoyo_task" instance for current thread as a kernel thread when tomoyo_task(current) is called for the first time. There is a hack for exporting currently not-exported functions. This hack will be removed after all relevant functions are exported. Link: https://bugzilla.redhat.com/show_bug.cgi?id=542986 [1] Link: https://lkml.kernel.org/r/caafb609-8bef-4840-a080-81537356fc60@I-love.SAKURA.ne.jp [2] Signed-off-by: Tetsuo Handa --- security/tomoyo/Kconfig | 15 +++ security/tomoyo/Makefile | 8 +- security/tomoyo/common.c | 14 ++- security/tomoyo/common.h | 72 +++++++++++ security/tomoyo/init.c | 262 ++++++++++++++++++++++++++++++++++++++++ security/tomoyo/load_policy.c | 12 ++ security/tomoyo/proxy.c | 82 +++++++++++++ security/tomoyo/securityfs_if.c | 6 +- 8 files changed, 467 insertions(+), 4 deletions(-) create mode 100644 security/tomoyo/proxy.c (limited to 'security') diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig index 1e0dd1a6d0b0..90eccc6cd464 100644 --- a/security/tomoyo/Kconfig +++ b/security/tomoyo/Kconfig @@ -13,6 +13,21 @@ config SECURITY_TOMOYO found at . If you are unsure how to answer this question, answer N. +config SECURITY_TOMOYO_LKM + bool "Cut out most of TOMOYO's code to a loadable kernel module" + default n + depends on SECURITY_TOMOYO + depends on MODULES + help + Say Y here if you want to include TOMOYO without bloating + vmlinux file. If you say Y, most of TOMOYO code is cut out to + a loadable kernel module named tomoyo.ko . This option will be + useful for kernels built by Linux distributors where TOMOYO is + included but TOMOYO is not enabled by default. Please be sure + to explicitly load tomoyo.ko if you want to activate TOMOYO + without calling userspace policy loader, for tomoyo.ko is + loaded immediately before calling userspace policy loader. + config SECURITY_TOMOYO_MAX_ACCEPT_ENTRY int "Default maximal count for learning mode" default 2048 diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index e573a5cad732..287a7d16fa15 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile @@ -1,5 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o init.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o util.o +tomoyo-objs := audit.o common.o condition.o domain.o environ.o file.o gc.o group.o memory.o mount.o network.o proxy.o realpath.o securityfs_if.o util.o +obj-y += init.o load_policy.o +ifdef CONFIG_SECURITY_TOMOYO_LKM +obj-m += tomoyo.o +else +obj-y += tomoyo.o +endif targets += builtin-policy.h diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 5c7b059a332a..c0ef014f8009 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -998,8 +998,13 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, p = find_task_by_pid_ns(pid, &init_pid_ns); else p = find_task_by_vpid(pid); - if (p) + if (p) { domain = tomoyo_task(p)->domain_info; +#ifdef CONFIG_SECURITY_TOMOYO_LKM + if (!domain) + domain = &tomoyo_kernel_domain; +#endif + } rcu_read_unlock(); } else if (!strncmp(data, "domain=", 7)) { if (tomoyo_domain_def(data + 7)) @@ -1710,8 +1715,13 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) p = find_task_by_pid_ns(pid, &init_pid_ns); else p = find_task_by_vpid(pid); - if (p) + if (p) { domain = tomoyo_task(p)->domain_info; +#ifdef CONFIG_SECURITY_TOMOYO_LKM + if (!domain) + domain = &tomoyo_kernel_domain; +#endif + } rcu_read_unlock(); if (!domain) return; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 0e8e2e959aef..4f6c52a9f478 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -978,6 +978,7 @@ int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, int tomoyo_init_request_info(struct tomoyo_request_info *r, struct tomoyo_domain_info *domain, const u8 index); +int __init tomoyo_interface_init(void); int tomoyo_mkdev_perm(const u8 operation, const struct path *path, const unsigned int mode, unsigned int dev); int tomoyo_mount_permission(const char *dev_name, const struct path *path, @@ -1214,10 +1215,14 @@ static inline void tomoyo_put_group(struct tomoyo_group *group) * * Returns pointer to "struct tomoyo_task" for specified thread. */ +#ifdef CONFIG_SECURITY_TOMOYO_LKM +extern struct tomoyo_task *tomoyo_task(struct task_struct *task); +#else static inline struct tomoyo_task *tomoyo_task(struct task_struct *task) { return task->security + tomoyo_blob_sizes.lbs_task; } +#endif /** * tomoyo_same_name_union - Check for duplicated "struct tomoyo_name_union" entry. @@ -1284,4 +1289,71 @@ static inline struct tomoyo_policy_namespace *tomoyo_current_namespace(void) pos = srcu_dereference((head)->next, &tomoyo_ss); \ for ( ; pos != (head); pos = srcu_dereference(pos->next, &tomoyo_ss)) +#ifdef CONFIG_SECURITY_TOMOYO_LKM + +#define LSM_HOOK(RET, DEFAULT, NAME, ...) typedef RET (NAME##_t)(__VA_ARGS__); +#include +#undef LSM_HOOK + +struct tomoyo_hooks { + cred_prepare_t *cred_prepare; + bprm_committed_creds_t *bprm_committed_creds; + task_alloc_t *task_alloc; + task_free_t *task_free; + bprm_check_security_t *bprm_check_security; + file_fcntl_t *file_fcntl; + file_open_t *file_open; + file_truncate_t *file_truncate; + path_truncate_t *path_truncate; + path_unlink_t *path_unlink; + path_mkdir_t *path_mkdir; + path_rmdir_t *path_rmdir; + path_symlink_t *path_symlink; + path_mknod_t *path_mknod; + path_link_t *path_link; + path_rename_t *path_rename; + inode_getattr_t *inode_getattr; + file_ioctl_t *file_ioctl; + file_ioctl_compat_t *file_ioctl_compat; + path_chmod_t *path_chmod; + path_chown_t *path_chown; + path_chroot_t *path_chroot; + sb_mount_t *sb_mount; + sb_umount_t *sb_umount; + sb_pivotroot_t *sb_pivotroot; + socket_bind_t *socket_bind; + socket_connect_t *socket_connect; + socket_listen_t *socket_listen; + socket_sendmsg_t *socket_sendmsg; +}; + +extern void tomoyo_register_hooks(const struct tomoyo_hooks *tomoyo_hooks); + +struct tomoyo_operations { + void (*check_profile)(void); + int enabled; +}; + +extern struct tomoyo_operations tomoyo_ops; + +/* + * Temporary hack: functions needed by tomoyo.ko . This will be removed + * after all functions are marked as EXPORT_STMBOL_GPL(). + */ +struct tomoyo_tmp_exports { + struct task_struct * (*find_task_by_vpid)(pid_t nr); + struct task_struct * (*find_task_by_pid_ns)(pid_t nr, struct pid_namespace *ns); + void (*put_filesystem)(struct file_system_type *fs); + struct file * (*get_mm_exe_file)(struct mm_struct *mm); + char * (*d_absolute_path)(const struct path *path, char *buf, int buflen); +}; +extern const struct tomoyo_tmp_exports tomoyo_tmp_exports; +#define find_task_by_vpid tomoyo_tmp_exports.find_task_by_vpid +#define find_task_by_pid_ns tomoyo_tmp_exports.find_task_by_pid_ns +#define put_filesystem tomoyo_tmp_exports.put_filesystem +#define get_mm_exe_file tomoyo_tmp_exports.get_mm_exe_file +#define d_absolute_path tomoyo_tmp_exports.d_absolute_path + +#endif /* defined(CONFIG_SECURITY_TOMOYO_LKM) */ + #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ diff --git a/security/tomoyo/init.c b/security/tomoyo/init.c index 2b38dbc7a559..034e7db22d4e 100644 --- a/security/tomoyo/init.c +++ b/security/tomoyo/init.c @@ -9,8 +9,248 @@ #include #include "common.h" +#ifndef CONFIG_SECURITY_TOMOYO_LKM + #include "hooks.h" +#else + +#define DEFINE_STATIC_CALL_PROXY(NAME) \ + static NAME##_t tomoyo_##NAME; \ + DEFINE_STATIC_CALL_RET0(tomoyo_##NAME, tomoyo_##NAME); +DEFINE_STATIC_CALL_PROXY(cred_prepare) +DEFINE_STATIC_CALL_PROXY(bprm_committed_creds) +DEFINE_STATIC_CALL_PROXY(bprm_check_security) +DEFINE_STATIC_CALL_PROXY(inode_getattr) +DEFINE_STATIC_CALL_PROXY(path_truncate) +DEFINE_STATIC_CALL_PROXY(file_truncate) +DEFINE_STATIC_CALL_PROXY(path_unlink) +DEFINE_STATIC_CALL_PROXY(path_mkdir) +DEFINE_STATIC_CALL_PROXY(path_rmdir) +DEFINE_STATIC_CALL_PROXY(path_symlink) +DEFINE_STATIC_CALL_PROXY(path_mknod) +DEFINE_STATIC_CALL_PROXY(path_link) +DEFINE_STATIC_CALL_PROXY(path_rename) +DEFINE_STATIC_CALL_PROXY(file_fcntl) +DEFINE_STATIC_CALL_PROXY(file_open) +DEFINE_STATIC_CALL_PROXY(file_ioctl) +DEFINE_STATIC_CALL_PROXY(path_chmod) +DEFINE_STATIC_CALL_PROXY(path_chown) +DEFINE_STATIC_CALL_PROXY(path_chroot) +DEFINE_STATIC_CALL_PROXY(sb_mount) +DEFINE_STATIC_CALL_PROXY(sb_umount) +DEFINE_STATIC_CALL_PROXY(sb_pivotroot) +DEFINE_STATIC_CALL_PROXY(socket_listen) +DEFINE_STATIC_CALL_PROXY(socket_connect) +DEFINE_STATIC_CALL_PROXY(socket_bind) +DEFINE_STATIC_CALL_PROXY(socket_sendmsg) +DEFINE_STATIC_CALL_PROXY(task_alloc) +DEFINE_STATIC_CALL_PROXY(task_free) +#undef DEFINE_STATIC_CALL_PROXY + +static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) +{ + return static_call(tomoyo_cred_prepare)(new, old, gfp); +} + +static void tomoyo_bprm_committed_creds(const struct linux_binprm *bprm) +{ + static_call(tomoyo_bprm_committed_creds)(bprm); +} + +static int tomoyo_bprm_check_security(struct linux_binprm *bprm) +{ + return static_call(tomoyo_bprm_check_security)(bprm); +} + +static int tomoyo_inode_getattr(const struct path *path) +{ + return static_call(tomoyo_inode_getattr)(path); +} + +static int tomoyo_path_truncate(const struct path *path) +{ + return static_call(tomoyo_path_truncate)(path); +} + +static int tomoyo_file_truncate(struct file *file) +{ + return static_call(tomoyo_file_truncate)(file); +} + +static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) +{ + return static_call(tomoyo_path_unlink)(parent, dentry); +} + +static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, umode_t mode) +{ + return static_call(tomoyo_path_mkdir)(parent, dentry, mode); +} + +static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) +{ + return static_call(tomoyo_path_rmdir)(parent, dentry); +} + +static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, + const char *old_name) +{ + return static_call(tomoyo_path_symlink)(parent, dentry, old_name); +} + +static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry, + umode_t mode, unsigned int dev) +{ + return static_call(tomoyo_path_mknod)(parent, dentry, mode, dev); +} + +static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry) +{ + return static_call(tomoyo_path_link)(old_dentry, new_dir, new_dentry); +} + +static int tomoyo_path_rename(const struct path *old_parent, struct dentry *old_dentry, + const struct path *new_parent, struct dentry *new_dentry, + const unsigned int flags) +{ + return static_call(tomoyo_path_rename)(old_parent, old_dentry, new_parent, new_dentry, flags); +} + +static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return static_call(tomoyo_file_fcntl)(file, cmd, arg); +} + +static int tomoyo_file_open(struct file *f) +{ + return static_call(tomoyo_file_open)(f); +} + +static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return static_call(tomoyo_file_ioctl)(file, cmd, arg); +} + +static int tomoyo_path_chmod(const struct path *path, umode_t mode) +{ + return static_call(tomoyo_path_chmod)(path, mode); +} + +static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid) +{ + return static_call(tomoyo_path_chown)(path, uid, gid); +} + +static int tomoyo_path_chroot(const struct path *path) +{ + return static_call(tomoyo_path_chroot)(path); +} + +static int tomoyo_sb_mount(const char *dev_name, const struct path *path, + const char *type, unsigned long flags, void *data) +{ + return static_call(tomoyo_sb_mount)(dev_name, path, type, flags, data); +} + +static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) +{ + return static_call(tomoyo_sb_umount)(mnt, flags); +} + +static int tomoyo_sb_pivotroot(const struct path *old_path, const struct path *new_path) +{ + return static_call(tomoyo_sb_pivotroot)(old_path, new_path); +} + +static int tomoyo_socket_listen(struct socket *sock, int backlog) +{ + return static_call(tomoyo_socket_listen)(sock, backlog); +} + +static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr, int addr_len) +{ + return static_call(tomoyo_socket_connect)(sock, addr, addr_len); +} + +static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +{ + return static_call(tomoyo_socket_bind)(sock, addr, addr_len); +} + +static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) +{ + return static_call(tomoyo_socket_sendmsg)(sock, msg, size); +} + +static int tomoyo_task_alloc(struct task_struct *task, unsigned long clone_flags) +{ + return static_call(tomoyo_task_alloc)(task, clone_flags); +} + +static void tomoyo_task_free(struct task_struct *task) +{ + static_call(tomoyo_task_free)(task); +} + +void tomoyo_register_hooks(const struct tomoyo_hooks *tomoyo_hooks) +{ + static void *registered; + + if (cmpxchg(®istered, NULL, ®istered)) + panic("%s was called twice!\n", __func__); + static_call_update(tomoyo_task_free, tomoyo_hooks->task_free); + static_call_update(tomoyo_task_alloc, tomoyo_hooks->task_alloc); + static_call_update(tomoyo_cred_prepare, tomoyo_hooks->cred_prepare); + static_call_update(tomoyo_bprm_committed_creds, tomoyo_hooks->bprm_committed_creds); + static_call_update(tomoyo_bprm_check_security, tomoyo_hooks->bprm_check_security); + static_call_update(tomoyo_inode_getattr, tomoyo_hooks->inode_getattr); + static_call_update(tomoyo_path_truncate, tomoyo_hooks->path_truncate); + static_call_update(tomoyo_file_truncate, tomoyo_hooks->file_truncate); + static_call_update(tomoyo_path_unlink, tomoyo_hooks->path_unlink); + static_call_update(tomoyo_path_mkdir, tomoyo_hooks->path_mkdir); + static_call_update(tomoyo_path_rmdir, tomoyo_hooks->path_rmdir); + static_call_update(tomoyo_path_symlink, tomoyo_hooks->path_symlink); + static_call_update(tomoyo_path_mknod, tomoyo_hooks->path_mknod); + static_call_update(tomoyo_path_link, tomoyo_hooks->path_link); + static_call_update(tomoyo_path_rename, tomoyo_hooks->path_rename); + static_call_update(tomoyo_file_fcntl, tomoyo_hooks->file_fcntl); + static_call_update(tomoyo_file_open, tomoyo_hooks->file_open); + static_call_update(tomoyo_file_ioctl, tomoyo_hooks->file_ioctl); + static_call_update(tomoyo_path_chmod, tomoyo_hooks->path_chmod); + static_call_update(tomoyo_path_chown, tomoyo_hooks->path_chown); + static_call_update(tomoyo_path_chroot, tomoyo_hooks->path_chroot); + static_call_update(tomoyo_sb_mount, tomoyo_hooks->sb_mount); + static_call_update(tomoyo_sb_umount, tomoyo_hooks->sb_umount); + static_call_update(tomoyo_sb_pivotroot, tomoyo_hooks->sb_pivotroot); + static_call_update(tomoyo_socket_listen, tomoyo_hooks->socket_listen); + static_call_update(tomoyo_socket_connect, tomoyo_hooks->socket_connect); + static_call_update(tomoyo_socket_bind, tomoyo_hooks->socket_bind); + static_call_update(tomoyo_socket_sendmsg, tomoyo_hooks->socket_sendmsg); +} +EXPORT_SYMBOL_GPL(tomoyo_register_hooks); + +/* + * Temporary hack: functions needed by tomoyo.ko . This hack will be removed + * after all functions are marked as EXPORT_STMBOL_GPL(). + */ +#undef find_task_by_vpid +#undef find_task_by_pid_ns +#undef put_filesystem +#undef get_mm_exe_file +#undef d_absolute_path +const struct tomoyo_tmp_exports tomoyo_tmp_exports = { + .find_task_by_vpid = find_task_by_vpid, + .find_task_by_pid_ns = find_task_by_pid_ns, + .put_filesystem = put_filesystem, + .get_mm_exe_file = get_mm_exe_file, + .d_absolute_path = d_absolute_path, +}; +EXPORT_SYMBOL_GPL(tomoyo_tmp_exports); + +#endif + #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER static int tomoyo_bprm_creds_for_exec(struct linux_binprm *bprm) { @@ -74,6 +314,27 @@ int tomoyo_enabled __ro_after_init = 1; /* Has /sbin/init started? */ bool tomoyo_policy_loaded; +#ifdef CONFIG_SECURITY_TOMOYO_LKM +EXPORT_SYMBOL_GPL(tomoyo_blob_sizes); +EXPORT_SYMBOL_GPL(tomoyo_policy_loaded); + +struct tomoyo_operations tomoyo_ops; +EXPORT_SYMBOL_GPL(tomoyo_ops); + +/** + * tomoyo_init - Reserve hooks for TOMOYO Linux. + * + * Returns 0. + */ +static int __init tomoyo_init(void) +{ + /* register ourselves with the security framework */ + security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), &tomoyo_lsmid); + tomoyo_ops.enabled = tomoyo_enabled; + pr_info("Hooks for initializing TOMOYO Linux are ready\n"); + return 0; +} +#else /** * tomoyo_init - Register TOMOYO Linux as a LSM module. * @@ -94,6 +355,7 @@ static int __init tomoyo_init(void) return 0; } +#endif DEFINE_LSM(tomoyo) = { .name = "tomoyo", diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c index 363b65be87ab..6a2a72354a64 100644 --- a/security/tomoyo/load_policy.c +++ b/security/tomoyo/load_policy.c @@ -97,6 +97,14 @@ void tomoyo_load_policy(const char *filename) if (!tomoyo_policy_loader_exists()) return; done = true; +#ifdef CONFIG_SECURITY_TOMOYO_LKM + /* Load tomoyo.ko if not yet loaded. */ + if (!tomoyo_ops.check_profile) + request_module("tomoyo"); + /* Check if tomoyo.ko was successfully loaded. */ + if (!tomoyo_ops.check_profile) + panic("Failed to load tomoyo module."); +#endif pr_info("Calling %s to load policy. Please wait.\n", tomoyo_loader); argv[0] = (char *) tomoyo_loader; argv[1] = NULL; @@ -104,7 +112,11 @@ void tomoyo_load_policy(const char *filename) envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; envp[2] = NULL; call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); +#ifdef CONFIG_SECURITY_TOMOYO_LKM + tomoyo_ops.check_profile(); +#else tomoyo_check_profile(); +#endif } #endif diff --git a/security/tomoyo/proxy.c b/security/tomoyo/proxy.c new file mode 100644 index 000000000000..1618cc0f2af8 --- /dev/null +++ b/security/tomoyo/proxy.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * security/tomoyo/proxy.c + * + * Copyright (C) 2005-2011 NTT DATA CORPORATION + */ + +#include +#include "common.h" + +#ifdef CONFIG_SECURITY_TOMOYO_LKM + +struct tomoyo_task *tomoyo_task(struct task_struct *task) +{ + struct tomoyo_task *s = task->security + tomoyo_blob_sizes.lbs_task; + + if (unlikely(!s->domain_info)) { + if (likely(task == current)) { + s->domain_info = &tomoyo_kernel_domain; + atomic_inc(&tomoyo_kernel_domain.users); + } else { + /* Caller handles s->domain_info == NULL case. */ + } + } + return s; +} + +#include "hooks.h" + +/** + * tomoyo_runtime_init - Register TOMOYO Linux as a loadable LSM module. + * + * Returns 0 if TOMOYO is enabled, -EINVAL otherwise. + */ +static int __init tomoyo_runtime_init(void) +{ + const struct tomoyo_hooks tomoyo_hooks = { + .cred_prepare = tomoyo_cred_prepare, + .bprm_committed_creds = tomoyo_bprm_committed_creds, + .task_alloc = tomoyo_task_alloc, + .task_free = tomoyo_task_free, + .bprm_check_security = tomoyo_bprm_check_security, + .file_fcntl = tomoyo_file_fcntl, + .file_open = tomoyo_file_open, + .file_truncate = tomoyo_file_truncate, + .path_truncate = tomoyo_path_truncate, + .path_unlink = tomoyo_path_unlink, + .path_mkdir = tomoyo_path_mkdir, + .path_rmdir = tomoyo_path_rmdir, + .path_symlink = tomoyo_path_symlink, + .path_mknod = tomoyo_path_mknod, + .path_link = tomoyo_path_link, + .path_rename = tomoyo_path_rename, + .inode_getattr = tomoyo_inode_getattr, + .file_ioctl = tomoyo_file_ioctl, + .file_ioctl_compat = tomoyo_file_ioctl, + .path_chmod = tomoyo_path_chmod, + .path_chown = tomoyo_path_chown, + .path_chroot = tomoyo_path_chroot, + .sb_mount = tomoyo_sb_mount, + .sb_umount = tomoyo_sb_umount, + .sb_pivotroot = tomoyo_sb_pivotroot, + .socket_bind = tomoyo_socket_bind, + .socket_connect = tomoyo_socket_connect, + .socket_listen = tomoyo_socket_listen, + .socket_sendmsg = tomoyo_socket_sendmsg, + }; + + if (!tomoyo_ops.enabled) + return -EINVAL; + tomoyo_ops.check_profile = tomoyo_check_profile; + pr_info("TOMOYO Linux initialized\n"); + tomoyo_task(current); + tomoyo_mm_init(); + tomoyo_interface_init(); + tomoyo_register_hooks(&tomoyo_hooks); + return 0; +} +module_init(tomoyo_runtime_init); +MODULE_LICENSE("GPL"); + +#endif diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index 7e69747b2f77..a3b821b7f477 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -233,13 +233,15 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode, * * Returns 0. */ -static int __init tomoyo_interface_init(void) +int __init tomoyo_interface_init(void) { struct tomoyo_domain_info *domain; struct dentry *tomoyo_dir; +#ifndef CONFIG_SECURITY_TOMOYO_LKM if (!tomoyo_enabled) return 0; +#endif domain = tomoyo_domain(); /* Don't create securityfs entries unless registered. */ if (domain != &tomoyo_kernel_domain) @@ -270,4 +272,6 @@ static int __init tomoyo_interface_init(void) return 0; } +#ifndef CONFIG_SECURITY_TOMOYO_LKM fs_initcall(tomoyo_interface_init); +#endif -- cgit v1.2.3 From ada1986d07976d60bed5017aa38b7f7cf27883f7 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 25 Sep 2024 22:30:59 +0900 Subject: tomoyo: fallback to realpath if symlink's pathname does not exist Alfred Agrell found that TOMOYO cannot handle execveat(AT_EMPTY_PATH) inside chroot environment where /dev and /proc are not mounted, for commit 51f39a1f0cea ("syscalls: implement execveat() system call") missed that TOMOYO tries to canonicalize argv[0] when the filename fed to the executed program as argv[0] is supplied using potentially nonexistent pathname. Since "/dev/fd/" already lost symlink information used for obtaining that , it is too late to reconstruct symlink's pathname. Although part of "/dev/fd//" might not be canonicalized, TOMOYO cannot use tomoyo_realpath_nofollow() when /dev or /proc is not mounted. Therefore, fallback to tomoyo_realpath_from_path() when tomoyo_realpath_nofollow() failed. Reported-by: Alfred Agrell Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1082001 Fixes: 51f39a1f0cea ("syscalls: implement execveat() system call") Cc: stable@vger.kernel.org # v3.19+ Signed-off-by: Tetsuo Handa --- security/tomoyo/domain.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'security') diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 90b53500a236..aed9e3ef2c9e 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -723,10 +723,13 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ee->r.obj = &ee->obj; ee->obj.path1 = bprm->file->f_path; /* Get symlink's pathname of program. */ - retval = -ENOENT; exename.name = tomoyo_realpath_nofollow(original_name); - if (!exename.name) - goto out; + if (!exename.name) { + /* Fallback to realpath if symlink's pathname does not exist. */ + exename.name = tomoyo_realpath_from_path(&bprm->file->f_path); + if (!exename.name) + goto out; + } tomoyo_fill_path_info(&exename); retry: /* Check 'aggregator' directive. */ -- cgit v1.2.3