TOMOYO: Simplify garbage collector.
[deliverable/linux.git] / security / tomoyo / domain.c
index 498fea732f4843f537fa3c66b5b1a96006a4d8e5..da16dfeed72800f26bd9bc12b8f68610f51706a1 100644 (file)
@@ -39,6 +39,8 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return -ENOMEM;
        list_for_each_entry_rcu(entry, list, list) {
+               if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
+                       continue;
                if (!check_duplicate(entry, new_entry))
                        continue;
                entry->is_deleted = param->is_delete;
@@ -102,10 +104,21 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
                new_entry->cond = tomoyo_get_condition(param);
                if (!new_entry->cond)
                        return -EINVAL;
+               /*
+                * Domain transition preference is allowed for only
+                * "file execute" entries.
+                */
+               if (new_entry->cond->transit &&
+                   !(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
+                     container_of(new_entry, struct tomoyo_path_acl, head)
+                     ->perm == 1 << TOMOYO_TYPE_EXECUTE))
+                       goto out;
        }
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                goto out;
        list_for_each_entry_rcu(entry, list, list) {
+               if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
+                       continue;
                if (!tomoyo_same_acl_head(entry, new_entry) ||
                    !check_duplicate(entry, new_entry))
                        continue;
@@ -558,6 +571,7 @@ out:
                        tomoyo_write_log(&r, "use_profile %u\n",
                                         entry->profile);
                        tomoyo_write_log(&r, "use_group %u\n", entry->group);
+                       tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
                }
        }
        return entry;
@@ -664,9 +678,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
        struct tomoyo_domain_info *domain = NULL;
        const char *original_name = bprm->filename;
        int retval = -ENOMEM;
-       bool need_kfree = false;
        bool reject_on_transition_failure = false;
-       struct tomoyo_path_info rn = { }; /* real name */
+       const struct tomoyo_path_info *candidate;
+       struct tomoyo_path_info exename;
        struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
 
        if (!ee)
@@ -682,40 +696,32 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
        ee->bprm = bprm;
        ee->r.obj = &ee->obj;
        ee->obj.path1 = bprm->file->f_path;
- retry:
-       if (need_kfree) {
-               kfree(rn.name);
-               need_kfree = false;
-       }
        /* Get symlink's pathname of program. */
        retval = -ENOENT;
-       rn.name = tomoyo_realpath_nofollow(original_name);
-       if (!rn.name)
+       exename.name = tomoyo_realpath_nofollow(original_name);
+       if (!exename.name)
                goto out;
-       tomoyo_fill_path_info(&rn);
-       need_kfree = true;
-
+       tomoyo_fill_path_info(&exename);
+retry:
        /* Check 'aggregator' directive. */
        {
                struct tomoyo_aggregator *ptr;
                struct list_head *list =
                        &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
                /* Check 'aggregator' directive. */
+               candidate = &exename;
                list_for_each_entry_rcu(ptr, list, head.list) {
                        if (ptr->head.is_deleted ||
-                           !tomoyo_path_matches_pattern(&rn,
+                           !tomoyo_path_matches_pattern(&exename,
                                                         ptr->original_name))
                                continue;
-                       kfree(rn.name);
-                       need_kfree = false;
-                       /* This is OK because it is read only. */
-                       rn = *ptr->aggregated_name;
+                       candidate = ptr->aggregated_name;
                        break;
                }
        }
 
        /* Check execute permission. */
-       retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn);
+       retval = tomoyo_execute_permission(&ee->r, candidate);
        if (retval == TOMOYO_RETRY_REQUEST)
                goto retry;
        if (retval < 0)
@@ -726,20 +732,51 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
         * wildcard) rather than the pathname passed to execve()
         * (which never contains wildcard).
         */
-       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 = *ee->r.param.path.matched_path;
-       }
+       if (ee->r.param.path.matched_path)
+               candidate = ee->r.param.path.matched_path;
 
-       /* Calculate domain to transit to. */
+       /*
+        * Check for domain transition preference if "file execute" matched.
+        * If preference is given, make do_execve() fail if domain transition
+        * has failed, for domain transition preference should be used with
+        * destination domain defined.
+        */
+       if (ee->transition) {
+               const char *domainname = ee->transition->name;
+               reject_on_transition_failure = true;
+               if (!strcmp(domainname, "keep"))
+                       goto force_keep_domain;
+               if (!strcmp(domainname, "child"))
+                       goto force_child_domain;
+               if (!strcmp(domainname, "reset"))
+                       goto force_reset_domain;
+               if (!strcmp(domainname, "initialize"))
+                       goto force_initialize_domain;
+               if (!strcmp(domainname, "parent")) {
+                       char *cp;
+                       strncpy(ee->tmp, old_domain->domainname->name,
+                               TOMOYO_EXEC_TMPSIZE - 1);
+                       cp = strrchr(ee->tmp, ' ');
+                       if (cp)
+                               *cp = '\0';
+               } else if (*domainname == '<')
+                       strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
+               else
+                       snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+                                old_domain->domainname->name, domainname);
+               goto force_jump_domain;
+       }
+       /*
+        * No domain transition preference specified.
+        * Calculate domain to transit to.
+        */
        switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
-                                      &rn)) {
+                                      candidate)) {
        case TOMOYO_TRANSITION_CONTROL_RESET:
+force_reset_domain:
                /* Transit to the root of specified namespace. */
-               snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
+               snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
+                        candidate->name);
                /*
                 * Make do_execve() fail if domain transition across namespaces
                 * has failed.
@@ -747,11 +784,13 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
                reject_on_transition_failure = true;
                break;
        case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
+force_initialize_domain:
                /* Transit to the child of current namespace's root. */
                snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
-                        old_domain->ns->name, rn.name);
+                        old_domain->ns->name, candidate->name);
                break;
        case TOMOYO_TRANSITION_CONTROL_KEEP:
+force_keep_domain:
                /* Keep current domain. */
                domain = old_domain;
                break;
@@ -765,13 +804,15 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
                         * before /sbin/init.
                         */
                        domain = old_domain;
-               } else {
-                       /* Normal domain transition. */
-                       snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
-                                old_domain->domainname->name, rn.name);
+                       break;
                }
+force_child_domain:
+               /* Normal domain transition. */
+               snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+                        old_domain->domainname->name, candidate->name);
                break;
        }
+force_jump_domain:
        if (!domain)
                domain = tomoyo_assign_domain(ee->tmp, true);
        if (domain)
@@ -799,8 +840,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
        /* Update reference count on "struct tomoyo_domain_info". */
        atomic_inc(&domain->users);
        bprm->cred->security = domain;
-       if (need_kfree)
-               kfree(rn.name);
+       kfree(exename.name);
        if (!retval) {
                ee->r.domain = domain;
                retval = tomoyo_environ(ee);
This page took 0.030862 seconds and 5 git commands to generate.