xref: /xnu-8019.80.24/bsd/kern/sysv_sem.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * Implementation of SVID semaphores
30  *
31  * Author:  Daniel Boulet
32  *
33  * This software is provided ``AS IS'' without any warranties of any kind.
34  */
35 /*
36  * John Bellardo modified the implementation for Darwin. 12/2000
37  */
38 /*
39  * NOTICE: This file was modified by McAfee Research in 2004 to introduce
40  * support for mandatory and extensible security protections.  This notice
41  * is included in support of clause 2.2 (b) of the Apple Public License,
42  * Version 2.0.
43  * Copyright (c) 2005-2006 SPARTA, Inc.
44  */
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/proc_internal.h>
50 #include <sys/kauth.h>
51 #include <sys/sem_internal.h>
52 #include <sys/malloc.h>
53 #include <mach/mach_types.h>
54 
55 #include <sys/filedesc.h>
56 #include <sys/file_internal.h>
57 #include <sys/sysctl.h>
58 #include <sys/ipcs.h>
59 #include <sys/sysent.h>
60 #include <sys/sysproto.h>
61 #if CONFIG_MACF
62 #include <security/mac_framework.h>
63 #endif
64 
65 #include <security/audit/audit.h>
66 
67 #if SYSV_SEM
68 
69 
70 /* Uncomment this line to see the debugging output */
71 /* #define SEM_DEBUG */
72 
73 /* Uncomment this line to see MAC debugging output. */
74 /* #define	MAC_DEBUG */
75 #if CONFIG_MACF_DEBUG
76 #define MPRINTF(a)      printf(a)
77 #else
78 #define MPRINTF(a)
79 #endif
80 
81 /* Hard system limits to avoid resource starvation / DOS attacks.
82  * These are not needed if we can make the semaphore pages swappable.
83  */
84 static struct seminfo limitseminfo = {
85 	.semmap = SEMMAP,        /* # of entries in semaphore map */
86 	.semmni = SEMMNI,        /* # of semaphore identifiers */
87 	.semmns = SEMMNS,        /* # of semaphores in system */
88 	.semmnu = SEMMNU,        /* # of undo structures in system */
89 	.semmsl = SEMMSL,        /* max # of semaphores per id */
90 	.semopm = SEMOPM,        /* max # of operations per semop call */
91 	.semume = SEMUME,        /* max # of undo entries per process */
92 	.semusz = SEMUSZ,        /* size in bytes of undo structure */
93 	.semvmx = SEMVMX,        /* semaphore maximum value */
94 	.semaem = SEMAEM         /* adjust on exit max value */
95 };
96 
97 /* Current system allocations.  We use this structure to track how many
98  * resources we have allocated so far.  This way we can set large hard limits
99  * and not allocate the memory for them up front.
100  */
101 struct seminfo seminfo = {
102 	.semmap = SEMMAP,       /* Unused, # of entries in semaphore map */
103 	.semmni = 0,            /* # of semaphore identifiers */
104 	.semmns = 0,            /* # of semaphores in system */
105 	.semmnu = 0,            /* # of undo entries in system */
106 	.semmsl = SEMMSL,       /* max # of semaphores per id */
107 	.semopm = SEMOPM,       /* max # of operations per semop call */
108 	.semume = SEMUME,       /* max # of undo entries per process */
109 	.semusz = SEMUSZ,       /* size in bytes of undo structure */
110 	.semvmx = SEMVMX,       /* semaphore maximum value */
111 	.semaem = SEMAEM        /* adjust on exit max value */
112 };
113 
114 
115 static int semu_alloc(struct proc *p);
116 static int semundo_adjust(struct proc *p, int *supidx,
117     int semid, int semnum, int adjval);
118 static void semundo_clear(int semid, int semnum);
119 
120 /* XXX casting to (sy_call_t *) is bogus, as usual. */
121 static sy_call_t* const semcalls[] = {
122 	(sy_call_t *)semctl, (sy_call_t *)semget,
123 	(sy_call_t *)semop
124 };
125 
126 static int                      semtot = 0;         /* # of used semaphores */
127 static struct semid_kernel    **semas = NULL;       /* semaphore id pool */
128 static struct sem              *sem_pool =  NULL;   /* semaphore pool */
129 static int                      semu_list_idx = -1; /* active undo structures */
130 static struct sem_undo         *semu = NULL;        /* semaphore undo pool */
131 
132 static LCK_GRP_DECLARE(sysv_sem_subsys_lck_grp, "sysv_sem_subsys_lock");
133 static LCK_MTX_DECLARE(sysv_sem_subsys_mutex, &sysv_sem_subsys_lck_grp);
134 
135 #define SYSV_SEM_SUBSYS_LOCK() lck_mtx_lock(&sysv_sem_subsys_mutex)
136 #define SYSV_SEM_SUBSYS_UNLOCK() lck_mtx_unlock(&sysv_sem_subsys_mutex)
137 
138 static __inline__ user_time_t
sysv_semtime(void)139 sysv_semtime(void)
140 {
141 	struct timeval  tv;
142 	microtime(&tv);
143 	return tv.tv_sec;
144 }
145 
146 /*
147  * XXX conversion of internal user_time_t to external tume_t loses
148  * XXX precision; not an issue for us now, since we are only ever
149  * XXX setting 32 bits worth of time into it.
150  *
151  * pad field contents are not moved correspondingly; contents will be lost
152  *
153  * NOTE: Source and target may *NOT* overlap! (target is smaller)
154  */
155 static void
semid_ds_kernelto32(struct user_semid_ds * in,struct user32_semid_ds * out)156 semid_ds_kernelto32(struct user_semid_ds *in, struct user32_semid_ds *out)
157 {
158 	out->sem_perm = in->sem_perm;
159 	out->sem_base = CAST_DOWN_EXPLICIT(__int32_t, in->sem_base);
160 	out->sem_nsems = in->sem_nsems;
161 	out->sem_otime = in->sem_otime;         /* XXX loses precision */
162 	out->sem_ctime = in->sem_ctime;         /* XXX loses precision */
163 }
164 
165 static void
semid_ds_kernelto64(struct user_semid_ds * in,struct user64_semid_ds * out)166 semid_ds_kernelto64(struct user_semid_ds *in, struct user64_semid_ds *out)
167 {
168 	out->sem_perm = in->sem_perm;
169 	out->sem_base = CAST_DOWN_EXPLICIT(__int32_t, in->sem_base);
170 	out->sem_nsems = in->sem_nsems;
171 	out->sem_otime = in->sem_otime;         /* XXX loses precision */
172 	out->sem_ctime = in->sem_ctime;         /* XXX loses precision */
173 }
174 
175 /*
176  * pad field contents are not moved correspondingly; contents will be lost
177  *
178  * NOTE: Source and target may are permitted to overlap! (source is smaller);
179  * this works because we copy fields in order from the end of the struct to
180  * the beginning.
181  *
182  * XXX use CAST_USER_ADDR_T() for lack of a CAST_USER_TIME_T(); net effect
183  * XXX is the same.
184  */
185 static void
semid_ds_32tokernel(struct user32_semid_ds * in,struct user_semid_ds * out)186 semid_ds_32tokernel(struct user32_semid_ds *in, struct user_semid_ds *out)
187 {
188 	out->sem_ctime = in->sem_ctime;
189 	out->sem_otime = in->sem_otime;
190 	out->sem_nsems = in->sem_nsems;
191 	out->sem_base = (void *)(uintptr_t)in->sem_base;
192 	out->sem_perm = in->sem_perm;
193 }
194 
195 static void
semid_ds_64tokernel(struct user64_semid_ds * in,struct user_semid_ds * out)196 semid_ds_64tokernel(struct user64_semid_ds *in, struct user_semid_ds *out)
197 {
198 	out->sem_ctime = in->sem_ctime;
199 	out->sem_otime = in->sem_otime;
200 	out->sem_nsems = in->sem_nsems;
201 	out->sem_base = (void *)(uintptr_t)in->sem_base;
202 	out->sem_perm = in->sem_perm;
203 }
204 
205 
206 /*
207  * semsys
208  *
209  * Entry point for all SEM calls: semctl, semget, semop
210  *
211  * Parameters:	p	Process requesting the call
212  *              uap	User argument descriptor (see below)
213  *              retval	Return value of the selected sem call
214  *
215  * Indirect parameters:	uap->which	sem call to invoke (index in array of sem calls)
216  *                      uap->a2		User argument descriptor
217  *
218  * Returns:	0	Success
219  *		!0	Not success
220  *
221  * Implicit returns: retval	Return value of the selected sem call
222  *
223  * DEPRECATED:  This interface should not be used to call the other SEM
224  *              functions (semctl, semget, semop). The correct usage is
225  *              to call the other SEM functions directly.
226  *
227  */
228 int
semsys(struct proc * p,struct semsys_args * uap,int32_t * retval)229 semsys(struct proc *p, struct semsys_args *uap, int32_t *retval)
230 {
231 	/* The individual calls handling the locking now */
232 
233 	if (uap->which >= sizeof(semcalls) / sizeof(semcalls[0])) {
234 		return EINVAL;
235 	}
236 	return (*semcalls[uap->which])(p, &uap->a2, retval);
237 }
238 
239 static inline struct semid_kernel *
sema_get_by_id(size_t i)240 sema_get_by_id(size_t i)
241 {
242 	return &semas[i / SEMMNI_INC][i % SEMMNI_INC];
243 }
244 
245 /*
246  * Expand the semu array to the given capacity.  If the expansion fails
247  * return 0, otherwise return 1.
248  *
249  * Assumes we already have the subsystem lock.
250  */
251 static int
grow_semu_array(int newSize)252 grow_semu_array(int newSize)
253 {
254 	int i;
255 	struct sem_undo *newSemu;
256 
257 	if (newSize <= seminfo.semmnu) {
258 		return 1;
259 	}
260 	if (newSize > limitseminfo.semmnu) { /* enforce hard limit */
261 #ifdef SEM_DEBUG
262 		printf("undo structure hard limit of %d reached, requested %d\n",
263 		    limitseminfo.semmnu, newSize);
264 #endif
265 		return 0;
266 	}
267 	newSize = (newSize / SEMMNU_INC + 1) * SEMMNU_INC;
268 	newSize = newSize > limitseminfo.semmnu ? limitseminfo.semmnu : newSize;
269 
270 #ifdef SEM_DEBUG
271 	printf("growing semu[] from %d to %d\n", seminfo.semmnu, newSize);
272 #endif
273 	newSemu = kalloc_type(struct sem_undo, newSize, Z_WAITOK | Z_ZERO);
274 	if (NULL == newSemu) {
275 #ifdef SEM_DEBUG
276 		printf("allocation failed.  no changes made.\n");
277 #endif
278 		return 0;
279 	}
280 
281 	/* copy the old data to the new array */
282 	for (i = 0; i < seminfo.semmnu; i++) {
283 		newSemu[i] = semu[i];
284 	}
285 	/*
286 	 * The new elements (from newSemu[i] to newSemu[newSize-1]) have their
287 	 * "un_proc" set to 0 (i.e. NULL) by the Z_ZERO flag above,
288 	 * so they're already marked as "not in use".
289 	 */
290 
291 	/* Clean up the old array */
292 	kfree_type(struct sem_undo, seminfo.semmnu, semu);
293 
294 	semu = newSemu;
295 	seminfo.semmnu = newSize;
296 #ifdef SEM_DEBUG
297 	printf("expansion successful\n");
298 #endif
299 	return 1;
300 }
301 
302 /*
303  * Expand the semas array.  If the expansion fails
304  * we return 0, otherwise we return 1.
305  *
306  * Assumes we already have the subsystem lock.
307  */
308 static int
grow_sema_array(void)309 grow_sema_array(void)
310 {
311 	struct semid_kernel *newSema, **newArr;
312 	int old_size = seminfo.semmni;
313 
314 	if (old_size >= limitseminfo.semmni) { /* enforce hard limit */
315 		return 0;
316 	}
317 
318 	newArr = krealloc(semas,
319 	    sizeof(struct semid_kernel *) * (old_size / SEMMNI_INC),
320 	    sizeof(struct semid_kernel *) * ((old_size / SEMMNI_INC) + 1),
321 	    Z_WAITOK | Z_ZERO);
322 	if (newArr == NULL) {
323 		return 0;
324 	}
325 
326 	newSema = zalloc_permanent(sizeof(struct semid_kernel) * SEMMNI_INC,
327 	    ZALIGN(struct semid_kernel));
328 
329 #if CONFIG_MACF
330 	for (int i = 0; i < SEMMNI_INC; i++) {
331 		mac_sysvsem_label_init(&newSema[i]);
332 	}
333 #endif
334 
335 	/*
336 	 * The new elements (from newSema[i] to newSema[newSize-1]) have their
337 	 * "sem_base" and "sem_perm.mode" set to 0 (i.e. NULL) by the Z_ZERO
338 	 * flag above, so they're already marked as "not in use".
339 	 */
340 
341 	semas = newArr;
342 	semas[old_size / SEMMNI_INC] = newSema;
343 	seminfo.semmni += SEMMNI_INC;
344 	return 1;
345 }
346 
347 /*
348  * Expand the sem_pool array to the given capacity.  If the expansion fails
349  * we return 0 (fail), otherwise we return 1 (success).
350  *
351  * Assumes we already hold the subsystem lock.
352  */
353 static int
grow_sem_pool(int new_pool_size)354 grow_sem_pool(int new_pool_size)
355 {
356 	struct sem *new_sem_pool = NULL;
357 
358 	if (new_pool_size < semtot) {
359 		return 0;
360 	}
361 	/* enforce hard limit */
362 	if (new_pool_size > limitseminfo.semmns) {
363 		return 0;
364 	}
365 
366 	new_pool_size = (new_pool_size / SEMMNS_INC + 1) * SEMMNS_INC;
367 	new_pool_size = new_pool_size > limitseminfo.semmns ? limitseminfo.semmns : new_pool_size;
368 
369 	new_sem_pool = krealloc_data(sem_pool,
370 	    sizeof(struct sem) * seminfo.semmns,
371 	    sizeof(struct sem) * new_pool_size,
372 	    Z_WAITOK | Z_ZERO);
373 
374 	if (NULL == new_sem_pool) {
375 		return 0;
376 	}
377 
378 	/* Update our id structures to point to the new semaphores */
379 	for (int i = 0; i < seminfo.semmni; i++) {
380 		struct semid_kernel *semakptr = sema_get_by_id(i);
381 
382 		if (semakptr->u.sem_perm.mode & SEM_ALLOC) { /* ID in use */
383 			semakptr->u.sem_base = new_sem_pool +
384 			    (semakptr->u.sem_base - sem_pool);
385 		}
386 	}
387 
388 	sem_pool = new_sem_pool;
389 	seminfo.semmns = new_pool_size;
390 	return 1;
391 }
392 
393 /*
394  * Allocate a new sem_undo structure for a process
395  * (returns ptr to structure or NULL if no more room)
396  *
397  * Assumes we already hold the subsystem lock.
398  */
399 
400 static int
semu_alloc(struct proc * p)401 semu_alloc(struct proc *p)
402 {
403 	int i;
404 	struct sem_undo *suptr;
405 	int *supidx;
406 	int attempt;
407 
408 	/*
409 	 * Try twice to allocate something.
410 	 * (we'll purge any empty structures after the first pass so
411 	 * two passes are always enough)
412 	 */
413 
414 	for (attempt = 0; attempt < 2; attempt++) {
415 		/*
416 		 * Look for a free structure.
417 		 * Fill it in and return it if we find one.
418 		 */
419 
420 		for (i = 0; i < seminfo.semmnu; i++) {
421 			suptr = SEMU(i);
422 			if (suptr->un_proc == NULL) {
423 				suptr->un_next_idx = semu_list_idx;
424 				semu_list_idx = i;
425 				suptr->un_cnt = 0;
426 				suptr->un_ent = NULL;
427 				suptr->un_proc = p;
428 				return i;
429 			}
430 		}
431 
432 		/*
433 		 * We didn't find a free one, if this is the first attempt
434 		 * then try to free some structures.
435 		 */
436 
437 		if (attempt == 0) {
438 			/* All the structures are in use - try to free some */
439 			int did_something = 0;
440 
441 			supidx = &semu_list_idx;
442 			while (*supidx != -1) {
443 				suptr = SEMU(*supidx);
444 				if (suptr->un_cnt == 0) {
445 					suptr->un_proc = NULL;
446 					*supidx = suptr->un_next_idx;
447 					did_something = 1;
448 				} else {
449 					supidx = &(suptr->un_next_idx);
450 				}
451 			}
452 
453 			/* If we didn't free anything. Try expanding
454 			 * the semu[] array.  If that doesn't work
455 			 * then fail.  We expand last to get the
456 			 * most reuse out of existing resources.
457 			 */
458 			if (!did_something) {
459 				if (!grow_semu_array(seminfo.semmnu + 1)) {
460 					return -1;
461 				}
462 			}
463 		} else {
464 			/*
465 			 * The second pass failed even though we freed
466 			 * something after the first pass!
467 			 * This is IMPOSSIBLE!
468 			 */
469 			panic("semu_alloc - second attempt failed");
470 		}
471 	}
472 	return -1;
473 }
474 
475 /*
476  * Adjust a particular entry for a particular proc
477  *
478  * Assumes we already hold the subsystem lock.
479  */
480 static int
semundo_adjust(struct proc * p,int * supidx,int semid,int semnum,int adjval)481 semundo_adjust(struct proc *p, int *supidx, int semid,
482     int semnum, int adjval)
483 {
484 	struct sem_undo *suptr;
485 	int suidx;
486 	struct undo *sueptr, **suepptr, *new_sueptr;
487 	int i;
488 
489 	/*
490 	 * Look for and remember the sem_undo if the caller doesn't provide it
491 	 */
492 
493 	suidx = *supidx;
494 	if (suidx == -1) {
495 		for (suidx = semu_list_idx; suidx != -1;
496 		    suidx = suptr->un_next_idx) {
497 			suptr = SEMU(suidx);
498 			if (suptr->un_proc == p) {
499 				*supidx = suidx;
500 				break;
501 			}
502 		}
503 		if (suidx == -1) {
504 			if (adjval == 0) {
505 				return 0;
506 			}
507 			suidx = semu_alloc(p);
508 			if (suidx == -1) {
509 				return ENOSPC;
510 			}
511 			*supidx = suidx;
512 		}
513 	}
514 
515 	/*
516 	 * Look for the requested entry and adjust it (delete if adjval becomes
517 	 * 0).
518 	 */
519 	suptr = SEMU(suidx);
520 	new_sueptr = NULL;
521 	for (i = 0, suepptr = &suptr->un_ent, sueptr = suptr->un_ent;
522 	    i < suptr->un_cnt;
523 	    i++, suepptr = &sueptr->une_next, sueptr = sueptr->une_next) {
524 		if (sueptr->une_id != semid || sueptr->une_num != semnum) {
525 			continue;
526 		}
527 		if (adjval == 0) {
528 			sueptr->une_adjval = 0;
529 		} else {
530 			sueptr->une_adjval += adjval;
531 		}
532 		if (sueptr->une_adjval == 0) {
533 			suptr->un_cnt--;
534 			*suepptr = sueptr->une_next;
535 			kfree_type(struct undo, sueptr);
536 		}
537 		return 0;
538 	}
539 
540 	/* Didn't find the right entry - create it */
541 	if (adjval == 0) {
542 		/* no adjustment: no need for a new entry */
543 		return 0;
544 	}
545 
546 	if (suptr->un_cnt == limitseminfo.semume) {
547 		/* reached the limit number of semaphore undo entries */
548 		return EINVAL;
549 	}
550 
551 	/* allocate a new semaphore undo entry */
552 	new_sueptr = kalloc_type(struct undo, Z_WAITOK | Z_NOFAIL);
553 
554 	/* fill in the new semaphore undo entry */
555 	new_sueptr->une_next = suptr->un_ent;
556 	suptr->un_ent = new_sueptr;
557 	suptr->un_cnt++;
558 	new_sueptr->une_adjval = adjval;
559 	new_sueptr->une_id = semid;
560 	new_sueptr->une_num = semnum;
561 
562 	return 0;
563 }
564 
565 /* Assumes we already hold the subsystem lock.
566  */
567 static void
semundo_clear(int semid,int semnum)568 semundo_clear(int semid, int semnum)
569 {
570 	struct sem_undo *suptr;
571 	int suidx;
572 
573 	for (suidx = semu_list_idx; suidx != -1; suidx = suptr->un_next_idx) {
574 		struct undo *sueptr;
575 		struct undo **suepptr;
576 		int i = 0;
577 
578 		suptr = SEMU(suidx);
579 		sueptr = suptr->un_ent;
580 		suepptr = &suptr->un_ent;
581 		while (i < suptr->un_cnt) {
582 			if (sueptr->une_id == semid) {
583 				if (semnum == -1 || sueptr->une_num == semnum) {
584 					suptr->un_cnt--;
585 					*suepptr = sueptr->une_next;
586 					kfree_type(struct undo, sueptr);
587 					sueptr = *suepptr;
588 					continue;
589 				}
590 				if (semnum != -1) {
591 					break;
592 				}
593 			}
594 			i++;
595 			suepptr = &sueptr->une_next;
596 			sueptr = sueptr->une_next;
597 		}
598 	}
599 }
600 
601 /*
602  * Note that the user-mode half of this passes a union coerced to a
603  * user_addr_t.  The union contains either an int or a pointer, and
604  * so we have to coerce it back, variant on whether the calling
605  * process is 64 bit or not.  The coercion works for the 'val' element
606  * because the alignment is the same in user and kernel space.
607  */
608 int
semctl(struct proc * p,struct semctl_args * uap,int32_t * retval)609 semctl(struct proc *p, struct semctl_args *uap, int32_t *retval)
610 {
611 	int semid = uap->semid;
612 	int semnum = uap->semnum;
613 	int cmd = uap->cmd;
614 	user_semun_t user_arg = (user_semun_t)uap->arg;
615 	kauth_cred_t cred = kauth_cred_get();
616 	int i, rval, eval;
617 	struct user_semid_ds sbuf;
618 	struct semid_kernel *semakptr;
619 
620 
621 	AUDIT_ARG(svipc_cmd, cmd);
622 	AUDIT_ARG(svipc_id, semid);
623 
624 	SYSV_SEM_SUBSYS_LOCK();
625 
626 #ifdef SEM_DEBUG
627 	printf("call to semctl(%d, %d, %d, 0x%qx)\n", semid, semnum, cmd, user_arg);
628 #endif
629 
630 	semid = IPCID_TO_IX(semid);
631 
632 	if (semid < 0 || semid >= seminfo.semmni) {
633 #ifdef SEM_DEBUG
634 		printf("Invalid semid\n");
635 #endif
636 		eval = EINVAL;
637 		goto semctlout;
638 	}
639 
640 	semakptr = sema_get_by_id(semid);
641 	if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
642 	    semakptr->u.sem_perm._seq != IPCID_TO_SEQ(uap->semid)) {
643 		eval = EINVAL;
644 		goto semctlout;
645 	}
646 #if CONFIG_MACF
647 	eval = mac_sysvsem_check_semctl(cred, semakptr, cmd);
648 	if (eval) {
649 		goto semctlout;
650 	}
651 #endif
652 
653 	eval = 0;
654 	rval = 0;
655 
656 	switch (cmd) {
657 	case IPC_RMID:
658 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_M))) {
659 			goto semctlout;
660 		}
661 
662 		semakptr->u.sem_perm.cuid = kauth_cred_getuid(cred);
663 		semakptr->u.sem_perm.uid = kauth_cred_getuid(cred);
664 		semtot -= semakptr->u.sem_nsems;
665 		for (i = semakptr->u.sem_base - sem_pool; i < semtot; i++) {
666 			sem_pool[i] = sem_pool[i + semakptr->u.sem_nsems];
667 		}
668 		for (i = 0; i < seminfo.semmni; i++) {
669 			struct semid_kernel *semakptr2 = sema_get_by_id(i);
670 
671 			if ((semakptr2->u.sem_perm.mode & SEM_ALLOC) &&
672 			    semakptr2->u.sem_base > semakptr->u.sem_base) {
673 				semakptr2->u.sem_base -= semakptr->u.sem_nsems;
674 			}
675 		}
676 		semakptr->u.sem_perm.mode = 0;
677 #if CONFIG_MACF
678 		mac_sysvsem_label_recycle(semakptr);
679 #endif
680 		semundo_clear(semid, -1);
681 		wakeup((caddr_t)semakptr);
682 		break;
683 
684 	case IPC_SET:
685 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_M))) {
686 			goto semctlout;
687 		}
688 
689 		if (IS_64BIT_PROCESS(p)) {
690 			struct user64_semid_ds ds64;
691 			eval = copyin(user_arg.buf, &ds64, sizeof(ds64));
692 			semid_ds_64tokernel(&ds64, &sbuf);
693 		} else {
694 			struct user32_semid_ds ds32;
695 			eval = copyin(user_arg.buf, &ds32, sizeof(ds32));
696 			semid_ds_32tokernel(&ds32, &sbuf);
697 		}
698 
699 		if (eval != 0) {
700 			goto semctlout;
701 		}
702 
703 		semakptr->u.sem_perm.uid = sbuf.sem_perm.uid;
704 		semakptr->u.sem_perm.gid = sbuf.sem_perm.gid;
705 		semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode &
706 		    ~0777) | (sbuf.sem_perm.mode & 0777);
707 		semakptr->u.sem_ctime = sysv_semtime();
708 		break;
709 
710 	case IPC_STAT:
711 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
712 			goto semctlout;
713 		}
714 
715 		if (IS_64BIT_PROCESS(p)) {
716 			struct user64_semid_ds semid_ds64;
717 			bzero(&semid_ds64, sizeof(semid_ds64));
718 			semid_ds_kernelto64(&semakptr->u, &semid_ds64);
719 			eval = copyout(&semid_ds64, user_arg.buf, sizeof(semid_ds64));
720 		} else {
721 			struct user32_semid_ds semid_ds32;
722 			bzero(&semid_ds32, sizeof(semid_ds32));
723 			semid_ds_kernelto32(&semakptr->u, &semid_ds32);
724 			eval = copyout(&semid_ds32, user_arg.buf, sizeof(semid_ds32));
725 		}
726 		break;
727 
728 	case GETNCNT:
729 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
730 			goto semctlout;
731 		}
732 		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
733 			eval = EINVAL;
734 			goto semctlout;
735 		}
736 		rval = semakptr->u.sem_base[semnum].semncnt;
737 		break;
738 
739 	case GETPID:
740 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
741 			goto semctlout;
742 		}
743 		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
744 			eval = EINVAL;
745 			goto semctlout;
746 		}
747 		rval = semakptr->u.sem_base[semnum].sempid;
748 		break;
749 
750 	case GETVAL:
751 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
752 			goto semctlout;
753 		}
754 		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
755 			eval = EINVAL;
756 			goto semctlout;
757 		}
758 		rval = semakptr->u.sem_base[semnum].semval;
759 		break;
760 
761 	case GETALL:
762 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
763 			goto semctlout;
764 		}
765 /* XXXXXXXXXXXXXXXX TBD XXXXXXXXXXXXXXXX */
766 		for (i = 0; i < semakptr->u.sem_nsems; i++) {
767 			/* XXX could be done in one go... */
768 			eval = copyout((caddr_t)&semakptr->u.sem_base[i].semval,
769 			    user_arg.array + (i * sizeof(unsigned short)),
770 			    sizeof(unsigned short));
771 			if (eval != 0) {
772 				break;
773 			}
774 		}
775 		break;
776 
777 	case GETZCNT:
778 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R))) {
779 			goto semctlout;
780 		}
781 		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
782 			eval = EINVAL;
783 			goto semctlout;
784 		}
785 		rval = semakptr->u.sem_base[semnum].semzcnt;
786 		break;
787 
788 	case SETVAL:
789 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_W))) {
790 #ifdef SEM_DEBUG
791 			printf("Invalid credentials for write\n");
792 #endif
793 			goto semctlout;
794 		}
795 		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
796 #ifdef SEM_DEBUG
797 			printf("Invalid number out of range for set\n");
798 #endif
799 			eval = EINVAL;
800 			goto semctlout;
801 		}
802 
803 		/*
804 		 * Cast down a pointer instead of using 'val' member directly
805 		 * to avoid introducing endieness and a pad field into the
806 		 * header file.  Ugly, but it works.
807 		 */
808 		u_int newsemval = CAST_DOWN_EXPLICIT(u_int, user_arg.buf);
809 
810 		/*
811 		 * The check is being performed as unsigned values to match
812 		 * eventual destination
813 		 */
814 		if (newsemval > (u_int)seminfo.semvmx) {
815 #ifdef SEM_DEBUG
816 			printf("Out of range sem value for set\n");
817 #endif
818 			eval = ERANGE;
819 			goto semctlout;
820 		}
821 		semakptr->u.sem_base[semnum].semval = newsemval;
822 		semakptr->u.sem_base[semnum].sempid = proc_getpid(p);
823 		/* XXX scottl Should there be a MAC call here? */
824 		semundo_clear(semid, semnum);
825 		wakeup((caddr_t)semakptr);
826 		break;
827 
828 	case SETALL:
829 		if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_W))) {
830 			goto semctlout;
831 		}
832 /*** XXXXXXXXXXXX TBD ********/
833 		for (i = 0; i < semakptr->u.sem_nsems; i++) {
834 			/* XXX could be done in one go... */
835 			eval = copyin(user_arg.array + (i * sizeof(unsigned short)),
836 			    (caddr_t)&semakptr->u.sem_base[i].semval,
837 			    sizeof(unsigned short));
838 			if (eval != 0) {
839 				break;
840 			}
841 			semakptr->u.sem_base[i].sempid = proc_getpid(p);
842 		}
843 		/* XXX scottl Should there be a MAC call here? */
844 		semundo_clear(semid, -1);
845 		wakeup((caddr_t)semakptr);
846 		break;
847 
848 	default:
849 		eval = EINVAL;
850 		goto semctlout;
851 	}
852 
853 	if (eval == 0) {
854 		*retval = rval;
855 	}
856 semctlout:
857 	SYSV_SEM_SUBSYS_UNLOCK();
858 	return eval;
859 }
860 
861 int
semget(__unused struct proc * p,struct semget_args * uap,int32_t * retval)862 semget(__unused struct proc *p, struct semget_args *uap, int32_t *retval)
863 {
864 	int semid, eval;
865 	int key = uap->key;
866 	int nsems = uap->nsems;
867 	int semflg = uap->semflg;
868 	kauth_cred_t cred = kauth_cred_get();
869 	struct semid_kernel *semakptr;
870 
871 #ifdef SEM_DEBUG
872 	if (key != IPC_PRIVATE) {
873 		printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
874 	} else {
875 		printf("semget(IPC_PRIVATE, %d, 0%o)\n", nsems, semflg);
876 	}
877 #endif
878 
879 
880 	SYSV_SEM_SUBSYS_LOCK();
881 
882 
883 	if (key != IPC_PRIVATE) {
884 		for (semid = 0; semid < seminfo.semmni; semid++) {
885 			semakptr = sema_get_by_id(semid);
886 			if ((semakptr->u.sem_perm.mode & SEM_ALLOC) &&
887 			    semakptr->u.sem_perm._key == key) {
888 				break;
889 			}
890 		}
891 		if (semid < seminfo.semmni) {
892 #ifdef SEM_DEBUG
893 			printf("found public key\n");
894 #endif
895 			if ((eval = ipcperm(cred, &semakptr->u.sem_perm,
896 			    semflg & 0700))) {
897 				goto semgetout;
898 			}
899 			if (nsems < 0 || semakptr->u.sem_nsems < nsems) {
900 #ifdef SEM_DEBUG
901 				printf("too small\n");
902 #endif
903 				eval = EINVAL;
904 				goto semgetout;
905 			}
906 			if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
907 #ifdef SEM_DEBUG
908 				printf("not exclusive\n");
909 #endif
910 				eval = EEXIST;
911 				goto semgetout;
912 			}
913 #if CONFIG_MACF
914 			eval = mac_sysvsem_check_semget(cred, semakptr);
915 			if (eval) {
916 				goto semgetout;
917 			}
918 #endif
919 			goto found;
920 		}
921 	}
922 
923 #ifdef SEM_DEBUG
924 	printf("need to allocate an id for the request\n");
925 #endif
926 	if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
927 		if (nsems <= 0 || nsems > limitseminfo.semmsl) {
928 #ifdef SEM_DEBUG
929 			printf("nsems out of range (0<%d<=%d)\n", nsems,
930 			    seminfo.semmsl);
931 #endif
932 			eval = EINVAL;
933 			goto semgetout;
934 		}
935 		if (nsems > seminfo.semmns - semtot) {
936 #ifdef SEM_DEBUG
937 			printf("not enough semaphores left (need %d, got %d)\n",
938 			    nsems, seminfo.semmns - semtot);
939 #endif
940 			if (!grow_sem_pool(semtot + nsems)) {
941 #ifdef SEM_DEBUG
942 				printf("failed to grow the sem array\n");
943 #endif
944 				eval = ENOSPC;
945 				goto semgetout;
946 			}
947 		}
948 		for (semid = 0; semid < seminfo.semmni; semid++) {
949 			if ((sema_get_by_id(semid)->u.sem_perm.mode & SEM_ALLOC) == 0) {
950 				break;
951 			}
952 		}
953 		if (semid == seminfo.semmni && !grow_sema_array()) {
954 			eval = ENOSPC;
955 			goto semgetout;
956 		}
957 #ifdef SEM_DEBUG
958 		printf("semid %d is available\n", semid);
959 #endif
960 		semakptr = sema_get_by_id(semid);
961 		semakptr->u.sem_perm._key = key;
962 		semakptr->u.sem_perm.cuid = kauth_cred_getuid(cred);
963 		semakptr->u.sem_perm.uid = kauth_cred_getuid(cred);
964 		semakptr->u.sem_perm.cgid = kauth_cred_getgid(cred);
965 		semakptr->u.sem_perm.gid = kauth_cred_getgid(cred);
966 		semakptr->u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
967 		semakptr->u.sem_perm._seq =
968 		    (semakptr->u.sem_perm._seq + 1) & 0x7fff;
969 		semakptr->u.sem_nsems = nsems;
970 		semakptr->u.sem_otime = 0;
971 		semakptr->u.sem_ctime = sysv_semtime();
972 		semakptr->u.sem_base = &sem_pool[semtot];
973 		semtot += nsems;
974 		bzero(semakptr->u.sem_base,
975 		    sizeof(semakptr->u.sem_base[0]) * nsems);
976 #if CONFIG_MACF
977 		mac_sysvsem_label_associate(cred, semakptr);
978 #endif
979 #ifdef SEM_DEBUG
980 		printf("sembase = 0x%x, next = 0x%x\n", semakptr->u.sem_base,
981 		    &sem_pool[semtot]);
982 #endif
983 	} else {
984 #ifdef SEM_DEBUG
985 		printf("didn't find it and wasn't asked to create it\n");
986 #endif
987 		eval = ENOENT;
988 		goto semgetout;
989 	}
990 
991 found:
992 	*retval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm);
993 	AUDIT_ARG(svipc_id, *retval);
994 #ifdef SEM_DEBUG
995 	printf("semget is done, returning %d\n", *retval);
996 #endif
997 	eval = 0;
998 
999 semgetout:
1000 	SYSV_SEM_SUBSYS_UNLOCK();
1001 	return eval;
1002 }
1003 
1004 int
semop(struct proc * p,struct semop_args * uap,int32_t * retval)1005 semop(struct proc *p, struct semop_args *uap, int32_t *retval)
1006 {
1007 	int semid = uap->semid;
1008 	int nsops = uap->nsops;
1009 	struct sembuf sops[seminfo.semopm];
1010 	struct semid_kernel *semakptr;
1011 	struct sembuf *sopptr = NULL;   /* protected by 'semptr' */
1012 	struct sem *semptr = NULL;      /* protected by 'if' */
1013 	int supidx = -1;
1014 	int i, j, eval;
1015 	int do_wakeup, do_undos;
1016 
1017 	AUDIT_ARG(svipc_id, uap->semid);
1018 
1019 	SYSV_SEM_SUBSYS_LOCK();
1020 
1021 #ifdef SEM_DEBUG
1022 	printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops);
1023 #endif
1024 
1025 	semid = IPCID_TO_IX(semid);     /* Convert back to zero origin */
1026 
1027 	if (semid < 0 || semid >= seminfo.semmni) {
1028 		eval = EINVAL;
1029 		goto semopout;
1030 	}
1031 
1032 	semakptr = sema_get_by_id(semid);
1033 	if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
1034 		eval = EINVAL;
1035 		goto semopout;
1036 	}
1037 	if (semakptr->u.sem_perm._seq != IPCID_TO_SEQ(uap->semid)) {
1038 		eval = EINVAL;
1039 		goto semopout;
1040 	}
1041 
1042 	if ((eval = ipcperm(kauth_cred_get(), &semakptr->u.sem_perm, IPC_W))) {
1043 #ifdef SEM_DEBUG
1044 		printf("eval = %d from ipaccess\n", eval);
1045 #endif
1046 		goto semopout;
1047 	}
1048 
1049 	if (nsops < 0 || nsops > seminfo.semopm) {
1050 #ifdef SEM_DEBUG
1051 		printf("too many sops (max=%d, nsops=%d)\n",
1052 		    seminfo.semopm, nsops);
1053 #endif
1054 		eval = E2BIG;
1055 		goto semopout;
1056 	}
1057 
1058 	/*  OK for LP64, since sizeof(struct sembuf) is currently invariant */
1059 	if ((eval = copyin(uap->sops, &sops, nsops * sizeof(struct sembuf))) != 0) {
1060 #ifdef SEM_DEBUG
1061 		printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval,
1062 		    uap->sops, &sops, nsops * sizeof(struct sembuf));
1063 #endif
1064 		goto semopout;
1065 	}
1066 
1067 #if CONFIG_MACF
1068 	/*
1069 	 * Initial pass thru sops to see what permissions are needed.
1070 	 */
1071 	j = 0;          /* permission needed */
1072 	for (i = 0; i < nsops; i++) {
1073 		j |= (sops[i].sem_op == 0) ? SEM_R : SEM_A;
1074 	}
1075 
1076 	/*
1077 	 * The MAC hook checks whether the thread has read (and possibly
1078 	 * write) permissions to the semaphore array based on the
1079 	 * sopptr->sem_op value.
1080 	 */
1081 	eval = mac_sysvsem_check_semop(kauth_cred_get(), semakptr, j);
1082 	if (eval) {
1083 		goto semopout;
1084 	}
1085 #endif
1086 
1087 	/*
1088 	 * Loop trying to satisfy the vector of requests.
1089 	 * If we reach a point where we must wait, any requests already
1090 	 * performed are rolled back and we go to sleep until some other
1091 	 * process wakes us up.  At this point, we start all over again.
1092 	 *
1093 	 * This ensures that from the perspective of other tasks, a set
1094 	 * of requests is atomic (never partially satisfied).
1095 	 */
1096 	do_undos = 0;
1097 
1098 	for (;;) {
1099 		do_wakeup = 0;
1100 
1101 		for (i = 0; i < nsops; i++) {
1102 			sopptr = &sops[i];
1103 
1104 			if (sopptr->sem_num >= semakptr->u.sem_nsems) {
1105 				eval = EFBIG;
1106 				goto semopout;
1107 			}
1108 
1109 			semptr = &semakptr->u.sem_base[sopptr->sem_num];
1110 
1111 #ifdef SEM_DEBUG
1112 			printf("semop:  semakptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
1113 			    semakptr, semakptr->u.sem_base, semptr,
1114 			    sopptr->sem_num, semptr->semval, sopptr->sem_op,
1115 			    (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
1116 #endif
1117 
1118 			if (sopptr->sem_op < 0) {
1119 				if (semptr->semval + sopptr->sem_op < 0) {
1120 #ifdef SEM_DEBUG
1121 					printf("semop:  can't do it now\n");
1122 #endif
1123 					break;
1124 				} else {
1125 					semptr->semval += sopptr->sem_op;
1126 					if (semptr->semval == 0 &&
1127 					    semptr->semzcnt > 0) {
1128 						do_wakeup = 1;
1129 					}
1130 				}
1131 				if (sopptr->sem_flg & SEM_UNDO) {
1132 					do_undos = 1;
1133 				}
1134 			} else if (sopptr->sem_op == 0) {
1135 				if (semptr->semval > 0) {
1136 #ifdef SEM_DEBUG
1137 					printf("semop:  not zero now\n");
1138 #endif
1139 					break;
1140 				}
1141 			} else {
1142 				if (semptr->semncnt > 0) {
1143 					do_wakeup = 1;
1144 				}
1145 				semptr->semval += sopptr->sem_op;
1146 				if (sopptr->sem_flg & SEM_UNDO) {
1147 					do_undos = 1;
1148 				}
1149 			}
1150 		}
1151 
1152 		/*
1153 		 * Did we get through the entire vector?
1154 		 */
1155 		if (i >= nsops) {
1156 			goto done;
1157 		}
1158 
1159 		/*
1160 		 * No ... rollback anything that we've already done
1161 		 */
1162 #ifdef SEM_DEBUG
1163 		printf("semop:  rollback 0 through %d\n", i - 1);
1164 #endif
1165 		for (j = 0; j < i; j++) {
1166 			semakptr->u.sem_base[sops[j].sem_num].semval -=
1167 			    sops[j].sem_op;
1168 		}
1169 
1170 		/*
1171 		 * If the request that we couldn't satisfy has the
1172 		 * NOWAIT flag set then return with EAGAIN.
1173 		 */
1174 		if (sopptr->sem_flg & IPC_NOWAIT) {
1175 			eval = EAGAIN;
1176 			goto semopout;
1177 		}
1178 
1179 		if (sopptr->sem_op == 0) {
1180 			semptr->semzcnt++;
1181 		} else {
1182 			semptr->semncnt++;
1183 		}
1184 
1185 #ifdef SEM_DEBUG
1186 		printf("semop:  good night!\n");
1187 #endif
1188 		/* Release our lock on the semaphore subsystem so
1189 		 * another thread can get at the semaphore we are
1190 		 * waiting for. We will get the lock back after we
1191 		 * wake up.
1192 		 */
1193 		eval = msleep((caddr_t)semakptr, &sysv_sem_subsys_mutex, (PZERO - 4) | PCATCH,
1194 		    "semwait", 0);
1195 
1196 #ifdef SEM_DEBUG
1197 		printf("semop:  good morning (eval=%d)!\n", eval);
1198 #endif
1199 		if (eval != 0) {
1200 			eval = EINTR;
1201 		}
1202 
1203 		/*
1204 		 * IMPORTANT: while we were asleep, the semaphore array might
1205 		 * have been reallocated somewhere else (see grow_sema_array()).
1206 		 * When we wake up, we have to re-lookup the semaphore
1207 		 * structures and re-validate them.
1208 		 */
1209 
1210 		semptr = NULL;
1211 
1212 		/*
1213 		 * Make sure that the semaphore still exists
1214 		 *
1215 		 * XXX POSIX: Third test this 'if' and 'EINTR' precedence may
1216 		 * fail testing; if so, we will need to revert this code.
1217 		 */
1218 		if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
1219 		    semakptr->u.sem_perm._seq != IPCID_TO_SEQ(uap->semid) ||
1220 		    sopptr->sem_num >= semakptr->u.sem_nsems) {
1221 			/* The man page says to return EIDRM. */
1222 			/* Unfortunately, BSD doesn't define that code! */
1223 			if (eval == EINTR) {
1224 				/*
1225 				 * EINTR takes precedence over the fact that
1226 				 * the semaphore disappeared while we were
1227 				 * sleeping...
1228 				 */
1229 			} else {
1230 #ifdef EIDRM
1231 				eval = EIDRM;
1232 #else
1233 				eval = EINVAL;          /* Ancient past */
1234 #endif
1235 			}
1236 			goto semopout;
1237 		}
1238 
1239 		/*
1240 		 * The semaphore is still alive.  Readjust the count of
1241 		 * waiting processes. semptr needs to be recomputed
1242 		 * because the sem[] may have been reallocated while
1243 		 * we were sleeping, updating our sem_base pointer.
1244 		 */
1245 		semptr = &semakptr->u.sem_base[sopptr->sem_num];
1246 		if (sopptr->sem_op == 0) {
1247 			semptr->semzcnt--;
1248 		} else {
1249 			semptr->semncnt--;
1250 		}
1251 
1252 		if (eval != 0) { /* EINTR */
1253 			goto semopout;
1254 		}
1255 	}
1256 
1257 done:
1258 	/*
1259 	 * Process any SEM_UNDO requests.
1260 	 */
1261 	if (do_undos) {
1262 		for (i = 0; i < nsops; i++) {
1263 			/*
1264 			 * We only need to deal with SEM_UNDO's for non-zero
1265 			 * op's.
1266 			 */
1267 			int adjval;
1268 
1269 			if ((sops[i].sem_flg & SEM_UNDO) == 0) {
1270 				continue;
1271 			}
1272 			adjval = sops[i].sem_op;
1273 			if (adjval == 0) {
1274 				continue;
1275 			}
1276 			eval = semundo_adjust(p, &supidx, semid,
1277 			    sops[i].sem_num, -adjval);
1278 			if (eval == 0) {
1279 				continue;
1280 			}
1281 
1282 			/*
1283 			 * Oh-Oh!  We ran out of either sem_undo's or undo's.
1284 			 * Rollback the adjustments to this point and then
1285 			 * rollback the semaphore ups and down so we can return
1286 			 * with an error with all structures restored.  We
1287 			 * rollback the undo's in the exact reverse order that
1288 			 * we applied them.  This guarantees that we won't run
1289 			 * out of space as we roll things back out.
1290 			 */
1291 			for (j = i - 1; j >= 0; j--) {
1292 				if ((sops[j].sem_flg & SEM_UNDO) == 0) {
1293 					continue;
1294 				}
1295 				adjval = sops[j].sem_op;
1296 				if (adjval == 0) {
1297 					continue;
1298 				}
1299 				if (semundo_adjust(p, &supidx, semid,
1300 				    sops[j].sem_num, adjval) != 0) {
1301 					panic("semop - can't undo undos");
1302 				}
1303 			}
1304 
1305 			for (j = 0; j < nsops; j++) {
1306 				semakptr->u.sem_base[sops[j].sem_num].semval -=
1307 				    sops[j].sem_op;
1308 			}
1309 
1310 #ifdef SEM_DEBUG
1311 			printf("eval = %d from semundo_adjust\n", eval);
1312 #endif
1313 			goto semopout;
1314 		} /* loop through the sops */
1315 	} /* if (do_undos) */
1316 
1317 	/* We're definitely done - set the sempid's */
1318 	for (i = 0; i < nsops; i++) {
1319 		sopptr = &sops[i];
1320 		semptr = &semakptr->u.sem_base[sopptr->sem_num];
1321 		semptr->sempid = proc_getpid(p);
1322 	}
1323 	semakptr->u.sem_otime = sysv_semtime();
1324 
1325 	if (do_wakeup) {
1326 #ifdef SEM_DEBUG
1327 		printf("semop:  doing wakeup\n");
1328 #ifdef SEM_WAKEUP
1329 		sem_wakeup((caddr_t)semakptr);
1330 #else
1331 		wakeup((caddr_t)semakptr);
1332 #endif
1333 		printf("semop:  back from wakeup\n");
1334 #else
1335 		wakeup((caddr_t)semakptr);
1336 #endif
1337 	}
1338 #ifdef SEM_DEBUG
1339 	printf("semop:  done\n");
1340 #endif
1341 	*retval = 0;
1342 	eval = 0;
1343 semopout:
1344 	SYSV_SEM_SUBSYS_UNLOCK();
1345 	return eval;
1346 }
1347 
1348 /*
1349  * Go through the undo structures for this process and apply the adjustments to
1350  * semaphores.
1351  */
1352 void
semexit(struct proc * p)1353 semexit(struct proc *p)
1354 {
1355 	struct sem_undo *suptr = NULL;
1356 	int suidx;
1357 	int *supidx;
1358 	int did_something;
1359 
1360 	/* If we have not allocated our semaphores yet there can't be
1361 	 * anything to undo, but we need the lock to prevent
1362 	 * dynamic memory race conditions.
1363 	 */
1364 	SYSV_SEM_SUBSYS_LOCK();
1365 
1366 	if (!sem_pool) {
1367 		SYSV_SEM_SUBSYS_UNLOCK();
1368 		return;
1369 	}
1370 	did_something = 0;
1371 
1372 	/*
1373 	 * Go through the chain of undo vectors looking for one
1374 	 * associated with this process.
1375 	 */
1376 
1377 	for (supidx = &semu_list_idx; (suidx = *supidx) != -1;
1378 	    supidx = &suptr->un_next_idx) {
1379 		suptr = SEMU(suidx);
1380 		if (suptr->un_proc == p) {
1381 			break;
1382 		}
1383 	}
1384 
1385 	if (suidx == -1) {
1386 		goto unlock;
1387 	}
1388 
1389 #ifdef SEM_DEBUG
1390 	printf("proc @%08x has undo structure with %d entries\n", p,
1391 	    suptr->un_cnt);
1392 #endif
1393 
1394 	/*
1395 	 * If there are any active undo elements then process them.
1396 	 */
1397 	if (suptr->un_cnt > 0) {
1398 		while (suptr->un_ent != NULL) {
1399 			struct undo *sueptr;
1400 			int semid;
1401 			int semnum;
1402 			int adjval;
1403 			struct semid_kernel *semakptr;
1404 
1405 			sueptr = suptr->un_ent;
1406 			semid = sueptr->une_id;
1407 			semnum = sueptr->une_num;
1408 			adjval = sueptr->une_adjval;
1409 
1410 			semakptr = sema_get_by_id(semid);
1411 			if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
1412 				panic("semexit - semid not allocated");
1413 			}
1414 			if (semnum >= semakptr->u.sem_nsems) {
1415 				panic("semexit - semnum out of range");
1416 			}
1417 
1418 #ifdef SEM_DEBUG
1419 			printf("semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
1420 			    suptr->un_proc,
1421 			    semid,
1422 			    semnum,
1423 			    adjval,
1424 			    semakptr->u.sem_base[semnum].semval);
1425 #endif
1426 
1427 			if (adjval < 0) {
1428 				if (semakptr->u.sem_base[semnum].semval < -adjval) {
1429 					semakptr->u.sem_base[semnum].semval = 0;
1430 				} else {
1431 					semakptr->u.sem_base[semnum].semval +=
1432 					    adjval;
1433 				}
1434 			} else {
1435 				semakptr->u.sem_base[semnum].semval += adjval;
1436 			}
1437 
1438 			/* Maybe we should build a list of semakptr's to wake
1439 			 * up, finish all access to data structures, release the
1440 			 * subsystem lock, and wake all the processes.  Something
1441 			 * to think about.
1442 			 */
1443 #ifdef SEM_WAKEUP
1444 			sem_wakeup((caddr_t)semakptr);
1445 #else
1446 			wakeup((caddr_t)semakptr);
1447 #endif
1448 #ifdef SEM_DEBUG
1449 			printf("semexit:  back from wakeup\n");
1450 #endif
1451 			suptr->un_cnt--;
1452 			suptr->un_ent = sueptr->une_next;
1453 			kfree_type(struct undo, sueptr);
1454 		}
1455 	}
1456 
1457 	/*
1458 	 * Deallocate the undo vector.
1459 	 */
1460 #ifdef SEM_DEBUG
1461 	printf("removing vector\n");
1462 #endif
1463 	suptr->un_proc = NULL;
1464 	*supidx = suptr->un_next_idx;
1465 
1466 unlock:
1467 	/*
1468 	 * There is a semaphore leak (i.e. memory leak) in this code.
1469 	 * We should be deleting the IPC_PRIVATE semaphores when they are
1470 	 * no longer needed, and we dont. We would have to track which processes
1471 	 * know about which IPC_PRIVATE semaphores, updating the list after
1472 	 * every fork.  We can't just delete them semaphore when the process
1473 	 * that created it dies, because that process may well have forked
1474 	 * some children.  So we need to wait until all of it's children have
1475 	 * died, and so on.  Maybe we should tag each IPC_PRIVATE sempahore
1476 	 * with the creating group ID, count the number of processes left in
1477 	 * that group, and delete the semaphore when the group is gone.
1478 	 * Until that code gets implemented we will leak IPC_PRIVATE semaphores.
1479 	 * There is an upper bound on the size of our semaphore array, so
1480 	 * leaking the semaphores should not work as a DOS attack.
1481 	 *
1482 	 * Please note that the original BSD code this file is based on had the
1483 	 * same leaky semaphore problem.
1484 	 */
1485 
1486 	SYSV_SEM_SUBSYS_UNLOCK();
1487 }
1488 
1489 
1490 /* (struct sysctl_oid *oidp, void *arg1, int arg2, \
1491  *       struct sysctl_req *req) */
1492 static int
sysctl_seminfo(__unused struct sysctl_oid * oidp,void * arg1,__unused int arg2,struct sysctl_req * req)1493 sysctl_seminfo(__unused struct sysctl_oid *oidp, void *arg1,
1494     __unused int arg2, struct sysctl_req *req)
1495 {
1496 	int error = 0;
1497 
1498 	error = SYSCTL_OUT(req, arg1, sizeof(int));
1499 	if (error || req->newptr == USER_ADDR_NULL) {
1500 		return error;
1501 	}
1502 
1503 	SYSV_SEM_SUBSYS_LOCK();
1504 
1505 	/* Set the values only if shared memory is not initialised */
1506 	if ((sem_pool == NULL) &&
1507 	    (semas == NULL) &&
1508 	    (semu == NULL) &&
1509 	    (semu_list_idx == -1)) {
1510 		if ((error = SYSCTL_IN(req, arg1, sizeof(int)))) {
1511 			goto out;
1512 		}
1513 	} else {
1514 		error = EINVAL;
1515 	}
1516 out:
1517 	SYSV_SEM_SUBSYS_UNLOCK();
1518 	return error;
1519 }
1520 
1521 /* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */
1522 extern struct sysctl_oid_list sysctl__kern_sysv_children;
1523 SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1524     &limitseminfo.semmni, 0, &sysctl_seminfo, "I", "semmni");
1525 
1526 SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1527     &limitseminfo.semmns, 0, &sysctl_seminfo, "I", "semmns");
1528 
1529 SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1530     &limitseminfo.semmnu, 0, &sysctl_seminfo, "I", "semmnu");
1531 
1532 SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1533     &limitseminfo.semmsl, 0, &sysctl_seminfo, "I", "semmsl");
1534 
1535 SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
1536     &limitseminfo.semume, 0, &sysctl_seminfo, "I", "semume");
1537 
1538 
1539 static int
IPCS_sem_sysctl(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1540 IPCS_sem_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1,
1541     __unused int arg2, struct sysctl_req *req)
1542 {
1543 	int error;
1544 	int cursor;
1545 	union {
1546 		struct user32_IPCS_command u32;
1547 		struct user_IPCS_command u64;
1548 	} ipcs = { };
1549 	struct user32_semid_ds semid_ds32 = { }; /* post conversion, 32 bit version */
1550 	struct user64_semid_ds semid_ds64 = { }; /* post conversion, 64 bit version */
1551 	void *semid_dsp;
1552 	size_t ipcs_sz;
1553 	size_t semid_ds_sz;
1554 	struct proc *p = current_proc();
1555 
1556 	if (IS_64BIT_PROCESS(p)) {
1557 		ipcs_sz = sizeof(struct user_IPCS_command);
1558 		semid_ds_sz = sizeof(struct user64_semid_ds);
1559 	} else {
1560 		ipcs_sz = sizeof(struct user32_IPCS_command);
1561 		semid_ds_sz = sizeof(struct user32_semid_ds);
1562 	}
1563 
1564 	/* Copy in the command structure */
1565 	if ((error = SYSCTL_IN(req, &ipcs, ipcs_sz)) != 0) {
1566 		return error;
1567 	}
1568 
1569 	if (!IS_64BIT_PROCESS(p)) { /* convert in place */
1570 		ipcs.u64.ipcs_data = CAST_USER_ADDR_T(ipcs.u32.ipcs_data);
1571 	}
1572 
1573 	/* Let us version this interface... */
1574 	if (ipcs.u64.ipcs_magic != IPCS_MAGIC) {
1575 		return EINVAL;
1576 	}
1577 
1578 	SYSV_SEM_SUBSYS_LOCK();
1579 	switch (ipcs.u64.ipcs_op) {
1580 	case IPCS_SEM_CONF:     /* Obtain global configuration data */
1581 		if (ipcs.u64.ipcs_datalen != sizeof(struct seminfo)) {
1582 			error = ERANGE;
1583 			break;
1584 		}
1585 		if (ipcs.u64.ipcs_cursor != 0) {        /* fwd. compat. */
1586 			error = EINVAL;
1587 			break;
1588 		}
1589 		error = copyout(&seminfo, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
1590 		break;
1591 
1592 	case IPCS_SEM_ITER:     /* Iterate over existing segments */
1593 		cursor = ipcs.u64.ipcs_cursor;
1594 		if (cursor < 0 || cursor >= seminfo.semmni) {
1595 			error = ERANGE;
1596 			break;
1597 		}
1598 		if (ipcs.u64.ipcs_datalen != (int)semid_ds_sz) {
1599 			error = EINVAL;
1600 			break;
1601 		}
1602 		for (; cursor < seminfo.semmni; cursor++) {
1603 			if (sema_get_by_id(cursor)->u.sem_perm.mode & SEM_ALLOC) {
1604 				break;
1605 			}
1606 			continue;
1607 		}
1608 		if (cursor == seminfo.semmni) {
1609 			error = ENOENT;
1610 			break;
1611 		}
1612 
1613 		semid_dsp = &sema_get_by_id(cursor)->u;    /* default: 64 bit */
1614 
1615 		/*
1616 		 * If necessary, convert the 64 bit kernel segment
1617 		 * descriptor to a 32 bit user one.
1618 		 */
1619 		if (!IS_64BIT_PROCESS(p)) {
1620 			bzero(&semid_ds32, sizeof(semid_ds32));
1621 			semid_ds_kernelto32(semid_dsp, &semid_ds32);
1622 			semid_dsp = &semid_ds32;
1623 		} else {
1624 			bzero(&semid_ds64, sizeof(semid_ds64));
1625 			semid_ds_kernelto64(semid_dsp, &semid_ds64);
1626 			semid_dsp = &semid_ds64;
1627 		}
1628 
1629 		error = copyout(semid_dsp, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
1630 		if (!error) {
1631 			/* update cursor */
1632 			ipcs.u64.ipcs_cursor = cursor + 1;
1633 
1634 			if (!IS_64BIT_PROCESS(p)) {     /* convert in place */
1635 				ipcs.u32.ipcs_data = CAST_DOWN_EXPLICIT(user32_addr_t, ipcs.u64.ipcs_data);
1636 			}
1637 
1638 			error = SYSCTL_OUT(req, &ipcs, ipcs_sz);
1639 		}
1640 		break;
1641 
1642 	default:
1643 		error = EINVAL;
1644 		break;
1645 	}
1646 	SYSV_SEM_SUBSYS_UNLOCK();
1647 	return error;
1648 }
1649 
1650 SYSCTL_DECL(_kern_sysv_ipcs);
1651 SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, sem, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
1652     0, 0, IPCS_sem_sysctl,
1653     "S,IPCS_sem_command",
1654     "ipcs sem command interface");
1655 
1656 #endif /* SYSV_SEM */
1657