[apparmor] [PATCH 17/36] apparmor: reuse name string from previous profile

John Johansen john.johansen at canonical.com
Wed May 1 21:31:02 UTC 2013


For profiles that have been replaced reuse the name string so the
old and new version of the profile share the same string.  This will
make some checks/comparisons in labeling quicker.

Signed-off-by: John Johansen <john.johansen at canonical.com>
---
 security/apparmor/apparmorfs.c       |  2 +-
 security/apparmor/include/apparmor.h | 30 ++++++++++++++++++++++++++++++
 security/apparmor/include/policy.h   |  6 +++---
 security/apparmor/lib.c              | 17 +++++++++++++++++
 security/apparmor/policy.c           | 35 +++++++++++++++++++++++++----------
 5 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 6d0f0f8..9397542 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -36,7 +36,7 @@
  *
  * Returns: length of mangled name
  */
-static int mangle_name(char *name, char *target)
+static int mangle_name(const char *name, char *target)
 {
 	char *t = target;
 
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 3172801..acdd923 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -119,4 +119,34 @@ static inline bool mediated_filesystem(struct inode *inode)
 	return !(inode->i_sb->s_flags & MS_NOUSER);
 }
 
+
+struct counted_str {
+	struct kref count;
+	char name[];
+};
+
+#define str_to_counted(str) \
+	((struct counted_str *)(str - offsetof(struct counted_str,name)))
+
+#define __counted	/* atm just a notation */
+
+void aa_str_kref(struct kref *kref);
+char *aa_str_alloc(int size, gfp_t gfp);
+
+
+static inline __counted char *aa_get_str(__counted char *str)
+{
+	if (str)
+		kref_get(&(str_to_counted(str)->count));
+
+	return str;
+}
+
+static inline void aa_put_str(__counted char *str)
+{
+	if (str)
+		kref_put(&str_to_counted(str)->count, aa_str_kref);
+}
+
+
 #endif /* __APPARMOR_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 4dd5e63..0b247b3 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -77,13 +77,13 @@ struct aa_profile;
 
 /* struct aa_policy - common part of both namespaces and profiles
  * @name: name of the object
- * @hname - The hierarchical name
+ * @hname - The hierarchical name, NOTE: is .name of struct counted_str
  * @list: list policy object is on
  * @profiles: head of the profiles list contained in the object
  */
 struct aa_policy {
-	char *name;
-	char *hname;
+	const char *name;
+	__counted char *hname;
 	struct list_head list;
 	struct list_head profiles;
 };
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index d40bc59..31fb900 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -141,3 +141,20 @@ void kvfree(void *buffer)
 	} else
 		kfree(buffer);
 }
+
+
+__counted char *aa_str_alloc(int size, gfp_t gfp)
+{
+	struct counted_str *str;
+	str = kmalloc(sizeof(struct counted_str) + size, gfp);
+	if (!str)
+		return NULL;
+
+	kref_init(&str->count);
+	return str->name;
+}
+
+void aa_str_kref(struct kref *kref)
+{
+	kfree(container_of(kref, struct counted_str, count));
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 4a5f55a..935ba8e 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -129,16 +129,22 @@ static const char *hname_tail(const char *hname)
 static bool policy_init(struct aa_policy *policy, const char *prefix,
 			const char *name)
 {
+	char *hname;
+
 	/* freed by policy_free */
 	if (prefix) {
-		policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
-					GFP_KERNEL);
-		if (policy->hname)
-			sprintf(policy->hname, "%s//%s", prefix, name);
-	} else
-		policy->hname = kstrdup(name, GFP_KERNEL);
-	if (!policy->hname)
+		hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3,
+				     GFP_KERNEL);
+		if (hname)
+			sprintf(hname, "%s//%s", prefix, name);
+	} else {
+		hname = aa_str_alloc(strlen(name) + 1, GFP_KERNEL);
+		if (hname)
+			strcpy(hname, name);
+	}
+	if (!hname)
 		return 0;
+	policy->hname = hname;
 	/* base.name is a substring of fqname */
 	policy->name = (char *)hname_tail(policy->hname);
 	INIT_LIST_HEAD(&policy->list);
@@ -167,7 +173,7 @@ static void policy_destroy(struct aa_policy *policy)
 	}
 
 	/* don't free name as its a subset of hname */
-	kzfree(policy->hname);
+	aa_put_str(policy->hname);
 }
 
 /**
@@ -710,7 +716,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
 		goto fail;
 
 	profile->mode = APPARMOR_COMPLAIN;
-	profile->flags = PFLAG_NULL;
+	profile->flags |= PFLAG_NULL;
 	if (hat)
 		profile->flags |= PFLAG_HAT;
 
@@ -739,7 +745,7 @@ struct aa_profile *aa_setup_default_profile(void)
 		return NULL;
 
 	/* the default profile pretends to be unconfined until it is replaced */
-	profile->flags = PFLAG_IX_ON_NAME_ERROR;
+	profile->flags |= PFLAG_IX_ON_NAME_ERROR;
 	profile->mode = APPARMOR_UNCONFINED;
 
 	profile->ns = aa_get_namespace(root_ns);
@@ -1084,6 +1090,14 @@ static int __lookup_replace(struct aa_namespace *ns, const char *hname,
 	return 0;
 }
 
+static void share_name(struct aa_profile *old, struct aa_profile *new)
+{
+	aa_put_str(new->base.hname);
+	aa_get_str(old->base.hname);
+	new->base.hname = old->base.hname;
+	new->base.name = old->base.name;
+}
+
 /**
  * aa_replace_profiles - replace profile(s) on the profile list
  * @udata: serialized data stream  (NOT NULL)
@@ -1197,6 +1211,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
 		audit_policy(op, GFP_ATOMIC, ent->new->base.name, NULL, error);
 
 		if (ent->old) {
+			share_name(ent->old, ent->new);
 			__replace_profile(ent->old, ent->new, 1);
 			if (ent->rename) {
 			/* aafs interface uses replacedby */
-- 
1.8.1.2




More information about the AppArmor mailing list