| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: sys_mqueue.c,v 1.12.4.1.2.1 2009/05/18 19:50:13 bouyer Exp $ */ | | 1 | /* $NetBSD: sys_mqueue.c,v 1.12.4.1.2.2 2009/05/27 21:33:50 snj Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org> | | 4 | * Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -32,27 +32,27 @@ | | | @@ -32,27 +32,27 @@ |
32 | * | | 32 | * |
33 | * Locking | | 33 | * Locking |
34 | * | | 34 | * |
35 | * Global list of message queues (mqueue_head) and proc_t::p_mqueue_cnt | | 35 | * Global list of message queues (mqueue_head) and proc_t::p_mqueue_cnt |
36 | * counter are protected by mqlist_mtx lock. The very message queue and | | 36 | * counter are protected by mqlist_mtx lock. The very message queue and |
37 | * its members are protected by mqueue::mq_mtx. | | 37 | * its members are protected by mqueue::mq_mtx. |
38 | * | | 38 | * |
39 | * Lock order: | | 39 | * Lock order: |
40 | * mqlist_mtx | | 40 | * mqlist_mtx |
41 | * -> mqueue::mq_mtx | | 41 | * -> mqueue::mq_mtx |
42 | */ | | 42 | */ |
43 | | | 43 | |
44 | #include <sys/cdefs.h> | | 44 | #include <sys/cdefs.h> |
45 | __KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.12.4.1.2.1 2009/05/18 19:50:13 bouyer Exp $"); | | 45 | __KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.12.4.1.2.2 2009/05/27 21:33:50 snj Exp $"); |
46 | | | 46 | |
47 | #include <sys/param.h> | | 47 | #include <sys/param.h> |
48 | #include <sys/types.h> | | 48 | #include <sys/types.h> |
49 | #include <sys/condvar.h> | | 49 | #include <sys/condvar.h> |
50 | #include <sys/errno.h> | | 50 | #include <sys/errno.h> |
51 | #include <sys/fcntl.h> | | 51 | #include <sys/fcntl.h> |
52 | #include <sys/file.h> | | 52 | #include <sys/file.h> |
53 | #include <sys/filedesc.h> | | 53 | #include <sys/filedesc.h> |
54 | #include <sys/kauth.h> | | 54 | #include <sys/kauth.h> |
55 | #include <sys/kernel.h> | | 55 | #include <sys/kernel.h> |
56 | #include <sys/kmem.h> | | 56 | #include <sys/kmem.h> |
57 | #include <sys/lwp.h> | | 57 | #include <sys/lwp.h> |
58 | #include <sys/mqueue.h> | | 58 | #include <sys/mqueue.h> |
| @@ -76,28 +76,26 @@ static u_int mq_open_max = MQ_OPEN_MAX | | | @@ -76,28 +76,26 @@ static u_int mq_open_max = MQ_OPEN_MAX |
76 | static u_int mq_prio_max = MQ_PRIO_MAX; | | 76 | static u_int mq_prio_max = MQ_PRIO_MAX; |
77 | | | 77 | |
78 | static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE; | | 78 | static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE; |
79 | static u_int mq_def_maxmsg = 32; | | 79 | static u_int mq_def_maxmsg = 32; |
80 | | | 80 | |
81 | static kmutex_t mqlist_mtx; | | 81 | static kmutex_t mqlist_mtx; |
82 | static pool_cache_t mqmsg_cache; | | 82 | static pool_cache_t mqmsg_cache; |
83 | static LIST_HEAD(, mqueue) mqueue_head = | | 83 | static LIST_HEAD(, mqueue) mqueue_head = |
84 | LIST_HEAD_INITIALIZER(mqueue_head); | | 84 | LIST_HEAD_INITIALIZER(mqueue_head); |
85 | | | 85 | |
86 | static int mq_poll_fop(file_t *, int); | | 86 | static int mq_poll_fop(file_t *, int); |
87 | static int mq_close_fop(file_t *); | | 87 | static int mq_close_fop(file_t *); |
88 | | | 88 | |
89 | #define FNOVAL -1 | | | |
90 | | | | |
91 | static const struct fileops mqops = { | | 89 | static const struct fileops mqops = { |
92 | .fo_read = fbadop_read, | | 90 | .fo_read = fbadop_read, |
93 | .fo_write = fbadop_write, | | 91 | .fo_write = fbadop_write, |
94 | .fo_ioctl = fbadop_ioctl, | | 92 | .fo_ioctl = fbadop_ioctl, |
95 | .fo_fcntl = fnullop_fcntl, | | 93 | .fo_fcntl = fnullop_fcntl, |
96 | .fo_poll = mq_poll_fop, | | 94 | .fo_poll = mq_poll_fop, |
97 | .fo_stat = fbadop_stat, | | 95 | .fo_stat = fbadop_stat, |
98 | .fo_close = mq_close_fop, | | 96 | .fo_close = mq_close_fop, |
99 | .fo_kqfilter = fnullop_kqfilter, | | 97 | .fo_kqfilter = fnullop_kqfilter, |
100 | .fo_drain = fnullop_drain, | | 98 | .fo_drain = fnullop_drain, |
101 | }; | | 99 | }; |
102 | | | 100 | |
103 | /* | | 101 | /* |
| @@ -156,77 +154,48 @@ mqueue_lookup(char *name) | | | @@ -156,77 +154,48 @@ mqueue_lookup(char *name) |
156 | KASSERT(mutex_owned(&mqlist_mtx)); | | 154 | KASSERT(mutex_owned(&mqlist_mtx)); |
157 | | | 155 | |
158 | LIST_FOREACH(mq, &mqueue_head, mq_list) { | | 156 | LIST_FOREACH(mq, &mqueue_head, mq_list) { |
159 | if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) { | | 157 | if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) { |
160 | mutex_enter(&mq->mq_mtx); | | 158 | mutex_enter(&mq->mq_mtx); |
161 | return mq; | | 159 | return mq; |
162 | } | | 160 | } |
163 | } | | 161 | } |
164 | | | 162 | |
165 | return NULL; | | 163 | return NULL; |
166 | } | | 164 | } |
167 | | | 165 | |
168 | /* | | 166 | /* |
169 | * Check access against message queue. | | 167 | * mqueue_get: get the mqueue from the descriptor. |
170 | */ | | 168 | * => locks the message queue, if found. |
171 | static inline int | | 169 | * => holds a reference on the file descriptor. |
172 | mqueue_access(struct lwp *l, struct mqueue *mq, int access) | | | |
173 | { | | | |
174 | mode_t acc_mode = 0; | | | |
175 | | | | |
176 | KASSERT(mutex_owned(&mq->mq_mtx)); | | | |
177 | KASSERT(access != FNOVAL); | | | |
178 | | | | |
179 | /* Note the difference between VREAD/VWRITE and FREAD/FWRITE */ | | | |
180 | if (access & FREAD) | | | |
181 | acc_mode |= VREAD; | | | |
182 | if (access & FWRITE) | | | |
183 | acc_mode |= VWRITE; | | | |
184 | | | | |
185 | return vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid, | | | |
186 | acc_mode, l->l_cred); | | | |
187 | } | | | |
188 | | | | |
189 | /* | | | |
190 | * Get the mqueue from the descriptor. | | | |
191 | * => locks the message queue, if found | | | |
192 | * => increments the reference on file entry | | | |
193 | */ | | 170 | */ |
194 | static int | | 171 | static int |
195 | mqueue_get(struct lwp *l, mqd_t mqd, int access, file_t **fpr) | | 172 | mqueue_get(mqd_t mqd, file_t **fpr) |
196 | { | | 173 | { |
197 | file_t *fp; | | | |
198 | struct mqueue *mq; | | 174 | struct mqueue *mq; |
| | | 175 | file_t *fp; |
199 | | | 176 | |
200 | /* Get the file and descriptor */ | | | |
201 | fp = fd_getfile((int)mqd); | | 177 | fp = fd_getfile((int)mqd); |
202 | if (fp == NULL) | | 178 | if (__predict_false(fp == NULL)) { |
203 | return EBADF; | | 179 | return EBADF; |
204 | | | | |
205 | /* Increment the reference of file entry, and lock the mqueue */ | | | |
206 | mq = fp->f_data; | | | |
207 | *fpr = fp; | | | |
208 | mutex_enter(&mq->mq_mtx); | | | |
209 | if (access == FNOVAL) { | | | |
210 | KASSERT(mutex_owned(&mq->mq_mtx)); | | | |
211 | return 0; | | | |
212 | } | | 180 | } |
213 | | | 181 | if (__predict_false(fp->f_type != DTYPE_MQUEUE)) { |
214 | /* Check the access mode and permission */ | | | |
215 | if ((fp->f_flag & access) != access || mqueue_access(l, mq, access)) { | | | |
216 | mutex_exit(&mq->mq_mtx); | | | |
217 | fd_putfile((int)mqd); | | 182 | fd_putfile((int)mqd); |
218 | return EPERM; | | 183 | return EBADF; |
219 | } | | 184 | } |
| | | 185 | mq = fp->f_data; |
| | | 186 | mutex_enter(&mq->mq_mtx); |
| | | 187 | |
| | | 188 | *fpr = fp; |
220 | return 0; | | 189 | return 0; |
221 | } | | 190 | } |
222 | | | 191 | |
223 | /* | | 192 | /* |
224 | * Converter from struct timespec to the ticks. | | 193 | * Converter from struct timespec to the ticks. |
225 | * Used by mq_timedreceive(), mq_timedsend(). | | 194 | * Used by mq_timedreceive(), mq_timedsend(). |
226 | */ | | 195 | */ |
227 | static int | | 196 | static int |
228 | abstimeout2timo(const void *uaddr, int *timo) | | 197 | abstimeout2timo(const void *uaddr, int *timo) |
229 | { | | 198 | { |
230 | struct timespec ts; | | 199 | struct timespec ts; |
231 | int error; | | 200 | int error; |
232 | | | 201 | |
| @@ -337,26 +306,32 @@ sys_mq_open(struct lwp *l, const struct | | | @@ -337,26 +306,32 @@ sys_mq_open(struct lwp *l, const struct |
337 | return error; | | 306 | return error; |
338 | } | | 307 | } |
339 | | | 308 | |
340 | if (oflag & O_CREAT) { | | 309 | if (oflag & O_CREAT) { |
341 | struct cwdinfo *cwdi = p->p_cwdi; | | 310 | struct cwdinfo *cwdi = p->p_cwdi; |
342 | struct mq_attr attr; | | 311 | struct mq_attr attr; |
343 | | | 312 | |
344 | /* Check the limit */ | | 313 | /* Check the limit */ |
345 | if (p->p_mqueue_cnt == mq_open_max) { | | 314 | if (p->p_mqueue_cnt == mq_open_max) { |
346 | kmem_free(name, MQ_NAMELEN); | | 315 | kmem_free(name, MQ_NAMELEN); |
347 | return EMFILE; | | 316 | return EMFILE; |
348 | } | | 317 | } |
349 | | | 318 | |
| | | 319 | /* Empty name is invalid */ |
| | | 320 | if (name[0] == '\0') { |
| | | 321 | kmem_free(name, MQ_NAMELEN); |
| | | 322 | return EINVAL; |
| | | 323 | } |
| | | 324 | |
350 | /* Check for mqueue attributes */ | | 325 | /* Check for mqueue attributes */ |
351 | if (SCARG(uap, attr)) { | | 326 | if (SCARG(uap, attr)) { |
352 | error = copyin(SCARG(uap, attr), &attr, | | 327 | error = copyin(SCARG(uap, attr), &attr, |
353 | sizeof(struct mq_attr)); | | 328 | sizeof(struct mq_attr)); |
354 | if (error) { | | 329 | if (error) { |
355 | kmem_free(name, MQ_NAMELEN); | | 330 | kmem_free(name, MQ_NAMELEN); |
356 | return error; | | 331 | return error; |
357 | } | | 332 | } |
358 | if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 || | | 333 | if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 || |
359 | attr.mq_msgsize > mq_max_msgsize) { | | 334 | attr.mq_msgsize > mq_max_msgsize) { |
360 | kmem_free(name, MQ_NAMELEN); | | 335 | kmem_free(name, MQ_NAMELEN); |
361 | return EINVAL; | | 336 | return EINVAL; |
362 | } | | 337 | } |
| @@ -373,65 +348,81 @@ sys_mq_open(struct lwp *l, const struct | | | @@ -373,65 +348,81 @@ sys_mq_open(struct lwp *l, const struct |
373 | * copy the name, attributes and set the flag. | | 348 | * copy the name, attributes and set the flag. |
374 | */ | | 349 | */ |
375 | mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP); | | 350 | mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP); |
376 | | | 351 | |
377 | mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE); | | 352 | mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE); |
378 | cv_init(&mq_new->mq_send_cv, "mqsendcv"); | | 353 | cv_init(&mq_new->mq_send_cv, "mqsendcv"); |
379 | cv_init(&mq_new->mq_recv_cv, "mqrecvcv"); | | 354 | cv_init(&mq_new->mq_recv_cv, "mqrecvcv"); |
380 | TAILQ_INIT(&mq_new->mq_head); | | 355 | TAILQ_INIT(&mq_new->mq_head); |
381 | selinit(&mq_new->mq_rsel); | | 356 | selinit(&mq_new->mq_rsel); |
382 | selinit(&mq_new->mq_wsel); | | 357 | selinit(&mq_new->mq_wsel); |
383 | | | 358 | |
384 | strlcpy(mq_new->mq_name, name, MQ_NAMELEN); | | 359 | strlcpy(mq_new->mq_name, name, MQ_NAMELEN); |
385 | memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr)); | | 360 | memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr)); |
386 | mq_new->mq_attrib.mq_flags = oflag; | | 361 | |
| | | 362 | CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0); |
| | | 363 | mq_new->mq_attrib.mq_flags = (O_MASK & oflag); |
387 | | | 364 | |
388 | /* Store mode and effective UID with GID */ | | 365 | /* Store mode and effective UID with GID */ |
389 | mq_new->mq_mode = ((SCARG(uap, mode) & | | 366 | mq_new->mq_mode = ((SCARG(uap, mode) & |
390 | ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT; | | 367 | ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT; |
391 | mq_new->mq_euid = kauth_cred_geteuid(l->l_cred); | | 368 | mq_new->mq_euid = kauth_cred_geteuid(l->l_cred); |
392 | mq_new->mq_egid = kauth_cred_getegid(l->l_cred); | | 369 | mq_new->mq_egid = kauth_cred_getegid(l->l_cred); |
393 | } | | 370 | } |
394 | | | 371 | |
395 | /* Allocate file structure and descriptor */ | | 372 | /* Allocate file structure and descriptor */ |
396 | error = fd_allocfile(&fp, &mqd); | | 373 | error = fd_allocfile(&fp, &mqd); |
397 | if (error) { | | 374 | if (error) { |
398 | if (mq_new) | | 375 | if (mq_new) |
399 | mqueue_destroy(mq_new); | | 376 | mqueue_destroy(mq_new); |
400 | kmem_free(name, MQ_NAMELEN); | | 377 | kmem_free(name, MQ_NAMELEN); |
401 | return error; | | 378 | return error; |
402 | } | | 379 | } |
403 | fp->f_type = DTYPE_MQUEUE; | | 380 | fp->f_type = DTYPE_MQUEUE; |
404 | fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE); | | 381 | fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE); |
405 | fp->f_ops = &mqops; | | 382 | fp->f_ops = &mqops; |
406 | | | 383 | |
407 | /* Look up for mqueue with such name */ | | 384 | /* Look up for mqueue with such name */ |
408 | mutex_enter(&mqlist_mtx); | | 385 | mutex_enter(&mqlist_mtx); |
409 | mq = mqueue_lookup(name); | | 386 | mq = mqueue_lookup(name); |
410 | if (mq) { | | 387 | if (mq) { |
| | | 388 | mode_t acc_mode; |
| | | 389 | |
411 | KASSERT(mutex_owned(&mq->mq_mtx)); | | 390 | KASSERT(mutex_owned(&mq->mq_mtx)); |
412 | | | 391 | |
413 | /* Check if mqueue is not marked as unlinking */ | | 392 | /* Check if mqueue is not marked as unlinking */ |
414 | if (mq->mq_attrib.mq_flags & MQ_UNLINK) { | | 393 | if (mq->mq_attrib.mq_flags & MQ_UNLINK) { |
415 | error = EACCES; | | 394 | error = EACCES; |
416 | goto exit; | | 395 | goto exit; |
417 | } | | 396 | } |
418 | /* Fail if O_EXCL is set, and mqueue already exists */ | | 397 | /* Fail if O_EXCL is set, and mqueue already exists */ |
419 | if ((oflag & O_CREAT) && (oflag & O_EXCL)) { | | 398 | if ((oflag & O_CREAT) && (oflag & O_EXCL)) { |
420 | error = EEXIST; | | 399 | error = EEXIST; |
421 | goto exit; | | 400 | goto exit; |
422 | } | | 401 | } |
423 | /* Check the permission */ | | 402 | |
424 | if (mqueue_access(l, mq, fp->f_flag)) { | | 403 | /* |
| | | 404 | * Check the permissions. Note the difference between |
| | | 405 | * VREAD/VWRITE and FREAD/FWRITE. |
| | | 406 | */ |
| | | 407 | acc_mode = 0; |
| | | 408 | if (fp->f_flag & FREAD) { |
| | | 409 | acc_mode |= VREAD; |
| | | 410 | } |
| | | 411 | if (fp->f_flag & FWRITE) { |
| | | 412 | acc_mode |= VWRITE; |
| | | 413 | } |
| | | 414 | if (vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid, |
| | | 415 | acc_mode, l->l_cred)) { |
425 | error = EACCES; | | 416 | error = EACCES; |
426 | goto exit; | | 417 | goto exit; |
427 | } | | 418 | } |
428 | } else { | | 419 | } else { |
429 | /* Fail if mqueue neither exists, nor we create it */ | | 420 | /* Fail if mqueue neither exists, nor we create it */ |
430 | if ((oflag & O_CREAT) == 0) { | | 421 | if ((oflag & O_CREAT) == 0) { |
431 | mutex_exit(&mqlist_mtx); | | 422 | mutex_exit(&mqlist_mtx); |
432 | KASSERT(mq_new == NULL); | | 423 | KASSERT(mq_new == NULL); |
433 | fd_abort(p, fp, mqd); | | 424 | fd_abort(p, fp, mqd); |
434 | kmem_free(name, MQ_NAMELEN); | | 425 | kmem_free(name, MQ_NAMELEN); |
435 | return ENOENT; | | 426 | return ENOENT; |
436 | } | | 427 | } |
437 | | | 428 | |
| @@ -480,27 +471,27 @@ sys_mq_close(struct lwp *l, const struct | | | @@ -480,27 +471,27 @@ sys_mq_close(struct lwp *l, const struct |
480 | /* | | 471 | /* |
481 | * Primary mq_receive1() function. | | 472 | * Primary mq_receive1() function. |
482 | */ | | 473 | */ |
483 | static int | | 474 | static int |
484 | mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len, | | 475 | mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len, |
485 | unsigned *msg_prio, int t, ssize_t *mlen) | | 476 | unsigned *msg_prio, int t, ssize_t *mlen) |
486 | { | | 477 | { |
487 | file_t *fp = NULL; | | 478 | file_t *fp = NULL; |
488 | struct mqueue *mq; | | 479 | struct mqueue *mq; |
489 | struct mq_msg *msg = NULL; | | 480 | struct mq_msg *msg = NULL; |
490 | int error; | | 481 | int error; |
491 | | | 482 | |
492 | /* Get the message queue */ | | 483 | /* Get the message queue */ |
493 | error = mqueue_get(l, mqdes, FREAD, &fp); | | 484 | error = mqueue_get(mqdes, &fp); |
494 | if (error) | | 485 | if (error) |
495 | return error; | | 486 | return error; |
496 | mq = fp->f_data; | | 487 | mq = fp->f_data; |
497 | | | 488 | |
498 | /* Check the message size limits */ | | 489 | /* Check the message size limits */ |
499 | if (msg_len < mq->mq_attrib.mq_msgsize) { | | 490 | if (msg_len < mq->mq_attrib.mq_msgsize) { |
500 | error = EMSGSIZE; | | 491 | error = EMSGSIZE; |
501 | goto error; | | 492 | goto error; |
502 | } | | 493 | } |
503 | | | 494 | |
504 | /* Check if queue is empty */ | | 495 | /* Check if queue is empty */ |
505 | while (TAILQ_EMPTY(&mq->mq_head)) { | | 496 | while (TAILQ_EMPTY(&mq->mq_head)) { |
506 | if (mq->mq_attrib.mq_flags & O_NONBLOCK) { | | 497 | if (mq->mq_attrib.mq_flags & O_NONBLOCK) { |
| @@ -635,27 +626,27 @@ mq_send1(struct lwp *l, mqd_t mqdes, con | | | @@ -635,27 +626,27 @@ mq_send1(struct lwp *l, mqd_t mqdes, con |
635 | else | | 626 | else |
636 | msg = pool_cache_get(mqmsg_cache, PR_WAITOK); | | 627 | msg = pool_cache_get(mqmsg_cache, PR_WAITOK); |
637 | | | 628 | |
638 | /* Get the data from user-space */ | | 629 | /* Get the data from user-space */ |
639 | error = copyin(msg_ptr, msg->msg_ptr, msg_len); | | 630 | error = copyin(msg_ptr, msg->msg_ptr, msg_len); |
640 | if (error) { | | 631 | if (error) { |
641 | mqueue_freemsg(msg, size); | | 632 | mqueue_freemsg(msg, size); |
642 | return error; | | 633 | return error; |
643 | } | | 634 | } |
644 | msg->msg_len = msg_len; | | 635 | msg->msg_len = msg_len; |
645 | msg->msg_prio = msg_prio; | | 636 | msg->msg_prio = msg_prio; |
646 | | | 637 | |
647 | /* Get the mqueue */ | | 638 | /* Get the mqueue */ |
648 | error = mqueue_get(l, mqdes, FWRITE, &fp); | | 639 | error = mqueue_get(mqdes, &fp); |
649 | if (error) { | | 640 | if (error) { |
650 | mqueue_freemsg(msg, size); | | 641 | mqueue_freemsg(msg, size); |
651 | return error; | | 642 | return error; |
652 | } | | 643 | } |
653 | mq = fp->f_data; | | 644 | mq = fp->f_data; |
654 | | | 645 | |
655 | /* Check the message size limit */ | | 646 | /* Check the message size limit */ |
656 | if (msg_len <= 0 || msg_len > mq->mq_attrib.mq_msgsize) { | | 647 | if (msg_len <= 0 || msg_len > mq->mq_attrib.mq_msgsize) { |
657 | error = EMSGSIZE; | | 648 | error = EMSGSIZE; |
658 | goto error; | | 649 | goto error; |
659 | } | | 650 | } |
660 | | | 651 | |
661 | /* Check if queue is full */ | | 652 | /* Check if queue is full */ |
| @@ -772,27 +763,27 @@ sys_mq_notify(struct lwp *l, const struc | | | @@ -772,27 +763,27 @@ sys_mq_notify(struct lwp *l, const struc |
772 | file_t *fp = NULL; | | 763 | file_t *fp = NULL; |
773 | struct mqueue *mq; | | 764 | struct mqueue *mq; |
774 | struct sigevent sig; | | 765 | struct sigevent sig; |
775 | int error; | | 766 | int error; |
776 | | | 767 | |
777 | if (SCARG(uap, notification)) { | | 768 | if (SCARG(uap, notification)) { |
778 | /* Get the signal from user-space */ | | 769 | /* Get the signal from user-space */ |
779 | error = copyin(SCARG(uap, notification), &sig, | | 770 | error = copyin(SCARG(uap, notification), &sig, |
780 | sizeof(struct sigevent)); | | 771 | sizeof(struct sigevent)); |
781 | if (error) | | 772 | if (error) |
782 | return error; | | 773 | return error; |
783 | } | | 774 | } |
784 | | | 775 | |
785 | error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp); | | 776 | error = mqueue_get(SCARG(uap, mqdes), &fp); |
786 | if (error) | | 777 | if (error) |
787 | return error; | | 778 | return error; |
788 | mq = fp->f_data; | | 779 | mq = fp->f_data; |
789 | | | 780 | |
790 | if (SCARG(uap, notification)) { | | 781 | if (SCARG(uap, notification)) { |
791 | /* Register notification: set the signal and target process */ | | 782 | /* Register notification: set the signal and target process */ |
792 | if (mq->mq_notify_proc == NULL) { | | 783 | if (mq->mq_notify_proc == NULL) { |
793 | memcpy(&mq->mq_sig_notify, &sig, | | 784 | memcpy(&mq->mq_sig_notify, &sig, |
794 | sizeof(struct sigevent)); | | 785 | sizeof(struct sigevent)); |
795 | mq->mq_notify_proc = l->l_proc; | | 786 | mq->mq_notify_proc = l->l_proc; |
796 | } else { | | 787 | } else { |
797 | /* Fail if someone else already registered */ | | 788 | /* Fail if someone else already registered */ |
798 | error = EBUSY; | | 789 | error = EBUSY; |
| @@ -811,27 +802,27 @@ int | | | @@ -811,27 +802,27 @@ int |
811 | sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap, | | 802 | sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap, |
812 | register_t *retval) | | 803 | register_t *retval) |
813 | { | | 804 | { |
814 | /* { | | 805 | /* { |
815 | syscallarg(mqd_t) mqdes; | | 806 | syscallarg(mqd_t) mqdes; |
816 | syscallarg(struct mq_attr *) mqstat; | | 807 | syscallarg(struct mq_attr *) mqstat; |
817 | } */ | | 808 | } */ |
818 | file_t *fp = NULL; | | 809 | file_t *fp = NULL; |
819 | struct mqueue *mq; | | 810 | struct mqueue *mq; |
820 | struct mq_attr attr; | | 811 | struct mq_attr attr; |
821 | int error; | | 812 | int error; |
822 | | | 813 | |
823 | /* Get the message queue */ | | 814 | /* Get the message queue */ |
824 | error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp); | | 815 | error = mqueue_get(SCARG(uap, mqdes), &fp); |
825 | if (error) | | 816 | if (error) |
826 | return error; | | 817 | return error; |
827 | mq = fp->f_data; | | 818 | mq = fp->f_data; |
828 | memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); | | 819 | memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); |
829 | mutex_exit(&mq->mq_mtx); | | 820 | mutex_exit(&mq->mq_mtx); |
830 | fd_putfile((int)SCARG(uap, mqdes)); | | 821 | fd_putfile((int)SCARG(uap, mqdes)); |
831 | | | 822 | |
832 | return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr)); | | 823 | return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr)); |
833 | } | | 824 | } |
834 | | | 825 | |
835 | int | | 826 | int |
836 | sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap, | | 827 | sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap, |
837 | register_t *retval) | | 828 | register_t *retval) |
| @@ -842,27 +833,27 @@ sys_mq_setattr(struct lwp *l, const stru | | | @@ -842,27 +833,27 @@ sys_mq_setattr(struct lwp *l, const stru |
842 | syscallarg(struct mq_attr *) omqstat; | | 833 | syscallarg(struct mq_attr *) omqstat; |
843 | } */ | | 834 | } */ |
844 | file_t *fp = NULL; | | 835 | file_t *fp = NULL; |
845 | struct mqueue *mq; | | 836 | struct mqueue *mq; |
846 | struct mq_attr attr; | | 837 | struct mq_attr attr; |
847 | int error, nonblock; | | 838 | int error, nonblock; |
848 | | | 839 | |
849 | error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr)); | | 840 | error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr)); |
850 | if (error) | | 841 | if (error) |
851 | return error; | | 842 | return error; |
852 | nonblock = (attr.mq_flags & O_NONBLOCK); | | 843 | nonblock = (attr.mq_flags & O_NONBLOCK); |
853 | | | 844 | |
854 | /* Get the message queue */ | | 845 | /* Get the message queue */ |
855 | error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp); | | 846 | error = mqueue_get(SCARG(uap, mqdes), &fp); |
856 | if (error) | | 847 | if (error) |
857 | return error; | | 848 | return error; |
858 | mq = fp->f_data; | | 849 | mq = fp->f_data; |
859 | | | 850 | |
860 | /* Copy the old attributes, if needed */ | | 851 | /* Copy the old attributes, if needed */ |
861 | if (SCARG(uap, omqstat)) | | 852 | if (SCARG(uap, omqstat)) |
862 | memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); | | 853 | memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); |
863 | | | 854 | |
864 | /* Ignore everything, except O_NONBLOCK */ | | 855 | /* Ignore everything, except O_NONBLOCK */ |
865 | if (nonblock) | | 856 | if (nonblock) |
866 | mq->mq_attrib.mq_flags |= O_NONBLOCK; | | 857 | mq->mq_attrib.mq_flags |= O_NONBLOCK; |
867 | else | | 858 | else |
868 | mq->mq_attrib.mq_flags &= ~O_NONBLOCK; | | 859 | mq->mq_attrib.mq_flags &= ~O_NONBLOCK; |
| @@ -900,27 +891,28 @@ sys_mq_unlink(struct lwp *l, const struc | | | @@ -900,27 +891,28 @@ sys_mq_unlink(struct lwp *l, const struc |
900 | kmem_free(name, MQ_NAMELEN); | | 891 | kmem_free(name, MQ_NAMELEN); |
901 | return error; | | 892 | return error; |
902 | } | | 893 | } |
903 | | | 894 | |
904 | /* Lookup for this file */ | | 895 | /* Lookup for this file */ |
905 | mutex_enter(&mqlist_mtx); | | 896 | mutex_enter(&mqlist_mtx); |
906 | mq = mqueue_lookup(name); | | 897 | mq = mqueue_lookup(name); |
907 | if (mq == NULL) { | | 898 | if (mq == NULL) { |
908 | error = ENOENT; | | 899 | error = ENOENT; |
909 | goto error; | | 900 | goto error; |
910 | } | | 901 | } |
911 | | | 902 | |
912 | /* Check the permissions */ | | 903 | /* Check the permissions */ |
913 | if (mqueue_access(l, mq, FWRITE)) { | | 904 | if (kauth_cred_geteuid(l->l_cred) != mq->mq_euid && |
| | | 905 | kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) { |
914 | mutex_exit(&mq->mq_mtx); | | 906 | mutex_exit(&mq->mq_mtx); |
915 | error = EACCES; | | 907 | error = EACCES; |
916 | goto error; | | 908 | goto error; |
917 | } | | 909 | } |
918 | | | 910 | |
919 | /* Mark message queue as unlinking, before leaving the window */ | | 911 | /* Mark message queue as unlinking, before leaving the window */ |
920 | mq->mq_attrib.mq_flags |= MQ_UNLINK; | | 912 | mq->mq_attrib.mq_flags |= MQ_UNLINK; |
921 | | | 913 | |
922 | /* Wake up all waiters, if there are such */ | | 914 | /* Wake up all waiters, if there are such */ |
923 | cv_broadcast(&mq->mq_send_cv); | | 915 | cv_broadcast(&mq->mq_send_cv); |
924 | cv_broadcast(&mq->mq_recv_cv); | | 916 | cv_broadcast(&mq->mq_recv_cv); |
925 | | | 917 | |
926 | selnotify(&mq->mq_rsel, POLLHUP, 0); | | 918 | selnotify(&mq->mq_rsel, POLLHUP, 0); |