summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/fork.c17
-rw-r--r--kernel/nsproxy.c32
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(&current->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);
}