Browse Source

apparmor: name null-XXX profiles after the executable

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>
John Johansen 8 years ago
parent
commit
181f7c9776
3 changed files with 47 additions and 17 deletions
  1. 5 3
      security/apparmor/domain.c
  2. 2 1
      security/apparmor/include/policy.h
  3. 40 13
      security/apparmor/policy.c

+ 5 - 3
security/apparmor/domain.c

@@ -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;

+ 2 - 1
security/apparmor/include/policy.h

@@ -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);

+ 40 - 13
security/apparmor/policy.c

@@ -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;
 }