From: Cyrill Gorcunov Date: Fri, 19 Oct 2012 20:56:53 +0000 (-0700) Subject: pidns: remove recursion from free_pid_ns() X-Git-Tag: v3.7-rc2~10^2~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bbc2e3ef87851bc5430b2b4cf4ca3a2f29baeda6;p=profile%2Fcommon%2Fkernel-common.git pidns: remove recursion from free_pid_ns() free_pid_ns() operates in a recursive fashion: free_pid_ns(parent) put_pid_ns(parent) kref_put(&ns->kref, free_pid_ns); free_pid_ns thus if there was a huge nesting of namespaces the userspace may trigger avalanche calling of free_pid_ns leading to kernel stack exhausting and a panic eventually. This patch turns the recursion into an iterative loop. Based on a patch by Andrew Vagin. [akpm@linux-foundation.org: export put_pid_ns() to modules] Signed-off-by: Cyrill Gorcunov Cc: Andrew Vagin Cc: Oleg Nesterov Cc: "Eric W. Biederman" Cc: Pavel Emelyanov Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 00474b0..65e3e87 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -47,15 +47,9 @@ static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns) } extern struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *ns); -extern void free_pid_ns(struct kref *kref); extern void zap_pid_ns_processes(struct pid_namespace *pid_ns); extern int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd); - -static inline void put_pid_ns(struct pid_namespace *ns) -{ - if (ns != &init_pid_ns) - kref_put(&ns->kref, free_pid_ns); -} +extern void put_pid_ns(struct pid_namespace *ns); #else /* !CONFIG_PID_NS */ #include diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 478bad2..eb00be2 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -133,19 +133,26 @@ struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old return create_pid_namespace(old_ns); } -void free_pid_ns(struct kref *kref) +static void free_pid_ns(struct kref *kref) { - struct pid_namespace *ns, *parent; + struct pid_namespace *ns; ns = container_of(kref, struct pid_namespace, kref); - - parent = ns->parent; destroy_pid_namespace(ns); +} - if (parent != NULL) - put_pid_ns(parent); +void put_pid_ns(struct pid_namespace *ns) +{ + struct pid_namespace *parent; + + while (ns != &init_pid_ns) { + parent = ns->parent; + if (!kref_put(&ns->kref, free_pid_ns)) + break; + ns = parent; + } } -EXPORT_SYMBOL_GPL(free_pid_ns); +EXPORT_SYMBOL_GPL(put_pid_ns); void zap_pid_ns_processes(struct pid_namespace *pid_ns) {