diff options
-rw-r--r-- | include/linux/init_task.h | 1 | ||||
-rw-r--r-- | include/linux/ipc.h | 36 | ||||
-rw-r--r-- | include/linux/nsproxy.h | 2 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | init/Kconfig | 9 | ||||
-rw-r--r-- | kernel/fork.c | 22 | ||||
-rw-r--r-- | kernel/nsproxy.c | 41 |
7 files changed, 95 insertions, 17 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index e08531ec32f0..ceecf69dfa39 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -74,6 +74,7 @@ extern struct nsproxy init_nsproxy; | |||
74 | .count = ATOMIC_INIT(1), \ | 74 | .count = ATOMIC_INIT(1), \ |
75 | .nslock = SPIN_LOCK_UNLOCKED, \ | 75 | .nslock = SPIN_LOCK_UNLOCKED, \ |
76 | .uts_ns = &init_uts_ns, \ | 76 | .uts_ns = &init_uts_ns, \ |
77 | .ipc_ns = &init_ipc_ns, \ | ||
77 | .namespace = NULL, \ | 78 | .namespace = NULL, \ |
78 | } | 79 | } |
79 | 80 | ||
diff --git a/include/linux/ipc.h b/include/linux/ipc.h index b291189737e7..36027b10f283 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _LINUX_IPC_H | 2 | #define _LINUX_IPC_H |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/kref.h> | ||
5 | 6 | ||
6 | #define IPC_PRIVATE ((__kernel_key_t) 0) | 7 | #define IPC_PRIVATE ((__kernel_key_t) 0) |
7 | 8 | ||
@@ -68,6 +69,41 @@ struct kern_ipc_perm | |||
68 | void *security; | 69 | void *security; |
69 | }; | 70 | }; |
70 | 71 | ||
72 | struct ipc_ids; | ||
73 | struct ipc_namespace { | ||
74 | struct kref kref; | ||
75 | struct ipc_ids *ids[3]; | ||
76 | |||
77 | int sem_ctls[4]; | ||
78 | int used_sems; | ||
79 | |||
80 | int msg_ctlmax; | ||
81 | int msg_ctlmnb; | ||
82 | int msg_ctlmni; | ||
83 | |||
84 | size_t shm_ctlmax; | ||
85 | size_t shm_ctlall; | ||
86 | int shm_ctlmni; | ||
87 | int shm_tot; | ||
88 | }; | ||
89 | |||
90 | extern struct ipc_namespace init_ipc_ns; | ||
91 | extern void free_ipc_ns(struct kref *kref); | ||
92 | extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); | ||
93 | extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns); | ||
94 | |||
95 | static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) | ||
96 | { | ||
97 | if (ns) | ||
98 | kref_get(&ns->kref); | ||
99 | return ns; | ||
100 | } | ||
101 | |||
102 | static inline void put_ipc_ns(struct ipc_namespace *ns) | ||
103 | { | ||
104 | kref_put(&ns->kref, free_ipc_ns); | ||
105 | } | ||
106 | |||
71 | #endif /* __KERNEL__ */ | 107 | #endif /* __KERNEL__ */ |
72 | 108 | ||
73 | #endif /* _LINUX_IPC_H */ | 109 | #endif /* _LINUX_IPC_H */ |
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 9c2e0ad508db..f6baecdeecd6 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | struct namespace; | 7 | struct namespace; |
8 | struct uts_namespace; | 8 | struct uts_namespace; |
9 | struct ipc_namespace; | ||
9 | 10 | ||
10 | /* | 11 | /* |
11 | * A structure to contain pointers to all per-process | 12 | * A structure to contain pointers to all per-process |
@@ -23,6 +24,7 @@ struct nsproxy { | |||
23 | atomic_t count; | 24 | atomic_t count; |
24 | spinlock_t nslock; | 25 | spinlock_t nslock; |
25 | struct uts_namespace *uts_ns; | 26 | struct uts_namespace *uts_ns; |
27 | struct ipc_namespace *ipc_ns; | ||
26 | struct namespace *namespace; | 28 | struct namespace *namespace; |
27 | }; | 29 | }; |
28 | extern struct nsproxy init_nsproxy; | 30 | extern struct nsproxy init_nsproxy; |
diff --git a/include/linux/sched.h b/include/linux/sched.h index a973e7012315..9ba959e34266 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ | 25 | #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ |
26 | #define CLONE_STOPPED 0x02000000 /* Start in stopped state */ | 26 | #define CLONE_STOPPED 0x02000000 /* Start in stopped state */ |
27 | #define CLONE_NEWUTS 0x04000000 /* New utsname group? */ | 27 | #define CLONE_NEWUTS 0x04000000 /* New utsname group? */ |
28 | #define CLONE_NEWIPC 0x08000000 /* New ipcs */ | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * Scheduling policies | 31 | * Scheduling policies |
diff --git a/init/Kconfig b/init/Kconfig index b0ea97554473..10382931eead 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -115,6 +115,15 @@ config SYSVIPC | |||
115 | section 6.4 of the Linux Programmer's Guide, available from | 115 | section 6.4 of the Linux Programmer's Guide, available from |
116 | <http://www.tldp.org/guides.html>. | 116 | <http://www.tldp.org/guides.html>. |
117 | 117 | ||
118 | config IPC_NS | ||
119 | bool "IPC Namespaces" | ||
120 | depends on SYSVIPC | ||
121 | default n | ||
122 | help | ||
123 | Support ipc namespaces. This allows containers, i.e. virtual | ||
124 | environments, to use ipc namespaces to provide different ipc | ||
125 | objects for different servers. If unsure, say N. | ||
126 | |||
118 | config POSIX_MQUEUE | 127 | config POSIX_MQUEUE |
119 | bool "POSIX Message Queues" | 128 | bool "POSIX Message Queues" |
120 | depends on NET && EXPERIMENTAL | 129 | depends on NET && EXPERIMENTAL |
diff --git a/kernel/fork.c b/kernel/fork.c index 208dd99f13bc..d6cc56558507 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1608,13 +1608,15 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1608 | struct sem_undo_list *new_ulist = NULL; | 1608 | struct sem_undo_list *new_ulist = NULL; |
1609 | struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL; | 1609 | struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL; |
1610 | struct uts_namespace *uts, *new_uts = NULL; | 1610 | struct uts_namespace *uts, *new_uts = NULL; |
1611 | struct ipc_namespace *ipc, *new_ipc = NULL; | ||
1611 | 1612 | ||
1612 | check_unshare_flags(&unshare_flags); | 1613 | check_unshare_flags(&unshare_flags); |
1613 | 1614 | ||
1614 | /* Return -EINVAL for all unsupported flags */ | 1615 | /* Return -EINVAL for all unsupported flags */ |
1615 | err = -EINVAL; | 1616 | err = -EINVAL; |
1616 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| | 1617 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| |
1617 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|CLONE_NEWUTS)) | 1618 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| |
1619 | CLONE_NEWUTS|CLONE_NEWIPC)) | ||
1618 | goto bad_unshare_out; | 1620 | goto bad_unshare_out; |
1619 | 1621 | ||
1620 | if ((err = unshare_thread(unshare_flags))) | 1622 | if ((err = unshare_thread(unshare_flags))) |
@@ -1633,18 +1635,20 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1633 | goto bad_unshare_cleanup_fd; | 1635 | goto bad_unshare_cleanup_fd; |
1634 | if ((err = unshare_utsname(unshare_flags, &new_uts))) | 1636 | if ((err = unshare_utsname(unshare_flags, &new_uts))) |
1635 | goto bad_unshare_cleanup_semundo; | 1637 | goto bad_unshare_cleanup_semundo; |
1638 | if ((err = unshare_ipcs(unshare_flags, &new_ipc))) | ||
1639 | goto bad_unshare_cleanup_uts; | ||
1636 | 1640 | ||
1637 | if (new_ns || new_uts) { | 1641 | if (new_ns || new_uts || new_ipc) { |
1638 | old_nsproxy = current->nsproxy; | 1642 | old_nsproxy = current->nsproxy; |
1639 | new_nsproxy = dup_namespaces(old_nsproxy); | 1643 | new_nsproxy = dup_namespaces(old_nsproxy); |
1640 | if (!new_nsproxy) { | 1644 | if (!new_nsproxy) { |
1641 | err = -ENOMEM; | 1645 | err = -ENOMEM; |
1642 | goto bad_unshare_cleanup_uts; | 1646 | goto bad_unshare_cleanup_ipc; |
1643 | } | 1647 | } |
1644 | } | 1648 | } |
1645 | 1649 | ||
1646 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || | 1650 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || |
1647 | new_uts) { | 1651 | new_uts || new_ipc) { |
1648 | 1652 | ||
1649 | task_lock(current); | 1653 | task_lock(current); |
1650 | 1654 | ||
@@ -1692,12 +1696,22 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1692 | new_uts = uts; | 1696 | new_uts = uts; |
1693 | } | 1697 | } |
1694 | 1698 | ||
1699 | if (new_ipc) { | ||
1700 | ipc = current->nsproxy->ipc_ns; | ||
1701 | current->nsproxy->ipc_ns = new_ipc; | ||
1702 | new_ipc = ipc; | ||
1703 | } | ||
1704 | |||
1695 | task_unlock(current); | 1705 | task_unlock(current); |
1696 | } | 1706 | } |
1697 | 1707 | ||
1698 | if (new_nsproxy) | 1708 | if (new_nsproxy) |
1699 | put_nsproxy(new_nsproxy); | 1709 | put_nsproxy(new_nsproxy); |
1700 | 1710 | ||
1711 | bad_unshare_cleanup_ipc: | ||
1712 | if (new_ipc) | ||
1713 | put_ipc_ns(new_ipc); | ||
1714 | |||
1701 | bad_unshare_cleanup_uts: | 1715 | bad_unshare_cleanup_uts: |
1702 | if (new_uts) | 1716 | if (new_uts) |
1703 | put_uts_ns(new_uts); | 1717 | put_uts_ns(new_uts); |
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 8246813335cc..8d6c852dc51e 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
@@ -7,6 +7,10 @@ | |||
7 | * modify it under the terms of the GNU General Public License as | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation, version 2 of the | 8 | * published by the Free Software Foundation, version 2 of the |
9 | * License. | 9 | * License. |
10 | * | ||
11 | * Jun 2006 - namespaces support | ||
12 | * OpenVZ, SWsoft Inc. | ||
13 | * Pavel Emelianov <xemul@openvz.org> | ||
10 | */ | 14 | */ |
11 | 15 | ||
12 | #include <linux/module.h> | 16 | #include <linux/module.h> |
@@ -62,6 +66,8 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig) | |||
62 | get_namespace(ns->namespace); | 66 | get_namespace(ns->namespace); |
63 | if (ns->uts_ns) | 67 | if (ns->uts_ns) |
64 | get_uts_ns(ns->uts_ns); | 68 | get_uts_ns(ns->uts_ns); |
69 | if (ns->ipc_ns) | ||
70 | get_ipc_ns(ns->ipc_ns); | ||
65 | } | 71 | } |
66 | 72 | ||
67 | return ns; | 73 | return ns; |
@@ -82,7 +88,7 @@ int copy_namespaces(int flags, struct task_struct *tsk) | |||
82 | 88 | ||
83 | get_nsproxy(old_ns); | 89 | get_nsproxy(old_ns); |
84 | 90 | ||
85 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS))) | 91 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) |
86 | return 0; | 92 | return 0; |
87 | 93 | ||
88 | new_ns = clone_namespaces(old_ns); | 94 | new_ns = clone_namespaces(old_ns); |
@@ -94,24 +100,31 @@ int copy_namespaces(int flags, struct task_struct *tsk) | |||
94 | tsk->nsproxy = new_ns; | 100 | tsk->nsproxy = new_ns; |
95 | 101 | ||
96 | err = copy_namespace(flags, tsk); | 102 | err = copy_namespace(flags, tsk); |
97 | if (err) { | 103 | if (err) |
98 | tsk->nsproxy = old_ns; | 104 | goto out_ns; |
99 | put_nsproxy(new_ns); | ||
100 | goto out; | ||
101 | } | ||
102 | 105 | ||
103 | err = copy_utsname(flags, tsk); | 106 | err = copy_utsname(flags, tsk); |
104 | if (err) { | 107 | if (err) |
105 | if (new_ns->namespace) | 108 | goto out_uts; |
106 | put_namespace(new_ns->namespace); | 109 | |
107 | tsk->nsproxy = old_ns; | 110 | err = copy_ipcs(flags, tsk); |
108 | put_nsproxy(new_ns); | 111 | if (err) |
109 | goto out; | 112 | goto out_ipc; |
110 | } | ||
111 | 113 | ||
112 | out: | 114 | out: |
113 | put_nsproxy(old_ns); | 115 | put_nsproxy(old_ns); |
114 | return err; | 116 | return err; |
117 | |||
118 | out_ipc: | ||
119 | if (new_ns->uts_ns) | ||
120 | put_uts_ns(new_ns->uts_ns); | ||
121 | out_uts: | ||
122 | if (new_ns->namespace) | ||
123 | put_namespace(new_ns->namespace); | ||
124 | out_ns: | ||
125 | tsk->nsproxy = old_ns; | ||
126 | put_nsproxy(new_ns); | ||
127 | goto out; | ||
115 | } | 128 | } |
116 | 129 | ||
117 | void free_nsproxy(struct nsproxy *ns) | 130 | void free_nsproxy(struct nsproxy *ns) |
@@ -120,5 +133,7 @@ void free_nsproxy(struct nsproxy *ns) | |||
120 | put_namespace(ns->namespace); | 133 | put_namespace(ns->namespace); |
121 | if (ns->uts_ns) | 134 | if (ns->uts_ns) |
122 | put_uts_ns(ns->uts_ns); | 135 | put_uts_ns(ns->uts_ns); |
136 | if (ns->ipc_ns) | ||
137 | put_ipc_ns(ns->ipc_ns); | ||
123 | kfree(ns); | 138 | kfree(ns); |
124 | } | 139 | } |