diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2010-07-12 18:50:25 -0700 |
---|---|---|
committer | Eric W. Biederman <ebiederm@aristanetworks.com> | 2011-08-09 05:00:14 -0500 |
commit | d6a5b1482d7ba86cf639f35540812d6d6e905ccd (patch) | |
tree | f7bf95a77788ee4ef2e8c07b5029232c6b48ecfe | |
parent | 4b5c41aad4f6a4f9d723b8b5aea8c01264bd0763 (diff) | |
download | linux-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.h | 18 | ||||
-rw-r--r-- | kernel/fork.c | 7 | ||||
-rw-r--r-- | kernel/pid.c | 3 | ||||
-rw-r--r-- | kernel/pid_namespace.c | 1 |
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(¤t->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(¤t->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)) { /* |