diff options
-rw-r--r-- | fs/namespace.c | 22 | ||||
-rw-r--r-- | fs/proc/base.c | 5 | ||||
-rw-r--r-- | include/linux/init_task.h | 1 | ||||
-rw-r--r-- | include/linux/namespace.h | 6 | ||||
-rw-r--r-- | include/linux/nsproxy.h | 3 | ||||
-rw-r--r-- | include/linux/sched.h | 4 | ||||
-rw-r--r-- | kernel/exit.c | 4 | ||||
-rw-r--r-- | kernel/fork.c | 17 | ||||
-rw-r--r-- | kernel/nsproxy.c | 32 |
9 files changed, 55 insertions, 39 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 66d921e14fee..55442a6cf221 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -133,7 +133,7 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) | |||
133 | 133 | ||
134 | static inline int check_mnt(struct vfsmount *mnt) | 134 | static inline int check_mnt(struct vfsmount *mnt) |
135 | { | 135 | { |
136 | return mnt->mnt_namespace == current->namespace; | 136 | return mnt->mnt_namespace == current->nsproxy->namespace; |
137 | } | 137 | } |
138 | 138 | ||
139 | static void touch_namespace(struct namespace *ns) | 139 | static void touch_namespace(struct namespace *ns) |
@@ -830,7 +830,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
830 | if (parent_nd) { | 830 | if (parent_nd) { |
831 | detach_mnt(source_mnt, parent_nd); | 831 | detach_mnt(source_mnt, parent_nd); |
832 | attach_mnt(source_mnt, nd); | 832 | attach_mnt(source_mnt, nd); |
833 | touch_namespace(current->namespace); | 833 | touch_namespace(current->nsproxy->namespace); |
834 | } else { | 834 | } else { |
835 | mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); | 835 | mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); |
836 | commit_tree(source_mnt); | 836 | commit_tree(source_mnt); |
@@ -1441,7 +1441,7 @@ dput_out: | |||
1441 | */ | 1441 | */ |
1442 | struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) | 1442 | struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) |
1443 | { | 1443 | { |
1444 | struct namespace *namespace = tsk->namespace; | 1444 | struct namespace *namespace = tsk->nsproxy->namespace; |
1445 | struct namespace *new_ns; | 1445 | struct namespace *new_ns; |
1446 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; | 1446 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; |
1447 | struct vfsmount *p, *q; | 1447 | struct vfsmount *p, *q; |
@@ -1508,7 +1508,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) | |||
1508 | 1508 | ||
1509 | int copy_namespace(int flags, struct task_struct *tsk) | 1509 | int copy_namespace(int flags, struct task_struct *tsk) |
1510 | { | 1510 | { |
1511 | struct namespace *namespace = tsk->namespace; | 1511 | struct namespace *namespace = tsk->nsproxy->namespace; |
1512 | struct namespace *new_ns; | 1512 | struct namespace *new_ns; |
1513 | int err = 0; | 1513 | int err = 0; |
1514 | 1514 | ||
@@ -1531,7 +1531,7 @@ int copy_namespace(int flags, struct task_struct *tsk) | |||
1531 | goto out; | 1531 | goto out; |
1532 | } | 1532 | } |
1533 | 1533 | ||
1534 | tsk->namespace = new_ns; | 1534 | tsk->nsproxy->namespace = new_ns; |
1535 | 1535 | ||
1536 | out: | 1536 | out: |
1537 | put_namespace(namespace); | 1537 | put_namespace(namespace); |
@@ -1754,7 +1754,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
1754 | detach_mnt(user_nd.mnt, &root_parent); | 1754 | detach_mnt(user_nd.mnt, &root_parent); |
1755 | attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ | 1755 | attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ |
1756 | attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ | 1756 | attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ |
1757 | touch_namespace(current->namespace); | 1757 | touch_namespace(current->nsproxy->namespace); |
1758 | spin_unlock(&vfsmount_lock); | 1758 | spin_unlock(&vfsmount_lock); |
1759 | chroot_fs_refs(&user_nd, &new_nd); | 1759 | chroot_fs_refs(&user_nd, &new_nd); |
1760 | security_sb_post_pivotroot(&user_nd, &new_nd); | 1760 | security_sb_post_pivotroot(&user_nd, &new_nd); |
@@ -1780,7 +1780,6 @@ static void __init init_mount_tree(void) | |||
1780 | { | 1780 | { |
1781 | struct vfsmount *mnt; | 1781 | struct vfsmount *mnt; |
1782 | struct namespace *namespace; | 1782 | struct namespace *namespace; |
1783 | struct task_struct *g, *p; | ||
1784 | 1783 | ||
1785 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); | 1784 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); |
1786 | if (IS_ERR(mnt)) | 1785 | if (IS_ERR(mnt)) |
@@ -1796,13 +1795,8 @@ static void __init init_mount_tree(void) | |||
1796 | namespace->root = mnt; | 1795 | namespace->root = mnt; |
1797 | mnt->mnt_namespace = namespace; | 1796 | mnt->mnt_namespace = namespace; |
1798 | 1797 | ||
1799 | init_task.namespace = namespace; | 1798 | init_task.nsproxy->namespace = namespace; |
1800 | read_lock(&tasklist_lock); | 1799 | get_namespace(namespace); |
1801 | do_each_thread(g, p) { | ||
1802 | get_namespace(namespace); | ||
1803 | p->namespace = namespace; | ||
1804 | } while_each_thread(g, p); | ||
1805 | read_unlock(&tasklist_lock); | ||
1806 | 1800 | ||
1807 | set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root); | 1801 | set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root); |
1808 | set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); | 1802 | set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 9c6a809f92b6..6d00ccc48c1c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -71,6 +71,7 @@ | |||
71 | #include <linux/cpuset.h> | 71 | #include <linux/cpuset.h> |
72 | #include <linux/audit.h> | 72 | #include <linux/audit.h> |
73 | #include <linux/poll.h> | 73 | #include <linux/poll.h> |
74 | #include <linux/nsproxy.h> | ||
74 | #include "internal.h" | 75 | #include "internal.h" |
75 | 76 | ||
76 | /* NOTE: | 77 | /* NOTE: |
@@ -473,7 +474,7 @@ static int mounts_open(struct inode *inode, struct file *file) | |||
473 | 474 | ||
474 | if (task) { | 475 | if (task) { |
475 | task_lock(task); | 476 | task_lock(task); |
476 | namespace = task->namespace; | 477 | namespace = task->nsproxy->namespace; |
477 | if (namespace) | 478 | if (namespace) |
478 | get_namespace(namespace); | 479 | get_namespace(namespace); |
479 | task_unlock(task); | 480 | task_unlock(task); |
@@ -544,7 +545,7 @@ static int mountstats_open(struct inode *inode, struct file *file) | |||
544 | 545 | ||
545 | if (task) { | 546 | if (task) { |
546 | task_lock(task); | 547 | task_lock(task); |
547 | namespace = task->namespace; | 548 | namespace = task->nsproxy->namespace; |
548 | if (namespace) | 549 | if (namespace) |
549 | get_namespace(namespace); | 550 | get_namespace(namespace); |
550 | task_unlock(task); | 551 | task_unlock(task); |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 8f8bb422a5c7..4865348ca8bd 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -72,6 +72,7 @@ extern struct nsproxy init_nsproxy; | |||
72 | #define INIT_NSPROXY(nsproxy) { \ | 72 | #define INIT_NSPROXY(nsproxy) { \ |
73 | .count = ATOMIC_INIT(1), \ | 73 | .count = ATOMIC_INIT(1), \ |
74 | .nslock = SPIN_LOCK_UNLOCKED, \ | 74 | .nslock = SPIN_LOCK_UNLOCKED, \ |
75 | .namespace = NULL, \ | ||
75 | } | 76 | } |
76 | 77 | ||
77 | #define INIT_SIGHAND(sighand) { \ | 78 | #define INIT_SIGHAND(sighand) { \ |
diff --git a/include/linux/namespace.h b/include/linux/namespace.h index 3abc8e3b4879..d137009f0b2b 100644 --- a/include/linux/namespace.h +++ b/include/linux/namespace.h | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | #include <linux/mount.h> | 5 | #include <linux/mount.h> |
6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
7 | #include <linux/nsproxy.h> | ||
7 | 8 | ||
8 | struct namespace { | 9 | struct namespace { |
9 | atomic_t count; | 10 | atomic_t count; |
@@ -26,11 +27,8 @@ static inline void put_namespace(struct namespace *namespace) | |||
26 | 27 | ||
27 | static inline void exit_namespace(struct task_struct *p) | 28 | static inline void exit_namespace(struct task_struct *p) |
28 | { | 29 | { |
29 | struct namespace *namespace = p->namespace; | 30 | struct namespace *namespace = p->nsproxy->namespace; |
30 | if (namespace) { | 31 | if (namespace) { |
31 | task_lock(p); | ||
32 | p->namespace = NULL; | ||
33 | task_unlock(p); | ||
34 | put_namespace(namespace); | 32 | put_namespace(namespace); |
35 | } | 33 | } |
36 | } | 34 | } |
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 7bdebfaab6a5..7ebe66670c59 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h | |||
@@ -4,6 +4,8 @@ | |||
4 | #include <linux/spinlock.h> | 4 | #include <linux/spinlock.h> |
5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
6 | 6 | ||
7 | struct namespace; | ||
8 | |||
7 | /* | 9 | /* |
8 | * A structure to contain pointers to all per-process | 10 | * A structure to contain pointers to all per-process |
9 | * namespaces - fs (mount), uts, network, sysvipc, etc. | 11 | * namespaces - fs (mount), uts, network, sysvipc, etc. |
@@ -19,6 +21,7 @@ | |||
19 | struct nsproxy { | 21 | struct nsproxy { |
20 | atomic_t count; | 22 | atomic_t count; |
21 | spinlock_t nslock; | 23 | spinlock_t nslock; |
24 | struct namespace *namespace; | ||
22 | }; | 25 | }; |
23 | extern struct nsproxy init_nsproxy; | 26 | extern struct nsproxy init_nsproxy; |
24 | 27 | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index 4fa631fa55e3..670b89a20070 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -238,7 +238,6 @@ extern signed long schedule_timeout_interruptible(signed long timeout); | |||
238 | extern signed long schedule_timeout_uninterruptible(signed long timeout); | 238 | extern signed long schedule_timeout_uninterruptible(signed long timeout); |
239 | asmlinkage void schedule(void); | 239 | asmlinkage void schedule(void); |
240 | 240 | ||
241 | struct namespace; | ||
242 | struct nsproxy; | 241 | struct nsproxy; |
243 | 242 | ||
244 | /* Maximum number of active map areas.. This is a random (large) number */ | 243 | /* Maximum number of active map areas.. This is a random (large) number */ |
@@ -897,8 +896,7 @@ struct task_struct { | |||
897 | struct fs_struct *fs; | 896 | struct fs_struct *fs; |
898 | /* open file information */ | 897 | /* open file information */ |
899 | struct files_struct *files; | 898 | struct files_struct *files; |
900 | /* namespace */ | 899 | /* namespaces */ |
901 | struct namespace *namespace; | ||
902 | struct nsproxy *nsproxy; | 900 | struct nsproxy *nsproxy; |
903 | /* signal handlers */ | 901 | /* signal handlers */ |
904 | struct signal_struct *signal; | 902 | struct signal_struct *signal; |
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, ...) | |||
399 | current->fs = fs; | 399 | current->fs = fs; |
400 | atomic_inc(&fs->count); | 400 | atomic_inc(&fs->count); |
401 | 401 | ||
402 | exit_namespace(current); | ||
403 | exit_task_namespaces(current); | 402 | exit_task_namespaces(current); |
404 | current->namespace = init_task.namespace; | ||
405 | current->nsproxy = init_task.nsproxy; | 403 | current->nsproxy = init_task.nsproxy; |
406 | get_namespace(current->namespace); | ||
407 | get_task_namespaces(current); | 404 | get_task_namespaces(current); |
408 | 405 | ||
409 | exit_files(current); | 406 | exit_files(current); |
@@ -923,7 +920,6 @@ fastcall NORET_TYPE void do_exit(long code) | |||
923 | exit_sem(tsk); | 920 | exit_sem(tsk); |
924 | __exit_files(tsk); | 921 | __exit_files(tsk); |
925 | __exit_fs(tsk); | 922 | __exit_fs(tsk); |
926 | exit_namespace(tsk); | ||
927 | exit_task_namespaces(tsk); | 923 | exit_task_namespaces(tsk); |
928 | exit_thread(); | 924 | exit_thread(); |
929 | cpuset_exit(tsk); | 925 | 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, | |||
1119 | goto bad_fork_cleanup_mm; | 1119 | goto bad_fork_cleanup_mm; |
1120 | if ((retval = copy_namespaces(clone_flags, p))) | 1120 | if ((retval = copy_namespaces(clone_flags, p))) |
1121 | goto bad_fork_cleanup_keys; | 1121 | goto bad_fork_cleanup_keys; |
1122 | if ((retval = copy_namespace(clone_flags, p))) | ||
1123 | goto bad_fork_cleanup_namespaces; | ||
1124 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); | 1122 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); |
1125 | if (retval) | 1123 | if (retval) |
1126 | goto bad_fork_cleanup_namespace; | 1124 | goto bad_fork_cleanup_namespaces; |
1127 | 1125 | ||
1128 | p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; | 1126 | p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; |
1129 | /* | 1127 | /* |
@@ -1215,7 +1213,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1215 | spin_unlock(¤t->sighand->siglock); | 1213 | spin_unlock(¤t->sighand->siglock); |
1216 | write_unlock_irq(&tasklist_lock); | 1214 | write_unlock_irq(&tasklist_lock); |
1217 | retval = -ERESTARTNOINTR; | 1215 | retval = -ERESTARTNOINTR; |
1218 | goto bad_fork_cleanup_namespace; | 1216 | goto bad_fork_cleanup_namespaces; |
1219 | } | 1217 | } |
1220 | 1218 | ||
1221 | if (clone_flags & CLONE_THREAD) { | 1219 | if (clone_flags & CLONE_THREAD) { |
@@ -1263,8 +1261,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1263 | proc_fork_connector(p); | 1261 | proc_fork_connector(p); |
1264 | return p; | 1262 | return p; |
1265 | 1263 | ||
1266 | bad_fork_cleanup_namespace: | ||
1267 | exit_namespace(p); | ||
1268 | bad_fork_cleanup_namespaces: | 1264 | bad_fork_cleanup_namespaces: |
1269 | exit_task_namespaces(p); | 1265 | exit_task_namespaces(p); |
1270 | bad_fork_cleanup_keys: | 1266 | bad_fork_cleanup_keys: |
@@ -1519,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) | |||
1519 | */ | 1515 | */ |
1520 | static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) | 1516 | static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) |
1521 | { | 1517 | { |
1522 | struct namespace *ns = current->namespace; | 1518 | struct namespace *ns = current->nsproxy->namespace; |
1523 | 1519 | ||
1524 | if ((unshare_flags & CLONE_NEWNS) && | 1520 | if ((unshare_flags & CLONE_NEWNS) && ns) { |
1525 | (ns && atomic_read(&ns->count) > 1)) { | ||
1526 | if (!capable(CAP_SYS_ADMIN)) | 1521 | if (!capable(CAP_SYS_ADMIN)) |
1527 | return -EPERM; | 1522 | return -EPERM; |
1528 | 1523 | ||
@@ -1655,8 +1650,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1655 | } | 1650 | } |
1656 | 1651 | ||
1657 | if (new_ns) { | 1652 | if (new_ns) { |
1658 | ns = current->namespace; | 1653 | ns = current->nsproxy->namespace; |
1659 | current->namespace = new_ns; | 1654 | current->nsproxy->namespace = new_ns; |
1660 | new_ns = ns; | 1655 | new_ns = ns; |
1661 | } | 1656 | } |
1662 | 1657 | ||
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 @@ | |||
13 | #include <linux/version.h> | 13 | #include <linux/version.h> |
14 | #include <linux/nsproxy.h> | 14 | #include <linux/nsproxy.h> |
15 | #include <linux/init_task.h> | 15 | #include <linux/init_task.h> |
16 | #include <linux/namespace.h> | ||
16 | 17 | ||
17 | struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); | 18 | struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); |
18 | 19 | ||
@@ -55,6 +56,11 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) | |||
55 | { | 56 | { |
56 | struct nsproxy *ns = clone_namespaces(orig); | 57 | struct nsproxy *ns = clone_namespaces(orig); |
57 | 58 | ||
59 | if (ns) { | ||
60 | if (ns->namespace) | ||
61 | get_namespace(ns->namespace); | ||
62 | } | ||
63 | |||
58 | return ns; | 64 | return ns; |
59 | } | 65 | } |
60 | 66 | ||
@@ -65,16 +71,40 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) | |||
65 | int copy_namespaces(int flags, struct task_struct *tsk) | 71 | int copy_namespaces(int flags, struct task_struct *tsk) |
66 | { | 72 | { |
67 | struct nsproxy *old_ns = tsk->nsproxy; | 73 | struct nsproxy *old_ns = tsk->nsproxy; |
74 | struct nsproxy *new_ns; | ||
75 | int err = 0; | ||
68 | 76 | ||
69 | if (!old_ns) | 77 | if (!old_ns) |
70 | return 0; | 78 | return 0; |
71 | 79 | ||
72 | get_nsproxy(old_ns); | 80 | get_nsproxy(old_ns); |
73 | 81 | ||
74 | return 0; | 82 | if (!(flags & CLONE_NEWNS)) |
83 | return 0; | ||
84 | |||
85 | new_ns = clone_namespaces(old_ns); | ||
86 | if (!new_ns) { | ||
87 | err = -ENOMEM; | ||
88 | goto out; | ||
89 | } | ||
90 | |||
91 | tsk->nsproxy = new_ns; | ||
92 | |||
93 | err = copy_namespace(flags, tsk); | ||
94 | if (err) { | ||
95 | tsk->nsproxy = old_ns; | ||
96 | put_nsproxy(new_ns); | ||
97 | goto out; | ||
98 | } | ||
99 | |||
100 | out: | ||
101 | put_nsproxy(old_ns); | ||
102 | return err; | ||
75 | } | 103 | } |
76 | 104 | ||
77 | void free_nsproxy(struct nsproxy *ns) | 105 | void free_nsproxy(struct nsproxy *ns) |
78 | { | 106 | { |
107 | if (ns->namespace) | ||
108 | put_namespace(ns->namespace); | ||
79 | kfree(ns); | 109 | kfree(ns); |
80 | } | 110 | } |