diff options
-rw-r--r-- | include/linux/init_task.h | 3 | ||||
-rw-r--r-- | include/linux/ipc.h | 18 | ||||
-rw-r--r-- | ipc/util.c | 132 | ||||
-rw-r--r-- | ipc/util.h | 24 | ||||
-rw-r--r-- | kernel/fork.c | 10 |
5 files changed, 173 insertions, 14 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index ceecf69dfa39..33c5daacc743 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/irqflags.h> | 6 | #include <linux/irqflags.h> |
7 | #include <linux/utsname.h> | 7 | #include <linux/utsname.h> |
8 | #include <linux/lockdep.h> | 8 | #include <linux/lockdep.h> |
9 | #include <linux/ipc.h> | ||
9 | 10 | ||
10 | #define INIT_FDTABLE \ | 11 | #define INIT_FDTABLE \ |
11 | { \ | 12 | { \ |
@@ -74,8 +75,8 @@ extern struct nsproxy init_nsproxy; | |||
74 | .count = ATOMIC_INIT(1), \ | 75 | .count = ATOMIC_INIT(1), \ |
75 | .nslock = SPIN_LOCK_UNLOCKED, \ | 76 | .nslock = SPIN_LOCK_UNLOCKED, \ |
76 | .uts_ns = &init_uts_ns, \ | 77 | .uts_ns = &init_uts_ns, \ |
77 | .ipc_ns = &init_ipc_ns, \ | ||
78 | .namespace = NULL, \ | 78 | .namespace = NULL, \ |
79 | INIT_IPC_NS(ipc_ns) \ | ||
79 | } | 80 | } |
80 | 81 | ||
81 | #define INIT_SIGHAND(sighand) { \ | 82 | #define INIT_SIGHAND(sighand) { \ |
diff --git a/include/linux/ipc.h b/include/linux/ipc.h index 36027b10f283..d9e2b3f36c35 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h | |||
@@ -88,20 +88,38 @@ struct ipc_namespace { | |||
88 | }; | 88 | }; |
89 | 89 | ||
90 | extern struct ipc_namespace init_ipc_ns; | 90 | extern struct ipc_namespace init_ipc_ns; |
91 | |||
92 | #ifdef CONFIG_SYSVIPC | ||
93 | #define INIT_IPC_NS(ns) .ns = &init_ipc_ns, | ||
94 | #else | ||
95 | #define INIT_IPC_NS(ns) | ||
96 | #endif | ||
97 | |||
98 | #ifdef CONFIG_IPC_NS | ||
91 | extern void free_ipc_ns(struct kref *kref); | 99 | extern void free_ipc_ns(struct kref *kref); |
92 | extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); | 100 | extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); |
93 | extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns); | 101 | extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns); |
102 | #else | ||
103 | static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk) | ||
104 | { | ||
105 | return 0; | ||
106 | } | ||
107 | #endif | ||
94 | 108 | ||
95 | static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) | 109 | static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) |
96 | { | 110 | { |
111 | #ifdef CONFIG_IPC_NS | ||
97 | if (ns) | 112 | if (ns) |
98 | kref_get(&ns->kref); | 113 | kref_get(&ns->kref); |
114 | #endif | ||
99 | return ns; | 115 | return ns; |
100 | } | 116 | } |
101 | 117 | ||
102 | static inline void put_ipc_ns(struct ipc_namespace *ns) | 118 | static inline void put_ipc_ns(struct ipc_namespace *ns) |
103 | { | 119 | { |
120 | #ifdef CONFIG_IPC_NS | ||
104 | kref_put(&ns->kref, free_ipc_ns); | 121 | kref_put(&ns->kref, free_ipc_ns); |
122 | #endif | ||
105 | } | 123 | } |
106 | 124 | ||
107 | #endif /* __KERNEL__ */ | 125 | #endif /* __KERNEL__ */ |
diff --git a/ipc/util.c b/ipc/util.c index 67b6d178db6e..42479e4eec59 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -12,6 +12,9 @@ | |||
12 | * Mingming Cao <cmm@us.ibm.com> | 12 | * Mingming Cao <cmm@us.ibm.com> |
13 | * Mar 2006 - support for audit of ipc object properties | 13 | * Mar 2006 - support for audit of ipc object properties |
14 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> | 14 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> |
15 | * Jun 2006 - namespaces ssupport | ||
16 | * OpenVZ, SWsoft Inc. | ||
17 | * Pavel Emelianov <xemul@openvz.org> | ||
15 | */ | 18 | */ |
16 | 19 | ||
17 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
@@ -29,6 +32,7 @@ | |||
29 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
30 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
31 | #include <linux/audit.h> | 34 | #include <linux/audit.h> |
35 | #include <linux/nsproxy.h> | ||
32 | 36 | ||
33 | #include <asm/unistd.h> | 37 | #include <asm/unistd.h> |
34 | 38 | ||
@@ -37,10 +41,111 @@ | |||
37 | struct ipc_proc_iface { | 41 | struct ipc_proc_iface { |
38 | const char *path; | 42 | const char *path; |
39 | const char *header; | 43 | const char *header; |
40 | struct ipc_ids *ids; | 44 | int ids; |
41 | int (*show)(struct seq_file *, void *); | 45 | int (*show)(struct seq_file *, void *); |
42 | }; | 46 | }; |
43 | 47 | ||
48 | struct ipc_namespace init_ipc_ns = { | ||
49 | .kref = { | ||
50 | .refcount = ATOMIC_INIT(2), | ||
51 | }, | ||
52 | }; | ||
53 | |||
54 | #ifdef CONFIG_IPC_NS | ||
55 | static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) | ||
56 | { | ||
57 | int err; | ||
58 | struct ipc_namespace *ns; | ||
59 | |||
60 | err = -ENOMEM; | ||
61 | ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); | ||
62 | if (ns == NULL) | ||
63 | goto err_mem; | ||
64 | |||
65 | err = sem_init_ns(ns); | ||
66 | if (err) | ||
67 | goto err_sem; | ||
68 | err = msg_init_ns(ns); | ||
69 | if (err) | ||
70 | goto err_msg; | ||
71 | err = shm_init_ns(ns); | ||
72 | if (err) | ||
73 | goto err_shm; | ||
74 | |||
75 | kref_init(&ns->kref); | ||
76 | return ns; | ||
77 | |||
78 | err_shm: | ||
79 | msg_exit_ns(ns); | ||
80 | err_msg: | ||
81 | sem_exit_ns(ns); | ||
82 | err_sem: | ||
83 | kfree(ns); | ||
84 | err_mem: | ||
85 | return ERR_PTR(err); | ||
86 | } | ||
87 | |||
88 | int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc) | ||
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 | |||
106 | int 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; | ||
110 | int err = 0; | ||
111 | |||
112 | if (!old_ns) | ||
113 | return 0; | ||
114 | |||
115 | get_ipc_ns(old_ns); | ||
116 | |||
117 | if (!(flags & CLONE_NEWIPC)) | ||
118 | return 0; | ||
119 | |||
120 | if (!capable(CAP_SYS_ADMIN)) { | ||
121 | err = -EPERM; | ||
122 | goto out; | ||
123 | } | ||
124 | |||
125 | new_ns = clone_ipc_ns(old_ns); | ||
126 | if (!new_ns) { | ||
127 | err = -ENOMEM; | ||
128 | goto out; | ||
129 | } | ||
130 | |||
131 | tsk->nsproxy->ipc_ns = new_ns; | ||
132 | out: | ||
133 | put_ipc_ns(old_ns); | ||
134 | return err; | ||
135 | } | ||
136 | |||
137 | void free_ipc_ns(struct kref *kref) | ||
138 | { | ||
139 | struct ipc_namespace *ns; | ||
140 | |||
141 | ns = container_of(kref, struct ipc_namespace, kref); | ||
142 | sem_exit_ns(ns); | ||
143 | msg_exit_ns(ns); | ||
144 | shm_exit_ns(ns); | ||
145 | kfree(ns); | ||
146 | } | ||
147 | #endif | ||
148 | |||
44 | /** | 149 | /** |
45 | * ipc_init - initialise IPC subsystem | 150 | * ipc_init - initialise IPC subsystem |
46 | * | 151 | * |
@@ -67,7 +172,7 @@ __initcall(ipc_init); | |||
67 | * array itself. | 172 | * array itself. |
68 | */ | 173 | */ |
69 | 174 | ||
70 | void __init ipc_init_ids(struct ipc_ids* ids, int size) | 175 | void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size) |
71 | { | 176 | { |
72 | int i; | 177 | int i; |
73 | 178 | ||
@@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops; | |||
110 | * @show: show routine. | 215 | * @show: show routine. |
111 | */ | 216 | */ |
112 | void __init ipc_init_proc_interface(const char *path, const char *header, | 217 | void __init ipc_init_proc_interface(const char *path, const char *header, |
113 | struct ipc_ids *ids, | 218 | int ids, int (*show)(struct seq_file *, void *)) |
114 | int (*show)(struct seq_file *, void *)) | ||
115 | { | 219 | { |
116 | struct proc_dir_entry *pde; | 220 | struct proc_dir_entry *pde; |
117 | struct ipc_proc_iface *iface; | 221 | struct ipc_proc_iface *iface; |
@@ -635,6 +739,9 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) | |||
635 | struct ipc_proc_iface *iface = s->private; | 739 | struct ipc_proc_iface *iface = s->private; |
636 | struct kern_ipc_perm *ipc = it; | 740 | struct kern_ipc_perm *ipc = it; |
637 | loff_t p; | 741 | loff_t p; |
742 | struct ipc_ids *ids; | ||
743 | |||
744 | ids = current->nsproxy->ipc_ns->ids[iface->ids]; | ||
638 | 745 | ||
639 | /* If we had an ipc id locked before, unlock it */ | 746 | /* If we had an ipc id locked before, unlock it */ |
640 | if (ipc && ipc != SEQ_START_TOKEN) | 747 | if (ipc && ipc != SEQ_START_TOKEN) |
@@ -644,8 +751,8 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) | |||
644 | * p = *pos - 1 (because id 0 starts at position 1) | 751 | * p = *pos - 1 (because id 0 starts at position 1) |
645 | * + 1 (because we increment the position by one) | 752 | * + 1 (because we increment the position by one) |
646 | */ | 753 | */ |
647 | for (p = *pos; p <= iface->ids->max_id; p++) { | 754 | for (p = *pos; p <= ids->max_id; p++) { |
648 | if ((ipc = ipc_lock(iface->ids, p)) != NULL) { | 755 | if ((ipc = ipc_lock(ids, p)) != NULL) { |
649 | *pos = p + 1; | 756 | *pos = p + 1; |
650 | return ipc; | 757 | return ipc; |
651 | } | 758 | } |
@@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) | |||
664 | struct ipc_proc_iface *iface = s->private; | 771 | struct ipc_proc_iface *iface = s->private; |
665 | struct kern_ipc_perm *ipc; | 772 | struct kern_ipc_perm *ipc; |
666 | loff_t p; | 773 | loff_t p; |
774 | struct ipc_ids *ids; | ||
775 | |||
776 | ids = current->nsproxy->ipc_ns->ids[iface->ids]; | ||
667 | 777 | ||
668 | /* | 778 | /* |
669 | * Take the lock - this will be released by the corresponding | 779 | * Take the lock - this will be released by the corresponding |
670 | * call to stop(). | 780 | * call to stop(). |
671 | */ | 781 | */ |
672 | mutex_lock(&iface->ids->mutex); | 782 | mutex_lock(&ids->mutex); |
673 | 783 | ||
674 | /* pos < 0 is invalid */ | 784 | /* pos < 0 is invalid */ |
675 | if (*pos < 0) | 785 | if (*pos < 0) |
@@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) | |||
680 | return SEQ_START_TOKEN; | 790 | return SEQ_START_TOKEN; |
681 | 791 | ||
682 | /* Find the (pos-1)th ipc */ | 792 | /* Find the (pos-1)th ipc */ |
683 | for (p = *pos - 1; p <= iface->ids->max_id; p++) { | 793 | for (p = *pos - 1; p <= ids->max_id; p++) { |
684 | if ((ipc = ipc_lock(iface->ids, p)) != NULL) { | 794 | if ((ipc = ipc_lock(ids, p)) != NULL) { |
685 | *pos = p + 1; | 795 | *pos = p + 1; |
686 | return ipc; | 796 | return ipc; |
687 | } | 797 | } |
@@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it) | |||
693 | { | 803 | { |
694 | struct kern_ipc_perm *ipc = it; | 804 | struct kern_ipc_perm *ipc = it; |
695 | struct ipc_proc_iface *iface = s->private; | 805 | struct ipc_proc_iface *iface = s->private; |
806 | struct ipc_ids *ids; | ||
696 | 807 | ||
697 | /* If we had a locked segment, release it */ | 808 | /* If we had a locked segment, release it */ |
698 | if (ipc && ipc != SEQ_START_TOKEN) | 809 | if (ipc && ipc != SEQ_START_TOKEN) |
699 | ipc_unlock(ipc); | 810 | ipc_unlock(ipc); |
700 | 811 | ||
812 | ids = current->nsproxy->ipc_ns->ids[iface->ids]; | ||
701 | /* Release the lock we took in start() */ | 813 | /* Release the lock we took in start() */ |
702 | mutex_unlock(&iface->ids->mutex); | 814 | mutex_unlock(&ids->mutex); |
703 | } | 815 | } |
704 | 816 | ||
705 | static int sysvipc_proc_show(struct seq_file *s, void *it) | 817 | static int sysvipc_proc_show(struct seq_file *s, void *it) |
diff --git a/ipc/util.h b/ipc/util.h index 0181553d31d8..c8fd6b9d77b5 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
@@ -3,6 +3,8 @@ | |||
3 | * Copyright (C) 1999 Christoph Rohland | 3 | * Copyright (C) 1999 Christoph Rohland |
4 | * | 4 | * |
5 | * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com> | 5 | * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com> |
6 | * namespaces support. 2006 OpenVZ, SWsoft Inc. | ||
7 | * Pavel Emelianov <xemul@openvz.org> | ||
6 | */ | 8 | */ |
7 | 9 | ||
8 | #ifndef _IPC_UTIL_H | 10 | #ifndef _IPC_UTIL_H |
@@ -15,6 +17,14 @@ void sem_init (void); | |||
15 | void msg_init (void); | 17 | void msg_init (void); |
16 | void shm_init (void); | 18 | void shm_init (void); |
17 | 19 | ||
20 | int sem_init_ns(struct ipc_namespace *ns); | ||
21 | int msg_init_ns(struct ipc_namespace *ns); | ||
22 | int shm_init_ns(struct ipc_namespace *ns); | ||
23 | |||
24 | void sem_exit_ns(struct ipc_namespace *ns); | ||
25 | void msg_exit_ns(struct ipc_namespace *ns); | ||
26 | void shm_exit_ns(struct ipc_namespace *ns); | ||
27 | |||
18 | struct ipc_id_ary { | 28 | struct ipc_id_ary { |
19 | int size; | 29 | int size; |
20 | struct kern_ipc_perm *p[0]; | 30 | struct kern_ipc_perm *p[0]; |
@@ -31,15 +41,23 @@ struct ipc_ids { | |||
31 | }; | 41 | }; |
32 | 42 | ||
33 | struct seq_file; | 43 | struct seq_file; |
34 | void __init ipc_init_ids(struct ipc_ids* ids, int size); | 44 | #ifdef CONFIG_IPC_NS |
45 | #define __ipc_init | ||
46 | #else | ||
47 | #define __ipc_init __init | ||
48 | #endif | ||
49 | void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size); | ||
35 | #ifdef CONFIG_PROC_FS | 50 | #ifdef CONFIG_PROC_FS |
36 | void __init ipc_init_proc_interface(const char *path, const char *header, | 51 | void __init ipc_init_proc_interface(const char *path, const char *header, |
37 | struct ipc_ids *ids, | 52 | int ids, int (*show)(struct seq_file *, void *)); |
38 | int (*show)(struct seq_file *, void *)); | ||
39 | #else | 53 | #else |
40 | #define ipc_init_proc_interface(path, header, ids, show) do {} while (0) | 54 | #define ipc_init_proc_interface(path, header, ids, show) do {} while (0) |
41 | #endif | 55 | #endif |
42 | 56 | ||
57 | #define IPC_SEM_IDS 0 | ||
58 | #define IPC_MSG_IDS 1 | ||
59 | #define IPC_SHM_IDS 2 | ||
60 | |||
43 | /* must be called with ids->mutex acquired.*/ | 61 | /* must be called with ids->mutex acquired.*/ |
44 | int ipc_findkey(struct ipc_ids* ids, key_t key); | 62 | int ipc_findkey(struct ipc_ids* ids, key_t key); |
45 | int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size); | 63 | int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size); |
diff --git a/kernel/fork.c b/kernel/fork.c index d6cc56558507..7dc6140baac6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1589,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n | |||
1589 | return 0; | 1589 | return 0; |
1590 | } | 1590 | } |
1591 | 1591 | ||
1592 | #ifndef CONFIG_IPC_NS | ||
1593 | static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns) | ||
1594 | { | ||
1595 | if (flags & CLONE_NEWIPC) | ||
1596 | return -EINVAL; | ||
1597 | |||
1598 | return 0; | ||
1599 | } | ||
1600 | #endif | ||
1601 | |||
1592 | /* | 1602 | /* |
1593 | * unshare allows a process to 'unshare' part of the process | 1603 | * unshare allows a process to 'unshare' part of the process |
1594 | * context which was originally shared using clone. copy_* | 1604 | * context which was originally shared using clone. copy_* |