TOMOYO: Enable conditional ACL.
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Fri, 8 Jul 2011 04:25:53 +0000 (13:25 +0900)
committerJames Morris <jmorris@namei.org>
Mon, 11 Jul 2011 01:05:34 +0000 (11:05 +1000)
Enable conditional ACL by passing object's pointers.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
security/tomoyo/common.h
security/tomoyo/domain.c
security/tomoyo/file.c
security/tomoyo/mount.c
security/tomoyo/tomoyo.c

index 6c013b1..f7fbaa6 100644 (file)
@@ -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);
index 565249c..878d020 100644 (file)
@@ -575,23 +575,27 @@ out:
  */
 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;
 }
 
index 6ab9e4c..31a9a4a 100644 (file)
@@ -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;
index 0bbba8b..4083853 100644 (file)
@@ -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;
 }
 
index d6f68a0..a536cb1 100644 (file)
@@ -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)