aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/namespace.c30
-rw-r--r--include/linux/ipc.h11
-rw-r--r--include/linux/mnt_namespace.h5
-rw-r--r--include/linux/nsproxy.h3
-rw-r--r--include/linux/pid_namespace.h2
-rw-r--r--include/linux/utsname.h19
-rw-r--r--ipc/util.c53
-rw-r--r--kernel/fork.c85
-rw-r--r--kernel/nsproxy.c139
-rw-r--r--kernel/pid.c11
-rw-r--r--kernel/utsname.c41
11 files changed, 131 insertions, 268 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index fd999cab7b57..be5e56bfb73e 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1441,10 +1441,9 @@ dput_out:
1441 * Allocate a new namespace structure and populate it with contents 1441 * Allocate a new namespace structure and populate it with contents
1442 * copied from the namespace of the passed in task structure. 1442 * copied from the namespace of the passed in task structure.
1443 */ 1443 */
1444struct mnt_namespace *dup_mnt_ns(struct task_struct *tsk, 1444static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
1445 struct fs_struct *fs) 1445 struct fs_struct *fs)
1446{ 1446{
1447 struct mnt_namespace *mnt_ns = tsk->nsproxy->mnt_ns;
1448 struct mnt_namespace *new_ns; 1447 struct mnt_namespace *new_ns;
1449 struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; 1448 struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
1450 struct vfsmount *p, *q; 1449 struct vfsmount *p, *q;
@@ -1509,36 +1508,21 @@ struct mnt_namespace *dup_mnt_ns(struct task_struct *tsk,
1509 return new_ns; 1508 return new_ns;
1510} 1509}
1511 1510
1512int copy_mnt_ns(int flags, struct task_struct *tsk) 1511struct mnt_namespace *copy_mnt_ns(int flags, struct mnt_namespace *ns,
1512 struct fs_struct *new_fs)
1513{ 1513{
1514 struct mnt_namespace *ns = tsk->nsproxy->mnt_ns;
1515 struct mnt_namespace *new_ns; 1514 struct mnt_namespace *new_ns;
1516 int err = 0;
1517
1518 if (!ns)
1519 return 0;
1520 1515
1516 BUG_ON(!ns);
1521 get_mnt_ns(ns); 1517 get_mnt_ns(ns);
1522 1518
1523 if (!(flags & CLONE_NEWNS)) 1519 if (!(flags & CLONE_NEWNS))
1524 return 0; 1520 return ns;
1525
1526 if (!capable(CAP_SYS_ADMIN)) {
1527 err = -EPERM;
1528 goto out;
1529 }
1530
1531 new_ns = dup_mnt_ns(tsk, tsk->fs);
1532 if (!new_ns) {
1533 err = -ENOMEM;
1534 goto out;
1535 }
1536 1521
1537 tsk->nsproxy->mnt_ns = new_ns; 1522 new_ns = dup_mnt_ns(ns, new_fs);
1538 1523
1539out:
1540 put_mnt_ns(ns); 1524 put_mnt_ns(ns);
1541 return err; 1525 return new_ns;
1542} 1526}
1543 1527
1544asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, 1528asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name,
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 6da6772c19ff..1980867a64a4 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -92,16 +92,19 @@ extern struct ipc_namespace init_ipc_ns;
92 92
93#ifdef CONFIG_SYSVIPC 93#ifdef CONFIG_SYSVIPC
94#define INIT_IPC_NS(ns) .ns = &init_ipc_ns, 94#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
95extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); 95extern struct ipc_namespace *copy_ipcs(unsigned long flags,
96 struct ipc_namespace *ns);
96#else 97#else
97#define INIT_IPC_NS(ns) 98#define INIT_IPC_NS(ns)
98static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk) 99static inline struct ipc_namespace *copy_ipcs(unsigned long flags,
99{ return 0; } 100 struct ipc_namespace *ns)
101{
102 return ns;
103}
100#endif 104#endif
101 105
102#ifdef CONFIG_IPC_NS 106#ifdef CONFIG_IPC_NS
103extern void free_ipc_ns(struct kref *kref); 107extern void free_ipc_ns(struct kref *kref);
104extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns);
105#endif 108#endif
106 109
107static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) 110static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h
index 4af0b1fc282a..1fa4d9813b31 100644
--- a/include/linux/mnt_namespace.h
+++ b/include/linux/mnt_namespace.h
@@ -14,10 +14,9 @@ struct mnt_namespace {
14 int event; 14 int event;
15}; 15};
16 16
17extern int copy_mnt_ns(int, struct task_struct *); 17extern struct mnt_namespace *copy_mnt_ns(int, struct mnt_namespace *,
18extern void __put_mnt_ns(struct mnt_namespace *ns);
19extern struct mnt_namespace *dup_mnt_ns(struct task_struct *,
20 struct fs_struct *); 18 struct fs_struct *);
19extern void __put_mnt_ns(struct mnt_namespace *ns);
21 20
22static inline void put_mnt_ns(struct mnt_namespace *ns) 21static inline void put_mnt_ns(struct mnt_namespace *ns)
23{ 22{
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index 0b9f0dc30d61..189e0dc993ab 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -31,10 +31,11 @@ struct nsproxy {
31}; 31};
32extern struct nsproxy init_nsproxy; 32extern struct nsproxy init_nsproxy;
33 33
34struct nsproxy *dup_namespaces(struct nsproxy *orig);
35int copy_namespaces(int flags, struct task_struct *tsk); 34int copy_namespaces(int flags, struct task_struct *tsk);
36void get_task_namespaces(struct task_struct *tsk); 35void get_task_namespaces(struct task_struct *tsk);
37void free_nsproxy(struct nsproxy *ns); 36void free_nsproxy(struct nsproxy *ns);
37int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **,
38 struct fs_struct *);
38 39
39static inline void put_nsproxy(struct nsproxy *ns) 40static inline void put_nsproxy(struct nsproxy *ns)
40{ 41{
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 2833806d42c6..169c6c24209b 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -29,7 +29,7 @@ static inline void get_pid_ns(struct pid_namespace *ns)
29 kref_get(&ns->kref); 29 kref_get(&ns->kref);
30} 30}
31 31
32extern int copy_pid_ns(int flags, struct task_struct *tsk); 32extern struct pid_namespace *copy_pid_ns(int flags, struct pid_namespace *ns);
33extern void free_pid_ns(struct kref *kref); 33extern void free_pid_ns(struct kref *kref);
34 34
35static inline void put_pid_ns(struct pid_namespace *ns) 35static inline void put_pid_ns(struct pid_namespace *ns)
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index e10267d402c5..f8d3b326e93a 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -49,9 +49,7 @@ static inline void get_uts_ns(struct uts_namespace *ns)
49} 49}
50 50
51#ifdef CONFIG_UTS_NS 51#ifdef CONFIG_UTS_NS
52extern int unshare_utsname(unsigned long unshare_flags, 52extern struct uts_namespace *copy_utsname(int flags, struct uts_namespace *ns);
53 struct uts_namespace **new_uts);
54extern int copy_utsname(int flags, struct task_struct *tsk);
55extern void free_uts_ns(struct kref *kref); 53extern void free_uts_ns(struct kref *kref);
56 54
57static inline void put_uts_ns(struct uts_namespace *ns) 55static inline void put_uts_ns(struct uts_namespace *ns)
@@ -59,21 +57,12 @@ static inline void put_uts_ns(struct uts_namespace *ns)
59 kref_put(&ns->kref, free_uts_ns); 57 kref_put(&ns->kref, free_uts_ns);
60} 58}
61#else 59#else
62static inline int unshare_utsname(unsigned long unshare_flags, 60static inline struct uts_namespace *copy_utsname(int flags,
63 struct uts_namespace **new_uts) 61 struct uts_namespace *ns)
64{ 62{
65 if (unshare_flags & CLONE_NEWUTS) 63 return ns;
66 return -EINVAL;
67
68 return 0;
69} 64}
70 65
71static inline int copy_utsname(int flags, struct task_struct *tsk)
72{
73 if (flags & CLONE_NEWUTS)
74 return -EINVAL;
75 return 0;
76}
77static inline void put_uts_ns(struct uts_namespace *ns) 66static inline void put_uts_ns(struct uts_namespace *ns)
78{ 67{
79} 68}
diff --git a/ipc/util.c b/ipc/util.c
index 0b652387d169..0ad5b1c3ca01 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -85,53 +85,20 @@ err_mem:
85 return ERR_PTR(err); 85 return ERR_PTR(err);
86} 86}
87 87
88int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc) 88struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
89{ 89{
90 struct ipc_namespace *new;
91
92 if (unshare_flags & CLONE_NEWIPC) {
93 if (!capable(CAP_SYS_ADMIN))
94 return -EPERM;
95
96 new = clone_ipc_ns(current->nsproxy->ipc_ns);
97 if (IS_ERR(new))
98 return PTR_ERR(new);
99
100 *new_ipc = new;
101 }
102
103 return 0;
104}
105
106int copy_ipcs(unsigned long flags, struct task_struct *tsk)
107{
108 struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns;
109 struct ipc_namespace *new_ns; 90 struct ipc_namespace *new_ns;
110 int err = 0;
111 91
112 if (!old_ns) 92 BUG_ON(!ns);
113 return 0; 93 get_ipc_ns(ns);
114
115 get_ipc_ns(old_ns);
116 94
117 if (!(flags & CLONE_NEWIPC)) 95 if (!(flags & CLONE_NEWIPC))
118 return 0; 96 return ns;
119 97
120 if (!capable(CAP_SYS_ADMIN)) { 98 new_ns = clone_ipc_ns(ns);
121 err = -EPERM;
122 goto out;
123 }
124 99
125 new_ns = clone_ipc_ns(old_ns); 100 put_ipc_ns(ns);
126 if (!new_ns) { 101 return new_ns;
127 err = -ENOMEM;
128 goto out;
129 }
130
131 tsk->nsproxy->ipc_ns = new_ns;
132out:
133 put_ipc_ns(old_ns);
134 return err;
135} 102}
136 103
137void free_ipc_ns(struct kref *kref) 104void free_ipc_ns(struct kref *kref)
@@ -145,11 +112,11 @@ void free_ipc_ns(struct kref *kref)
145 kfree(ns); 112 kfree(ns);
146} 113}
147#else 114#else
148int copy_ipcs(unsigned long flags, struct task_struct *tsk) 115struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
149{ 116{
150 if (flags & CLONE_NEWIPC) 117 if (flags & CLONE_NEWIPC)
151 return -EINVAL; 118 return ERR_PTR(-EINVAL);
152 return 0; 119 return ns;
153} 120}
154#endif 121#endif
155 122
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)