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 <[email protected]> --- 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 -- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
