aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2010-07-12 18:50:25 -0700
committerEric W. Biederman <ebiederm@aristanetworks.com>2011-08-09 05:00:14 -0500
commitd6a5b1482d7ba86cf639f35540812d6d6e905ccd (patch)
treef7bf95a77788ee4ef2e8c07b5029232c6b48ecfe
parent4b5c41aad4f6a4f9d723b8b5aea8c01264bd0763 (diff)
downloadlinux-namespace-control-devel-d6a5b1482d7ba86cf639f35540812d6d6e905ccd.tar.gz
pidns: Don't allow new processes in a dead pid namespace.
By adding a flag to track when a pid namespace is dead, and by testing that flag just before a process attaches to the pid namespace, it is possible to guarantee that processes never enter a dead pid namespace. Currently sending SIGKILL to all of the process in a dead pid namespace gives us this guarantee but we need something a little strong to support unsharing and joining a pid namespace. To ensure that this does not slow down the common case I tested this code with lat_proc from lm_bench and I did not see any increase in the fork overhead. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r--include/linux/pid_namespace.h18
-rw-r--r--kernel/fork.c7
-rw-r--r--kernel/pid.c3
-rw-r--r--kernel/pid_namespace.c1
4 files changed, 29 insertions, 0 deletions
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 8e0bee8c26739..e9a836ddbf0bb 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -20,6 +20,7 @@ struct pid_namespace {
struct kref kref;
struct pidmap pidmap[PIDMAP_ENTRIES];
int last_pid;
+ int dead;
struct task_struct *child_reaper;
struct kmem_cache *pid_cachep;
unsigned int level;
@@ -53,6 +54,17 @@ static inline void put_pid_ns(struct pid_namespace *ns)
kref_put(&ns->kref, free_pid_ns);
}
+static inline bool pid_ns_dead(struct pid *pid)
+{
+ int i;
+
+ for (i = 0; i <= pid->level; i++) {
+ if (pid->numbers[i].ns->dead)
+ return true;
+ }
+ return false;
+}
+
#else /* !CONFIG_PID_NS */
#include <linux/err.h>
@@ -78,6 +90,12 @@ static inline void zap_pid_ns_processes(struct pid_namespace *ns)
{
BUG();
}
+
+static inline bool pid_ns_dead(struct pid *pid)
+{
+ return false;
+}
+
#endif /* CONFIG_PID_NS */
extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk);
diff --git a/kernel/fork.c b/kernel/fork.c
index 59e37567a3e8e..98619829059a0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1329,6 +1329,13 @@ static struct task_struct *copy_process(unsigned long clone_flags,
goto bad_fork_free_pid;
}
+ if (pid_ns_dead(pid)) {
+ spin_unlock(&current->sighand->siglock);
+ write_unlock_irq(&tasklist_lock);
+ retval = -EPERM;
+ goto bad_fork_free_pid;
+ }
+
if (clone_flags & CLONE_THREAD) {
current->signal->nr_threads++;
atomic_inc(&current->signal->live);
diff --git a/kernel/pid.c b/kernel/pid.c
index 5641acaa9029e..8c51c264242b2 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -76,6 +76,7 @@ struct pid_namespace init_pid_ns = {
[ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL }
},
.last_pid = 0,
+ .dead = 0,
.level = 0,
.child_reaper = &init_task,
.proc_inum = PROC_PID_INIT_INO,
@@ -292,6 +293,8 @@ struct pid *alloc_pid(struct pid_namespace *ns)
tmp = ns;
for (i = ns->level; i >= 0; i--) {
+ if (ns->dead)
+ goto out_free;
nr = alloc_pidmap(tmp);
if (nr < 0)
goto out_free;
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 0190b26dbdf36..c5da309246707 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -175,6 +175,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
*
*/
read_lock(&tasklist_lock);
+ pid_ns->dead = 1;
for (nr = next_pidmap(pid_ns, 0); nr > 0; nr = next_pidmap(pid_ns, nr)) {
/*