apparmor: convert change_profile to use fqname later to give better control
authorJohn Johansen <john.johansen@canonical.com>
Mon, 16 Jan 2017 08:43:06 +0000 (00:43 -0800)
committerJohn Johansen <john.johansen@canonical.com>
Mon, 16 Jan 2017 09:18:49 +0000 (01:18 -0800)
Moving the use of fqname to later allows learning profiles to be based
on the fqname request instead of just the hname. It also allows cleaning
up some of the name parsing and lookup by allowing the use of
the fqlookupn_profile() lib fn.

Signed-off-by: John Johansen <john.johansen@canonical.com>
security/apparmor/apparmorfs.c
security/apparmor/domain.c
security/apparmor/include/domain.h
security/apparmor/lsm.c
security/apparmor/procattr.c

index fd0d9e38b6c6089f75ce67b5eaae139723bcc499..7613a28f157e185ec62f761e8d5b97b355989d85 100644 (file)
@@ -1052,6 +1052,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
        AA_FS_FILE_BOOLEAN("change_onexec",     1),
        AA_FS_FILE_BOOLEAN("change_profile",    1),
        AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap",       1),
+       AA_FS_FILE_STRING("version", "1.2"),
        { }
 };
 
index d18b3f0e553442a77b2b0a111a1fcde6e26d2319..ef4beef06e9d8f84e8b2364f286642452349bf00 100644 (file)
@@ -729,8 +729,7 @@ out:
 
 /**
  * aa_change_profile - perform a one-way profile transition
- * @ns_name: name of the profile namespace to change to (MAYBE NULL)
- * @hname: name of profile to change to (MAYBE NULL)
+ * @fqname: name of profile may include namespace (NOT NULL)
  * @onexec: whether this transition is to take place immediately or at exec
  * @permtest: true if this is just a permission test
  *
@@ -742,19 +741,20 @@ out:
  *
  * Returns %0 on success, error otherwise.
  */
-int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
-                     bool permtest)
+int aa_change_profile(const char *fqname, bool onexec,
+                     bool permtest, bool stack)
 {
        const struct cred *cred;
        struct aa_profile *profile, *target = NULL;
-       struct aa_ns *ns = NULL;
        struct file_perms perms = {};
-       const char *name = NULL, *info = NULL, *op;
+       const char *info = NULL, *op;
        int error = 0;
        u32 request;
 
-       if (!hname && !ns_name)
+       if (!fqname || !*fqname) {
+               AA_DEBUG("no profile name");
                return -EINVAL;
+       }
 
        if (onexec) {
                request = AA_MAY_ONEXEC;
@@ -779,44 +779,15 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
                return -EPERM;
        }
 
-       if (ns_name) {
-               /* released below */
-               ns = aa_find_ns(profile->ns, ns_name);
-               if (!ns) {
-                       /* we don't create new namespace in complain mode */
-                       name = ns_name;
-                       info = "namespace not found";
-                       error = -ENOENT;
-                       goto audit;
-               }
-       } else
-               /* released below */
-               ns = aa_get_ns(profile->ns);
-
-       /* if the name was not specified, use the name of the current profile */
-       if (!hname) {
-               if (unconfined(profile))
-                       hname = ns->unconfined->base.hname;
-               else
-                       hname = profile->base.hname;
-       }
-
-       perms = change_profile_perms(profile, ns, hname, request,
-                                    profile->file.start);
-       if (!(perms.allow & request)) {
-               error = -EACCES;
-               goto audit;
-       }
-
-       /* released below */
-       target = aa_lookup_profile(ns, hname);
+       target = aa_fqlookupn_profile(profile, fqname, strlen(fqname));
        if (!target) {
                info = "profile not found";
                error = -ENOENT;
                if (permtest || !COMPLAIN_MODE(profile))
                        goto audit;
                /* released below */
-               target = aa_new_null_profile(profile, false, hname, GFP_KERNEL);
+               target = aa_new_null_profile(profile, false, fqname,
+                                            GFP_KERNEL);
                if (!target) {
                        info = "failed null profile create";
                        error = -ENOMEM;
@@ -824,6 +795,13 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
                }
        }
 
+       perms = change_profile_perms(profile, target->ns, target->base.hname,
+                                    request, profile->file.start);
+       if (!(perms.allow & request)) {
+               error = -EACCES;
+               goto audit;
+       }
+
        /* check if tracing task is allowed to trace target domain */
        error = may_change_ptraced_domain(target);
        if (error) {
@@ -841,10 +819,9 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
 
 audit:
        if (!permtest)
-               error = aa_audit_file(profile, &perms, op, request, name,
-                                     hname, GLOBAL_ROOT_UID, info, error);
+               error = aa_audit_file(profile, &perms, op, request, NULL,
+                                     fqname, GLOBAL_ROOT_UID, info, error);
 
-       aa_put_ns(ns);
        aa_put_profile(target);
        put_cred(cred);
 
index de04464f0a3fdb0232d4343ef26afffa02613613..30544729878a22903c6b374ce270b0c9a7a5bdd5 100644 (file)
@@ -30,7 +30,7 @@ void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
 
 void aa_free_domain_entries(struct aa_domain *domain);
 int aa_change_hat(const char *hats[], int count, u64 token, bool permtest);
-int aa_change_profile(const char *ns_name, const char *name, bool onexec,
-                     bool permtest);
+int aa_change_profile(const char *fqname, bool onexec, bool permtest,
+                     bool stack);
 
 #endif /* __AA_DOMAIN_H */
index c4bae8ae538ffb1f21493b6994d7087df81f916a..264aa192032edb2be253ccb802c9f2b5fc1472a5 100644 (file)
@@ -543,17 +543,17 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
                        error = aa_setprocattr_changehat(args, arg_size,
                                                         AA_DO_TEST);
                } else if (strcmp(command, "changeprofile") == 0) {
-                       error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
-                                                            !AA_DO_TEST);
+                       error = aa_change_profile(args, !AA_ONEXEC,
+                                                 !AA_DO_TEST, false);
                } else if (strcmp(command, "permprofile") == 0) {
-                       error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
-                                                            AA_DO_TEST);
+                       error = aa_change_profile(args, !AA_ONEXEC, AA_DO_TEST,
+                                                 false);
                } else
                        goto fail;
        } else if (strcmp(name, "exec") == 0) {
                if (strcmp(command, "exec") == 0)
-                       error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
-                                                            !AA_DO_TEST);
+                       error = aa_change_profile(args, AA_ONEXEC, !AA_DO_TEST,
+                                                 false);
                else
                        goto fail;
        } else
index a9a9ee6659ae5ebc70e860a7bb5a98a308c33960..3466a27bca098fc4d75324fc5df4f744d43e8077 100644 (file)
@@ -149,19 +149,3 @@ int aa_setprocattr_changehat(char *args, size_t size, int test)
 
        return aa_change_hat(hats, count, token, test);
 }
-
-/**
- * aa_setprocattr_changeprofile - handle procattr interface to changeprofile
- * @fqname: args received from writting to /proc/<pid>/attr/current (NOT NULL)
- * @onexec: true if change_profile should be delayed until exec
- * @test: true if this is a test of change_profile permissions
- *
- * Returns: %0 or error code if change_profile fails
- */
-int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
-{
-       char *name, *ns_name;
-
-       name = aa_split_fqname(fqname, &ns_name);
-       return aa_change_profile(ns_name, name, onexec, test);
-}