From 18e99f191a8e66ec8fd06e4820de44bd9faa296a Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 26 May 2017 01:45:08 -0700 Subject: [PATCH] apparmor: provide finer control over policy management Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 15 +++++++-------- security/apparmor/include/policy.h | 8 ++++++-- security/apparmor/policy.c | 35 ++++++++++++++++++++++------------- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index c847f60..570d6b5 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -400,17 +400,16 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, return data; } -static ssize_t policy_update(int binop, const char __user *buf, size_t size, +static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, loff_t *pos, struct aa_ns *ns) { ssize_t error; struct aa_loaddata *data; struct aa_profile *profile = aa_current_profile(); - const char *op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL; /* high level check about policy management - fine grained in * below after unpack */ - error = aa_may_manage_policy(profile, ns, op); + error = aa_may_manage_policy(profile, ns, mask); if (error) return error; @@ -418,7 +417,7 @@ static ssize_t policy_update(int binop, const char __user *buf, size_t size, error = PTR_ERR(data); if (!IS_ERR(data)) { error = aa_replace_profiles(ns ? ns : profile->ns, profile, - binop, data); + mask, data); aa_put_loaddata(data); } @@ -430,7 +429,7 @@ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, loff_t *pos) { struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); - int error = policy_update(PROF_ADD, buf, size, pos, ns); + int error = policy_update(AA_MAY_LOAD_POLICY, buf, size, pos, ns); aa_put_ns(ns); @@ -447,8 +446,8 @@ static ssize_t profile_replace(struct file *f, const char __user *buf, size_t size, loff_t *pos) { struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); - int error = policy_update(PROF_REPLACE, buf, size, pos, ns); - + int error = policy_update(AA_MAY_LOAD_POLICY | AA_MAY_REPLACE_POLICY, + buf, size, pos, ns); aa_put_ns(ns); return error; @@ -472,7 +471,7 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, /* high level check about policy management - fine grained in * below after unpack */ - error = aa_may_manage_policy(profile, ns, OP_PROF_RM); + error = aa_may_manage_policy(profile, ns, AA_MAY_REMOVE_POLICY); if (error) goto out; diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 0f87f70..97bfbdd 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -188,6 +188,10 @@ struct aa_profile { extern enum profile_mode aa_g_profile_mode; +#define AA_MAY_LOAD_POLICY AA_MAY_APPEND +#define AA_MAY_REPLACE_POLICY AA_MAY_WRITE +#define AA_MAY_REMOVE_POLICY AA_MAY_DELETE + void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new); void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); @@ -208,7 +212,7 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, - bool noreplace, struct aa_loaddata *udata); + u32 mask, struct aa_loaddata *udata); ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile, char *name, size_t size); void __aa_profile_list_release(struct list_head *head); @@ -323,6 +327,6 @@ static inline int AUDIT_MODE(struct aa_profile *profile) bool policy_view_capable(struct aa_ns *ns); bool policy_admin_capable(struct aa_ns *ns); int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, - const char *op); + u32 mask); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index a5e8559..65e98d0 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -690,17 +690,25 @@ bool policy_admin_capable(struct aa_ns *ns) * * 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_profile *profile, 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(profile, 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(profile, op, NULL, NULL, "not policy admin", + -EACCES); /* TODO: add fine grained mediation of policy loads */ return 0; @@ -825,7 +833,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, * aa_replace_profiles - replace profile(s) on the profile list * @view: namespace load is viewed from * @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 @@ -835,17 +843,17 @@ 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) + u32 mask, struct aa_loaddata *udata) { const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; struct aa_load_ent *ent, *tmp; struct aa_loaddata *rawdata_ent; - const char *op = OP_PROF_REPL; + 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); @@ -909,15 +917,16 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, 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; } -- 2.7.4