From: Krzysztof Struczynski krzysztof.struczynski@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49KW1 CVE: NA
--------------------------------
It's possible that the user first unshares the ima namespace and then creates a new user namespace using clone3(). In that case the owning user namespace is the newly created one, because it is associated with the first process in the new ima namespace.
Signed-off-by: Krzysztof Struczynski krzysztof.struczynski@huawei.com Reviewed-by: Zhang Tianxing zhangtianxing3@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- include/linux/ima.h | 6 +++-- kernel/nsproxy.c | 2 +- security/integrity/ima/ima_ns.c | 42 +++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/include/linux/ima.h b/include/linux/ima.h index cfdd1280daff..91c637c943ed 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -246,7 +246,8 @@ struct ima_namespace *copy_ima_ns(unsigned long flags,
void free_ima_ns(struct kref *kref);
-int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk); +int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk, + struct user_namespace *user_ns);
static inline struct ima_namespace *get_ima_ns(struct ima_namespace *ns) { @@ -269,7 +270,8 @@ static inline struct ima_namespace *copy_ima_ns(unsigned long flags, }
static inline int imans_on_fork(struct nsproxy *nsproxy, - struct task_struct *tsk) + struct task_struct *tsk, + struct user_namespace *user_ns) { return 0; } diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index e2cddc22dc53..ff138b24b25d 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -204,7 +204,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) return ret; }
- ret = imans_on_fork(new_ns, tsk); + ret = imans_on_fork(new_ns, tsk, user_ns); if (ret) { free_nsproxy(new_ns); return ret; diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c index 26c9bcd5ff74..ac000920d486 100644 --- a/security/integrity/ima/ima_ns.c +++ b/security/integrity/ima/ima_ns.c @@ -93,6 +93,24 @@ static void ima_set_ns_policy(struct ima_namespace *ima_ns, ima_init_ns_policy(ima_ns, &setup_data); }
+static int ima_swap_user_ns(struct ima_namespace *ima_ns, + struct user_namespace *user_ns) +{ + struct ucounts *ucounts; + + dec_ima_namespaces(ima_ns->ucounts); + put_user_ns(ima_ns->user_ns); + + ucounts = inc_ima_namespaces(user_ns); + if (!ucounts) + return -ENOSPC; + + ima_ns->user_ns = get_user_ns(user_ns); + ima_ns->ucounts = ucounts; + + return 0; +} + /** * Clone a new ns copying an original ima namespace, setting refcount to 1 * @@ -352,23 +370,33 @@ static int imans_install(struct nsset *nsset, struct ns_common *new) return res; }
-int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk) +int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk, + struct user_namespace *user_ns) { int res; - struct ns_common *nsc = &nsproxy->ima_ns_for_children->ns; - struct ima_namespace *ns = to_ima_ns(nsc); + struct ima_namespace *ima_ns = nsproxy->ima_ns_for_children;
/* create_new_namespaces() already incremented the ref counter */ - if (nsproxy->ima_ns == nsproxy->ima_ns_for_children) + if (nsproxy->ima_ns == ima_ns) return 0;
- res = imans_activate(ns); + /* It's possible that the user first unshares the IMA namespace and + * then creates a new user namespace on clone3(). In that case swap + * user namespace for the "current" one. + */ + if (ima_ns->user_ns != user_ns) { + res = ima_swap_user_ns(ima_ns, user_ns); + if (res) + return res; + } + + res = imans_activate(ima_ns); if (res) return res;
- get_ima_ns(ns); + get_ima_ns(ima_ns); put_ima_ns(nsproxy->ima_ns); - nsproxy->ima_ns = ns; + nsproxy->ima_ns = ima_ns;
return res; }