From 97fb35e413f256ded07b88c73b3d932ec31ea84e Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 8 Jul 2011 13:25:53 +0900 Subject: [PATCH] TOMOYO: Enable conditional ACL. Enable conditional ACL by passing object's pointers. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.h | 3 ++- security/tomoyo/domain.c | 53 +++++++++++++++++++++++----------------- security/tomoyo/file.c | 35 +++++++++++++++++++++++++- security/tomoyo/mount.c | 8 +++++- security/tomoyo/tomoyo.c | 14 +++++------ 5 files changed, 80 insertions(+), 33 deletions(-) diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 6c013b177791..f7fbaa66e443 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -836,7 +836,8 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, struct path *path2); int tomoyo_path_number_perm(const u8 operation, struct path *path, unsigned long number); -int tomoyo_path_perm(const u8 operation, struct path *path); +int tomoyo_path_perm(const u8 operation, struct path *path, + const char *target); int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, const struct tomoyo_path_info *filename); int tomoyo_poll_control(struct file *file, poll_table *wait); diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 565249c42e39..878d0206f43e 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -575,23 +575,27 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, */ int tomoyo_find_next_domain(struct linux_binprm *bprm) { - struct tomoyo_request_info r; - char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); struct tomoyo_domain_info *old_domain = tomoyo_domain(); struct tomoyo_domain_info *domain = NULL; const char *original_name = bprm->filename; - u8 mode; - bool is_enforce; int retval = -ENOMEM; bool need_kfree = false; bool reject_on_transition_failure = false; struct tomoyo_path_info rn = { }; /* real name */ - - mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); - is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); - if (!tmp) - goto out; - + struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); + if (!ee) + return -ENOMEM; + ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); + if (!ee->tmp) { + kfree(ee); + return -ENOMEM; + } + /* ee->dump->data is allocated by tomoyo_dump_page(). */ + tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE); + ee->r.ee = ee; + ee->bprm = bprm; + ee->r.obj = &ee->obj; + ee->obj.path1 = bprm->file->f_path; retry: if (need_kfree) { kfree(rn.name); @@ -625,7 +629,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) } /* Check execute permission. */ - retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn); + retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn); if (retval == TOMOYO_RETRY_REQUEST) goto retry; if (retval < 0) @@ -636,12 +640,12 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) * wildcard) rather than the pathname passed to execve() * (which never contains wildcard). */ - if (r.param.path.matched_path) { + if (ee->r.param.path.matched_path) { if (need_kfree) kfree(rn.name); need_kfree = false; /* This is OK because it is read only. */ - rn = *r.param.path.matched_path; + rn = *ee->r.param.path.matched_path; } /* Calculate domain to transit to. */ @@ -649,7 +653,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) &rn)) { case TOMOYO_TRANSITION_CONTROL_RESET: /* Transit to the root of specified namespace. */ - snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); + snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); /* * Make do_execve() fail if domain transition across namespaces * has failed. @@ -658,7 +662,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) break; case TOMOYO_TRANSITION_CONTROL_INITIALIZE: /* Transit to the child of current namespace's root. */ - snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", + snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", old_domain->ns->name, rn.name); break; case TOMOYO_TRANSITION_CONTROL_KEEP: @@ -677,29 +681,30 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) domain = old_domain; } else { /* Normal domain transition. */ - snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", + snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", old_domain->domainname->name, rn.name); } break; } if (!domain) - domain = tomoyo_assign_domain(tmp, true); + domain = tomoyo_assign_domain(ee->tmp, true); if (domain) retval = 0; else if (reject_on_transition_failure) { - printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", tmp); + printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", + ee->tmp); retval = -ENOMEM; - } else if (r.mode == TOMOYO_CONFIG_ENFORCING) + } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING) retval = -ENOMEM; else { retval = 0; if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) { old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true; - r.granted = false; - tomoyo_write_log(&r, "%s", tomoyo_dif + ee->r.granted = false; + tomoyo_write_log(&ee->r, "%s", tomoyo_dif [TOMOYO_DIF_TRANSITION_FAILED]); printk(KERN_WARNING - "ERROR: Domain '%s' not defined.\n", tmp); + "ERROR: Domain '%s' not defined.\n", ee->tmp); } } out: @@ -710,7 +715,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) bprm->cred->security = domain; if (need_kfree) kfree(rn.name); - kfree(tmp); + kfree(ee->tmp); + kfree(ee->dump.data); + kfree(ee); return retval; } diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 6ab9e4cdd61f..31a9a4ab7af9 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -667,6 +667,9 @@ int tomoyo_path_number_perm(const u8 type, struct path *path, unsigned long number) { struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path, + }; int error = -ENOMEM; struct tomoyo_path_info buf; int idx; @@ -677,6 +680,7 @@ int tomoyo_path_number_perm(const u8 type, struct path *path, idx = tomoyo_read_lock(); if (!tomoyo_get_realpath(&buf, path)) goto out; + r.obj = &obj; if (type == TOMOYO_TYPE_MKDIR) tomoyo_add_slash(&buf); r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; @@ -711,6 +715,9 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, int error = 0; struct tomoyo_path_info buf; struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path, + }; int idx; buf.name = NULL; @@ -723,6 +730,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, error = -ENOMEM; goto out; } + r.obj = &obj; if (acc_mode & MAY_READ) error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ, &buf); @@ -745,15 +753,21 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, * * @operation: Type of operation. * @path: Pointer to "struct path". + * @target: Symlink's target if @operation is TOMOYO_TYPE_SYMLINK, + * NULL otherwise. * * Returns 0 on success, negative value otherwise. */ -int tomoyo_path_perm(const u8 operation, struct path *path) +int tomoyo_path_perm(const u8 operation, struct path *path, const char *target) { struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path, + }; int error; struct tomoyo_path_info buf; bool is_enforce; + struct tomoyo_path_info symlink_target; int idx; if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) @@ -765,13 +779,23 @@ int tomoyo_path_perm(const u8 operation, struct path *path) idx = tomoyo_read_lock(); if (!tomoyo_get_realpath(&buf, path)) goto out; + r.obj = &obj; switch (operation) { case TOMOYO_TYPE_RMDIR: case TOMOYO_TYPE_CHROOT: tomoyo_add_slash(&buf); break; + case TOMOYO_TYPE_SYMLINK: + symlink_target.name = tomoyo_encode(target); + if (!symlink_target.name) + goto out; + tomoyo_fill_path_info(&symlink_target); + obj.symlink_target = &symlink_target; + break; } error = tomoyo_path_permission(&r, operation, &buf); + if (operation == TOMOYO_TYPE_SYMLINK) + kfree(symlink_target.name); out: kfree(buf.name); tomoyo_read_unlock(idx); @@ -794,6 +818,9 @@ int tomoyo_mkdev_perm(const u8 operation, struct path *path, const unsigned int mode, unsigned int dev) { struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path, + }; int error = -ENOMEM; struct tomoyo_path_info buf; int idx; @@ -804,6 +831,7 @@ int tomoyo_mkdev_perm(const u8 operation, struct path *path, idx = tomoyo_read_lock(); error = -ENOMEM; if (tomoyo_get_realpath(&buf, path)) { + r.obj = &obj; dev = new_decode_dev(dev); r.param_type = TOMOYO_TYPE_MKDEV_ACL; r.param.mkdev.filename = &buf; @@ -837,6 +865,10 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, struct tomoyo_path_info buf1; struct tomoyo_path_info buf2; struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path1, + .path2 = *path2, + }; int idx; if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) @@ -861,6 +893,7 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, tomoyo_add_slash(&buf2); break; } + r.obj = &obj; r.param_type = TOMOYO_TYPE_PATH2_ACL; r.param.path2.operation = operation; r.param.path2.filename1 = &buf1; diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 0bbba8b67821..408385307470 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -75,6 +75,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, struct path *dir, const char *type, unsigned long flags) { + struct tomoyo_obj_info obj = { }; struct path path; struct file_system_type *fstype = NULL; const char *requested_type = NULL; @@ -85,6 +86,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, struct tomoyo_path_info rdir; int need_dev = 0; int error = -ENOMEM; + r->obj = &obj; /* Get fstype. */ requested_type = tomoyo_encode(type); @@ -94,6 +96,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, tomoyo_fill_path_info(&rtype); /* Get mount point. */ + obj.path2 = *dir; requested_dir_name = tomoyo_realpath_from_path(dir); if (!requested_dir_name) { error = -ENOMEM; @@ -129,8 +132,8 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, error = -ENOENT; goto out; } + obj.path1 = path; requested_dev_name = tomoyo_realpath_from_path(&path); - path_put(&path); if (!requested_dev_name) { error = -ENOENT; goto out; @@ -163,6 +166,9 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, if (fstype) put_filesystem(fstype); kfree(requested_type); + /* Drop refcount obtained by kern_path(). */ + if (obj.path1.dentry) + path_put(&obj.path1); return error; } diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index d6f68a0ec2dc..a536cb182c05 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -98,18 +98,18 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) { struct path path = { mnt, dentry }; - return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path); + return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path, NULL); } static int tomoyo_path_truncate(struct path *path) { - return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path); + return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL); } static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) { struct path path = { parent->mnt, dentry }; - return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path); + return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); } static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, @@ -123,14 +123,14 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) { struct path path = { parent->mnt, dentry }; - return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path); + return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); } static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, const char *old_name) { struct path path = { parent->mnt, dentry }; - return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path); + return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); } static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, @@ -225,7 +225,7 @@ static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) static int tomoyo_path_chroot(struct path *path) { - return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path); + return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL); } static int tomoyo_sb_mount(char *dev_name, struct path *path, @@ -237,7 +237,7 @@ static int tomoyo_sb_mount(char *dev_name, struct path *path, static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) { struct path path = { mnt, mnt->mnt_root }; - return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path); + return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); } static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path)