Smack: allow to access /smack/access as normal user

Allow query access as a normal user removing the need
for CAP_MAC_ADMIN. Give RW access to /smack/access
for UGO. Do not import smack labels in access check.

Signed-off-by: Jarkko Sakkinen <jarkko.j.sakkinen@gmail.com>
Signed-off-by: Casey Schaufler <cschaufler@cschaufler-intel.(none)>
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 381eecf..6aceef5 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -191,19 +191,37 @@
 }
 
 /**
- * smk_parse_rule - parse subject, object and access type
+ * smk_parse_rule - parse Smack rule from load string
  * @data: string to be parsed whose size is SMK_LOADLEN
- * @rule: parsed entities are stored in here
+ * @rule: Smack rule
+ * @import: if non-zero, import labels
  */
-static int smk_parse_rule(const char *data, struct smack_rule *rule)
+static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)
 {
-	rule->smk_subject = smk_import(data, 0);
-	if (rule->smk_subject == NULL)
-		return -1;
+	char smack[SMK_LABELLEN];
+	struct smack_known *skp;
 
-	rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
-	if (rule->smk_object == NULL)
-		return -1;
+	if (import) {
+		rule->smk_subject = smk_import(data, 0);
+		if (rule->smk_subject == NULL)
+			return -1;
+
+		rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
+		if (rule->smk_object == NULL)
+			return -1;
+	} else {
+		smk_parse_smack(data, 0, smack);
+		skp = smk_find_entry(smack);
+		if (skp == NULL)
+			return -1;
+		rule->smk_subject = skp->smk_known;
+
+		smk_parse_smack(data + SMK_LABELLEN, 0, smack);
+		skp = smk_find_entry(smack);
+		if (skp == NULL)
+			return -1;
+		rule->smk_object = skp->smk_known;
+	}
 
 	rule->smk_access = 0;
 
@@ -327,7 +345,7 @@
 		goto out;
 	}
 
-	if (smk_parse_rule(data, rule))
+	if (smk_parse_rule(data, rule, 1))
 		goto out_free_rule;
 
 	if (rule_list == NULL) {
@@ -1499,14 +1517,11 @@
 	char *data;
 	int res;
 
-	if (!capable(CAP_MAC_ADMIN))
-		return -EPERM;
-
 	data = simple_transaction_get(file, buf, count);
 	if (IS_ERR(data))
 		return PTR_ERR(data);
 
-	if (count < SMK_LOADLEN || smk_parse_rule(data, &rule))
+	if (count < SMK_LOADLEN || smk_parse_rule(data, &rule, 0))
 		return -EINVAL;
 
 	res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access,
@@ -1560,7 +1575,7 @@
 		[SMK_LOAD_SELF] = {
 			"load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
 		[SMK_ACCESSES] = {
-			"access", &smk_access_ops, S_IRUGO|S_IWUSR},
+			"access", &smk_access_ops, S_IRUGO|S_IWUGO},
 		/* last one */
 			{""}
 	};