aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorBadari Pulavarty <pbadari@us.ibm.com>2007-05-08 03:25:21 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:00 -0400
commite3222c4ecc649c4ae568e61dda9349482401b501 (patch)
treed96614ef67d947a3dd8ab0929a4755bce9fdbcc1 /kernel
parent4fc75ff4816c3483b4b772b2f6cb3d8fd88ca547 (diff)
Merge sys_clone()/sys_unshare() nsproxy and namespace handling
sys_clone() and sys_unshare() both makes copies of nsproxy and its associated namespaces. But they have different code paths. This patch merges all the nsproxy and its associated namespace copy/clone handling (as much as possible). Posted on container list earlier for feedback. - Create a new nsproxy and its associated namespaces and pass it back to caller to attach it to right process. - Changed all copy_*_ns() routines to return a new copy of namespace instead of attaching it to task->nsproxy. - Moved the CAP_SYS_ADMIN checks out of copy_*_ns() routines. - Removed unnessary !ns checks from copy_*_ns() and added BUG_ON() just incase. - Get rid of all individual unshare_*_ns() routines and make use of copy_*_ns() instead. [akpm@osdl.org: cleanups, warning fix] [clg@fr.ibm.com: remove dup_namespaces() declaration] [serue@us.ibm.com: fix CONFIG_IPC_NS=n, clone(CLONE_NEWIPC) retval] [akpm@linux-foundation.org: fix build with CONFIG_SYSVIPC=n] Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com> Signed-off-by: Serge Hallyn <serue@us.ibm.com> Cc: Cedric Le Goater <clg@fr.ibm.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: <containers@lists.osdl.org> Signed-off-by: Cedric Le Goater <clg@fr.ibm.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c85
-rw-r--r--kernel/nsproxy.c139
-rw-r--r--kernel/pid.c11
-rw-r--r--kernel/utsname.c41
4 files changed, 98 insertions, 178 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index b7d169def942..fd211b9dddd4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1516,26 +1516,6 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
1516} 1516}
1517 1517
1518/* 1518/*
1519 * Unshare the mnt_namespace structure if it is being shared
1520 */
1521static int unshare_mnt_namespace(unsigned long unshare_flags,
1522 struct mnt_namespace **new_nsp, struct fs_struct *new_fs)
1523{
1524 struct mnt_namespace *ns = current->nsproxy->mnt_ns;
1525
1526 if ((unshare_flags & CLONE_NEWNS) && ns) {
1527 if (!capable(CAP_SYS_ADMIN))
1528 return -EPERM;
1529
1530 *new_nsp = dup_mnt_ns(current, new_fs ? new_fs : current->fs);
1531 if (!*new_nsp)
1532 return -ENOMEM;
1533 }
1534
1535 return 0;
1536}
1537
1538/*
1539 * Unsharing of sighand is not supported yet 1519 * Unsharing of sighand is not supported yet
1540 */ 1520 */
1541static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp) 1521static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp)
@@ -1593,16 +1573,6 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n
1593 return 0; 1573 return 0;
1594} 1574}
1595 1575
1596#ifndef CONFIG_IPC_NS
1597static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns)
1598{
1599 if (flags & CLONE_NEWIPC)
1600 return -EINVAL;
1601
1602 return 0;
1603}
1604#endif
1605
1606/* 1576/*
1607 * unshare allows a process to 'unshare' part of the process 1577 * unshare allows a process to 'unshare' part of the process
1608 * context which was originally shared using clone. copy_* 1578 * context which was originally shared using clone. copy_*
@@ -1615,14 +1585,11 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
1615{ 1585{
1616 int err = 0; 1586 int err = 0;
1617 struct fs_struct *fs, *new_fs = NULL; 1587 struct fs_struct *fs, *new_fs = NULL;
1618 struct mnt_namespace *ns, *new_ns = NULL;
1619 struct sighand_struct *new_sigh = NULL; 1588 struct sighand_struct *new_sigh = NULL;
1620 struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; 1589 struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
1621 struct files_struct *fd, *new_fd = NULL; 1590 struct files_struct *fd, *new_fd = NULL;
1622 struct sem_undo_list *new_ulist = NULL; 1591 struct sem_undo_list *new_ulist = NULL;
1623 struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL; 1592 struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL;
1624 struct uts_namespace *uts, *new_uts = NULL;
1625 struct ipc_namespace *ipc, *new_ipc = NULL;
1626 1593
1627 check_unshare_flags(&unshare_flags); 1594 check_unshare_flags(&unshare_flags);
1628 1595
@@ -1637,36 +1604,24 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
1637 goto bad_unshare_out; 1604 goto bad_unshare_out;
1638 if ((err = unshare_fs(unshare_flags, &new_fs))) 1605 if ((err = unshare_fs(unshare_flags, &new_fs)))
1639 goto bad_unshare_cleanup_thread; 1606 goto bad_unshare_cleanup_thread;
1640 if ((err = unshare_mnt_namespace(unshare_flags, &new_ns, new_fs)))
1641 goto bad_unshare_cleanup_fs;
1642 if ((err = unshare_sighand(unshare_flags, &new_sigh))) 1607 if ((err = unshare_sighand(unshare_flags, &new_sigh)))
1643 goto bad_unshare_cleanup_ns; 1608 goto bad_unshare_cleanup_fs;
1644 if ((err = unshare_vm(unshare_flags, &new_mm))) 1609 if ((err = unshare_vm(unshare_flags, &new_mm)))
1645 goto bad_unshare_cleanup_sigh; 1610 goto bad_unshare_cleanup_sigh;
1646 if ((err = unshare_fd(unshare_flags, &new_fd))) 1611 if ((err = unshare_fd(unshare_flags, &new_fd)))
1647 goto bad_unshare_cleanup_vm; 1612 goto bad_unshare_cleanup_vm;
1648 if ((err = unshare_semundo(unshare_flags, &new_ulist))) 1613 if ((err = unshare_semundo(unshare_flags, &new_ulist)))
1649 goto bad_unshare_cleanup_fd; 1614 goto bad_unshare_cleanup_fd;
1650 if ((err = unshare_utsname(unshare_flags, &new_uts))) 1615 if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy,
1616 new_fs)))
1651 goto bad_unshare_cleanup_semundo; 1617 goto bad_unshare_cleanup_semundo;
1652 if ((err = unshare_ipcs(unshare_flags, &new_ipc)))
1653 goto bad_unshare_cleanup_uts;
1654
1655 if (new_ns || new_uts || new_ipc) {
1656 old_nsproxy = current->nsproxy;
1657 new_nsproxy = dup_namespaces(old_nsproxy);
1658 if (!new_nsproxy) {
1659 err = -ENOMEM;
1660 goto bad_unshare_cleanup_ipc;
1661 }
1662 }
1663 1618
1664 if (new_fs || new_ns || new_mm || new_fd || new_ulist || 1619 if (new_fs || new_mm || new_fd || new_ulist || new_nsproxy) {
1665 new_uts || new_ipc) {
1666 1620
1667 task_lock(current); 1621 task_lock(current);
1668 1622
1669 if (new_nsproxy) { 1623 if (new_nsproxy) {
1624 old_nsproxy = current->nsproxy;
1670 current->nsproxy = new_nsproxy; 1625 current->nsproxy = new_nsproxy;
1671 new_nsproxy = old_nsproxy; 1626 new_nsproxy = old_nsproxy;
1672 } 1627 }
@@ -1677,12 +1632,6 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
1677 new_fs = fs; 1632 new_fs = fs;
1678 } 1633 }
1679 1634
1680 if (new_ns) {
1681 ns = current->nsproxy->mnt_ns;
1682 current->nsproxy->mnt_ns = new_ns;
1683 new_ns = ns;
1684 }
1685
1686 if (new_mm) { 1635 if (new_mm) {
1687 mm = current->mm; 1636 mm = current->mm;
1688 active_mm = current->active_mm; 1637 active_mm = current->active_mm;
@@ -1698,32 +1647,12 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
1698 new_fd = fd; 1647 new_fd = fd;
1699 } 1648 }
1700 1649
1701 if (new_uts) {
1702 uts = current->nsproxy->uts_ns;
1703 current->nsproxy->uts_ns = new_uts;
1704 new_uts = uts;
1705 }
1706
1707 if (new_ipc) {
1708 ipc = current->nsproxy->ipc_ns;
1709 current->nsproxy->ipc_ns = new_ipc;
1710 new_ipc = ipc;
1711 }
1712
1713 task_unlock(current); 1650 task_unlock(current);
1714 } 1651 }
1715 1652
1716 if (new_nsproxy) 1653 if (new_nsproxy)
1717 put_nsproxy(new_nsproxy); 1654 put_nsproxy(new_nsproxy);
1718 1655
1719bad_unshare_cleanup_ipc:
1720 if (new_ipc)
1721 put_ipc_ns(new_ipc);
1722
1723bad_unshare_cleanup_uts:
1724 if (new_uts)
1725 put_uts_ns(new_uts);
1726
1727bad_unshare_cleanup_semundo: 1656bad_unshare_cleanup_semundo:
1728bad_unshare_cleanup_fd: 1657bad_unshare_cleanup_fd:
1729 if (new_fd) 1658 if (new_fd)
@@ -1738,10 +1667,6 @@ bad_unshare_cleanup_sigh:
1738 if (atomic_dec_and_test(&new_sigh->count)) 1667 if (atomic_dec_and_test(&new_sigh->count))
1739 kmem_cache_free(sighand_cachep, new_sigh); 1668 kmem_cache_free(sighand_cachep, new_sigh);
1740 1669
1741bad_unshare_cleanup_ns:
1742 if (new_ns)
1743 put_mnt_ns(new_ns);
1744
1745bad_unshare_cleanup_fs: 1670bad_unshare_cleanup_fs:
1746 if (new_fs) 1671 if (new_fs)
1747 put_fs_struct(new_fs); 1672 put_fs_struct(new_fs);
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index f5b9ee6f6bbb..1bc4b55241a8 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -38,10 +38,8 @@ void get_task_namespaces(struct task_struct *tsk)
38 38
39/* 39/*
40 * creates a copy of "orig" with refcount 1. 40 * creates a copy of "orig" with refcount 1.
41 * This does not grab references to the contained namespaces,
42 * so that needs to be done by dup_namespaces.
43 */ 41 */
44static inline struct nsproxy *clone_namespaces(struct nsproxy *orig) 42static inline struct nsproxy *clone_nsproxy(struct nsproxy *orig)
45{ 43{
46 struct nsproxy *ns; 44 struct nsproxy *ns;
47 45
@@ -52,26 +50,49 @@ static inline struct nsproxy *clone_namespaces(struct nsproxy *orig)
52} 50}
53 51
54/* 52/*
55 * copies the nsproxy, setting refcount to 1, and grabbing a 53 * Create new nsproxy and all of its the associated namespaces.
56 * reference to all contained namespaces. Called from 54 * Return the newly created nsproxy. Do not attach this to the task,
57 * sys_unshare() 55 * leave it to the caller to do proper locking and attach it to task.
58 */ 56 */
59struct nsproxy *dup_namespaces(struct nsproxy *orig) 57static struct nsproxy *create_new_namespaces(int flags, struct task_struct *tsk,
58 struct fs_struct *new_fs)
60{ 59{
61 struct nsproxy *ns = clone_namespaces(orig); 60 struct nsproxy *new_nsp;
62 61
63 if (ns) { 62 new_nsp = clone_nsproxy(tsk->nsproxy);
64 if (ns->mnt_ns) 63 if (!new_nsp)
65 get_mnt_ns(ns->mnt_ns); 64 return ERR_PTR(-ENOMEM);
66 if (ns->uts_ns)
67 get_uts_ns(ns->uts_ns);
68 if (ns->ipc_ns)
69 get_ipc_ns(ns->ipc_ns);
70 if (ns->pid_ns)
71 get_pid_ns(ns->pid_ns);
72 }
73 65
74 return ns; 66 new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs);
67 if (IS_ERR(new_nsp->mnt_ns))
68 goto out_ns;
69
70 new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns);
71 if (IS_ERR(new_nsp->uts_ns))
72 goto out_uts;
73
74 new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns);
75 if (IS_ERR(new_nsp->ipc_ns))
76 goto out_ipc;
77
78 new_nsp->pid_ns = copy_pid_ns(flags, tsk->nsproxy->pid_ns);
79 if (IS_ERR(new_nsp->pid_ns))
80 goto out_pid;
81
82 return new_nsp;
83
84out_pid:
85 if (new_nsp->ipc_ns)
86 put_ipc_ns(new_nsp->ipc_ns);
87out_ipc:
88 if (new_nsp->uts_ns)
89 put_uts_ns(new_nsp->uts_ns);
90out_uts:
91 if (new_nsp->mnt_ns)
92 put_mnt_ns(new_nsp->mnt_ns);
93out_ns:
94 kfree(new_nsp);
95 return ERR_PTR(-ENOMEM);
75} 96}
76 97
77/* 98/*
@@ -92,47 +113,21 @@ int copy_namespaces(int flags, struct task_struct *tsk)
92 if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) 113 if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
93 return 0; 114 return 0;
94 115
95 new_ns = clone_namespaces(old_ns); 116 if (!capable(CAP_SYS_ADMIN)) {
96 if (!new_ns) { 117 err = -EPERM;
97 err = -ENOMEM;
98 goto out; 118 goto out;
99 } 119 }
100 120
101 tsk->nsproxy = new_ns; 121 new_ns = create_new_namespaces(flags, tsk, tsk->fs);
102 122 if (IS_ERR(new_ns)) {
103 err = copy_mnt_ns(flags, tsk); 123 err = PTR_ERR(new_ns);
104 if (err) 124 goto out;
105 goto out_ns; 125 }
106
107 err = copy_utsname(flags, tsk);
108 if (err)
109 goto out_uts;
110
111 err = copy_ipcs(flags, tsk);
112 if (err)
113 goto out_ipc;
114
115 err = copy_pid_ns(flags, tsk);
116 if (err)
117 goto out_pid;
118 126
127 tsk->nsproxy = new_ns;
119out: 128out:
120 put_nsproxy(old_ns); 129 put_nsproxy(old_ns);
121 return err; 130 return err;
122
123out_pid:
124 if (new_ns->ipc_ns)
125 put_ipc_ns(new_ns->ipc_ns);
126out_ipc:
127 if (new_ns->uts_ns)
128 put_uts_ns(new_ns->uts_ns);
129out_uts:
130 if (new_ns->mnt_ns)
131 put_mnt_ns(new_ns->mnt_ns);
132out_ns:
133 tsk->nsproxy = old_ns;
134 kfree(new_ns);
135 goto out;
136} 131}
137 132
138void free_nsproxy(struct nsproxy *ns) 133void free_nsproxy(struct nsproxy *ns)
@@ -147,3 +142,41 @@ void free_nsproxy(struct nsproxy *ns)
147 put_pid_ns(ns->pid_ns); 142 put_pid_ns(ns->pid_ns);
148 kfree(ns); 143 kfree(ns);
149} 144}
145
146/*
147 * Called from unshare. Unshare all the namespaces part of nsproxy.
148 * On sucess, returns the new nsproxy and a reference to old nsproxy
149 * to make sure it stays around.
150 */
151int unshare_nsproxy_namespaces(unsigned long unshare_flags,
152 struct nsproxy **new_nsp, struct fs_struct *new_fs)
153{
154 struct nsproxy *old_ns = current->nsproxy;
155 int err = 0;
156
157 if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
158 return 0;
159
160#ifndef CONFIG_IPC_NS
161 if (unshare_flags & CLONE_NEWIPC)
162 return -EINVAL;
163#endif
164
165#ifndef CONFIG_UTS_NS
166 if (unshare_flags & CLONE_NEWUTS)
167 return -EINVAL;
168#endif
169
170 if (!capable(CAP_SYS_ADMIN))
171 return -EPERM;
172
173 get_nsproxy(old_ns);
174
175 *new_nsp = create_new_namespaces(unshare_flags, current,
176 new_fs ? new_fs : current->fs);
177 if (IS_ERR(*new_nsp)) {
178 err = PTR_ERR(*new_nsp);
179 put_nsproxy(old_ns);
180 }
181 return err;
182}
diff --git a/kernel/pid.c b/kernel/pid.c
index 9c80bc23d6b8..d3ad724afa83 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -360,16 +360,11 @@ struct pid *find_ge_pid(int nr)
360} 360}
361EXPORT_SYMBOL_GPL(find_get_pid); 361EXPORT_SYMBOL_GPL(find_get_pid);
362 362
363int copy_pid_ns(int flags, struct task_struct *tsk) 363struct pid_namespace *copy_pid_ns(int flags, struct pid_namespace *old_ns)
364{ 364{
365 struct pid_namespace *old_ns = tsk->nsproxy->pid_ns; 365 BUG_ON(!old_ns);
366 int err = 0;
367
368 if (!old_ns)
369 return 0;
370
371 get_pid_ns(old_ns); 366 get_pid_ns(old_ns);
372 return err; 367 return old_ns;
373} 368}
374 369
375void free_pid_ns(struct kref *kref) 370void free_pid_ns(struct kref *kref)
diff --git a/kernel/utsname.c b/kernel/utsname.c
index c859164a6993..160c8c5136bd 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -32,58 +32,25 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
32} 32}
33 33
34/* 34/*
35 * unshare the current process' utsname namespace.
36 * called only in sys_unshare()
37 */
38int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts)
39{
40 if (unshare_flags & CLONE_NEWUTS) {
41 if (!capable(CAP_SYS_ADMIN))
42 return -EPERM;
43
44 *new_uts = clone_uts_ns(current->nsproxy->uts_ns);
45 if (!*new_uts)
46 return -ENOMEM;
47 }
48
49 return 0;
50}
51
52/*
53 * Copy task tsk's utsname namespace, or clone it if flags 35 * Copy task tsk's utsname namespace, or clone it if flags
54 * specifies CLONE_NEWUTS. In latter case, changes to the 36 * specifies CLONE_NEWUTS. In latter case, changes to the
55 * utsname of this process won't be seen by parent, and vice 37 * utsname of this process won't be seen by parent, and vice
56 * versa. 38 * versa.
57 */ 39 */
58int copy_utsname(int flags, struct task_struct *tsk) 40struct uts_namespace *copy_utsname(int flags, struct uts_namespace *old_ns)
59{ 41{
60 struct uts_namespace *old_ns = tsk->nsproxy->uts_ns;
61 struct uts_namespace *new_ns; 42 struct uts_namespace *new_ns;
62 int err = 0;
63
64 if (!old_ns)
65 return 0;
66 43
44 BUG_ON(!old_ns);
67 get_uts_ns(old_ns); 45 get_uts_ns(old_ns);
68 46
69 if (!(flags & CLONE_NEWUTS)) 47 if (!(flags & CLONE_NEWUTS))
70 return 0; 48 return old_ns;
71
72 if (!capable(CAP_SYS_ADMIN)) {
73 err = -EPERM;
74 goto out;
75 }
76 49
77 new_ns = clone_uts_ns(old_ns); 50 new_ns = clone_uts_ns(old_ns);
78 if (!new_ns) {
79 err = -ENOMEM;
80 goto out;
81 }
82 tsk->nsproxy->uts_ns = new_ns;
83 51
84out:
85 put_uts_ns(old_ns); 52 put_uts_ns(old_ns);
86 return err; 53 return new_ns;
87} 54}
88 55
89void free_uts_ns(struct kref *kref) 56void free_uts_ns(struct kref *kref)