[RFC PATCH 22/30] ima: Remap IDs of subject based rules if necessary

krzysztof.struczynski at huawei.com krzysztof.struczynski at huawei.com
Tue Aug 18 15:42:22 UTC 2020


From: Krzysztof Struczynski <krzysztof.struczynski at huawei.com>

If subject based rule is added to the policy before the user namespace
uid mapping is defined, ID has to be recalculated.

It can happen if the new user namespace is created alongside the new
ima namespace. The default policy rules are loaded when the first
process is born into the new ima namespace. In that case, user has no
chance to define the mapping. It can also happen for the custom policy
rules loaded from within the new ima namespace, before the mapping is
created.

Signed-off-by: Krzysztof Struczynski <krzysztof.struczynski at huawei.com>
---
 security/integrity/ima/ima_policy.c | 83 ++++++++++++++++++++++++-----
 1 file changed, 70 insertions(+), 13 deletions(-)

diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index d4774eab6a98..bc1a4bb10bd0 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -18,6 +18,7 @@
 #include <linux/genhd.h>
 #include <linux/seq_file.h>
 #include <linux/ima.h>
+#include <linux/user_namespace.h>
 
 #include "ima.h"
 
@@ -78,6 +79,10 @@ struct ima_rule_entry {
 	char *fsname;
 	char *keyrings; /* Measure keys added to these keyrings */
 	struct ima_template_desc *template;
+	bool remap_uid; /* IDs of all subject oriented rules, added before the
+			 * user namespace mapping is defined,
+			 * have to be remapped.
+			 */
 };
 
 /*
@@ -484,6 +489,8 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
 			    const char *keyring)
 {
 	int i;
+	kuid_t remapped_kuid;
+	struct ima_namespace *current_ima_ns = get_current_ns();
 
 	if (func == KEY_CHECK) {
 		return (rule->flags & IMA_FUNC) && (rule->func == func) &&
@@ -507,21 +514,45 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
 	if ((rule->flags & IMA_FSUUID) &&
 	    !uuid_equal(&rule->fsuuid, &inode->i_sb->s_uuid))
 		return false;
-	if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid))
-		return false;
+	if (rule->flags & IMA_UID) {
+		if (rule->remap_uid) {
+			remapped_kuid = make_kuid(current_ima_ns->user_ns,
+						  __kuid_val(rule->uid));
+			if (!uid_valid(remapped_kuid))
+				return false;
+		} else
+			remapped_kuid = rule->uid;
+		if (!rule->uid_op(cred->uid, remapped_kuid))
+			return false;
+	}
 	if (rule->flags & IMA_EUID) {
+		if (rule->remap_uid) {
+			remapped_kuid = make_kuid(current_ima_ns->user_ns,
+						  __kuid_val(rule->uid));
+			if (!uid_valid(remapped_kuid))
+				return false;
+		} else
+			remapped_kuid = rule->uid;
 		if (has_capability_noaudit(current, CAP_SETUID)) {
-			if (!rule->uid_op(cred->euid, rule->uid)
-			    && !rule->uid_op(cred->suid, rule->uid)
-			    && !rule->uid_op(cred->uid, rule->uid))
+			if (!rule->uid_op(cred->euid, remapped_kuid)
+			    && !rule->uid_op(cred->suid, remapped_kuid)
+			    && !rule->uid_op(cred->uid, remapped_kuid))
 				return false;
-		} else if (!rule->uid_op(cred->euid, rule->uid))
+		} else if (!rule->uid_op(cred->euid, remapped_kuid))
 			return false;
 	}
 
-	if ((rule->flags & IMA_FOWNER) &&
-	    !rule->fowner_op(inode->i_uid, rule->fowner))
-		return false;
+	if (rule->flags & IMA_FOWNER) {
+		if (rule->remap_uid) {
+			remapped_kuid = make_kuid(current_ima_ns->user_ns,
+						  __kuid_val(rule->fowner));
+			if (!uid_valid(remapped_kuid))
+				return false;
+		} else
+			remapped_kuid = rule->fowner;
+		if (!rule->fowner_op(inode->i_uid, remapped_kuid))
+			return false;
+	}
 	for (i = 0; i < MAX_LSM_RULES; i++) {
 		int rc = 0;
 		u32 osid;
@@ -701,6 +732,9 @@ static void add_rules(struct ima_namespace *ima_ns,
 
 	for (i = 0; i < count; i++) {
 		struct ima_rule_entry *entry;
+		bool set_uidmap;
+
+		set_uidmap = userns_set_uidmap(ima_ns->user_ns);
 
 		if (policy_rule & IMA_DEFAULT_POLICY) {
 			entry = &entries[i];
@@ -709,6 +743,9 @@ static void add_rules(struct ima_namespace *ima_ns,
 						GFP_KERNEL);
 				if (!entry)
 					continue;
+
+				if (!set_uidmap)
+					entry->remap_uid = true;
 			}
 
 			list_add_tail(&entry->list,
@@ -721,6 +758,9 @@ static void add_rules(struct ima_namespace *ima_ns,
 			if (!entry)
 				continue;
 
+			if (ima_ns != &init_ima_ns && !set_uidmap)
+				entry->remap_uid = true;
+
 			list_add_tail(&entry->list,
 				      &ima_ns->policy_data->ima_policy_rules);
 		}
@@ -1165,6 +1205,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry,
 	ab = integrity_audit_log_start(audit_context(), GFP_KERNEL,
 				       AUDIT_INTEGRITY_POLICY_RULE);
 
+	if ((ima_ns != &init_ima_ns) &&
+	    (!userns_set_uidmap(ima_ns->user_ns)))
+		entry->remap_uid = true;
+
 	entry->uid = INVALID_UID;
 	entry->fowner = INVALID_UID;
 	entry->uid_op = &uid_eq;
@@ -1396,8 +1440,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry,
 
 			result = kstrtoul(args[0].from, 10, &lnum);
 			if (!result) {
-				entry->uid = make_kuid(current_user_ns(),
-						       (uid_t) lnum);
+				if (!entry->remap_uid)
+					entry->uid =
+						make_kuid(current_user_ns(),
+							  (uid_t) lnum);
+				else
+					entry->uid = KUIDT_INIT((uid_t) lnum);
+
 				if (!uid_valid(entry->uid) ||
 				    (uid_t)lnum != lnum)
 					result = -EINVAL;
@@ -1424,8 +1473,16 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry,
 
 			result = kstrtoul(args[0].from, 10, &lnum);
 			if (!result) {
-				entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum);
-				if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum))
+				if (!entry->remap_uid)
+					entry->fowner =
+						make_kuid(current_user_ns(),
+							  (uid_t) lnum);
+				else
+					entry->fowner =
+						KUIDT_INIT((uid_t) lnum);
+
+				if (!uid_valid(entry->fowner) ||
+				    (((uid_t)lnum) != lnum))
 					result = -EINVAL;
 				else
 					entry->flags |= IMA_FOWNER;
-- 
2.20.1



More information about the Linux-security-module-archive mailing list