Browse Source

apparmor: provide finer control over policy management

Signed-off-by: John Johansen <john.johansen@canonical.com>
John Johansen 8 years ago
parent
commit
18e99f191a
3 changed files with 35 additions and 23 deletions
  1. 7 8
      security/apparmor/apparmorfs.c
  2. 6 2
      security/apparmor/include/policy.h
  3. 22 13
      security/apparmor/policy.c

+ 7 - 8
security/apparmor/apparmorfs.c

@@ -400,17 +400,16 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
 	return data;
 	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)
 			     loff_t *pos, struct aa_ns *ns)
 {
 {
 	ssize_t error;
 	ssize_t error;
 	struct aa_loaddata *data;
 	struct aa_loaddata *data;
 	struct aa_profile *profile = aa_current_profile();
 	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
 	/* high level check about policy management - fine grained in
 	 * below after unpack
 	 * below after unpack
 	 */
 	 */
-	error = aa_may_manage_policy(profile, ns, op);
+	error = aa_may_manage_policy(profile, ns, mask);
 	if (error)
 	if (error)
 		return 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);
 	error = PTR_ERR(data);
 	if (!IS_ERR(data)) {
 	if (!IS_ERR(data)) {
 		error = aa_replace_profiles(ns ? ns : profile->ns, profile,
 		error = aa_replace_profiles(ns ? ns : profile->ns, profile,
-					    binop, data);
+					    mask, data);
 		aa_put_loaddata(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)
 			    loff_t *pos)
 {
 {
 	struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
 	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);
 	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)
 			       size_t size, loff_t *pos)
 {
 {
 	struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
 	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);
 	aa_put_ns(ns);
 
 
 	return error;
 	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
 	/* high level check about policy management - fine grained in
 	 * below after unpack
 	 * 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)
 	if (error)
 		goto out;
 		goto out;
 
 

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

@@ -188,6 +188,10 @@ struct aa_profile {
 
 
 extern enum profile_mode aa_g_profile_mode;
 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_update_proxy(struct aa_profile *orig, struct aa_profile *new);
 
 
 void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
 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);
 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,
 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,
 ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile,
 			    char *name, size_t size);
 			    char *name, size_t size);
 void __aa_profile_list_release(struct list_head *head);
 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_view_capable(struct aa_ns *ns);
 bool policy_admin_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,
 int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns,
-			 const char *op);
+			 u32 mask);
 
 
 #endif /* __AA_POLICY_H */
 #endif /* __AA_POLICY_H */

+ 22 - 13
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
  * 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 */
 	/* check if loading policy is locked out */
 	if (aa_g_lock_policy)
 	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))
 	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 */
 	/* TODO: add fine grained mediation of policy loads */
 	return 0;
 	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
  * aa_replace_profiles - replace profile(s) on the profile list
  * @view: namespace load is viewed from
  * @view: namespace load is viewed from
  * @label: label that is attempting to load/replace policy
  * @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)
  * @udata: serialized data stream  (NOT NULL)
  *
  *
  * unpack and replace a profile on the profile list and uses of that profile
  * 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.
  * Returns: size of data consumed else error code on failure.
  */
  */
 ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
 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;
 	const char *ns_name, *info = NULL;
 	struct aa_ns *ns = NULL;
 	struct aa_ns *ns = NULL;
 	struct aa_load_ent *ent, *tmp;
 	struct aa_load_ent *ent, *tmp;
 	struct aa_loaddata *rawdata_ent;
 	struct aa_loaddata *rawdata_ent;
-	const char *op = OP_PROF_REPL;
+	const char *op;
 	ssize_t count, error;
 	ssize_t count, error;
-
 	LIST_HEAD(lh);
 	LIST_HEAD(lh);
 
 
+	op = mask & AA_MAY_REPLACE_POLICY ? OP_PROF_REPL : OP_PROF_LOAD;
 	aa_get_loaddata(udata);
 	aa_get_loaddata(udata);
 	/* released below */
 	/* released below */
 	error = aa_unpack(udata, &lh, &ns_name);
 	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;
 		struct aa_policy *policy;
 
 
 		ent->new->rawdata = aa_get_loaddata(udata);
 		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);
 					 &ent->old, &info);
 		if (error)
 		if (error)
 			goto fail_lock;
 			goto fail_lock;
 
 
 		if (ent->new->rename) {
 		if (ent->new->rename) {
 			error = __lookup_replace(ns, ent->new->rename,
 			error = __lookup_replace(ns, ent->new->rename,
-						 noreplace, &ent->rename,
-						 &info);
+					!(mask & AA_MAY_REPLACE_POLICY),
+					 &ent->rename, &info);
 			if (error)
 			if (error)
 				goto fail_lock;
 				goto fail_lock;
 		}
 		}