diff options
author | Kirill Korotaev <dev@openvz.org> | 2006-10-02 05:18:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 10:57:22 -0400 |
commit | 73ea41302bab5e02c9e86ab15c509494a550f1db (patch) | |
tree | 10971a839dd53a9e18d6c866c9be93517fe8de25 /ipc/util.c | |
parent | 25b21cb2f6d69b0475b134e0a3e8e269137270fa (diff) |
[PATCH] IPC namespace - utils
This patch adds basic IPC namespace functionality to
IPC utils:
- init_ipc_ns
- copy/clone/unshare/free IPC ns
- /proc preparations
Signed-off-by: Pavel Emelianov <xemul@openvz.org>
Signed-off-by: Kirill Korotaev <dev@openvz.org>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Cedric Le Goater <clg@fr.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'ipc/util.c')
-rw-r--r-- | ipc/util.c | 132 |
1 files changed, 122 insertions, 10 deletions
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) |