From: Krzysztof Struczynski <[email protected]>

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 <[email protected]>
---
 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

Reply via email to