diff options
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/Makefile | 2 | ||||
-rw-r--r-- | ipc/compat.c | 1 | ||||
-rw-r--r-- | ipc/ipc_sysctl.c | 77 | ||||
-rw-r--r-- | ipc/mq_sysctl.c | 7 | ||||
-rw-r--r-- | ipc/mqueue.c | 125 | ||||
-rw-r--r-- | ipc/msg.c | 4 | ||||
-rw-r--r-- | ipc/sem.c | 214 | ||||
-rw-r--r-- | ipc/shm.c | 46 | ||||
-rw-r--r-- | ipc/syscall.c | 99 |
9 files changed, 349 insertions, 226 deletions
diff --git a/ipc/Makefile b/ipc/Makefile index 4e1955ea815d..9075e172e52c 100644 --- a/ipc/Makefile +++ b/ipc/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o | 5 | obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o |
6 | obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o ipcns_notifier.o | 6 | obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o ipcns_notifier.o syscall.o |
7 | obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o | 7 | obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o |
8 | obj_mq-$(CONFIG_COMPAT) += compat_mq.o | 8 | obj_mq-$(CONFIG_COMPAT) += compat_mq.o |
9 | obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) | 9 | obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) |
diff --git a/ipc/compat.c b/ipc/compat.c index ab76fb0ef844..9dc2c7d3c9e6 100644 --- a/ipc/compat.c +++ b/ipc/compat.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/msg.h> | 27 | #include <linux/msg.h> |
28 | #include <linux/shm.h> | 28 | #include <linux/shm.h> |
29 | #include <linux/slab.h> | ||
30 | #include <linux/syscalls.h> | 29 | #include <linux/syscalls.h> |
31 | 30 | ||
32 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index 7d3704750efc..56410faa4550 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c | |||
@@ -129,136 +129,60 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, | |||
129 | #define proc_ipcauto_dointvec_minmax NULL | 129 | #define proc_ipcauto_dointvec_minmax NULL |
130 | #endif | 130 | #endif |
131 | 131 | ||
132 | #ifdef CONFIG_SYSCTL_SYSCALL | ||
133 | /* The generic sysctl ipc data routine. */ | ||
134 | static int sysctl_ipc_data(ctl_table *table, | ||
135 | void __user *oldval, size_t __user *oldlenp, | ||
136 | void __user *newval, size_t newlen) | ||
137 | { | ||
138 | size_t len; | ||
139 | void *data; | ||
140 | |||
141 | /* Get out of I don't have a variable */ | ||
142 | if (!table->data || !table->maxlen) | ||
143 | return -ENOTDIR; | ||
144 | |||
145 | data = get_ipc(table); | ||
146 | if (!data) | ||
147 | return -ENOTDIR; | ||
148 | |||
149 | if (oldval && oldlenp) { | ||
150 | if (get_user(len, oldlenp)) | ||
151 | return -EFAULT; | ||
152 | if (len) { | ||
153 | if (len > table->maxlen) | ||
154 | len = table->maxlen; | ||
155 | if (copy_to_user(oldval, data, len)) | ||
156 | return -EFAULT; | ||
157 | if (put_user(len, oldlenp)) | ||
158 | return -EFAULT; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | if (newval && newlen) { | ||
163 | if (newlen > table->maxlen) | ||
164 | newlen = table->maxlen; | ||
165 | |||
166 | if (copy_from_user(data, newval, newlen)) | ||
167 | return -EFAULT; | ||
168 | } | ||
169 | return 1; | ||
170 | } | ||
171 | |||
172 | static int sysctl_ipc_registered_data(ctl_table *table, | ||
173 | void __user *oldval, size_t __user *oldlenp, | ||
174 | void __user *newval, size_t newlen) | ||
175 | { | ||
176 | int rc; | ||
177 | |||
178 | rc = sysctl_ipc_data(table, oldval, oldlenp, newval, newlen); | ||
179 | |||
180 | if (newval && newlen && rc > 0) | ||
181 | /* | ||
182 | * Tunable has successfully been changed from userland | ||
183 | */ | ||
184 | unregister_ipcns_notifier(current->nsproxy->ipc_ns); | ||
185 | |||
186 | return rc; | ||
187 | } | ||
188 | #else | ||
189 | #define sysctl_ipc_data NULL | ||
190 | #define sysctl_ipc_registered_data NULL | ||
191 | #endif | ||
192 | |||
193 | static int zero; | 132 | static int zero; |
194 | static int one = 1; | 133 | static int one = 1; |
195 | 134 | ||
196 | static struct ctl_table ipc_kern_table[] = { | 135 | static struct ctl_table ipc_kern_table[] = { |
197 | { | 136 | { |
198 | .ctl_name = KERN_SHMMAX, | ||
199 | .procname = "shmmax", | 137 | .procname = "shmmax", |
200 | .data = &init_ipc_ns.shm_ctlmax, | 138 | .data = &init_ipc_ns.shm_ctlmax, |
201 | .maxlen = sizeof (init_ipc_ns.shm_ctlmax), | 139 | .maxlen = sizeof (init_ipc_ns.shm_ctlmax), |
202 | .mode = 0644, | 140 | .mode = 0644, |
203 | .proc_handler = proc_ipc_doulongvec_minmax, | 141 | .proc_handler = proc_ipc_doulongvec_minmax, |
204 | .strategy = sysctl_ipc_data, | ||
205 | }, | 142 | }, |
206 | { | 143 | { |
207 | .ctl_name = KERN_SHMALL, | ||
208 | .procname = "shmall", | 144 | .procname = "shmall", |
209 | .data = &init_ipc_ns.shm_ctlall, | 145 | .data = &init_ipc_ns.shm_ctlall, |
210 | .maxlen = sizeof (init_ipc_ns.shm_ctlall), | 146 | .maxlen = sizeof (init_ipc_ns.shm_ctlall), |
211 | .mode = 0644, | 147 | .mode = 0644, |
212 | .proc_handler = proc_ipc_doulongvec_minmax, | 148 | .proc_handler = proc_ipc_doulongvec_minmax, |
213 | .strategy = sysctl_ipc_data, | ||
214 | }, | 149 | }, |
215 | { | 150 | { |
216 | .ctl_name = KERN_SHMMNI, | ||
217 | .procname = "shmmni", | 151 | .procname = "shmmni", |
218 | .data = &init_ipc_ns.shm_ctlmni, | 152 | .data = &init_ipc_ns.shm_ctlmni, |
219 | .maxlen = sizeof (init_ipc_ns.shm_ctlmni), | 153 | .maxlen = sizeof (init_ipc_ns.shm_ctlmni), |
220 | .mode = 0644, | 154 | .mode = 0644, |
221 | .proc_handler = proc_ipc_dointvec, | 155 | .proc_handler = proc_ipc_dointvec, |
222 | .strategy = sysctl_ipc_data, | ||
223 | }, | 156 | }, |
224 | { | 157 | { |
225 | .ctl_name = KERN_MSGMAX, | ||
226 | .procname = "msgmax", | 158 | .procname = "msgmax", |
227 | .data = &init_ipc_ns.msg_ctlmax, | 159 | .data = &init_ipc_ns.msg_ctlmax, |
228 | .maxlen = sizeof (init_ipc_ns.msg_ctlmax), | 160 | .maxlen = sizeof (init_ipc_ns.msg_ctlmax), |
229 | .mode = 0644, | 161 | .mode = 0644, |
230 | .proc_handler = proc_ipc_dointvec, | 162 | .proc_handler = proc_ipc_dointvec, |
231 | .strategy = sysctl_ipc_data, | ||
232 | }, | 163 | }, |
233 | { | 164 | { |
234 | .ctl_name = KERN_MSGMNI, | ||
235 | .procname = "msgmni", | 165 | .procname = "msgmni", |
236 | .data = &init_ipc_ns.msg_ctlmni, | 166 | .data = &init_ipc_ns.msg_ctlmni, |
237 | .maxlen = sizeof (init_ipc_ns.msg_ctlmni), | 167 | .maxlen = sizeof (init_ipc_ns.msg_ctlmni), |
238 | .mode = 0644, | 168 | .mode = 0644, |
239 | .proc_handler = proc_ipc_callback_dointvec, | 169 | .proc_handler = proc_ipc_callback_dointvec, |
240 | .strategy = sysctl_ipc_registered_data, | ||
241 | }, | 170 | }, |
242 | { | 171 | { |
243 | .ctl_name = KERN_MSGMNB, | ||
244 | .procname = "msgmnb", | 172 | .procname = "msgmnb", |
245 | .data = &init_ipc_ns.msg_ctlmnb, | 173 | .data = &init_ipc_ns.msg_ctlmnb, |
246 | .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), | 174 | .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), |
247 | .mode = 0644, | 175 | .mode = 0644, |
248 | .proc_handler = proc_ipc_dointvec, | 176 | .proc_handler = proc_ipc_dointvec, |
249 | .strategy = sysctl_ipc_data, | ||
250 | }, | 177 | }, |
251 | { | 178 | { |
252 | .ctl_name = KERN_SEM, | ||
253 | .procname = "sem", | 179 | .procname = "sem", |
254 | .data = &init_ipc_ns.sem_ctls, | 180 | .data = &init_ipc_ns.sem_ctls, |
255 | .maxlen = 4*sizeof (int), | 181 | .maxlen = 4*sizeof (int), |
256 | .mode = 0644, | 182 | .mode = 0644, |
257 | .proc_handler = proc_ipc_dointvec, | 183 | .proc_handler = proc_ipc_dointvec, |
258 | .strategy = sysctl_ipc_data, | ||
259 | }, | 184 | }, |
260 | { | 185 | { |
261 | .ctl_name = CTL_UNNUMBERED, | ||
262 | .procname = "auto_msgmni", | 186 | .procname = "auto_msgmni", |
263 | .data = &init_ipc_ns.auto_msgmni, | 187 | .data = &init_ipc_ns.auto_msgmni, |
264 | .maxlen = sizeof(int), | 188 | .maxlen = sizeof(int), |
@@ -272,7 +196,6 @@ static struct ctl_table ipc_kern_table[] = { | |||
272 | 196 | ||
273 | static struct ctl_table ipc_root_table[] = { | 197 | static struct ctl_table ipc_root_table[] = { |
274 | { | 198 | { |
275 | .ctl_name = CTL_KERN, | ||
276 | .procname = "kernel", | 199 | .procname = "kernel", |
277 | .mode = 0555, | 200 | .mode = 0555, |
278 | .child = ipc_kern_table, | 201 | .child = ipc_kern_table, |
diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c index 8a058711fc10..0c09366b96f3 100644 --- a/ipc/mq_sysctl.c +++ b/ipc/mq_sysctl.c | |||
@@ -88,7 +88,7 @@ static ctl_table mq_sysctls[] = { | |||
88 | .extra1 = &msg_maxsize_limit_min, | 88 | .extra1 = &msg_maxsize_limit_min, |
89 | .extra2 = &msg_maxsize_limit_max, | 89 | .extra2 = &msg_maxsize_limit_max, |
90 | }, | 90 | }, |
91 | { .ctl_name = 0 } | 91 | {} |
92 | }; | 92 | }; |
93 | 93 | ||
94 | static ctl_table mq_sysctl_dir[] = { | 94 | static ctl_table mq_sysctl_dir[] = { |
@@ -97,17 +97,16 @@ static ctl_table mq_sysctl_dir[] = { | |||
97 | .mode = 0555, | 97 | .mode = 0555, |
98 | .child = mq_sysctls, | 98 | .child = mq_sysctls, |
99 | }, | 99 | }, |
100 | { .ctl_name = 0 } | 100 | {} |
101 | }; | 101 | }; |
102 | 102 | ||
103 | static ctl_table mq_sysctl_root[] = { | 103 | static ctl_table mq_sysctl_root[] = { |
104 | { | 104 | { |
105 | .ctl_name = CTL_FS, | ||
106 | .procname = "fs", | 105 | .procname = "fs", |
107 | .mode = 0555, | 106 | .mode = 0555, |
108 | .child = mq_sysctl_dir, | 107 | .child = mq_sysctl_dir, |
109 | }, | 108 | }, |
110 | { .ctl_name = 0 } | 109 | {} |
111 | }; | 110 | }; |
112 | 111 | ||
113 | struct ctl_table_header *mq_register_sysctl_table(void) | 112 | struct ctl_table_header *mq_register_sysctl_table(void) |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index ee9d69707c0a..59a009dc54a8 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/nsproxy.h> | 32 | #include <linux/nsproxy.h> |
33 | #include <linux/pid.h> | 33 | #include <linux/pid.h> |
34 | #include <linux/ipc_namespace.h> | 34 | #include <linux/ipc_namespace.h> |
35 | #include <linux/ima.h> | 35 | #include <linux/slab.h> |
36 | 36 | ||
37 | #include <net/sock.h> | 37 | #include <net/sock.h> |
38 | #include "util.h" | 38 | #include "util.h" |
@@ -135,7 +135,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, | |||
135 | init_waitqueue_head(&info->wait_q); | 135 | init_waitqueue_head(&info->wait_q); |
136 | INIT_LIST_HEAD(&info->e_wait_q[0].list); | 136 | INIT_LIST_HEAD(&info->e_wait_q[0].list); |
137 | INIT_LIST_HEAD(&info->e_wait_q[1].list); | 137 | INIT_LIST_HEAD(&info->e_wait_q[1].list); |
138 | info->messages = NULL; | ||
139 | info->notify_owner = NULL; | 138 | info->notify_owner = NULL; |
140 | info->qsize = 0; | 139 | info->qsize = 0; |
141 | info->user = NULL; /* set when all is ok */ | 140 | info->user = NULL; /* set when all is ok */ |
@@ -147,26 +146,24 @@ static struct inode *mqueue_get_inode(struct super_block *sb, | |||
147 | info->attr.mq_msgsize = attr->mq_msgsize; | 146 | info->attr.mq_msgsize = attr->mq_msgsize; |
148 | } | 147 | } |
149 | mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *); | 148 | mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *); |
149 | info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); | ||
150 | if (!info->messages) | ||
151 | goto out_inode; | ||
152 | |||
150 | mq_bytes = (mq_msg_tblsz + | 153 | mq_bytes = (mq_msg_tblsz + |
151 | (info->attr.mq_maxmsg * info->attr.mq_msgsize)); | 154 | (info->attr.mq_maxmsg * info->attr.mq_msgsize)); |
152 | 155 | ||
153 | spin_lock(&mq_lock); | 156 | spin_lock(&mq_lock); |
154 | if (u->mq_bytes + mq_bytes < u->mq_bytes || | 157 | if (u->mq_bytes + mq_bytes < u->mq_bytes || |
155 | u->mq_bytes + mq_bytes > | 158 | u->mq_bytes + mq_bytes > |
156 | p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) { | 159 | task_rlimit(p, RLIMIT_MSGQUEUE)) { |
157 | spin_unlock(&mq_lock); | 160 | spin_unlock(&mq_lock); |
161 | /* mqueue_delete_inode() releases info->messages */ | ||
158 | goto out_inode; | 162 | goto out_inode; |
159 | } | 163 | } |
160 | u->mq_bytes += mq_bytes; | 164 | u->mq_bytes += mq_bytes; |
161 | spin_unlock(&mq_lock); | 165 | spin_unlock(&mq_lock); |
162 | 166 | ||
163 | info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); | ||
164 | if (!info->messages) { | ||
165 | spin_lock(&mq_lock); | ||
166 | u->mq_bytes -= mq_bytes; | ||
167 | spin_unlock(&mq_lock); | ||
168 | goto out_inode; | ||
169 | } | ||
170 | /* all is ok */ | 167 | /* all is ok */ |
171 | info->user = get_uid(u); | 168 | info->user = get_uid(u); |
172 | } else if (S_ISDIR(mode)) { | 169 | } else if (S_ISDIR(mode)) { |
@@ -188,7 +185,7 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent) | |||
188 | { | 185 | { |
189 | struct inode *inode; | 186 | struct inode *inode; |
190 | struct ipc_namespace *ns = data; | 187 | struct ipc_namespace *ns = data; |
191 | int error = 0; | 188 | int error; |
192 | 189 | ||
193 | sb->s_blocksize = PAGE_CACHE_SIZE; | 190 | sb->s_blocksize = PAGE_CACHE_SIZE; |
194 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 191 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
@@ -206,7 +203,9 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent) | |||
206 | if (!sb->s_root) { | 203 | if (!sb->s_root) { |
207 | iput(inode); | 204 | iput(inode); |
208 | error = -ENOMEM; | 205 | error = -ENOMEM; |
206 | goto out; | ||
209 | } | 207 | } |
208 | error = 0; | ||
210 | 209 | ||
211 | out: | 210 | out: |
212 | return error; | 211 | return error; |
@@ -265,8 +264,9 @@ static void mqueue_delete_inode(struct inode *inode) | |||
265 | 264 | ||
266 | clear_inode(inode); | 265 | clear_inode(inode); |
267 | 266 | ||
268 | mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) + | 267 | /* Total amount of bytes accounted for the mqueue */ |
269 | (info->attr.mq_maxmsg * info->attr.mq_msgsize)); | 268 | mq_bytes = info->attr.mq_maxmsg * (sizeof(struct msg_msg *) |
269 | + info->attr.mq_msgsize); | ||
270 | user = info->user; | 270 | user = info->user; |
271 | if (user) { | 271 | if (user) { |
272 | spin_lock(&mq_lock); | 272 | spin_lock(&mq_lock); |
@@ -605,8 +605,8 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr) | |||
605 | /* check for overflow */ | 605 | /* check for overflow */ |
606 | if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg) | 606 | if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg) |
607 | return 0; | 607 | return 0; |
608 | if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) + | 608 | if ((unsigned long)(attr->mq_maxmsg * (attr->mq_msgsize |
609 | (attr->mq_maxmsg * sizeof (struct msg_msg *)) < | 609 | + sizeof (struct msg_msg *))) < |
610 | (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize)) | 610 | (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize)) |
611 | return 0; | 611 | return 0; |
612 | return 1; | 612 | return 1; |
@@ -624,9 +624,10 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir, | |||
624 | int ret; | 624 | int ret; |
625 | 625 | ||
626 | if (attr) { | 626 | if (attr) { |
627 | ret = -EINVAL; | 627 | if (!mq_attr_ok(ipc_ns, attr)) { |
628 | if (!mq_attr_ok(ipc_ns, attr)) | 628 | ret = -EINVAL; |
629 | goto out; | 629 | goto out; |
630 | } | ||
630 | /* store for use during create */ | 631 | /* store for use during create */ |
631 | dentry->d_fsdata = attr; | 632 | dentry->d_fsdata = attr; |
632 | } | 633 | } |
@@ -660,24 +661,28 @@ out: | |||
660 | static struct file *do_open(struct ipc_namespace *ipc_ns, | 661 | static struct file *do_open(struct ipc_namespace *ipc_ns, |
661 | struct dentry *dentry, int oflag) | 662 | struct dentry *dentry, int oflag) |
662 | { | 663 | { |
664 | int ret; | ||
663 | const struct cred *cred = current_cred(); | 665 | const struct cred *cred = current_cred(); |
664 | 666 | ||
665 | static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, | 667 | static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, |
666 | MAY_READ | MAY_WRITE }; | 668 | MAY_READ | MAY_WRITE }; |
667 | 669 | ||
668 | if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { | 670 | if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { |
669 | dput(dentry); | 671 | ret = -EINVAL; |
670 | mntput(ipc_ns->mq_mnt); | 672 | goto err; |
671 | return ERR_PTR(-EINVAL); | ||
672 | } | 673 | } |
673 | 674 | ||
674 | if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { | 675 | if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { |
675 | dput(dentry); | 676 | ret = -EACCES; |
676 | mntput(ipc_ns->mq_mnt); | 677 | goto err; |
677 | return ERR_PTR(-EACCES); | ||
678 | } | 678 | } |
679 | 679 | ||
680 | return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); | 680 | return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); |
681 | |||
682 | err: | ||
683 | dput(dentry); | ||
684 | mntput(ipc_ns->mq_mnt); | ||
685 | return ERR_PTR(ret); | ||
681 | } | 686 | } |
682 | 687 | ||
683 | SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | 688 | SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, |
@@ -706,16 +711,17 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | |||
706 | dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); | 711 | dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); |
707 | if (IS_ERR(dentry)) { | 712 | if (IS_ERR(dentry)) { |
708 | error = PTR_ERR(dentry); | 713 | error = PTR_ERR(dentry); |
709 | goto out_err; | 714 | goto out_putfd; |
710 | } | 715 | } |
711 | mntget(ipc_ns->mq_mnt); | 716 | mntget(ipc_ns->mq_mnt); |
712 | 717 | ||
713 | if (oflag & O_CREAT) { | 718 | if (oflag & O_CREAT) { |
714 | if (dentry->d_inode) { /* entry already exists */ | 719 | if (dentry->d_inode) { /* entry already exists */ |
715 | audit_inode(name, dentry); | 720 | audit_inode(name, dentry); |
716 | error = -EEXIST; | 721 | if (oflag & O_EXCL) { |
717 | if (oflag & O_EXCL) | 722 | error = -EEXIST; |
718 | goto out; | 723 | goto out; |
724 | } | ||
719 | filp = do_open(ipc_ns, dentry, oflag); | 725 | filp = do_open(ipc_ns, dentry, oflag); |
720 | } else { | 726 | } else { |
721 | filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, | 727 | filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, |
@@ -723,9 +729,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | |||
723 | u_attr ? &attr : NULL); | 729 | u_attr ? &attr : NULL); |
724 | } | 730 | } |
725 | } else { | 731 | } else { |
726 | error = -ENOENT; | 732 | if (!dentry->d_inode) { |
727 | if (!dentry->d_inode) | 733 | error = -ENOENT; |
728 | goto out; | 734 | goto out; |
735 | } | ||
729 | audit_inode(name, dentry); | 736 | audit_inode(name, dentry); |
730 | filp = do_open(ipc_ns, dentry, oflag); | 737 | filp = do_open(ipc_ns, dentry, oflag); |
731 | } | 738 | } |
@@ -734,7 +741,6 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | |||
734 | error = PTR_ERR(filp); | 741 | error = PTR_ERR(filp); |
735 | goto out_putfd; | 742 | goto out_putfd; |
736 | } | 743 | } |
737 | ima_counts_get(filp); | ||
738 | 744 | ||
739 | fd_install(fd, filp); | 745 | fd_install(fd, filp); |
740 | goto out_upsem; | 746 | goto out_upsem; |
@@ -744,7 +750,6 @@ out: | |||
744 | mntput(ipc_ns->mq_mnt); | 750 | mntput(ipc_ns->mq_mnt); |
745 | out_putfd: | 751 | out_putfd: |
746 | put_unused_fd(fd); | 752 | put_unused_fd(fd); |
747 | out_err: | ||
748 | fd = error; | 753 | fd = error; |
749 | out_upsem: | 754 | out_upsem: |
750 | mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); | 755 | mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); |
@@ -874,19 +879,24 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, | |||
874 | audit_mq_sendrecv(mqdes, msg_len, msg_prio, p); | 879 | audit_mq_sendrecv(mqdes, msg_len, msg_prio, p); |
875 | timeout = prepare_timeout(p); | 880 | timeout = prepare_timeout(p); |
876 | 881 | ||
877 | ret = -EBADF; | ||
878 | filp = fget(mqdes); | 882 | filp = fget(mqdes); |
879 | if (unlikely(!filp)) | 883 | if (unlikely(!filp)) { |
884 | ret = -EBADF; | ||
880 | goto out; | 885 | goto out; |
886 | } | ||
881 | 887 | ||
882 | inode = filp->f_path.dentry->d_inode; | 888 | inode = filp->f_path.dentry->d_inode; |
883 | if (unlikely(filp->f_op != &mqueue_file_operations)) | 889 | if (unlikely(filp->f_op != &mqueue_file_operations)) { |
890 | ret = -EBADF; | ||
884 | goto out_fput; | 891 | goto out_fput; |
892 | } | ||
885 | info = MQUEUE_I(inode); | 893 | info = MQUEUE_I(inode); |
886 | audit_inode(NULL, filp->f_path.dentry); | 894 | audit_inode(NULL, filp->f_path.dentry); |
887 | 895 | ||
888 | if (unlikely(!(filp->f_mode & FMODE_WRITE))) | 896 | if (unlikely(!(filp->f_mode & FMODE_WRITE))) { |
897 | ret = -EBADF; | ||
889 | goto out_fput; | 898 | goto out_fput; |
899 | } | ||
890 | 900 | ||
891 | if (unlikely(msg_len > info->attr.mq_msgsize)) { | 901 | if (unlikely(msg_len > info->attr.mq_msgsize)) { |
892 | ret = -EMSGSIZE; | 902 | ret = -EMSGSIZE; |
@@ -963,19 +973,24 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, | |||
963 | audit_mq_sendrecv(mqdes, msg_len, 0, p); | 973 | audit_mq_sendrecv(mqdes, msg_len, 0, p); |
964 | timeout = prepare_timeout(p); | 974 | timeout = prepare_timeout(p); |
965 | 975 | ||
966 | ret = -EBADF; | ||
967 | filp = fget(mqdes); | 976 | filp = fget(mqdes); |
968 | if (unlikely(!filp)) | 977 | if (unlikely(!filp)) { |
978 | ret = -EBADF; | ||
969 | goto out; | 979 | goto out; |
980 | } | ||
970 | 981 | ||
971 | inode = filp->f_path.dentry->d_inode; | 982 | inode = filp->f_path.dentry->d_inode; |
972 | if (unlikely(filp->f_op != &mqueue_file_operations)) | 983 | if (unlikely(filp->f_op != &mqueue_file_operations)) { |
984 | ret = -EBADF; | ||
973 | goto out_fput; | 985 | goto out_fput; |
986 | } | ||
974 | info = MQUEUE_I(inode); | 987 | info = MQUEUE_I(inode); |
975 | audit_inode(NULL, filp->f_path.dentry); | 988 | audit_inode(NULL, filp->f_path.dentry); |
976 | 989 | ||
977 | if (unlikely(!(filp->f_mode & FMODE_READ))) | 990 | if (unlikely(!(filp->f_mode & FMODE_READ))) { |
991 | ret = -EBADF; | ||
978 | goto out_fput; | 992 | goto out_fput; |
993 | } | ||
979 | 994 | ||
980 | /* checks if buffer is big enough */ | 995 | /* checks if buffer is big enough */ |
981 | if (unlikely(msg_len < info->attr.mq_msgsize)) { | 996 | if (unlikely(msg_len < info->attr.mq_msgsize)) { |
@@ -1065,13 +1080,14 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, | |||
1065 | 1080 | ||
1066 | /* create the notify skb */ | 1081 | /* create the notify skb */ |
1067 | nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL); | 1082 | nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL); |
1068 | ret = -ENOMEM; | 1083 | if (!nc) { |
1069 | if (!nc) | 1084 | ret = -ENOMEM; |
1070 | goto out; | 1085 | goto out; |
1071 | ret = -EFAULT; | 1086 | } |
1072 | if (copy_from_user(nc->data, | 1087 | if (copy_from_user(nc->data, |
1073 | notification.sigev_value.sival_ptr, | 1088 | notification.sigev_value.sival_ptr, |
1074 | NOTIFY_COOKIE_LEN)) { | 1089 | NOTIFY_COOKIE_LEN)) { |
1090 | ret = -EFAULT; | ||
1075 | goto out; | 1091 | goto out; |
1076 | } | 1092 | } |
1077 | 1093 | ||
@@ -1080,9 +1096,10 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, | |||
1080 | /* and attach it to the socket */ | 1096 | /* and attach it to the socket */ |
1081 | retry: | 1097 | retry: |
1082 | filp = fget(notification.sigev_signo); | 1098 | filp = fget(notification.sigev_signo); |
1083 | ret = -EBADF; | 1099 | if (!filp) { |
1084 | if (!filp) | 1100 | ret = -EBADF; |
1085 | goto out; | 1101 | goto out; |
1102 | } | ||
1086 | sock = netlink_getsockbyfilp(filp); | 1103 | sock = netlink_getsockbyfilp(filp); |
1087 | fput(filp); | 1104 | fput(filp); |
1088 | if (IS_ERR(sock)) { | 1105 | if (IS_ERR(sock)) { |
@@ -1094,7 +1111,7 @@ retry: | |||
1094 | timeo = MAX_SCHEDULE_TIMEOUT; | 1111 | timeo = MAX_SCHEDULE_TIMEOUT; |
1095 | ret = netlink_attachskb(sock, nc, &timeo, NULL); | 1112 | ret = netlink_attachskb(sock, nc, &timeo, NULL); |
1096 | if (ret == 1) | 1113 | if (ret == 1) |
1097 | goto retry; | 1114 | goto retry; |
1098 | if (ret) { | 1115 | if (ret) { |
1099 | sock = NULL; | 1116 | sock = NULL; |
1100 | nc = NULL; | 1117 | nc = NULL; |
@@ -1103,14 +1120,17 @@ retry: | |||
1103 | } | 1120 | } |
1104 | } | 1121 | } |
1105 | 1122 | ||
1106 | ret = -EBADF; | ||
1107 | filp = fget(mqdes); | 1123 | filp = fget(mqdes); |
1108 | if (!filp) | 1124 | if (!filp) { |
1125 | ret = -EBADF; | ||
1109 | goto out; | 1126 | goto out; |
1127 | } | ||
1110 | 1128 | ||
1111 | inode = filp->f_path.dentry->d_inode; | 1129 | inode = filp->f_path.dentry->d_inode; |
1112 | if (unlikely(filp->f_op != &mqueue_file_operations)) | 1130 | if (unlikely(filp->f_op != &mqueue_file_operations)) { |
1131 | ret = -EBADF; | ||
1113 | goto out_fput; | 1132 | goto out_fput; |
1133 | } | ||
1114 | info = MQUEUE_I(inode); | 1134 | info = MQUEUE_I(inode); |
1115 | 1135 | ||
1116 | ret = 0; | 1136 | ret = 0; |
@@ -1173,14 +1193,17 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, | |||
1173 | return -EINVAL; | 1193 | return -EINVAL; |
1174 | } | 1194 | } |
1175 | 1195 | ||
1176 | ret = -EBADF; | ||
1177 | filp = fget(mqdes); | 1196 | filp = fget(mqdes); |
1178 | if (!filp) | 1197 | if (!filp) { |
1198 | ret = -EBADF; | ||
1179 | goto out; | 1199 | goto out; |
1200 | } | ||
1180 | 1201 | ||
1181 | inode = filp->f_path.dentry->d_inode; | 1202 | inode = filp->f_path.dentry->d_inode; |
1182 | if (unlikely(filp->f_op != &mqueue_file_operations)) | 1203 | if (unlikely(filp->f_op != &mqueue_file_operations)) { |
1204 | ret = -EBADF; | ||
1183 | goto out_fput; | 1205 | goto out_fput; |
1206 | } | ||
1184 | info = MQUEUE_I(inode); | 1207 | info = MQUEUE_I(inode); |
1185 | 1208 | ||
1186 | spin_lock(&info->lock); | 1209 | spin_lock(&info->lock); |
@@ -1274,7 +1297,7 @@ static int __init init_mqueue_fs(void) | |||
1274 | if (mqueue_inode_cachep == NULL) | 1297 | if (mqueue_inode_cachep == NULL) |
1275 | return -ENOMEM; | 1298 | return -ENOMEM; |
1276 | 1299 | ||
1277 | /* ignore failues - they are not fatal */ | 1300 | /* ignore failures - they are not fatal */ |
1278 | mq_sysctl_table = mq_register_sysctl_table(); | 1301 | mq_sysctl_table = mq_register_sysctl_table(); |
1279 | 1302 | ||
1280 | error = register_filesystem(&mqueue_fs_type); | 1303 | error = register_filesystem(&mqueue_fs_type); |
@@ -23,7 +23,6 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/capability.h> | 25 | #include <linux/capability.h> |
26 | #include <linux/slab.h> | ||
27 | #include <linux/msg.h> | 26 | #include <linux/msg.h> |
28 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
29 | #include <linux/init.h> | 28 | #include <linux/init.h> |
@@ -125,6 +124,7 @@ void msg_init_ns(struct ipc_namespace *ns) | |||
125 | void msg_exit_ns(struct ipc_namespace *ns) | 124 | void msg_exit_ns(struct ipc_namespace *ns) |
126 | { | 125 | { |
127 | free_ipcs(ns, &msg_ids(ns), freeque); | 126 | free_ipcs(ns, &msg_ids(ns), freeque); |
127 | idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); | ||
128 | } | 128 | } |
129 | #endif | 129 | #endif |
130 | 130 | ||
@@ -412,7 +412,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, | |||
412 | struct msqid_ds __user *buf, int version) | 412 | struct msqid_ds __user *buf, int version) |
413 | { | 413 | { |
414 | struct kern_ipc_perm *ipcp; | 414 | struct kern_ipc_perm *ipcp; |
415 | struct msqid64_ds msqid64; | 415 | struct msqid64_ds uninitialized_var(msqid64); |
416 | struct msg_queue *msq; | 416 | struct msg_queue *msq; |
417 | int err; | 417 | int err; |
418 | 418 | ||
@@ -129,6 +129,7 @@ void sem_init_ns(struct ipc_namespace *ns) | |||
129 | void sem_exit_ns(struct ipc_namespace *ns) | 129 | void sem_exit_ns(struct ipc_namespace *ns) |
130 | { | 130 | { |
131 | free_ipcs(ns, &sem_ids(ns), freeary); | 131 | free_ipcs(ns, &sem_ids(ns), freeary); |
132 | idr_destroy(&ns->ids[IPC_SEM_IDS].ipcs_idr); | ||
132 | } | 133 | } |
133 | #endif | 134 | #endif |
134 | 135 | ||
@@ -240,6 +241,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
240 | key_t key = params->key; | 241 | key_t key = params->key; |
241 | int nsems = params->u.nsems; | 242 | int nsems = params->u.nsems; |
242 | int semflg = params->flg; | 243 | int semflg = params->flg; |
244 | int i; | ||
243 | 245 | ||
244 | if (!nsems) | 246 | if (!nsems) |
245 | return -EINVAL; | 247 | return -EINVAL; |
@@ -272,6 +274,11 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
272 | ns->used_sems += nsems; | 274 | ns->used_sems += nsems; |
273 | 275 | ||
274 | sma->sem_base = (struct sem *) &sma[1]; | 276 | sma->sem_base = (struct sem *) &sma[1]; |
277 | |||
278 | for (i = 0; i < nsems; i++) | ||
279 | INIT_LIST_HEAD(&sma->sem_base[i].sem_pending); | ||
280 | |||
281 | sma->complex_count = 0; | ||
275 | INIT_LIST_HEAD(&sma->sem_pending); | 282 | INIT_LIST_HEAD(&sma->sem_pending); |
276 | INIT_LIST_HEAD(&sma->list_id); | 283 | INIT_LIST_HEAD(&sma->list_id); |
277 | sma->sem_nsems = nsems; | 284 | sma->sem_nsems = nsems; |
@@ -397,63 +404,109 @@ undo: | |||
397 | return result; | 404 | return result; |
398 | } | 405 | } |
399 | 406 | ||
400 | /* Go through the pending queue for the indicated semaphore | 407 | /* |
401 | * looking for tasks that can be completed. | 408 | * Wake up a process waiting on the sem queue with a given error. |
409 | * The queue is invalid (may not be accessed) after the function returns. | ||
402 | */ | 410 | */ |
403 | static void update_queue (struct sem_array * sma) | 411 | static void wake_up_sem_queue(struct sem_queue *q, int error) |
404 | { | 412 | { |
405 | int error; | 413 | /* |
406 | struct sem_queue * q; | 414 | * Hold preempt off so that we don't get preempted and have the |
415 | * wakee busy-wait until we're scheduled back on. We're holding | ||
416 | * locks here so it may not strictly be needed, however if the | ||
417 | * locks become preemptible then this prevents such a problem. | ||
418 | */ | ||
419 | preempt_disable(); | ||
420 | q->status = IN_WAKEUP; | ||
421 | wake_up_process(q->sleeper); | ||
422 | /* hands-off: q can disappear immediately after writing q->status. */ | ||
423 | smp_wmb(); | ||
424 | q->status = error; | ||
425 | preempt_enable(); | ||
426 | } | ||
427 | |||
428 | static void unlink_queue(struct sem_array *sma, struct sem_queue *q) | ||
429 | { | ||
430 | list_del(&q->list); | ||
431 | if (q->nsops == 1) | ||
432 | list_del(&q->simple_list); | ||
433 | else | ||
434 | sma->complex_count--; | ||
435 | } | ||
436 | |||
437 | |||
438 | /** | ||
439 | * update_queue(sma, semnum): Look for tasks that can be completed. | ||
440 | * @sma: semaphore array. | ||
441 | * @semnum: semaphore that was modified. | ||
442 | * | ||
443 | * update_queue must be called after a semaphore in a semaphore array | ||
444 | * was modified. If multiple semaphore were modified, then @semnum | ||
445 | * must be set to -1. | ||
446 | */ | ||
447 | static void update_queue(struct sem_array *sma, int semnum) | ||
448 | { | ||
449 | struct sem_queue *q; | ||
450 | struct list_head *walk; | ||
451 | struct list_head *pending_list; | ||
452 | int offset; | ||
453 | |||
454 | /* if there are complex operations around, then knowing the semaphore | ||
455 | * that was modified doesn't help us. Assume that multiple semaphores | ||
456 | * were modified. | ||
457 | */ | ||
458 | if (sma->complex_count) | ||
459 | semnum = -1; | ||
460 | |||
461 | if (semnum == -1) { | ||
462 | pending_list = &sma->sem_pending; | ||
463 | offset = offsetof(struct sem_queue, list); | ||
464 | } else { | ||
465 | pending_list = &sma->sem_base[semnum].sem_pending; | ||
466 | offset = offsetof(struct sem_queue, simple_list); | ||
467 | } | ||
468 | |||
469 | again: | ||
470 | walk = pending_list->next; | ||
471 | while (walk != pending_list) { | ||
472 | int error, alter; | ||
473 | |||
474 | q = (struct sem_queue *)((char *)walk - offset); | ||
475 | walk = walk->next; | ||
476 | |||
477 | /* If we are scanning the single sop, per-semaphore list of | ||
478 | * one semaphore and that semaphore is 0, then it is not | ||
479 | * necessary to scan the "alter" entries: simple increments | ||
480 | * that affect only one entry succeed immediately and cannot | ||
481 | * be in the per semaphore pending queue, and decrements | ||
482 | * cannot be successful if the value is already 0. | ||
483 | */ | ||
484 | if (semnum != -1 && sma->sem_base[semnum].semval == 0 && | ||
485 | q->alter) | ||
486 | break; | ||
407 | 487 | ||
408 | q = list_entry(sma->sem_pending.next, struct sem_queue, list); | ||
409 | while (&q->list != &sma->sem_pending) { | ||
410 | error = try_atomic_semop(sma, q->sops, q->nsops, | 488 | error = try_atomic_semop(sma, q->sops, q->nsops, |
411 | q->undo, q->pid); | 489 | q->undo, q->pid); |
412 | 490 | ||
413 | /* Does q->sleeper still need to sleep? */ | 491 | /* Does q->sleeper still need to sleep? */ |
414 | if (error <= 0) { | 492 | if (error > 0) |
415 | struct sem_queue *n; | 493 | continue; |
416 | |||
417 | /* | ||
418 | * Continue scanning. The next operation | ||
419 | * that must be checked depends on the type of the | ||
420 | * completed operation: | ||
421 | * - if the operation modified the array, then | ||
422 | * restart from the head of the queue and | ||
423 | * check for threads that might be waiting | ||
424 | * for semaphore values to become 0. | ||
425 | * - if the operation didn't modify the array, | ||
426 | * then just continue. | ||
427 | * The order of list_del() and reading ->next | ||
428 | * is crucial: In the former case, the list_del() | ||
429 | * must be done first [because we might be the | ||
430 | * first entry in ->sem_pending], in the latter | ||
431 | * case the list_del() must be done last | ||
432 | * [because the list is invalid after the list_del()] | ||
433 | */ | ||
434 | if (q->alter) { | ||
435 | list_del(&q->list); | ||
436 | n = list_entry(sma->sem_pending.next, | ||
437 | struct sem_queue, list); | ||
438 | } else { | ||
439 | n = list_entry(q->list.next, struct sem_queue, | ||
440 | list); | ||
441 | list_del(&q->list); | ||
442 | } | ||
443 | |||
444 | /* wake up the waiting thread */ | ||
445 | q->status = IN_WAKEUP; | ||
446 | 494 | ||
447 | wake_up_process(q->sleeper); | 495 | unlink_queue(sma, q); |
448 | /* hands-off: q will disappear immediately after | 496 | |
449 | * writing q->status. | 497 | /* |
450 | */ | 498 | * The next operation that must be checked depends on the type |
451 | smp_wmb(); | 499 | * of the completed operation: |
452 | q->status = error; | 500 | * - if the operation modified the array, then restart from the |
453 | q = n; | 501 | * head of the queue and check for threads that might be |
454 | } else { | 502 | * waiting for the new semaphore values. |
455 | q = list_entry(q->list.next, struct sem_queue, list); | 503 | * - if the operation didn't modify the array, then just |
456 | } | 504 | * continue. |
505 | */ | ||
506 | alter = q->alter; | ||
507 | wake_up_sem_queue(q, error); | ||
508 | if (alter && !error) | ||
509 | goto again; | ||
457 | } | 510 | } |
458 | } | 511 | } |
459 | 512 | ||
@@ -533,12 +586,8 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
533 | 586 | ||
534 | /* Wake up all pending processes and let them fail with EIDRM. */ | 587 | /* Wake up all pending processes and let them fail with EIDRM. */ |
535 | list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { | 588 | list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { |
536 | list_del(&q->list); | 589 | unlink_queue(sma, q); |
537 | 590 | wake_up_sem_queue(q, -EIDRM); | |
538 | q->status = IN_WAKEUP; | ||
539 | wake_up_process(q->sleeper); /* doesn't sleep */ | ||
540 | smp_wmb(); | ||
541 | q->status = -EIDRM; /* hands-off q */ | ||
542 | } | 591 | } |
543 | 592 | ||
544 | /* Remove the semaphore set from the IDR */ | 593 | /* Remove the semaphore set from the IDR */ |
@@ -575,7 +624,7 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, | |||
575 | static int semctl_nolock(struct ipc_namespace *ns, int semid, | 624 | static int semctl_nolock(struct ipc_namespace *ns, int semid, |
576 | int cmd, int version, union semun arg) | 625 | int cmd, int version, union semun arg) |
577 | { | 626 | { |
578 | int err = -EINVAL; | 627 | int err; |
579 | struct sem_array *sma; | 628 | struct sem_array *sma; |
580 | 629 | ||
581 | switch(cmd) { | 630 | switch(cmd) { |
@@ -652,7 +701,6 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, | |||
652 | default: | 701 | default: |
653 | return -EINVAL; | 702 | return -EINVAL; |
654 | } | 703 | } |
655 | return err; | ||
656 | out_unlock: | 704 | out_unlock: |
657 | sem_unlock(sma); | 705 | sem_unlock(sma); |
658 | return err; | 706 | return err; |
@@ -759,7 +807,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
759 | } | 807 | } |
760 | sma->sem_ctime = get_seconds(); | 808 | sma->sem_ctime = get_seconds(); |
761 | /* maybe some queued-up processes were waiting for this */ | 809 | /* maybe some queued-up processes were waiting for this */ |
762 | update_queue(sma); | 810 | update_queue(sma, -1); |
763 | err = 0; | 811 | err = 0; |
764 | goto out_unlock; | 812 | goto out_unlock; |
765 | } | 813 | } |
@@ -801,7 +849,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, | |||
801 | curr->sempid = task_tgid_vnr(current); | 849 | curr->sempid = task_tgid_vnr(current); |
802 | sma->sem_ctime = get_seconds(); | 850 | sma->sem_ctime = get_seconds(); |
803 | /* maybe some queued-up processes were waiting for this */ | 851 | /* maybe some queued-up processes were waiting for this */ |
804 | update_queue(sma); | 852 | update_queue(sma, semnum); |
805 | err = 0; | 853 | err = 0; |
806 | goto out_unlock; | 854 | goto out_unlock; |
807 | } | 855 | } |
@@ -961,17 +1009,31 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp) | |||
961 | return 0; | 1009 | return 0; |
962 | } | 1010 | } |
963 | 1011 | ||
964 | static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | 1012 | static struct sem_undo *__lookup_undo(struct sem_undo_list *ulp, int semid) |
965 | { | 1013 | { |
966 | struct sem_undo *walk; | 1014 | struct sem_undo *un; |
967 | 1015 | ||
968 | list_for_each_entry_rcu(walk, &ulp->list_proc, list_proc) { | 1016 | list_for_each_entry_rcu(un, &ulp->list_proc, list_proc) { |
969 | if (walk->semid == semid) | 1017 | if (un->semid == semid) |
970 | return walk; | 1018 | return un; |
971 | } | 1019 | } |
972 | return NULL; | 1020 | return NULL; |
973 | } | 1021 | } |
974 | 1022 | ||
1023 | static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | ||
1024 | { | ||
1025 | struct sem_undo *un; | ||
1026 | |||
1027 | assert_spin_locked(&ulp->lock); | ||
1028 | |||
1029 | un = __lookup_undo(ulp, semid); | ||
1030 | if (un) { | ||
1031 | list_del_rcu(&un->list_proc); | ||
1032 | list_add_rcu(&un->list_proc, &ulp->list_proc); | ||
1033 | } | ||
1034 | return un; | ||
1035 | } | ||
1036 | |||
975 | /** | 1037 | /** |
976 | * find_alloc_undo - Lookup (and if not present create) undo array | 1038 | * find_alloc_undo - Lookup (and if not present create) undo array |
977 | * @ns: namespace | 1039 | * @ns: namespace |
@@ -1163,7 +1225,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1163 | error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current)); | 1225 | error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current)); |
1164 | if (error <= 0) { | 1226 | if (error <= 0) { |
1165 | if (alter && error == 0) | 1227 | if (alter && error == 0) |
1166 | update_queue (sma); | 1228 | update_queue(sma, (nsops == 1) ? sops[0].sem_num : -1); |
1229 | |||
1167 | goto out_unlock_free; | 1230 | goto out_unlock_free; |
1168 | } | 1231 | } |
1169 | 1232 | ||
@@ -1181,6 +1244,19 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1181 | else | 1244 | else |
1182 | list_add(&queue.list, &sma->sem_pending); | 1245 | list_add(&queue.list, &sma->sem_pending); |
1183 | 1246 | ||
1247 | if (nsops == 1) { | ||
1248 | struct sem *curr; | ||
1249 | curr = &sma->sem_base[sops->sem_num]; | ||
1250 | |||
1251 | if (alter) | ||
1252 | list_add_tail(&queue.simple_list, &curr->sem_pending); | ||
1253 | else | ||
1254 | list_add(&queue.simple_list, &curr->sem_pending); | ||
1255 | } else { | ||
1256 | INIT_LIST_HEAD(&queue.simple_list); | ||
1257 | sma->complex_count++; | ||
1258 | } | ||
1259 | |||
1184 | queue.status = -EINTR; | 1260 | queue.status = -EINTR; |
1185 | queue.sleeper = current; | 1261 | queue.sleeper = current; |
1186 | current->state = TASK_INTERRUPTIBLE; | 1262 | current->state = TASK_INTERRUPTIBLE; |
@@ -1222,7 +1298,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, | |||
1222 | */ | 1298 | */ |
1223 | if (timeout && jiffies_left == 0) | 1299 | if (timeout && jiffies_left == 0) |
1224 | error = -EAGAIN; | 1300 | error = -EAGAIN; |
1225 | list_del(&queue.list); | 1301 | unlink_queue(sma, &queue); |
1226 | 1302 | ||
1227 | out_unlock_free: | 1303 | out_unlock_free: |
1228 | sem_unlock(sma); | 1304 | sem_unlock(sma); |
@@ -1307,7 +1383,7 @@ void exit_sem(struct task_struct *tsk) | |||
1307 | if (IS_ERR(sma)) | 1383 | if (IS_ERR(sma)) |
1308 | continue; | 1384 | continue; |
1309 | 1385 | ||
1310 | un = lookup_undo(ulp, semid); | 1386 | un = __lookup_undo(ulp, semid); |
1311 | if (un == NULL) { | 1387 | if (un == NULL) { |
1312 | /* exit_sem raced with IPC_RMID+semget() that created | 1388 | /* exit_sem raced with IPC_RMID+semget() that created |
1313 | * exactly the same semid. Nothing to do. | 1389 | * exactly the same semid. Nothing to do. |
@@ -1351,7 +1427,7 @@ void exit_sem(struct task_struct *tsk) | |||
1351 | } | 1427 | } |
1352 | sma->sem_otime = get_seconds(); | 1428 | sma->sem_otime = get_seconds(); |
1353 | /* maybe some queued-up processes were waiting for this */ | 1429 | /* maybe some queued-up processes were waiting for this */ |
1354 | update_queue(sma); | 1430 | update_queue(sma, -1); |
1355 | sem_unlock(sma); | 1431 | sem_unlock(sma); |
1356 | 1432 | ||
1357 | call_rcu(&un->rcu, free_un); | 1433 | call_rcu(&un->rcu, free_un); |
@@ -1365,7 +1441,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it) | |||
1365 | struct sem_array *sma = it; | 1441 | struct sem_array *sma = it; |
1366 | 1442 | ||
1367 | return seq_printf(s, | 1443 | return seq_printf(s, |
1368 | "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", | 1444 | "%10d %10d %4o %10u %5u %5u %5u %5u %10lu %10lu\n", |
1369 | sma->sem_perm.key, | 1445 | sma->sem_perm.key, |
1370 | sma->sem_perm.id, | 1446 | sma->sem_perm.id, |
1371 | sma->sem_perm.mode, | 1447 | sma->sem_perm.mode, |
@@ -39,7 +39,6 @@ | |||
39 | #include <linux/nsproxy.h> | 39 | #include <linux/nsproxy.h> |
40 | #include <linux/mount.h> | 40 | #include <linux/mount.h> |
41 | #include <linux/ipc_namespace.h> | 41 | #include <linux/ipc_namespace.h> |
42 | #include <linux/ima.h> | ||
43 | 42 | ||
44 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
45 | 44 | ||
@@ -101,6 +100,7 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) | |||
101 | void shm_exit_ns(struct ipc_namespace *ns) | 100 | void shm_exit_ns(struct ipc_namespace *ns) |
102 | { | 101 | { |
103 | free_ipcs(ns, &shm_ids(ns), do_shm_rmid); | 102 | free_ipcs(ns, &shm_ids(ns), do_shm_rmid); |
103 | idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr); | ||
104 | } | 104 | } |
105 | #endif | 105 | #endif |
106 | 106 | ||
@@ -290,28 +290,31 @@ static unsigned long shm_get_unmapped_area(struct file *file, | |||
290 | unsigned long flags) | 290 | unsigned long flags) |
291 | { | 291 | { |
292 | struct shm_file_data *sfd = shm_file_data(file); | 292 | struct shm_file_data *sfd = shm_file_data(file); |
293 | return get_unmapped_area(sfd->file, addr, len, pgoff, flags); | 293 | return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len, |
294 | } | 294 | pgoff, flags); |
295 | |||
296 | int is_file_shm_hugepages(struct file *file) | ||
297 | { | ||
298 | int ret = 0; | ||
299 | |||
300 | if (file->f_op == &shm_file_operations) { | ||
301 | struct shm_file_data *sfd; | ||
302 | sfd = shm_file_data(file); | ||
303 | ret = is_file_hugepages(sfd->file); | ||
304 | } | ||
305 | return ret; | ||
306 | } | 295 | } |
307 | 296 | ||
308 | static const struct file_operations shm_file_operations = { | 297 | static const struct file_operations shm_file_operations = { |
309 | .mmap = shm_mmap, | 298 | .mmap = shm_mmap, |
310 | .fsync = shm_fsync, | 299 | .fsync = shm_fsync, |
311 | .release = shm_release, | 300 | .release = shm_release, |
301 | #ifndef CONFIG_MMU | ||
302 | .get_unmapped_area = shm_get_unmapped_area, | ||
303 | #endif | ||
304 | }; | ||
305 | |||
306 | static const struct file_operations shm_file_operations_huge = { | ||
307 | .mmap = shm_mmap, | ||
308 | .fsync = shm_fsync, | ||
309 | .release = shm_release, | ||
312 | .get_unmapped_area = shm_get_unmapped_area, | 310 | .get_unmapped_area = shm_get_unmapped_area, |
313 | }; | 311 | }; |
314 | 312 | ||
313 | int is_file_shm_hugepages(struct file *file) | ||
314 | { | ||
315 | return file->f_op == &shm_file_operations_huge; | ||
316 | } | ||
317 | |||
315 | static const struct vm_operations_struct shm_vm_ops = { | 318 | static const struct vm_operations_struct shm_vm_ops = { |
316 | .open = shm_open, /* callback for a new vm-area open */ | 319 | .open = shm_open, /* callback for a new vm-area open */ |
317 | .close = shm_close, /* callback for when the vm-area is released */ | 320 | .close = shm_close, /* callback for when the vm-area is released */ |
@@ -761,8 +764,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | |||
761 | if (euid != shp->shm_perm.uid && | 764 | if (euid != shp->shm_perm.uid && |
762 | euid != shp->shm_perm.cuid) | 765 | euid != shp->shm_perm.cuid) |
763 | goto out_unlock; | 766 | goto out_unlock; |
764 | if (cmd == SHM_LOCK && | 767 | if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) |
765 | !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur) | ||
766 | goto out_unlock; | 768 | goto out_unlock; |
767 | } | 769 | } |
768 | 770 | ||
@@ -878,8 +880,8 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
878 | if (err) | 880 | if (err) |
879 | goto out_unlock; | 881 | goto out_unlock; |
880 | 882 | ||
881 | path.dentry = dget(shp->shm_file->f_path.dentry); | 883 | path = shp->shm_file->f_path; |
882 | path.mnt = shp->shm_file->f_path.mnt; | 884 | path_get(&path); |
883 | shp->shm_nattch++; | 885 | shp->shm_nattch++; |
884 | size = i_size_read(path.dentry->d_inode); | 886 | size = i_size_read(path.dentry->d_inode); |
885 | shm_unlock(shp); | 887 | shm_unlock(shp); |
@@ -889,10 +891,12 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
889 | if (!sfd) | 891 | if (!sfd) |
890 | goto out_put_dentry; | 892 | goto out_put_dentry; |
891 | 893 | ||
892 | file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); | 894 | file = alloc_file(&path, f_mode, |
895 | is_file_hugepages(shp->shm_file) ? | ||
896 | &shm_file_operations_huge : | ||
897 | &shm_file_operations); | ||
893 | if (!file) | 898 | if (!file) |
894 | goto out_free; | 899 | goto out_free; |
895 | ima_counts_get(file); | ||
896 | 900 | ||
897 | file->private_data = sfd; | 901 | file->private_data = sfd; |
898 | file->f_mapping = shp->shm_file->f_mapping; | 902 | file->f_mapping = shp->shm_file->f_mapping; |
@@ -947,7 +951,7 @@ out_unlock: | |||
947 | out_free: | 951 | out_free: |
948 | kfree(sfd); | 952 | kfree(sfd); |
949 | out_put_dentry: | 953 | out_put_dentry: |
950 | dput(path.dentry); | 954 | path_put(&path); |
951 | goto out_nattch; | 955 | goto out_nattch; |
952 | } | 956 | } |
953 | 957 | ||
diff --git a/ipc/syscall.c b/ipc/syscall.c new file mode 100644 index 000000000000..1d6f53f6b562 --- /dev/null +++ b/ipc/syscall.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * sys_ipc() is the old de-multiplexer for the SysV IPC calls. | ||
3 | * | ||
4 | * This is really horribly ugly, and new architectures should just wire up | ||
5 | * the individual syscalls instead. | ||
6 | */ | ||
7 | #include <linux/unistd.h> | ||
8 | |||
9 | #ifdef __ARCH_WANT_SYS_IPC | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/ipc.h> | ||
12 | #include <linux/shm.h> | ||
13 | #include <linux/syscalls.h> | ||
14 | #include <linux/uaccess.h> | ||
15 | |||
16 | SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, | ||
17 | unsigned long, third, void __user *, ptr, long, fifth) | ||
18 | { | ||
19 | int version, ret; | ||
20 | |||
21 | version = call >> 16; /* hack for backward compatibility */ | ||
22 | call &= 0xffff; | ||
23 | |||
24 | switch (call) { | ||
25 | case SEMOP: | ||
26 | return sys_semtimedop(first, (struct sembuf __user *)ptr, | ||
27 | second, NULL); | ||
28 | case SEMTIMEDOP: | ||
29 | return sys_semtimedop(first, (struct sembuf __user *)ptr, | ||
30 | second, | ||
31 | (const struct timespec __user *)fifth); | ||
32 | |||
33 | case SEMGET: | ||
34 | return sys_semget(first, second, third); | ||
35 | case SEMCTL: { | ||
36 | union semun fourth; | ||
37 | if (!ptr) | ||
38 | return -EINVAL; | ||
39 | if (get_user(fourth.__pad, (void __user * __user *) ptr)) | ||
40 | return -EFAULT; | ||
41 | return sys_semctl(first, second, third, fourth); | ||
42 | } | ||
43 | |||
44 | case MSGSND: | ||
45 | return sys_msgsnd(first, (struct msgbuf __user *) ptr, | ||
46 | second, third); | ||
47 | case MSGRCV: | ||
48 | switch (version) { | ||
49 | case 0: { | ||
50 | struct ipc_kludge tmp; | ||
51 | if (!ptr) | ||
52 | return -EINVAL; | ||
53 | |||
54 | if (copy_from_user(&tmp, | ||
55 | (struct ipc_kludge __user *) ptr, | ||
56 | sizeof(tmp))) | ||
57 | return -EFAULT; | ||
58 | return sys_msgrcv(first, tmp.msgp, second, | ||
59 | tmp.msgtyp, third); | ||
60 | } | ||
61 | default: | ||
62 | return sys_msgrcv(first, | ||
63 | (struct msgbuf __user *) ptr, | ||
64 | second, fifth, third); | ||
65 | } | ||
66 | case MSGGET: | ||
67 | return sys_msgget((key_t) first, second); | ||
68 | case MSGCTL: | ||
69 | return sys_msgctl(first, second, (struct msqid_ds __user *)ptr); | ||
70 | |||
71 | case SHMAT: | ||
72 | switch (version) { | ||
73 | default: { | ||
74 | unsigned long raddr; | ||
75 | ret = do_shmat(first, (char __user *)ptr, | ||
76 | second, &raddr); | ||
77 | if (ret) | ||
78 | return ret; | ||
79 | return put_user(raddr, (unsigned long __user *) third); | ||
80 | } | ||
81 | case 1: | ||
82 | /* | ||
83 | * This was the entry point for kernel-originating calls | ||
84 | * from iBCS2 in 2.2 days. | ||
85 | */ | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | case SHMDT: | ||
89 | return sys_shmdt((char __user *)ptr); | ||
90 | case SHMGET: | ||
91 | return sys_shmget(first, second, third); | ||
92 | case SHMCTL: | ||
93 | return sys_shmctl(first, second, | ||
94 | (struct shmid_ds __user *) ptr); | ||
95 | default: | ||
96 | return -ENOSYS; | ||
97 | } | ||
98 | } | ||
99 | #endif | ||