This check will be needed in later patches, and there's no point open-coding it each time.
Signed-off-by: Aleksa Sarai cyphar@cyphar.com --- include/linux/pid_namespace.h | 9 +++++++++ kernel/pid_namespace.c | 21 ++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 7c67a5811199..df421a1e3e0b 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -84,6 +84,9 @@ extern void zap_pid_ns_processes(struct pid_namespace *pid_ns); extern int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd); extern void put_pid_ns(struct pid_namespace *ns);
+extern bool pidns_is_ancestor(struct pid_namespace *child, + struct pid_namespace *ancestor); + #else /* !CONFIG_PID_NS */ #include <linux/err.h>
@@ -118,6 +121,12 @@ static inline int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd) { return 0; } + +bool pidns_is_ancestor(struct pid_namespace *child, + struct pid_namespace *ancestor) +{ + return false; +} #endif /* CONFIG_PID_NS */
extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk); diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 7098ed44e717..5719b1f679ad 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -390,6 +390,19 @@ static void pidns_put(struct ns_common *ns) put_pid_ns(to_pid_ns(ns)); }
+bool pidns_is_ancestor(struct pid_namespace *child, + struct pid_namespace *ancestor) +{ + struct pid_namespace *ns; + + if (child->level < ancestor->level) + return false; + for (ns = child; ns->level > ancestor->level; ns = ns->parent) + ; + return ns == ancestor; +} +EXPORT_SYMBOL_GPL(pidns_is_ancestor); + static int pidns_install(struct nsset *nsset, struct ns_common *ns) { struct nsproxy *nsproxy = nsset->nsproxy; @@ -408,13 +421,7 @@ static int pidns_install(struct nsset *nsset, struct ns_common *ns) * this maintains the property that processes and their * children can not escape their current pid namespace. */ - if (new->level < active->level) - return -EINVAL; - - ancestor = new; - while (ancestor->level > active->level) - ancestor = ancestor->parent; - if (ancestor != active) + if (!pidns_is_ancestor(new, active)) return -EINVAL;
put_pid_ns(nsproxy->pid_ns_for_children);