xref: /freebsd/sys/kern/uipc_sem.c (revision 721351876cd4d3a8a700f62d2061331fa951a488)
1 /*-
2  * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org>
3  * Copyright (c) 2003-2005 SPARTA, Inc.
4  * Copyright (c) 2005 Robert N. M. Watson
5  * All rights reserved.
6  *
7  * This software was developed for the FreeBSD Project in part by Network
8  * Associates Laboratories, the Security Research Division of Network
9  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
10  * as part of the DARPA CHATS research program.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include "opt_mac.h"
38 #include "opt_posix.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/sysproto.h>
43 #include <sys/eventhandler.h>
44 #include <sys/kernel.h>
45 #include <sys/ksem.h>
46 #include <sys/priv.h>
47 #include <sys/proc.h>
48 #include <sys/posix4.h>
49 #include <sys/lock.h>
50 #include <sys/mutex.h>
51 #include <sys/module.h>
52 #include <sys/condvar.h>
53 #include <sys/sem.h>
54 #include <sys/uio.h>
55 #include <sys/semaphore.h>
56 #include <sys/syscall.h>
57 #include <sys/stat.h>
58 #include <sys/sysent.h>
59 #include <sys/sysctl.h>
60 #include <sys/time.h>
61 #include <sys/malloc.h>
62 #include <sys/fcntl.h>
63 #include <sys/_semaphore.h>
64 
65 #include <security/mac/mac_framework.h>
66 
67 static int sem_count_proc(struct proc *p);
68 static struct ksem *sem_lookup_byname(const char *name);
69 static int sem_create(struct thread *td, const char *name,
70     struct ksem **ksret, mode_t mode, unsigned int value);
71 static void sem_free(struct ksem *ksnew);
72 static int sem_perm(struct thread *td, struct ksem *ks);
73 static void sem_enter(struct proc *p, struct ksem *ks);
74 static int sem_leave(struct proc *p, struct ksem *ks);
75 static void sem_exechook(void *arg, struct proc *p,
76     struct image_params *imgp);
77 static void sem_exithook(void *arg, struct proc *p);
78 static void sem_forkhook(void *arg, struct proc *p1, struct proc *p2,
79     int flags);
80 static int sem_hasopen(struct thread *td, struct ksem *ks);
81 
82 static int kern_sem_close(struct thread *td, semid_t id);
83 static int kern_sem_post(struct thread *td, semid_t id);
84 static int kern_sem_wait(struct thread *td, semid_t id, int tryflag,
85     struct timespec *abstime);
86 static int kern_sem_init(struct thread *td, int dir, unsigned int value,
87     semid_t *idp);
88 static int kern_sem_open(struct thread *td, int dir, const char *name,
89     int oflag, mode_t mode, unsigned int value, semid_t *idp);
90 static int kern_sem_unlink(struct thread *td, const char *name);
91 
92 #ifndef SEM_MAX
93 #define	SEM_MAX	30
94 #endif
95 
96 #define	SEM_MAX_NAMELEN	14
97 
98 #define	SEM_TO_ID(x)	((intptr_t)(x))
99 #define	ID_TO_SEM(x)	id_to_sem(x)
100 
101 /*
102  * Available semaphores go here, this includes sem_init and any semaphores
103  * created via sem_open that have not yet been unlinked.
104  */
105 LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
106 
107 /*
108  * Semaphores still in use but have been sem_unlink()'d go here.
109  */
110 LIST_HEAD(, ksem) ksem_deadhead = LIST_HEAD_INITIALIZER(&ksem_deadhead);
111 
112 static struct mtx sem_lock;
113 static MALLOC_DEFINE(M_SEM, "sems", "semaphore data");
114 
115 static int nsems = 0;
116 SYSCTL_DECL(_p1003_1b);
117 SYSCTL_INT(_p1003_1b, OID_AUTO, nsems, CTLFLAG_RD, &nsems, 0, "");
118 
119 static eventhandler_tag sem_exit_tag, sem_exec_tag, sem_fork_tag;
120 
121 #ifdef SEM_DEBUG
122 #define	DP(x)	printf x
123 #else
124 #define	DP(x)
125 #endif
126 
127 static __inline void
128 sem_ref(struct ksem *ks)
129 {
130 
131 	mtx_assert(&sem_lock, MA_OWNED);
132 	ks->ks_ref++;
133 	DP(("sem_ref: ks = %p, ref = %d\n", ks, ks->ks_ref));
134 }
135 
136 static __inline void
137 sem_rel(struct ksem *ks)
138 {
139 
140 	mtx_assert(&sem_lock, MA_OWNED);
141 	DP(("sem_rel: ks = %p, ref = %d\n", ks, ks->ks_ref - 1));
142 	if (--ks->ks_ref == 0)
143 		sem_free(ks);
144 }
145 
146 static __inline
147 struct ksem *
148 id_to_sem(semid_t id)
149 {
150 	struct ksem *ks;
151 
152 	mtx_assert(&sem_lock, MA_OWNED);
153 	DP(("id_to_sem: id = %0x,%p\n", id, (struct ksem *)id));
154 	LIST_FOREACH(ks, &ksem_head, ks_entry) {
155 		DP(("id_to_sem: ks = %p\n", ks));
156 		if (ks == (struct ksem *)id)
157 			return (ks);
158 	}
159 	return (NULL);
160 }
161 
162 static struct ksem *
163 sem_lookup_byname(const char *name)
164 {
165 	struct ksem *ks;
166 
167 	mtx_assert(&sem_lock, MA_OWNED);
168 	LIST_FOREACH(ks, &ksem_head, ks_entry)
169 		if (ks->ks_name != NULL && strcmp(ks->ks_name, name) == 0)
170 			return (ks);
171 	return (NULL);
172 }
173 
174 static int
175 sem_create(struct thread *td, const char *name, struct ksem **ksret,
176     mode_t mode, unsigned int value)
177 {
178 	struct ksem *ret;
179 	struct proc *p;
180 	struct ucred *uc;
181 	size_t len;
182 	int error;
183 
184 	DP(("sem_create\n"));
185 	p = td->td_proc;
186 	uc = td->td_ucred;
187 	if (value > SEM_VALUE_MAX)
188 		return (EINVAL);
189 	ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
190 	if (name != NULL) {
191 		len = strlen(name);
192 		if (len > SEM_MAX_NAMELEN) {
193 			free(ret, M_SEM);
194 			return (ENAMETOOLONG);
195 		}
196 
197 		/* Name must start with a '/' but not contain one. */
198 		if (*name != '/' || len < 2 || index(name + 1, '/') != NULL) {
199 			free(ret, M_SEM);
200 			return (EINVAL);
201 		}
202 		ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
203 		strcpy(ret->ks_name, name);
204 	} else {
205 		ret->ks_name = NULL;
206 	}
207 	ret->ks_mode = mode;
208 	ret->ks_value = value;
209 	ret->ks_ref = 1;
210 	ret->ks_waiters = 0;
211 	ret->ks_uid = uc->cr_uid;
212 	ret->ks_gid = uc->cr_gid;
213 	ret->ks_onlist = 0;
214 	cv_init(&ret->ks_cv, "sem");
215 	LIST_INIT(&ret->ks_users);
216 #ifdef MAC
217 	mac_posixsem_init(ret);
218 	mac_posixsem_create(uc, ret);
219 #endif
220 	if (name != NULL)
221 		sem_enter(td->td_proc, ret);
222 	*ksret = ret;
223 	mtx_lock(&sem_lock);
224 	nsems++;
225 	if (nsems > p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX)) {
226 		sem_leave(td->td_proc, ret);
227 		sem_free(ret);
228 		error = ENFILE;
229 	} else
230 		error = 0;
231 	mtx_unlock(&sem_lock);
232 	return (error);
233 }
234 
235 #ifndef _SYS_SYSPROTO_H_
236 struct ksem_init_args {
237 	unsigned int value;
238 	semid_t *idp;
239 };
240 int ksem_init(struct thread *td, struct ksem_init_args *uap);
241 #endif
242 int
243 ksem_init(struct thread *td, struct ksem_init_args *uap)
244 {
245 
246 	return (kern_sem_init(td, UIO_USERSPACE, uap->value, uap->idp));
247 }
248 
249 static int
250 kern_sem_init(struct thread *td, int dir, unsigned int value, semid_t *idp)
251 {
252 	struct ksem *ks;
253 	semid_t id;
254 	int error;
255 
256 	error = sem_create(td, NULL, &ks, S_IRWXU | S_IRWXG, value);
257 	if (error)
258 		return (error);
259 	id = SEM_TO_ID(ks);
260 	if (dir == UIO_USERSPACE) {
261 		error = copyout(&id, idp, sizeof(id));
262 		if (error) {
263 			mtx_lock(&sem_lock);
264 			sem_rel(ks);
265 			mtx_unlock(&sem_lock);
266 			return (error);
267 		}
268 	} else {
269 		*idp = id;
270 	}
271 	mtx_lock(&sem_lock);
272 	LIST_INSERT_HEAD(&ksem_head, ks, ks_entry);
273 	ks->ks_onlist = 1;
274 	mtx_unlock(&sem_lock);
275 	return (error);
276 }
277 
278 #ifndef _SYS_SYSPROTO_H_
279 struct ksem_open_args {
280 	char *name;
281 	int oflag;
282 	mode_t mode;
283 	unsigned int value;
284 	semid_t *idp;
285 };
286 int ksem_open(struct thread *td, struct ksem_open_args *uap);
287 #endif
288 int
289 ksem_open(struct thread *td, struct ksem_open_args *uap)
290 {
291 	char name[SEM_MAX_NAMELEN + 1];
292 	size_t done;
293 	int error;
294 
295 	error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
296 	if (error)
297 		return (error);
298 	DP((">>> sem_open start\n"));
299 	error = kern_sem_open(td, UIO_USERSPACE,
300 	    name, uap->oflag, uap->mode, uap->value, uap->idp);
301 	DP(("<<< sem_open end\n"));
302 	return (error);
303 }
304 
305 static int
306 kern_sem_open(struct thread *td, int dir, const char *name, int oflag,
307     mode_t mode, unsigned int value, semid_t *idp)
308 {
309 	struct ksem *ksnew, *ks;
310 	int error;
311 	semid_t id;
312 
313 	ksnew = NULL;
314 	mtx_lock(&sem_lock);
315 	ks = sem_lookup_byname(name);
316 
317 	/*
318 	 * If we found it but O_EXCL is set, error.
319 	 */
320 	if (ks != NULL && (oflag & O_EXCL) != 0) {
321 		mtx_unlock(&sem_lock);
322 		return (EEXIST);
323 	}
324 
325 	/*
326 	 * If we didn't find it...
327 	 */
328 	if (ks == NULL) {
329 		/*
330 		 * didn't ask for creation? error.
331 		 */
332 		if ((oflag & O_CREAT) == 0) {
333 			mtx_unlock(&sem_lock);
334 			return (ENOENT);
335 		}
336 
337 		/*
338 		 * We may block during creation, so drop the lock.
339 		 */
340 		mtx_unlock(&sem_lock);
341 		error = sem_create(td, name, &ksnew, mode, value);
342 		if (error != 0)
343 			return (error);
344 		id = SEM_TO_ID(ksnew);
345 		if (dir == UIO_USERSPACE) {
346 			DP(("about to copyout! %d to %p\n", id, idp));
347 			error = copyout(&id, idp, sizeof(id));
348 			if (error) {
349 				mtx_lock(&sem_lock);
350 				sem_leave(td->td_proc, ksnew);
351 				sem_rel(ksnew);
352 				mtx_unlock(&sem_lock);
353 				return (error);
354 			}
355 		} else {
356 			DP(("about to set! %d to %p\n", id, idp));
357 			*idp = id;
358 		}
359 
360 		/*
361 		 * We need to make sure we haven't lost a race while
362 		 * allocating during creation.
363 		 */
364 		mtx_lock(&sem_lock);
365 		ks = sem_lookup_byname(name);
366 		if (ks != NULL) {
367 			/* we lost... */
368 			sem_leave(td->td_proc, ksnew);
369 			sem_rel(ksnew);
370 			/* we lost and we can't loose... */
371 			if ((oflag & O_EXCL) != 0) {
372 				mtx_unlock(&sem_lock);
373 				return (EEXIST);
374 			}
375 		} else {
376 			DP(("sem_create: about to add to list...\n"));
377 			LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry);
378 			DP(("sem_create: setting list bit...\n"));
379 			ksnew->ks_onlist = 1;
380 			DP(("sem_create: done, about to unlock...\n"));
381 		}
382 	} else {
383 #ifdef MAC
384 		error = mac_posixsem_check_open(td->td_ucred, ks);
385 		if (error)
386 			goto err_open;
387 #endif
388 		/*
389 		 * if we aren't the creator, then enforce permissions.
390 		 */
391 		error = sem_perm(td, ks);
392 		if (error)
393 			goto err_open;
394 		sem_ref(ks);
395 		mtx_unlock(&sem_lock);
396 		id = SEM_TO_ID(ks);
397 		if (dir == UIO_USERSPACE) {
398 			error = copyout(&id, idp, sizeof(id));
399 			if (error) {
400 				mtx_lock(&sem_lock);
401 				sem_rel(ks);
402 				mtx_unlock(&sem_lock);
403 				return (error);
404 			}
405 		} else {
406 			*idp = id;
407 		}
408 		sem_enter(td->td_proc, ks);
409 		mtx_lock(&sem_lock);
410 		sem_rel(ks);
411 	}
412 err_open:
413 	mtx_unlock(&sem_lock);
414 	return (error);
415 }
416 
417 static int
418 sem_perm(struct thread *td, struct ksem *ks)
419 {
420 	struct ucred *uc;
421 
422 	/*
423 	 * XXXRW: This permission routine appears to be incorrect.  If the
424 	 * user matches, we shouldn't go on to the group if the user
425 	 * permissions don't allow the action?  Not changed for now.  To fix,
426 	 * change from a series of if (); if (); to if () else if () else...
427 	 */
428 	uc = td->td_ucred;
429 	DP(("sem_perm: uc(%d,%d) ks(%d,%d,%o)\n",
430 	    uc->cr_uid, uc->cr_gid,
431 	     ks->ks_uid, ks->ks_gid, ks->ks_mode));
432 	if ((uc->cr_uid == ks->ks_uid) && (ks->ks_mode & S_IWUSR) != 0)
433 		return (0);
434 	if ((uc->cr_gid == ks->ks_gid) && (ks->ks_mode & S_IWGRP) != 0)
435 		return (0);
436 	if ((ks->ks_mode & S_IWOTH) != 0)
437 		return (0);
438 	return (priv_check(td, PRIV_SEM_WRITE));
439 }
440 
441 static void
442 sem_free(struct ksem *ks)
443 {
444 
445 #ifdef MAC
446 	mac_posixsem_destroy(ks);
447 #endif
448 	nsems--;
449 	if (ks->ks_onlist)
450 		LIST_REMOVE(ks, ks_entry);
451 	if (ks->ks_name != NULL)
452 		free(ks->ks_name, M_SEM);
453 	cv_destroy(&ks->ks_cv);
454 	free(ks, M_SEM);
455 }
456 
457 static __inline struct kuser *
458 sem_getuser(struct proc *p, struct ksem *ks)
459 {
460 	struct kuser *k;
461 
462 	LIST_FOREACH(k, &ks->ks_users, ku_next)
463 		if (k->ku_pid == p->p_pid)
464 			return (k);
465 	return (NULL);
466 }
467 
468 static int
469 sem_hasopen(struct thread *td, struct ksem *ks)
470 {
471 
472 	return ((ks->ks_name == NULL && sem_perm(td, ks) == 0)
473 	    || sem_getuser(td->td_proc, ks) != NULL);
474 }
475 
476 static int
477 sem_leave(struct proc *p, struct ksem *ks)
478 {
479 	struct kuser *k;
480 
481 	DP(("sem_leave: ks = %p\n", ks));
482 	k = sem_getuser(p, ks);
483 	DP(("sem_leave: ks = %p, k = %p\n", ks, k));
484 	if (k != NULL) {
485 		LIST_REMOVE(k, ku_next);
486 		sem_rel(ks);
487 		DP(("sem_leave: about to free k\n"));
488 		free(k, M_SEM);
489 		DP(("sem_leave: returning\n"));
490 		return (0);
491 	}
492 	return (EINVAL);
493 }
494 
495 static void
496 sem_enter(struct proc *p, struct ksem *ks)
497 {
498 	struct kuser *ku, *k;
499 
500 	ku = malloc(sizeof(*ku), M_SEM, M_WAITOK);
501 	ku->ku_pid = p->p_pid;
502 	mtx_lock(&sem_lock);
503 	k = sem_getuser(p, ks);
504 	if (k != NULL) {
505 		mtx_unlock(&sem_lock);
506 		free(ku, M_TEMP);
507 		return;
508 	}
509 	LIST_INSERT_HEAD(&ks->ks_users, ku, ku_next);
510 	sem_ref(ks);
511 	mtx_unlock(&sem_lock);
512 }
513 
514 #ifndef _SYS_SYSPROTO_H_
515 struct ksem_unlink_args {
516 	char *name;
517 };
518 int ksem_unlink(struct thread *td, struct ksem_unlink_args *uap);
519 #endif
520 int
521 ksem_unlink(struct thread *td, struct ksem_unlink_args *uap)
522 {
523 	char name[SEM_MAX_NAMELEN + 1];
524 	size_t done;
525 	int error;
526 
527 	error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
528 	return (error ? error :
529 	    kern_sem_unlink(td, name));
530 }
531 
532 static int
533 kern_sem_unlink(struct thread *td, const char *name)
534 {
535 	struct ksem *ks;
536 	int error;
537 
538 	mtx_lock(&sem_lock);
539 	ks = sem_lookup_byname(name);
540 	if (ks != NULL) {
541 #ifdef MAC
542 		error = mac_posixsem_check_unlink(td->td_ucred, ks);
543 		if (error) {
544 			mtx_unlock(&sem_lock);
545 			return (error);
546 		}
547 #endif
548 		error = sem_perm(td, ks);
549 	} else
550 		error = ENOENT;
551 	DP(("sem_unlink: '%s' ks = %p, error = %d\n", name, ks, error));
552 	if (error == 0) {
553 		LIST_REMOVE(ks, ks_entry);
554 		LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry);
555 		sem_rel(ks);
556 	}
557 	mtx_unlock(&sem_lock);
558 	return (error);
559 }
560 
561 #ifndef _SYS_SYSPROTO_H_
562 struct ksem_close_args {
563 	semid_t id;
564 };
565 int ksem_close(struct thread *td, struct ksem_close_args *uap);
566 #endif
567 int
568 ksem_close(struct thread *td, struct ksem_close_args *uap)
569 {
570 
571 	return (kern_sem_close(td, uap->id));
572 }
573 
574 static int
575 kern_sem_close(struct thread *td, semid_t id)
576 {
577 	struct ksem *ks;
578 	int error;
579 
580 	error = EINVAL;
581 	mtx_lock(&sem_lock);
582 	ks = ID_TO_SEM(id);
583 
584 	/*
585 	 * This is not a valid operation for unnamed sems.
586 	 */
587 	if (ks != NULL && ks->ks_name != NULL)
588 		error = sem_leave(td->td_proc, ks);
589 	mtx_unlock(&sem_lock);
590 	return (error);
591 }
592 
593 #ifndef _SYS_SYSPROTO_H_
594 struct ksem_post_args {
595 	semid_t id;
596 };
597 int ksem_post(struct thread *td, struct ksem_post_args *uap);
598 #endif
599 int
600 ksem_post(struct thread *td, struct ksem_post_args *uap)
601 {
602 
603 	return (kern_sem_post(td, uap->id));
604 }
605 
606 static int
607 kern_sem_post(struct thread *td, semid_t id)
608 {
609 	struct ksem *ks;
610 	int error;
611 
612 	mtx_lock(&sem_lock);
613 	ks = ID_TO_SEM(id);
614 	if (ks == NULL || !sem_hasopen(td, ks)) {
615 		error = EINVAL;
616 		goto err;
617 	}
618 #ifdef MAC
619 	error = mac_posixsem_check_post(td->td_ucred, ks);
620 	if (error)
621 		goto err;
622 #endif
623 	if (ks->ks_value == SEM_VALUE_MAX) {
624 		error = EOVERFLOW;
625 		goto err;
626 	}
627 	++ks->ks_value;
628 	if (ks->ks_waiters > 0)
629 		cv_signal(&ks->ks_cv);
630 	error = 0;
631 err:
632 	mtx_unlock(&sem_lock);
633 	return (error);
634 }
635 
636 #ifndef _SYS_SYSPROTO_H_
637 struct ksem_wait_args {
638 	semid_t id;
639 };
640 int ksem_wait(struct thread *td, struct ksem_wait_args *uap);
641 #endif
642 int
643 ksem_wait(struct thread *td, struct ksem_wait_args *uap)
644 {
645 
646 	return (kern_sem_wait(td, uap->id, 0, NULL));
647 }
648 
649 #ifndef _SYS_SYSPROTO_H_
650 struct ksem_timedwait_args {
651 	semid_t id;
652 	const struct timespec *abstime;
653 };
654 int ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap);
655 #endif
656 int
657 ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap)
658 {
659 	struct timespec abstime;
660 	struct timespec *ts;
661 	int error;
662 
663 	/*
664 	 * We allow a null timespec (wait forever).
665 	 */
666 	if (uap->abstime == NULL)
667 		ts = NULL;
668 	else {
669 		error = copyin(uap->abstime, &abstime, sizeof(abstime));
670 		if (error != 0)
671 			return (error);
672 		if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
673 			return (EINVAL);
674 		ts = &abstime;
675 	}
676 	return (kern_sem_wait(td, uap->id, 0, ts));
677 }
678 
679 #ifndef _SYS_SYSPROTO_H_
680 struct ksem_trywait_args {
681 	semid_t id;
682 };
683 int ksem_trywait(struct thread *td, struct ksem_trywait_args *uap);
684 #endif
685 int
686 ksem_trywait(struct thread *td, struct ksem_trywait_args *uap)
687 {
688 
689 	return (kern_sem_wait(td, uap->id, 1, NULL));
690 }
691 
692 static int
693 kern_sem_wait(struct thread *td, semid_t id, int tryflag,
694     struct timespec *abstime)
695 {
696 	struct timespec ts1, ts2;
697 	struct timeval tv;
698 	struct ksem *ks;
699 	int error;
700 
701 	DP((">>> kern_sem_wait entered!\n"));
702 	mtx_lock(&sem_lock);
703 	ks = ID_TO_SEM(id);
704 	if (ks == NULL) {
705 		DP(("kern_sem_wait ks == NULL\n"));
706 		error = EINVAL;
707 		goto err;
708 	}
709 	sem_ref(ks);
710 	if (!sem_hasopen(td, ks)) {
711 		DP(("kern_sem_wait hasopen failed\n"));
712 		error = EINVAL;
713 		goto err;
714 	}
715 #ifdef MAC
716 	error = mac_posixsem_check_wait(td->td_ucred, ks);
717 	if (error) {
718 		DP(("kern_sem_wait mac failed\n"));
719 		goto err;
720 	}
721 #endif
722 	DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
723 	if (ks->ks_value == 0) {
724 		ks->ks_waiters++;
725 		if (tryflag != 0)
726 			error = EAGAIN;
727 		else if (abstime == NULL)
728 			error = cv_wait_sig(&ks->ks_cv, &sem_lock);
729 		else {
730 			for (;;) {
731 				ts1 = *abstime;
732 				getnanotime(&ts2);
733 				timespecsub(&ts1, &ts2);
734 				TIMESPEC_TO_TIMEVAL(&tv, &ts1);
735 				if (tv.tv_sec < 0) {
736 					error = ETIMEDOUT;
737 					break;
738 				}
739 				error = cv_timedwait_sig(&ks->ks_cv,
740 				    &sem_lock, tvtohz(&tv));
741 				if (error != EWOULDBLOCK)
742 					break;
743 			}
744 		}
745 		ks->ks_waiters--;
746 		if (error)
747 			goto err;
748 	}
749 	ks->ks_value--;
750 	error = 0;
751 err:
752 	if (ks != NULL)
753 		sem_rel(ks);
754 	mtx_unlock(&sem_lock);
755 	DP(("<<< kern_sem_wait leaving, error = %d\n", error));
756 	return (error);
757 }
758 
759 #ifndef _SYS_SYSPROTO_H_
760 struct ksem_getvalue_args {
761 	semid_t id;
762 	int *val;
763 };
764 int ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap);
765 #endif
766 int
767 ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap)
768 {
769 	struct ksem *ks;
770 	int error, val;
771 
772 	mtx_lock(&sem_lock);
773 	ks = ID_TO_SEM(uap->id);
774 	if (ks == NULL || !sem_hasopen(td, ks)) {
775 		mtx_unlock(&sem_lock);
776 		return (EINVAL);
777 	}
778 #ifdef MAC
779 	error = mac_posixsem_check_getvalue(td->td_ucred, ks);
780 	if (error) {
781 		mtx_unlock(&sem_lock);
782 		return (error);
783 	}
784 #endif
785 	val = ks->ks_value;
786 	mtx_unlock(&sem_lock);
787 	error = copyout(&val, uap->val, sizeof(val));
788 	return (error);
789 }
790 
791 #ifndef _SYS_SYSPROTO_H_
792 struct ksem_destroy_args {
793 	semid_t id;
794 };
795 int ksem_destroy(struct thread *td, struct ksem_destroy_args *uap);
796 #endif
797 int
798 ksem_destroy(struct thread *td, struct ksem_destroy_args *uap)
799 {
800 	struct ksem *ks;
801 	int error;
802 
803 	mtx_lock(&sem_lock);
804 	ks = ID_TO_SEM(uap->id);
805 	if (ks == NULL || !sem_hasopen(td, ks) ||
806 	    ks->ks_name != NULL) {
807 		error = EINVAL;
808 		goto err;
809 	}
810 	if (ks->ks_waiters != 0) {
811 		error = EBUSY;
812 		goto err;
813 	}
814 	sem_rel(ks);
815 	error = 0;
816 err:
817 	mtx_unlock(&sem_lock);
818 	return (error);
819 }
820 
821 /*
822  * Count the number of kusers associated with a proc, so as to guess at how
823  * many to allocate when forking.
824  */
825 static int
826 sem_count_proc(struct proc *p)
827 {
828 	struct ksem *ks;
829 	struct kuser *ku;
830 	int count;
831 
832 	mtx_assert(&sem_lock, MA_OWNED);
833 
834 	count = 0;
835 	LIST_FOREACH(ks, &ksem_head, ks_entry) {
836 		LIST_FOREACH(ku, &ks->ks_users, ku_next) {
837 			if (ku->ku_pid == p->p_pid)
838 				count++;
839 		}
840 	}
841 	LIST_FOREACH(ks, &ksem_deadhead, ks_entry) {
842 		LIST_FOREACH(ku, &ks->ks_users, ku_next) {
843 			if (ku->ku_pid == p->p_pid)
844 				count++;
845 		}
846 	}
847 	return (count);
848 }
849 
850 /*
851  * When a process forks, the child process must gain a reference to each open
852  * semaphore in the parent process, whether it is unlinked or not.  This
853  * requires allocating a kuser structure for each semaphore reference in the
854  * new process.  Because the set of semaphores in the parent can change while
855  * the fork is in progress, we have to handle races -- first we attempt to
856  * allocate enough storage to acquire references to each of the semaphores,
857  * then we enter the semaphores and release the temporary references.
858  */
859 static void
860 sem_forkhook(void *arg, struct proc *p1, struct proc *p2, int flags)
861 {
862 	struct ksem *ks, **sem_array;
863 	int count, i, new_count;
864 	struct kuser *ku;
865 
866 	mtx_lock(&sem_lock);
867 	count = sem_count_proc(p1);
868 	if (count == 0) {
869 		mtx_unlock(&sem_lock);
870 		return;
871 	}
872 race_lost:
873 	mtx_assert(&sem_lock, MA_OWNED);
874 	mtx_unlock(&sem_lock);
875 	sem_array = malloc(sizeof(struct ksem *) * count, M_TEMP, M_WAITOK);
876 	mtx_lock(&sem_lock);
877 	new_count = sem_count_proc(p1);
878 	if (count < new_count) {
879 		/* Lost race, repeat and allocate more storage. */
880 		free(sem_array, M_TEMP);
881 		count = new_count;
882 		goto race_lost;
883 	}
884 
885 	/*
886 	 * Given an array capable of storing an adequate number of semaphore
887 	 * references, now walk the list of semaphores and acquire a new
888 	 * reference for any semaphore opened by p1.
889 	 */
890 	count = new_count;
891 	i = 0;
892 	LIST_FOREACH(ks, &ksem_head, ks_entry) {
893 		LIST_FOREACH(ku, &ks->ks_users, ku_next) {
894 			if (ku->ku_pid == p1->p_pid) {
895 				sem_ref(ks);
896 				sem_array[i] = ks;
897 				i++;
898 				break;
899 			}
900 		}
901 	}
902 	LIST_FOREACH(ks, &ksem_deadhead, ks_entry) {
903 		LIST_FOREACH(ku, &ks->ks_users, ku_next) {
904 			if (ku->ku_pid == p1->p_pid) {
905 				sem_ref(ks);
906 				sem_array[i] = ks;
907 				i++;
908 				break;
909 			}
910 		}
911 	}
912 	mtx_unlock(&sem_lock);
913 	KASSERT(i == count, ("sem_forkhook: i != count (%d, %d)", i, count));
914 
915 	/*
916 	 * Now cause p2 to enter each of the referenced semaphores, then
917 	 * release our temporary reference.  This is pretty inefficient.
918 	 * Finally, free our temporary array.
919 	 */
920 	for (i = 0; i < count; i++) {
921 		sem_enter(p2, sem_array[i]);
922 		mtx_lock(&sem_lock);
923 		sem_rel(sem_array[i]);
924 		mtx_unlock(&sem_lock);
925 	}
926 	free(sem_array, M_TEMP);
927 }
928 
929 static void
930 sem_exechook(void *arg, struct proc *p, struct image_params *imgp __unused)
931 {
932    	sem_exithook(arg, p);
933 }
934 
935 static void
936 sem_exithook(void *arg, struct proc *p)
937 {
938 	struct ksem *ks, *ksnext;
939 
940 	mtx_lock(&sem_lock);
941 	ks = LIST_FIRST(&ksem_head);
942 	while (ks != NULL) {
943 		ksnext = LIST_NEXT(ks, ks_entry);
944 		sem_leave(p, ks);
945 		ks = ksnext;
946 	}
947 	ks = LIST_FIRST(&ksem_deadhead);
948 	while (ks != NULL) {
949 		ksnext = LIST_NEXT(ks, ks_entry);
950 		sem_leave(p, ks);
951 		ks = ksnext;
952 	}
953 	mtx_unlock(&sem_lock);
954 }
955 
956 static int
957 sem_modload(struct module *module, int cmd, void *arg)
958 {
959         int error = 0;
960 
961         switch (cmd) {
962         case MOD_LOAD:
963 		mtx_init(&sem_lock, "sem", "semaphore", MTX_DEF);
964 		p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
965 		p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
966 		sem_exit_tag = EVENTHANDLER_REGISTER(process_exit,
967 		    sem_exithook, NULL, EVENTHANDLER_PRI_ANY);
968 		sem_exec_tag = EVENTHANDLER_REGISTER(process_exec,
969 		    sem_exechook, NULL, EVENTHANDLER_PRI_ANY);
970 		sem_fork_tag = EVENTHANDLER_REGISTER(process_fork,
971 		    sem_forkhook, NULL, EVENTHANDLER_PRI_ANY);
972                 break;
973 
974         case MOD_UNLOAD:
975 		if (nsems != 0) {
976 			error = EOPNOTSUPP;
977 			break;
978 		}
979 		EVENTHANDLER_DEREGISTER(process_exit, sem_exit_tag);
980 		EVENTHANDLER_DEREGISTER(process_exec, sem_exec_tag);
981 		EVENTHANDLER_DEREGISTER(process_fork, sem_fork_tag);
982 		mtx_destroy(&sem_lock);
983                 break;
984 
985         case MOD_SHUTDOWN:
986                 break;
987         default:
988                 error = EINVAL;
989                 break;
990         }
991         return (error);
992 }
993 
994 static moduledata_t sem_mod = {
995         "sem",
996         &sem_modload,
997         NULL
998 };
999 
1000 SYSCALL_MODULE_HELPER(ksem_init);
1001 SYSCALL_MODULE_HELPER(ksem_open);
1002 SYSCALL_MODULE_HELPER(ksem_unlink);
1003 SYSCALL_MODULE_HELPER(ksem_close);
1004 SYSCALL_MODULE_HELPER(ksem_post);
1005 SYSCALL_MODULE_HELPER(ksem_wait);
1006 SYSCALL_MODULE_HELPER(ksem_timedwait);
1007 SYSCALL_MODULE_HELPER(ksem_trywait);
1008 SYSCALL_MODULE_HELPER(ksem_getvalue);
1009 SYSCALL_MODULE_HELPER(ksem_destroy);
1010 
1011 DECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
1012 MODULE_VERSION(sem, 1);
1013