TOMOYO: Allow specifying domain transition preference.
[pandora-kernel.git] / security / tomoyo / domain.c
index a1fc6b5..860390e 100644 (file)
@@ -102,6 +102,15 @@ 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;
@@ -707,8 +716,7 @@ retry:
        }
 
        /* Check execute permission. */
-       retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE,
-                                       candidate);
+       retval = tomoyo_execute_permission(&ee->r, candidate);
        if (retval == TOMOYO_RETRY_REQUEST)
                goto retry;
        if (retval < 0)
@@ -722,10 +730,45 @@ retry:
        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,
                                       candidate)) {
        case TOMOYO_TRANSITION_CONTROL_RESET:
+force_reset_domain:
                /* Transit to the root of specified namespace. */
                snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
                         candidate->name);
@@ -736,11 +779,13 @@ retry:
                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, candidate->name);
                break;
        case TOMOYO_TRANSITION_CONTROL_KEEP:
+force_keep_domain:
                /* Keep current domain. */
                domain = old_domain;
                break;
@@ -756,11 +801,13 @@ retry:
                        domain = old_domain;
                        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)