diff options
Diffstat (limited to 'security/tomoyo/tomoyo.c')
| -rw-r--r-- | security/tomoyo/tomoyo.c | 346 |
1 files changed, 203 insertions, 143 deletions
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index f0b756e27fed..c66e02ed8ee3 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -1,24 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 /* * security/tomoyo/tomoyo.c * * Copyright (C) 2005-2011 NTT DATA CORPORATION */ -#include <linux/security.h> +#include <linux/lsm_hooks.h> +#include <uapi/linux/lsm.h> #include "common.h" /** - * tomoyo_cred_alloc_blank - Target for security_cred_alloc_blank(). + * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread. * - * @new: Pointer to "struct cred". - * @gfp: Memory allocation flags. - * - * Returns 0. + * Returns pointer to "struct tomoyo_domain_info" for current thread. */ -static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) +struct tomoyo_domain_info *tomoyo_domain(void) { - new->security = NULL; - return 0; + 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; } /** @@ -33,80 +37,50 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { - struct tomoyo_domain_info *domain = old->security; - new->security = domain; - if (domain) - atomic_inc(&domain->users); + /* 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_cred_transfer - Target for security_transfer_creds(). + * tomoyo_bprm_committed_creds - Target for security_bprm_committed_creds(). * - * @new: Pointer to "struct cred". - * @old: Pointer to "struct cred". + * @bprm: Pointer to "struct linux_binprm". */ -static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) +static void tomoyo_bprm_committed_creds(const struct linux_binprm *bprm) { - tomoyo_cred_prepare(new, old, 0); -} + /* Clear old_domain_info saved by execve() request. */ + struct tomoyo_task *s = tomoyo_task(current); -/** - * tomoyo_cred_free - Target for security_cred_free(). - * - * @cred: Pointer to "struct cred". - */ -static void tomoyo_cred_free(struct cred *cred) -{ - struct tomoyo_domain_info *domain = cred->security; - if (domain) - atomic_dec(&domain->users); + atomic_dec(&s->old_domain_info->users); + s->old_domain_info = NULL; } +#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER /** - * tomoyo_bprm_set_creds - Target for security_bprm_set_creds(). + * tomoyo_bprm_creds_for_exec - Target for security_bprm_creds_for_exec(). * * @bprm: Pointer to "struct linux_binprm". * - * Returns 0 on success, negative value otherwise. + * Returns 0. */ -static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) +static int tomoyo_bprm_creds_for_exec(struct linux_binprm *bprm) { - int rc; - - rc = cap_bprm_set_creds(bprm); - if (rc) - return rc; - - /* - * Do only if this function is called for the first time of an execve - * operation. - */ - if (bprm->cred_prepared) - return 0; -#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER /* * 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); -#endif - /* - * Release reference to "struct tomoyo_domain_info" stored inside - * "bprm->cred->security". New reference to "struct tomoyo_domain_info" - * stored inside "bprm->cred->security" will be acquired later inside - * tomoyo_find_next_domain(). - */ - atomic_dec(&((struct tomoyo_domain_info *) - bprm->cred->security)->users); - /* - * Tell tomoyo_bprm_check_security() is called for the first time of an - * execve operation. - */ - bprm->cred->security = NULL; return 0; } +#endif /** * tomoyo_bprm_check_security - Target for security_bprm_check(). @@ -117,37 +91,36 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) */ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) { - struct tomoyo_domain_info *domain = bprm->cred->security; + struct tomoyo_task *s = tomoyo_task(current); /* - * Execute permission is checked against pathname passed to do_execve() + * Execute permission is checked against pathname passed to execve() * using current domain. */ - if (!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(domain, &bprm->file->f_path, - O_RDONLY); + return tomoyo_check_open_permission(s->domain_info, + &bprm->file->f_path, O_RDONLY); } /** * tomoyo_inode_getattr - Target for security_inode_getattr(). * - * @mnt: Pointer to "struct vfsmount". - * @dentry: Pointer to "struct dentry". + * @path: Pointer to "struct path". * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) +static int tomoyo_inode_getattr(const struct path *path) { - struct path path = { mnt, dentry }; - return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path, NULL); + return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, path, NULL); } /** @@ -157,12 +130,24 @@ static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_truncate(struct path *path) +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". @@ -170,9 +155,10 @@ static int tomoyo_path_truncate(struct path *path) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) +static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); } @@ -185,10 +171,11 @@ static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, +static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, umode_t mode) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, mode & S_IALLUGO); } @@ -201,9 +188,10 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) +static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); } @@ -216,10 +204,11 @@ static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, +static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, const char *old_name) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; + return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); } @@ -233,10 +222,10 @@ static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, +static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry, umode_t mode, unsigned int dev) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; int type = TOMOYO_TYPE_CREATE; const unsigned int perm = mode & S_IALLUGO; @@ -272,11 +261,12 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, +static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry) { - struct path path1 = { new_dir->mnt, old_dentry }; - struct path path2 = { new_dir->mnt, 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); } @@ -287,16 +277,26 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, * @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(struct path *old_parent, +static int tomoyo_path_rename(const struct path *old_parent, struct dentry *old_dentry, - struct path *new_parent, - struct dentry *new_dentry) + const struct path *new_parent, + struct dentry *new_dentry, + const unsigned int flags) { - struct path path1 = { old_parent->mnt, old_dentry }; - struct path path2 = { new_parent->mnt, new_dentry }; + 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); } @@ -321,18 +321,18 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, /** * tomoyo_file_open - Target for security_file_open(). * - * @f: Pointer to "struct file". - * @cred: Pointer to "struct cred". + * @f: Pointer to "struct file". * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_file_open(struct file *f, const struct cred *cred) +static int tomoyo_file_open(struct file *f) { - int flags = f->f_flags; - /* Don't check read permission here if called from do_execve(). */ - if (current->in_execve) + /* 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, flags); + return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, + f->f_flags); } /** @@ -358,7 +358,7 @@ static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_chmod(struct path *path, umode_t mode) +static int tomoyo_path_chmod(const struct path *path, umode_t mode) { return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, path, mode & S_IALLUGO); @@ -373,9 +373,10 @@ static int tomoyo_path_chmod(struct path *path, umode_t mode) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_chown(struct path *path, kuid_t uid, kgid_t gid) +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)); @@ -392,7 +393,7 @@ static int tomoyo_path_chown(struct path *path, kuid_t uid, kgid_t gid) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_chroot(struct path *path) +static int tomoyo_path_chroot(const struct path *path) { return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL); } @@ -408,7 +409,7 @@ static int tomoyo_path_chroot(struct path *path) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_sb_mount(const char *dev_name, struct path *path, +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); @@ -424,7 +425,8 @@ static int tomoyo_sb_mount(const char *dev_name, struct path *path, */ static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) { - struct path path = { mnt, mnt->mnt_root }; + struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; + return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); } @@ -436,7 +438,7 @@ static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) +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); } @@ -499,45 +501,95 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, return tomoyo_socket_sendmsg_permission(sock, msg, size); } -/* - * tomoyo_security_ops is a "struct security_operations" which is used for - * registering TOMOYO. - */ -static struct security_operations tomoyo_security_ops = { - .name = "tomoyo", - .cred_alloc_blank = tomoyo_cred_alloc_blank, - .cred_prepare = tomoyo_cred_prepare, - .cred_transfer = tomoyo_cred_transfer, - .cred_free = tomoyo_cred_free, - .bprm_set_creds = tomoyo_bprm_set_creds, - .bprm_check_security = tomoyo_bprm_check_security, - .file_fcntl = tomoyo_file_fcntl, - .file_open = tomoyo_file_open, - .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, - .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, +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, + u64 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_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), }; /* Lock for GC. */ DEFINE_SRCU(tomoyo_ss); +int tomoyo_enabled __ro_after_init = 1; + /** * tomoyo_init - Register TOMOYO Linux as a LSM module. * @@ -545,17 +597,25 @@ DEFINE_SRCU(tomoyo_ss); */ static int __init tomoyo_init(void) { - struct cred *cred = (struct cred *) current_cred(); + struct tomoyo_task *s = tomoyo_task(current); - if (!security_module_enable(&tomoyo_security_ops)) - return 0; /* register ourselves with the security framework */ - if (register_security(&tomoyo_security_ops)) - panic("Failure registering TOMOYO Linux"); - printk(KERN_INFO "TOMOYO Linux initialized\n"); - cred->security = &tomoyo_kernel_domain; + 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; } -security_initcall(tomoyo_init); +DEFINE_LSM(tomoyo) = { + .id = &tomoyo_lsmid, + .enabled = &tomoyo_enabled, + .flags = LSM_FLAG_LEGACY_MAJOR, + .blobs = &tomoyo_blob_sizes, + .init = tomoyo_init, + .initcall_fs = tomoyo_interface_init, +}; |
