apparmor: name null-XXX profiles after the executable
authorJohn Johansen <john.johansen@canonical.com>
Mon, 16 Jan 2017 08:42:36 +0000 (00:42 -0800)
committerJohn Johansen <john.johansen@canonical.com>
Mon, 16 Jan 2017 09:18:30 +0000 (01:18 -0800)
When possible its better to name a learning profile after the missing
profile in question. This allows for both more informative names and
for profile reuse.

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

index 503cb2c..1a8ffc5 100644 (file)
@@ -442,7 +442,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                }
        } else if (COMPLAIN_MODE(profile)) {
                /* no exec permission - are we in learning mode */
-               new_profile = aa_new_null_profile(profile, 0);
+               new_profile = aa_new_null_profile(profile, false, name,
+                                                 GFP_ATOMIC);
                if (!new_profile) {
                        error = -ENOMEM;
                        info = "could not create null profile";
@@ -667,7 +668,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
                        aa_put_profile(root);
                        target = name;
                        /* released below */
-                       hat = aa_new_null_profile(profile, 1);
+                       hat = aa_new_null_profile(profile, true, hats[0],
+                                                 GFP_KERNEL);
                        if (!hat) {
                                info = "failed null profile create";
                                error = -ENOMEM;
@@ -815,7 +817,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
                if (permtest || !COMPLAIN_MODE(profile))
                        goto audit;
                /* released below */
-               target = aa_new_null_profile(profile, 0);
+               target = aa_new_null_profile(profile, false, hname, GFP_KERNEL);
                if (!target) {
                        info = "failed null profile create";
                        error = -ENOMEM;
index b44eaea..3527e3f 100644 (file)
@@ -173,7 +173,8 @@ void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
 
 void aa_free_proxy_kref(struct kref *kref);
 struct aa_profile *aa_alloc_profile(const char *name, gfp_t gfp);
-struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+                                      const char *base, gfp_t gfp);
 void aa_free_profile(struct aa_profile *profile);
 void aa_free_profile_kref(struct kref *kref);
 struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
index e310f3b..dd63ac9 100644 (file)
@@ -288,12 +288,16 @@ fail:
 }
 
 /**
- * aa_new_null_profile - create a new null-X learning profile
+ * aa_new_null_profile - create or find a null-X learning profile
  * @parent: profile that caused this profile to be created (NOT NULL)
  * @hat: true if the null- learning profile is a hat
+ * @base: name to base the null profile off of
+ * @gfp: type of allocation
  *
- * Create a null- complain mode profile used in learning mode.  The name of
- * the profile is unique and follows the format of parent//null-<uniq>.
+ * Find/Create a null- complain mode profile used in learning mode.  The
+ * name of the profile is unique and follows the format of parent//null-XXX.
+ * where XXX is based on the @name or if that fails or is not supplied
+ * a unique number
  *
  * null profiles are added to the profile list but the list does not
  * hold a count on them so that they are automatically released when
@@ -301,27 +305,45 @@ fail:
  *
  * Returns: new refcounted profile else NULL on failure
  */
-struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+                                      const char *base, gfp_t gfp)
 {
-       struct aa_profile *profile = NULL;
+       struct aa_profile *profile;
        char *name;
-       int uniq = atomic_inc_return(&parent->ns->uniq_null);
 
-       /* freed below */
-       name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
+       AA_BUG(!parent);
+
+       if (base) {
+               name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
+                              gfp);
+               if (name) {
+                       sprintf(name, "%s//null-%s", parent->base.hname, base);
+                       goto name;
+               }
+               /* fall through to try shorter uniq */
+       }
+
+       name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
        if (!name)
-               goto fail;
-       sprintf(name, "%s//null-%x", parent->base.hname, uniq);
+               return NULL;
+       sprintf(name, "%s//null-%x", parent->base.hname,
+               atomic_inc_return(&parent->ns->uniq_null));
 
-       profile = aa_alloc_profile(name, GFP_KERNEL);
-       kfree(name);
+name:
+       /* lookup to see if this is a dup creation */
+       profile = aa_find_child(parent, basename(name));
+       if (profile)
+               goto out;
+
+       profile = aa_alloc_profile(name, gfp);
        if (!profile)
                goto fail;
 
        profile->mode = APPARMOR_COMPLAIN;
-       profile->flags = PFLAG_NULL;
+       profile->flags |= PFLAG_NULL;
        if (hat)
                profile->flags |= PFLAG_HAT;
+       profile->path_flags = parent->path_flags;
 
        /* released on free_profile */
        rcu_assign_pointer(profile->parent, aa_get_profile(parent));
@@ -332,9 +354,14 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
        mutex_unlock(&profile->ns->lock);
 
        /* refcount released by caller */
+out:
+       kfree(name);
+
        return profile;
 
 fail:
+       kfree(name);
+       aa_free_profile(profile);
        return NULL;
 }