diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/exit.c | 4 | ||||
-rw-r--r-- | kernel/fork.c | 17 | ||||
-rw-r--r-- | kernel/nsproxy.c | 32 |
3 files changed, 37 insertions, 16 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 1d0e9ea1fa05..741bbe42dfe8 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -399,11 +399,8 @@ void daemonize(const char *name, ...) current->fs = fs; atomic_inc(&fs->count); - exit_namespace(current); exit_task_namespaces(current); - current->namespace = init_task.namespace; current->nsproxy = init_task.nsproxy; - get_namespace(current->namespace); get_task_namespaces(current); exit_files(current); @@ -923,7 +920,6 @@ fastcall NORET_TYPE void do_exit(long code) exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); - exit_namespace(tsk); exit_task_namespaces(tsk); exit_thread(); cpuset_exit(tsk); diff --git a/kernel/fork.c b/kernel/fork.c index c9e660ae47aa..33fcf0733ca6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1119,11 +1119,9 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto bad_fork_cleanup_mm; if ((retval = copy_namespaces(clone_flags, p))) goto bad_fork_cleanup_keys; - if ((retval = copy_namespace(clone_flags, p))) - goto bad_fork_cleanup_namespaces; retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); if (retval) - goto bad_fork_cleanup_namespace; + goto bad_fork_cleanup_namespaces; p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; /* @@ -1215,7 +1213,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); retval = -ERESTARTNOINTR; - goto bad_fork_cleanup_namespace; + goto bad_fork_cleanup_namespaces; } if (clone_flags & CLONE_THREAD) { @@ -1263,8 +1261,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, proc_fork_connector(p); return p; -bad_fork_cleanup_namespace: - exit_namespace(p); bad_fork_cleanup_namespaces: exit_task_namespaces(p); bad_fork_cleanup_keys: @@ -1519,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) */ static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) { - struct namespace *ns = current->namespace; + struct namespace *ns = current->nsproxy->namespace; - if ((unshare_flags & CLONE_NEWNS) && - (ns && atomic_read(&ns->count) > 1)) { + if ((unshare_flags & CLONE_NEWNS) && ns) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1655,8 +1650,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) } if (new_ns) { - ns = current->namespace; - current->namespace = new_ns; + ns = current->nsproxy->namespace; + current->nsproxy->namespace = new_ns; new_ns = ns; } diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index a3612f82f187..e10385c17f73 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -13,6 +13,7 @@ #include <linux/version.h> #include <linux/nsproxy.h> #include <linux/init_task.h> +#include <linux/namespace.h> struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); @@ -55,6 +56,11 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) { struct nsproxy *ns = clone_namespaces(orig); + if (ns) { + if (ns->namespace) + get_namespace(ns->namespace); + } + return ns; } @@ -65,16 +71,40 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) int copy_namespaces(int flags, struct task_struct *tsk) { struct nsproxy *old_ns = tsk->nsproxy; + struct nsproxy *new_ns; + int err = 0; if (!old_ns) return 0; get_nsproxy(old_ns); - return 0; + if (!(flags & CLONE_NEWNS)) + return 0; + + new_ns = clone_namespaces(old_ns); + if (!new_ns) { + err = -ENOMEM; + goto out; + } + + tsk->nsproxy = new_ns; + + err = copy_namespace(flags, tsk); + if (err) { + tsk->nsproxy = old_ns; + put_nsproxy(new_ns); + goto out; + } + +out: + put_nsproxy(old_ns); + return err; } void free_nsproxy(struct nsproxy *ns) { + if (ns->namespace) + put_namespace(ns->namespace); kfree(ns); } |