[RFC PATCH 28/30] ima: Load per ima namespace x509 certificate

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


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

If configured, load the x509 certificate when the first process is
born into the new ima namespace. User can set the path to the
certificate by writing to the x509_for_children entry in the ima
securityfs.

Signed-off-by: Krzysztof Struczynski <krzysztof.struczynski at huawei.com>
---
 security/integrity/digsig.c     |  6 +--
 security/integrity/ima/ima_ns.c | 69 ++++++++++++++++++++++++++++-----
 security/integrity/integrity.h  |  2 +-
 3 files changed, 63 insertions(+), 14 deletions(-)

diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 523fc786c4d7..8cd54bc83892 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -170,8 +170,8 @@ int __init integrity_init_keyring(const unsigned int id)
 	return __integrity_init_keyring(id, perm, restriction);
 }
 
-int __init integrity_add_key(const unsigned int id, const void *data,
-			     off_t size, key_perm_t perm)
+int integrity_add_key(const unsigned int id, const void *data,
+		      off_t size, key_perm_t perm)
 {
 	key_ref_t key;
 	int rc = 0;
@@ -195,7 +195,7 @@ int __init integrity_add_key(const unsigned int id, const void *data,
 
 }
 
-int __init integrity_load_x509(const unsigned int id, const char *path)
+int integrity_load_x509(const unsigned int id, const char *path)
 {
 	void *data;
 	loff_t size;
diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c
index 872dc6a96a96..11e1d896f603 100644
--- a/security/integrity/ima/ima_ns.c
+++ b/security/integrity/ima/ima_ns.c
@@ -48,6 +48,30 @@ static void dec_ima_namespaces(struct ucounts *ucounts)
 	return dec_ucount(ucounts, UCOUNT_IMA_NAMESPACES);
 }
 
+#ifdef CONFIG_IMA_LOAD_X509
+static int ima_ns_load_x509(struct ima_namespace *ima_ns)
+{
+	int res = 0;
+	int unset_flags =
+		ima_ns->policy_data->ima_policy_flag & IMA_APPRAISE;
+
+	if (!ima_ns->x509_path_for_children)
+		return res;
+
+	ima_ns->policy_data->ima_policy_flag &= ~unset_flags;
+	res = integrity_load_x509(INTEGRITY_KEYRING_IMA,
+				  ima_ns->x509_path_for_children);
+	ima_ns->policy_data->ima_policy_flag |= unset_flags;
+
+	return res;
+}
+#else
+static inline int ima_ns_load_x509(struct ima_namespace *ima_ns)
+{
+	return 0;
+}
+#endif
+
 static struct ima_namespace *ima_ns_alloc(void)
 {
 	struct ima_namespace *ima_ns;
@@ -365,6 +389,10 @@ static int imans_activate(struct ima_namespace *ima_ns)
 	if (res < 0)
 		goto out;
 
+	res = ima_ns_load_x509(ima_ns);
+	if (res < 0)
+		goto out;
+
 	ima_ns->frozen = true;
 
 	/* Set current last element as list's head */
@@ -388,6 +416,7 @@ static int imans_install(struct nsset *nsset, struct ns_common *new)
 	int res;
 	struct nsproxy *nsproxy = nsset->nsproxy;
 	struct ima_namespace *ns = to_ima_ns(new);
+	struct ima_namespace *old_ns = nsproxy->ima_ns;
 
 	if (!current_is_single_threaded())
 		return -EUSERS;
@@ -396,14 +425,24 @@ static int imans_install(struct nsset *nsset, struct ns_common *new)
 	    !ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN))
 		return -EPERM;
 
-	res = imans_activate(ns);
-	if (res)
-		return res;
-
 	get_ima_ns(ns);
-	put_ima_ns(nsproxy->ima_ns);
+	put_ima_ns(old_ns);
 	nsproxy->ima_ns = ns;
 
+	/* The activation has to take place, after attaching the new namespace
+	 * to the nsproxy. This is because one part of the activation process,
+	 * is loading the appraisal keys, which temporary disables appraisal in
+	 * the current ima namespace, and it must not happen for the "old" ima
+	 * namespace.
+	 */
+	res = imans_activate(ns);
+	if (res) {
+		get_ima_ns(old_ns);
+		put_ima_ns(ns);
+		nsproxy->ima_ns = old_ns;
+		return res;
+	}
+
 	get_ima_ns(ns);
 	put_ima_ns(nsproxy->ima_ns_for_children);
 	nsproxy->ima_ns_for_children = ns;
@@ -416,6 +455,7 @@ int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk,
 {
 	int res;
 	struct ima_namespace *ima_ns = nsproxy->ima_ns_for_children;
+	struct ima_namespace *old_ima_ns = nsproxy->ima_ns;
 
 	/* create_new_namespaces() already incremented the ref counter */
 	if (nsproxy->ima_ns == ima_ns)
@@ -431,14 +471,23 @@ int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk,
 			return res;
 	}
 
-	res = imans_activate(ima_ns);
-	if (res)
-		return res;
-
 	get_ima_ns(ima_ns);
-	put_ima_ns(nsproxy->ima_ns);
+	put_ima_ns(old_ima_ns);
 	nsproxy->ima_ns = ima_ns;
 
+	/* The activation has to take place, after attaching the new namespace
+	 * to the nsproxy. This is because one part of the activation process,
+	 * is loading the appraisal keys, which temporary disables appraisal in
+	 * the current ima namespace, and it must not happen for the "old" ima
+	 * namespace.
+	 */
+	res = imans_activate(ima_ns);
+	if (res) {
+		get_ima_ns(old_ima_ns);
+		put_ima_ns(ima_ns);
+		nsproxy->ima_ns = old_ima_ns;
+	}
+
 	return res;
 }
 
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 207a1aef28e4..9b080b9fe242 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -179,7 +179,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 int integrity_modsig_verify(unsigned int id, const struct modsig *modsig);
 
 int __init integrity_init_keyring(const unsigned int id);
-int __init integrity_load_x509(const unsigned int id, const char *path);
+int integrity_load_x509(const unsigned int id, const char *path);
 int __init integrity_load_cert(const unsigned int id, const char *source,
 			       const void *data, size_t len, key_perm_t perm);
 #else
-- 
2.20.1



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