| 2326 | } |
| 2327 | |
| 2328 | static int |
| 2329 | kern_kmq_notify(struct thread *td, int mqd, struct sigevent *sigev) |
| 2330 | { |
| 2331 | struct filedesc *fdp; |
| 2332 | struct proc *p; |
| 2333 | struct mqueue *mq; |
| 2334 | struct file *fp, *fp2; |
| 2335 | struct mqueue_notifier *nt, *newnt = NULL; |
| 2336 | int error; |
| 2337 | |
| 2338 | AUDIT_ARG_FD(mqd); |
| 2339 | if (sigev != NULL) { |
| 2340 | if (sigev->sigev_notify != SIGEV_SIGNAL && |
| 2341 | sigev->sigev_notify != SIGEV_THREAD_ID && |
| 2342 | sigev->sigev_notify != SIGEV_NONE) |
| 2343 | return (EINVAL); |
| 2344 | if ((sigev->sigev_notify == SIGEV_SIGNAL || |
| 2345 | sigev->sigev_notify == SIGEV_THREAD_ID) && |
| 2346 | !_SIG_VALID(sigev->sigev_signo)) |
| 2347 | return (EINVAL); |
| 2348 | } |
| 2349 | p = td->td_proc; |
| 2350 | fdp = td->td_proc->p_fd; |
| 2351 | error = getmq(td, mqd, &fp, NULL, &mq); |
| 2352 | if (error) |
| 2353 | return (error); |
| 2354 | again: |
| 2355 | FILEDESC_SLOCK(fdp); |
| 2356 | fp2 = fget_locked(fdp, mqd); |
| 2357 | if (fp2 == NULL) { |
| 2358 | FILEDESC_SUNLOCK(fdp); |
| 2359 | error = EBADF; |
| 2360 | goto out; |
| 2361 | } |
| 2362 | #ifdef CAPABILITIES |
| 2363 | error = cap_check(cap_rights(fdp, mqd), &cap_event_rights); |
| 2364 | if (error) { |
| 2365 | FILEDESC_SUNLOCK(fdp); |
| 2366 | goto out; |
| 2367 | } |
| 2368 | #endif |
| 2369 | if (fp2 != fp) { |
| 2370 | FILEDESC_SUNLOCK(fdp); |
| 2371 | error = EBADF; |
| 2372 | goto out; |
| 2373 | } |
| 2374 | mtx_lock(&mq->mq_mutex); |
| 2375 | FILEDESC_SUNLOCK(fdp); |
| 2376 | if (sigev != NULL) { |
| 2377 | if (mq->mq_notifier != NULL) { |
| 2378 | error = EBUSY; |
| 2379 | } else { |
| 2380 | PROC_LOCK(p); |
| 2381 | nt = notifier_search(p, mqd); |
| 2382 | if (nt == NULL) { |
| 2383 | if (newnt == NULL) { |
| 2384 | PROC_UNLOCK(p); |
| 2385 | mtx_unlock(&mq->mq_mutex); |
no test coverage detected