summaryrefslogtreecommitdiffstats
path: root/security/apparmor/policy.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 11:26:35 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 11:26:35 -0700
commite24dd9ee5399747b71c1d982a484fc7601795f31 (patch)
tree14fcec8728916092a9f6dbeb0f2b8d5c5a4e5c9a /security/apparmor/policy.c
parent7391786a64dcfe9c609a1f8e2204c1abf42ded23 (diff)
parentc4758fa59285fe4dbfeab4364a6957936d040fbf (diff)
downloadlinux-e24dd9ee5399747b71c1d982a484fc7601795f31.tar.gz
linux-e24dd9ee5399747b71c1d982a484fc7601795f31.tar.bz2
linux-e24dd9ee5399747b71c1d982a484fc7601795f31.zip
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris: - a major update for AppArmor. From JJ: * several bug fixes and cleanups * the patch to add symlink support to securityfs that was floated on the list earlier and the apparmorfs changes that make use of securityfs symlinks * it introduces the domain labeling base code that Ubuntu has been carrying for several years, with several cleanups applied. And it converts the current mediation over to using the domain labeling base, which brings domain stacking support with it. This finally will bring the base upstream code in line with Ubuntu and provide a base to upstream the new feature work that Ubuntu carries. * This does _not_ contain any of the newer apparmor mediation features/controls (mount, signals, network, keys, ...) that Ubuntu is currently carrying, all of which will be RFC'd on top of this. - Notable also is the Infiniband work in SELinux, and the new file:map permission. From Paul: "While we're down to 21 patches for v4.13 (it was 31 for v4.12), the diffstat jumps up tremendously with over 2k of line changes. Almost all of these changes are the SELinux/IB work done by Daniel Jurgens; some other noteworthy changes include a NFS v4.2 labeling fix, a new file:map permission, and reporting of policy capabilities on policy load" There's also now genfscon labeling support for tracefs, which was lost in v4.1 with the separation from debugfs. - Smack incorporates a safer socket check in file_receive, and adds a cap_capable call in privilege check. - TPM as usual has a bunch of fixes and enhancements. - Multiple calls to security_add_hooks() can now be made for the same LSM, to allow LSMs to have hook declarations across multiple files. - IMA now supports different "ima_appraise=" modes (eg. log, fix) from the boot command line. * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (126 commits) apparmor: put back designators in struct initialisers seccomp: Switch from atomic_t to recount_t seccomp: Adjust selftests to avoid double-join seccomp: Clean up core dump logic IMA: update IMA policy documentation to include pcr= option ima: Log the same audit cause whenever a file has no signature ima: Simplify policy_func_show. integrity: Small code improvements ima: fix get_binary_runtime_size() ima: use ima_parse_buf() to parse template data ima: use ima_parse_buf() to parse measurements headers ima: introduce ima_parse_buf() ima: Add cgroups2 to the defaults list ima: use memdup_user_nul ima: fix up #endif comments IMA: Correct Kconfig dependencies for hash selection ima: define is_ima_appraise_enabled() ima: define Kconfig IMA_APPRAISE_BOOTPARAM option ima: define a set of appraisal rules requiring file signatures ima: extend the "ima_policy" boot command line to support multiple policies ...
Diffstat (limited to 'security/apparmor/policy.c')
-rw-r--r--security/apparmor/policy.c392
1 files changed, 210 insertions, 182 deletions
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index cf9d670dca94..244ea4a4a8f0 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -101,20 +101,9 @@ const char *const aa_profile_mode_names[] = {
"unconfined",
};
-/* requires profile list write lock held */
-void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new)
-{
- struct aa_profile *tmp;
-
- tmp = rcu_dereference_protected(orig->proxy->profile,
- mutex_is_locked(&orig->ns->lock));
- rcu_assign_pointer(orig->proxy->profile, aa_get_profile(new));
- orig->flags |= PFLAG_STALE;
- aa_put_profile(tmp);
-}
/**
- * __list_add_profile - add a profile to a list
+ * __add_profile - add a profiles to list and label tree
* @list: list to add it to (NOT NULL)
* @profile: the profile to add (NOT NULL)
*
@@ -122,12 +111,21 @@ void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new)
*
* Requires: namespace lock be held, or list not be shared
*/
-static void __list_add_profile(struct list_head *list,
- struct aa_profile *profile)
+static void __add_profile(struct list_head *list, struct aa_profile *profile)
{
+ struct aa_label *l;
+
+ AA_BUG(!list);
+ AA_BUG(!profile);
+ AA_BUG(!profile->ns);
+ AA_BUG(!mutex_is_locked(&profile->ns->lock));
+
list_add_rcu(&profile->base.list, list);
/* get list reference */
aa_get_profile(profile);
+ l = aa_label_insert(&profile->ns->labels, &profile->label);
+ AA_BUG(l != &profile->label);
+ aa_put_label(l);
}
/**
@@ -144,6 +142,10 @@ static void __list_add_profile(struct list_head *list,
*/
static void __list_remove_profile(struct aa_profile *profile)
{
+ AA_BUG(!profile);
+ AA_BUG(!profile->ns);
+ AA_BUG(!mutex_is_locked(&profile->ns->lock));
+
list_del_rcu(&profile->base.list);
aa_put_profile(profile);
}
@@ -156,11 +158,15 @@ static void __list_remove_profile(struct aa_profile *profile)
*/
static void __remove_profile(struct aa_profile *profile)
{
+ AA_BUG(!profile);
+ AA_BUG(!profile->ns);
+ AA_BUG(!mutex_is_locked(&profile->ns->lock));
+
/* release any children lists first */
__aa_profile_list_release(&profile->base.profiles);
/* released by free_profile */
- __aa_update_proxy(profile, profile->ns->unconfined);
- __aa_fs_profile_rmdir(profile);
+ aa_label_remove(&profile->label);
+ __aafs_profile_rmdir(profile);
__list_remove_profile(profile);
}
@@ -177,24 +183,6 @@ void __aa_profile_list_release(struct list_head *head)
__remove_profile(profile);
}
-
-static void free_proxy(struct aa_proxy *p)
-{
- if (p) {
- /* r->profile will not be updated any more as r is dead */
- aa_put_profile(rcu_dereference_protected(p->profile, true));
- kzfree(p);
- }
-}
-
-
-void aa_free_proxy_kref(struct kref *kref)
-{
- struct aa_proxy *p = container_of(kref, struct aa_proxy, count);
-
- free_proxy(p);
-}
-
/**
* aa_free_data - free a data blob
* @ptr: data to free
@@ -242,7 +230,6 @@ void aa_free_profile(struct aa_profile *profile)
kzfree(profile->dirname);
aa_put_dfa(profile->xmatch);
aa_put_dfa(profile->policy.dfa);
- aa_put_proxy(profile->proxy);
if (profile->data) {
rht = profile->data;
@@ -253,30 +240,8 @@ void aa_free_profile(struct aa_profile *profile)
kzfree(profile->hash);
aa_put_loaddata(profile->rawdata);
- kzfree(profile);
-}
-
-/**
- * aa_free_profile_rcu - free aa_profile by rcu (called by aa_free_profile_kref)
- * @head: rcu_head callback for freeing of a profile (NOT NULL)
- */
-static void aa_free_profile_rcu(struct rcu_head *head)
-{
- struct aa_profile *p = container_of(head, struct aa_profile, rcu);
- if (p->flags & PFLAG_NS_COUNT)
- aa_free_ns(p->ns);
- else
- aa_free_profile(p);
-}
-/**
- * aa_free_profile_kref - free aa_profile by kref (called by aa_put_profile)
- * @kr: kref callback for freeing of a profile (NOT NULL)
- */
-void aa_free_profile_kref(struct kref *kref)
-{
- struct aa_profile *p = container_of(kref, struct aa_profile, count);
- call_rcu(&p->rcu, aa_free_profile_rcu);
+ kzfree(profile);
}
/**
@@ -286,30 +251,40 @@ void aa_free_profile_kref(struct kref *kref)
*
* Returns: refcount profile or NULL on failure
*/
-struct aa_profile *aa_alloc_profile(const char *hname, gfp_t gfp)
+struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
+ gfp_t gfp)
{
struct aa_profile *profile;
/* freed by free_profile - usually through aa_put_profile */
- profile = kzalloc(sizeof(*profile), gfp);
+ profile = kzalloc(sizeof(*profile) + sizeof(struct aa_profile *) * 2,
+ gfp);
if (!profile)
return NULL;
- profile->proxy = kzalloc(sizeof(struct aa_proxy), gfp);
- if (!profile->proxy)
- goto fail;
- kref_init(&profile->proxy->count);
-
if (!aa_policy_init(&profile->base, NULL, hname, gfp))
goto fail;
- kref_init(&profile->count);
+ if (!aa_label_init(&profile->label, 1))
+ goto fail;
+
+ /* update being set needed by fs interface */
+ if (!proxy) {
+ proxy = aa_alloc_proxy(&profile->label, gfp);
+ if (!proxy)
+ goto fail;
+ } else
+ aa_get_proxy(proxy);
+ profile->label.proxy = proxy;
+
+ profile->label.hname = profile->base.hname;
+ profile->label.flags |= FLAG_PROFILE;
+ profile->label.vec[0] = profile;
/* refcount released by caller */
return profile;
fail:
- kzfree(profile->proxy);
- kzfree(profile);
+ aa_free_profile(profile);
return NULL;
}
@@ -362,14 +337,14 @@ name:
if (profile)
goto out;
- profile = aa_alloc_profile(name, gfp);
+ profile = aa_alloc_profile(name, NULL, gfp);
if (!profile)
goto fail;
profile->mode = APPARMOR_COMPLAIN;
- profile->flags |= PFLAG_NULL;
+ profile->label.flags |= FLAG_NULL;
if (hat)
- profile->flags |= PFLAG_HAT;
+ profile->label.flags |= FLAG_HAT;
profile->path_flags = parent->path_flags;
/* released on free_profile */
@@ -379,7 +354,7 @@ name:
profile->policy.dfa = aa_get_dfa(nulldfa);
mutex_lock(&profile->ns->lock);
- __list_add_profile(&parent->base.profiles, profile);
+ __add_profile(&parent->base.profiles, profile);
mutex_unlock(&profile->ns->lock);
/* refcount released by caller */
@@ -389,7 +364,6 @@ out:
return profile;
fail:
- kfree(name);
aa_free_profile(profile);
return NULL;
}
@@ -397,33 +371,33 @@ fail:
/* TODO: profile accounting - setup in remove */
/**
- * __find_child - find a profile on @head list with a name matching @name
+ * __strn_find_child - find a profile on @head list using substring of @name
* @head: list to search (NOT NULL)
* @name: name of profile (NOT NULL)
+ * @len: length of @name substring to match
*
* Requires: rcu_read_lock be held
*
* Returns: unrefcounted profile ptr, or NULL if not found
*/
-static struct aa_profile *__find_child(struct list_head *head, const char *name)
+static struct aa_profile *__strn_find_child(struct list_head *head,
+ const char *name, int len)
{
- return (struct aa_profile *)__policy_find(head, name);
+ return (struct aa_profile *)__policy_strn_find(head, name, len);
}
/**
- * __strn_find_child - find a profile on @head list using substring of @name
+ * __find_child - find a profile on @head list with a name matching @name
* @head: list to search (NOT NULL)
* @name: name of profile (NOT NULL)
- * @len: length of @name substring to match
*
* Requires: rcu_read_lock be held
*
* Returns: unrefcounted profile ptr, or NULL if not found
*/
-static struct aa_profile *__strn_find_child(struct list_head *head,
- const char *name, int len)
+static struct aa_profile *__find_child(struct list_head *head, const char *name)
{
- return (struct aa_profile *)__policy_strn_find(head, name, len);
+ return __strn_find_child(head, name, strlen(name));
}
/**
@@ -556,7 +530,7 @@ struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname)
return aa_lookupn_profile(ns, hname, strlen(hname));
}
-struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
+struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
const char *fqname, size_t n)
{
struct aa_profile *profile;
@@ -566,11 +540,11 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
name = aa_splitn_fqname(fqname, n, &ns_name, &ns_len);
if (ns_name) {
- ns = aa_findn_ns(base->ns, ns_name, ns_len);
+ ns = aa_lookupn_ns(labels_ns(base), ns_name, ns_len);
if (!ns)
return NULL;
} else
- ns = aa_get_ns(base->ns);
+ ns = aa_get_ns(labels_ns(base));
if (name)
profile = aa_lookupn_profile(ns, name, n - (name - fqname));
@@ -596,7 +570,7 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace,
const char **info)
{
if (profile) {
- if (profile->flags & PFLAG_IMMUTABLE) {
+ if (profile->label.flags & FLAG_IMMUTIBLE) {
*info = "cannot replace immutible profile";
return -EPERM;
} else if (noreplace) {
@@ -619,29 +593,31 @@ static void audit_cb(struct audit_buffer *ab, void *va)
}
/**
- * aa_audit_policy - Do auditing of policy changes
- * @profile: profile to check if it can manage policy
+ * audit_policy - Do auditing of policy changes
+ * @label: label to check if it can manage policy
* @op: policy operation being performed
- * @gfp: memory allocation flags
- * @nsname: name of the ns being manipulated (MAY BE NULL)
+ * @ns_name: name of namespace being manipulated
* @name: name of profile being manipulated (NOT NULL)
* @info: any extra information to be audited (MAYBE NULL)
* @error: error code
*
* Returns: the error to be returned after audit is done
*/
-static int audit_policy(struct aa_profile *profile, const char *op,
- const char *nsname, const char *name,
+static int audit_policy(struct aa_label *label, const char *op,
+ const char *ns_name, const char *name,
const char *info, int error)
{
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
- aad(&sa)->iface.ns = nsname;
+ aad(&sa)->iface.ns = ns_name;
aad(&sa)->name = name;
aad(&sa)->info = info;
aad(&sa)->error = error;
+ aad(&sa)->label = label;
+
+ aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, audit_cb);
- return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb);
+ return error;
}
/**
@@ -685,22 +661,30 @@ bool policy_admin_capable(struct aa_ns *ns)
/**
* aa_may_manage_policy - can the current task manage policy
- * @profile: profile to check if it can manage policy
+ * @label: label to check if it can manage policy
* @op: the policy manipulation operation being done
*
* Returns: 0 if the task is allowed to manipulate policy else error
*/
-int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns,
- const char *op)
+int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask)
{
+ const char *op;
+
+ if (mask & AA_MAY_REMOVE_POLICY)
+ op = OP_PROF_RM;
+ else if (mask & AA_MAY_REPLACE_POLICY)
+ op = OP_PROF_REPL;
+ else
+ op = OP_PROF_LOAD;
+
/* check if loading policy is locked out */
if (aa_g_lock_policy)
- return audit_policy(profile, op, NULL, NULL,
- "policy_locked", -EACCES);
+ return audit_policy(label, op, NULL, NULL, "policy_locked",
+ -EACCES);
if (!policy_admin_capable(ns))
- return audit_policy(profile, op, NULL, NULL,
- "not policy admin", -EACCES);
+ return audit_policy(label, op, NULL, NULL, "not policy admin",
+ -EACCES);
/* TODO: add fine grained mediation of policy loads */
return 0;
@@ -742,8 +726,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh,
*
* Requires: namespace list lock be held, or list not be shared
*/
-static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
- bool share_proxy)
+static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
{
struct aa_profile *child, *tmp;
@@ -758,7 +741,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
p = __find_child(&new->base.profiles, child->base.name);
if (p) {
/* @p replaces @child */
- __replace_profile(child, p, share_proxy);
+ __replace_profile(child, p);
continue;
}
@@ -776,15 +759,9 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
struct aa_profile *parent = aa_deref_parent(old);
rcu_assign_pointer(new->parent, aa_get_profile(parent));
}
- __aa_update_proxy(old, new);
- if (share_proxy) {
- aa_put_proxy(new->proxy);
- new->proxy = aa_get_proxy(old->proxy);
- } else if (!rcu_access_pointer(new->proxy->profile))
- /* aafs interface uses proxy */
- rcu_assign_pointer(new->proxy->profile,
- aa_get_profile(new));
- __aa_fs_profile_migrate_dents(old, new);
+ aa_label_replace(&old->label, &new->label);
+ /* migrate dents must come after label replacement b/c update */
+ __aafs_profile_migrate_dents(old, new);
if (list_empty(&new->base.list)) {
/* new is not on a list already */
@@ -821,11 +798,41 @@ static int __lookup_replace(struct aa_ns *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;
+ new->label.hname = old->label.hname;
+}
+
+/* Update to newest version of parent after previous replacements
+ * Returns: unrefcount newest version of parent
+ */
+static struct aa_profile *update_to_newest_parent(struct aa_profile *new)
+{
+ struct aa_profile *parent, *newest;
+
+ parent = rcu_dereference_protected(new->parent,
+ mutex_is_locked(&new->ns->lock));
+ newest = aa_get_newest_profile(parent);
+
+ /* parent replaced in this atomic set? */
+ if (newest != parent) {
+ aa_put_profile(parent);
+ rcu_assign_pointer(new->parent, newest);
+ } else
+ aa_put_profile(newest);
+
+ return newest;
+}
+
/**
* aa_replace_profiles - replace profile(s) on the profile list
- * @view: namespace load is viewed from
+ * @policy_ns: namespace load is occurring on
* @label: label that is attempting to load/replace policy
- * @noreplace: true if only doing addition, no replacement allowed
+ * @mask: permission mask
* @udata: serialized data stream (NOT NULL)
*
* unpack and replace a profile on the profile list and uses of that profile
@@ -834,16 +841,19 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,
*
* Returns: size of data consumed else error code on failure.
*/
-ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
- bool noreplace, struct aa_loaddata *udata)
+ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
+ u32 mask, struct aa_loaddata *udata)
{
const char *ns_name, *info = NULL;
struct aa_ns *ns = NULL;
struct aa_load_ent *ent, *tmp;
- const char *op = OP_PROF_REPL;
+ struct aa_loaddata *rawdata_ent;
+ const char *op;
ssize_t count, error;
LIST_HEAD(lh);
+ op = mask & AA_MAY_REPLACE_POLICY ? OP_PROF_REPL : OP_PROF_LOAD;
+ aa_get_loaddata(udata);
/* released below */
error = aa_unpack(udata, &lh, &ns_name);
if (error)
@@ -874,7 +884,8 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
count++;
}
if (ns_name) {
- ns = aa_prepare_ns(view, ns_name);
+ ns = aa_prepare_ns(policy_ns ? policy_ns : labels_ns(label),
+ ns_name);
if (IS_ERR(ns)) {
op = OP_PROF_LOAD;
info = "failed to prepare namespace";
@@ -884,22 +895,38 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
goto fail;
}
} else
- ns = aa_get_ns(view);
+ ns = aa_get_ns(policy_ns ? policy_ns : labels_ns(label));
mutex_lock(&ns->lock);
+ /* check for duplicate rawdata blobs: space and file dedup */
+ list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) {
+ if (aa_rawdata_eq(rawdata_ent, udata)) {
+ struct aa_loaddata *tmp;
+
+ tmp = __aa_get_loaddata(rawdata_ent);
+ /* check we didn't fail the race */
+ if (tmp) {
+ aa_put_loaddata(udata);
+ udata = tmp;
+ break;
+ }
+ }
+ }
/* setup parent and ns info */
list_for_each_entry(ent, &lh, list) {
struct aa_policy *policy;
+
ent->new->rawdata = aa_get_loaddata(udata);
- error = __lookup_replace(ns, ent->new->base.hname, noreplace,
+ error = __lookup_replace(ns, ent->new->base.hname,
+ !(mask & AA_MAY_REPLACE_POLICY),
&ent->old, &info);
if (error)
goto fail_lock;
if (ent->new->rename) {
error = __lookup_replace(ns, ent->new->rename,
- noreplace, &ent->rename,
- &info);
+ !(mask & AA_MAY_REPLACE_POLICY),
+ &ent->rename, &info);
if (error)
goto fail_lock;
}
@@ -929,15 +956,16 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
}
/* create new fs entries for introspection if needed */
+ if (!udata->dents[AAFS_LOADDATA_DIR]) {
+ error = __aa_fs_create_rawdata(ns, udata);
+ if (error) {
+ info = "failed to create raw_data dir and files";
+ ent = NULL;
+ goto fail_lock;
+ }
+ }
list_for_each_entry(ent, &lh, list) {
- if (ent->old) {
- /* inherit old interface files */
-
- /* if (ent->rename)
- TODO: support rename */
- /* } else if (ent->rename) {
- TODO: support rename */
- } else {
+ if (!ent->old) {
struct dentry *parent;
if (rcu_access_pointer(ent->new->parent)) {
struct aa_profile *p;
@@ -945,65 +973,61 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
parent = prof_child_dir(p);
} else
parent = ns_subprofs_dir(ent->new->ns);
- error = __aa_fs_profile_mkdir(ent->new, parent);
+ error = __aafs_profile_mkdir(ent->new, parent);
}
if (error) {
- info = "failed to create ";
+ info = "failed to create";
goto fail_lock;
}
}
/* Done with checks that may fail - do actual replacement */
+ __aa_bump_ns_revision(ns);
+ __aa_loaddata_update(udata, ns->revision);
list_for_each_entry_safe(ent, tmp, &lh, list) {
list_del_init(&ent->list);
op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
- audit_policy(profile, op, NULL, ent->new->base.hname,
- NULL, error);
+ if (ent->old && ent->old->rawdata == ent->new->rawdata) {
+ /* dedup actual profile replacement */
+ audit_policy(label, op, ns_name, ent->new->base.hname,
+ "same as current profile, skipping",
+ error);
+ goto skip;
+ }
+
+ /*
+ * TODO: finer dedup based on profile range in data. Load set
+ * can differ but profile may remain unchanged
+ */
+ audit_policy(label, op, ns_name, ent->new->base.hname, NULL,
+ error);
if (ent->old) {
- __replace_profile(ent->old, ent->new, 1);
- if (ent->rename) {
- /* aafs interface uses proxy */
- struct aa_proxy *r = ent->new->proxy;
- rcu_assign_pointer(r->profile,
- aa_get_profile(ent->new));
- __replace_profile(ent->rename, ent->new, 0);
- }
- } else if (ent->rename) {
- /* aafs interface uses proxy */
- rcu_assign_pointer(ent->new->proxy->profile,
- aa_get_profile(ent->new));
- __replace_profile(ent->rename, ent->new, 0);
- } else if (ent->new->parent) {
- struct aa_profile *parent, *newest;
- parent = aa_deref_parent(ent->new);
- newest = aa_get_newest_profile(parent);
-
- /* parent replaced in this atomic set? */
- if (newest != parent) {
- aa_get_profile(newest);
- rcu_assign_pointer(ent->new->parent, newest);
- aa_put_profile(parent);
- }
- /* aafs interface uses proxy */
- rcu_assign_pointer(ent->new->proxy->profile,
- aa_get_profile(ent->new));
- __list_add_profile(&newest->base.profiles, ent->new);
- aa_put_profile(newest);
+ share_name(ent->old, ent->new);
+ __replace_profile(ent->old, ent->new);
} else {
- /* aafs interface uses proxy */
- rcu_assign_pointer(ent->new->proxy->profile,
- aa_get_profile(ent->new));
- __list_add_profile(&ns->base.profiles, ent->new);
+ struct list_head *lh;
+
+ if (rcu_access_pointer(ent->new->parent)) {
+ struct aa_profile *parent;
+
+ parent = update_to_newest_parent(ent->new);
+ lh = &parent->base.profiles;
+ } else
+ lh = &ns->base.profiles;
+ __add_profile(lh, ent->new);
}
+ skip:
aa_load_ent_free(ent);
}
+ __aa_labelset_update_subtree(ns);
mutex_unlock(&ns->lock);
out:
aa_put_ns(ns);
+ aa_put_loaddata(udata);
if (error)
return error;
@@ -1013,10 +1037,10 @@ fail_lock:
mutex_unlock(&ns->lock);
/* audit cause of failure */
- op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
+ op = (ent && !ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
fail:
- audit_policy(profile, op, ns_name, ent ? ent->new->base.hname : NULL,
- info, error);
+ audit_policy(label, op, ns_name, ent ? ent->new->base.hname : NULL,
+ info, error);
/* audit status that rest of profiles in the atomic set failed too */
info = "valid profile in failed atomic policy load";
list_for_each_entry(tmp, &lh, list) {
@@ -1026,8 +1050,8 @@ fail:
continue;
}
op = (!tmp->old) ? OP_PROF_LOAD : OP_PROF_REPL;
- audit_policy(profile, op, ns_name,
- tmp->new->base.hname, info, error);
+ audit_policy(label, op, ns_name, tmp->new->base.hname, info,
+ error);
}
list_for_each_entry_safe(ent, tmp, &lh, list) {
list_del_init(&ent->list);
@@ -1039,8 +1063,8 @@ fail:
/**
* aa_remove_profiles - remove profile(s) from the system
- * @view: namespace the remove is being done from
- * @subj: profile attempting to remove policy
+ * @policy_ns: namespace the remove is being done from
+ * @subj: label attempting to remove policy
* @fqname: name of the profile or namespace to remove (NOT NULL)
* @size: size of the name
*
@@ -1051,13 +1075,13 @@ fail:
*
* Returns: size of data consume else error code if fails
*/
-ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj,
+ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj,
char *fqname, size_t size)
{
- struct aa_ns *root = NULL, *ns = NULL;
+ struct aa_ns *ns = NULL;
struct aa_profile *profile = NULL;
const char *name = fqname, *info = NULL;
- char *ns_name = NULL;
+ const char *ns_name = NULL;
ssize_t error = 0;
if (*fqname == 0) {
@@ -1066,12 +1090,13 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj,
goto fail;
}
- root = view;
-
if (fqname[0] == ':') {
- name = aa_split_fqname(fqname, &ns_name);
+ size_t ns_len;
+
+ name = aa_splitn_fqname(fqname, size, &ns_name, &ns_len);
/* released below */
- ns = aa_find_ns(root, ns_name);
+ ns = aa_lookupn_ns(policy_ns ? policy_ns : labels_ns(subj),
+ ns_name, ns_len);
if (!ns) {
info = "namespace does not exist";
error = -ENOENT;
@@ -1079,12 +1104,13 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj,
}
} else
/* released below */
- ns = aa_get_ns(root);
+ ns = aa_get_ns(policy_ns ? policy_ns : labels_ns(subj));
if (!name) {
/* remove namespace - can only happen if fqname[0] == ':' */
mutex_lock(&ns->parent->lock);
__aa_remove_ns(ns);
+ __aa_bump_ns_revision(ns);
mutex_unlock(&ns->parent->lock);
} else {
/* remove profile */
@@ -1097,6 +1123,8 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj,
}
name = profile->base.hname;
__remove_profile(profile);
+ __aa_labelset_update_subtree(ns);
+ __aa_bump_ns_revision(ns);
mutex_unlock(&ns->lock);
}