1 /*- 2 * Implementation of SVID semaphores 3 * 4 * Author: Daniel Boulet 5 * 6 * This software is provided ``AS IS'' without any warranties of any kind. 7 */ 8 /*- 9 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 10 * 11 * Copyright (c) 2003-2005 McAfee, Inc. 12 * Copyright (c) 2016-2017 Robert N. M. Watson 13 * All rights reserved. 14 * 15 * This software was developed for the FreeBSD Project in part by McAfee 16 * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR 17 * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research 18 * program. 19 * 20 * Portions of this software were developed by BAE Systems, the University of 21 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 22 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 23 * Computing (TC) research program. 24 * 25 * Redistribution and use in source and binary forms, with or without 26 * modification, are permitted provided that the following conditions 27 * are met: 28 * 1. Redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer. 30 * 2. Redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 */ 46 47 #include <sys/cdefs.h> 48 __FBSDID("$FreeBSD$"); 49 50 #include "opt_sysvipc.h" 51 52 #include <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/sysproto.h> 55 #include <sys/eventhandler.h> 56 #include <sys/kernel.h> 57 #include <sys/proc.h> 58 #include <sys/lock.h> 59 #include <sys/module.h> 60 #include <sys/mutex.h> 61 #include <sys/racct.h> 62 #include <sys/sem.h> 63 #include <sys/sx.h> 64 #include <sys/syscall.h> 65 #include <sys/syscallsubr.h> 66 #include <sys/sysent.h> 67 #include <sys/sysctl.h> 68 #include <sys/uio.h> 69 #include <sys/malloc.h> 70 #include <sys/jail.h> 71 72 #include <security/audit/audit.h> 73 #include <security/mac/mac_framework.h> 74 75 FEATURE(sysv_sem, "System V semaphores support"); 76 77 static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 78 79 #ifdef SEM_DEBUG 80 #define DPRINTF(a) printf a 81 #else 82 #define DPRINTF(a) 83 #endif 84 85 static int seminit(void); 86 static int sysvsem_modload(struct module *, int, void *); 87 static int semunload(void); 88 static void semexit_myhook(void *arg, struct proc *p); 89 static int sysctl_sema(SYSCTL_HANDLER_ARGS); 90 static int semvalid(int semid, struct prison *rpr, 91 struct semid_kernel *semakptr); 92 static void sem_remove(int semidx, struct ucred *cred); 93 static struct prison *sem_find_prison(struct ucred *); 94 static int sem_prison_cansee(struct prison *, struct semid_kernel *); 95 static int sem_prison_check(void *, void *); 96 static int sem_prison_set(void *, void *); 97 static int sem_prison_get(void *, void *); 98 static int sem_prison_remove(void *, void *); 99 static void sem_prison_cleanup(struct prison *); 100 101 #ifndef _SYS_SYSPROTO_H_ 102 struct __semctl_args; 103 int __semctl(struct thread *td, struct __semctl_args *uap); 104 struct semget_args; 105 int semget(struct thread *td, struct semget_args *uap); 106 struct semop_args; 107 int semop(struct thread *td, struct semop_args *uap); 108 #endif 109 110 static struct sem_undo *semu_alloc(struct thread *td); 111 static int semundo_adjust(struct thread *td, struct sem_undo **supptr, 112 int semid, int semseq, int semnum, int adjval); 113 static void semundo_clear(int semid, int semnum); 114 115 static struct mtx sem_mtx; /* semaphore global lock */ 116 static struct mtx sem_undo_mtx; 117 static int semtot = 0; 118 static struct semid_kernel *sema; /* semaphore id pool */ 119 static struct mtx *sema_mtx; /* semaphore id pool mutexes*/ 120 static struct sem *sem; /* semaphore pool */ 121 LIST_HEAD(, sem_undo) semu_list; /* list of active undo structures */ 122 LIST_HEAD(, sem_undo) semu_free_list; /* list of free undo structures */ 123 static int *semu; /* undo structure pool */ 124 static eventhandler_tag semexit_tag; 125 static unsigned sem_prison_slot; /* prison OSD slot */ 126 127 #define SEMUNDO_MTX sem_undo_mtx 128 #define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX); 129 #define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX); 130 #define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how)); 131 132 struct sem { 133 u_short semval; /* semaphore value */ 134 pid_t sempid; /* pid of last operation */ 135 u_short semncnt; /* # awaiting semval > cval */ 136 u_short semzcnt; /* # awaiting semval = 0 */ 137 }; 138 139 /* 140 * Undo structure (one per process) 141 */ 142 struct sem_undo { 143 LIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */ 144 struct proc *un_proc; /* owner of this structure */ 145 short un_cnt; /* # of active entries */ 146 struct undo { 147 short un_adjval; /* adjust on exit values */ 148 short un_num; /* semaphore # */ 149 int un_id; /* semid */ 150 unsigned short un_seq; 151 } un_ent[1]; /* undo entries */ 152 }; 153 154 /* 155 * Configuration parameters 156 */ 157 #ifndef SEMMNI 158 #define SEMMNI 50 /* # of semaphore identifiers */ 159 #endif 160 #ifndef SEMMNS 161 #define SEMMNS 340 /* # of semaphores in system */ 162 #endif 163 #ifndef SEMUME 164 #define SEMUME 50 /* max # of undo entries per process */ 165 #endif 166 #ifndef SEMMNU 167 #define SEMMNU 150 /* # of undo structures in system */ 168 #endif 169 170 /* shouldn't need tuning */ 171 #ifndef SEMMSL 172 #define SEMMSL SEMMNS /* max # of semaphores per id */ 173 #endif 174 #ifndef SEMOPM 175 #define SEMOPM 100 /* max # of operations per semop call */ 176 #endif 177 178 #define SEMVMX 32767 /* semaphore maximum value */ 179 #define SEMAEM 16384 /* adjust on exit max value */ 180 181 /* 182 * Due to the way semaphore memory is allocated, we have to ensure that 183 * SEMUSZ is properly aligned. 184 */ 185 186 #define SEM_ALIGN(bytes) roundup2(bytes, sizeof(long)) 187 188 /* actual size of an undo structure */ 189 #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 190 191 /* 192 * Macro to find a particular sem_undo vector 193 */ 194 #define SEMU(ix) \ 195 ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 196 197 /* 198 * semaphore info struct 199 */ 200 struct seminfo seminfo = { 201 SEMMNI, /* # of semaphore identifiers */ 202 SEMMNS, /* # of semaphores in system */ 203 SEMMNU, /* # of undo structures in system */ 204 SEMMSL, /* max # of semaphores per id */ 205 SEMOPM, /* max # of operations per semop call */ 206 SEMUME, /* max # of undo entries per process */ 207 SEMUSZ, /* size in bytes of undo structure */ 208 SEMVMX, /* semaphore maximum value */ 209 SEMAEM /* adjust on exit max value */ 210 }; 211 212 SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, 213 "Number of semaphore identifiers"); 214 SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, 215 "Maximum number of semaphores in the system"); 216 SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, 217 "Maximum number of undo structures in the system"); 218 SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RWTUN, &seminfo.semmsl, 0, 219 "Max semaphores per id"); 220 SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, 221 "Max operations per semop call"); 222 SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, 223 "Max undo entries per process"); 224 SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0, 225 "Size in bytes of undo structure"); 226 SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RWTUN, &seminfo.semvmx, 0, 227 "Semaphore maximum value"); 228 SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RWTUN, &seminfo.semaem, 0, 229 "Adjust on exit max value"); 230 SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, 231 CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 232 NULL, 0, sysctl_sema, "", 233 "Array of struct semid_kernel for each potential semaphore"); 234 235 static struct syscall_helper_data sem_syscalls[] = { 236 SYSCALL_INIT_HELPER(__semctl), 237 SYSCALL_INIT_HELPER(semget), 238 SYSCALL_INIT_HELPER(semop), 239 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 240 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 241 SYSCALL_INIT_HELPER(semsys), 242 SYSCALL_INIT_HELPER_COMPAT(freebsd7___semctl), 243 #endif 244 SYSCALL_INIT_LAST 245 }; 246 247 #ifdef COMPAT_FREEBSD32 248 #include <compat/freebsd32/freebsd32.h> 249 #include <compat/freebsd32/freebsd32_ipc.h> 250 #include <compat/freebsd32/freebsd32_proto.h> 251 #include <compat/freebsd32/freebsd32_signal.h> 252 #include <compat/freebsd32/freebsd32_syscall.h> 253 #include <compat/freebsd32/freebsd32_util.h> 254 255 static struct syscall_helper_data sem32_syscalls[] = { 256 SYSCALL32_INIT_HELPER(freebsd32_semctl), 257 SYSCALL32_INIT_HELPER_COMPAT(semget), 258 SYSCALL32_INIT_HELPER_COMPAT(semop), 259 SYSCALL32_INIT_HELPER(freebsd32_semsys), 260 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 261 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 262 SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl), 263 #endif 264 SYSCALL_INIT_LAST 265 }; 266 #endif 267 268 static int 269 seminit(void) 270 { 271 struct prison *pr; 272 void **rsv; 273 int i, error; 274 osd_method_t methods[PR_MAXMETHOD] = { 275 [PR_METHOD_CHECK] = sem_prison_check, 276 [PR_METHOD_SET] = sem_prison_set, 277 [PR_METHOD_GET] = sem_prison_get, 278 [PR_METHOD_REMOVE] = sem_prison_remove, 279 }; 280 281 sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 282 sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 283 M_WAITOK | M_ZERO); 284 sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 285 M_WAITOK | M_ZERO); 286 semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 287 288 for (i = 0; i < seminfo.semmni; i++) { 289 sema[i].u.__sem_base = 0; 290 sema[i].u.sem_perm.mode = 0; 291 sema[i].u.sem_perm.seq = 0; 292 #ifdef MAC 293 mac_sysvsem_init(&sema[i]); 294 #endif 295 } 296 for (i = 0; i < seminfo.semmni; i++) 297 mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 298 LIST_INIT(&semu_free_list); 299 for (i = 0; i < seminfo.semmnu; i++) { 300 struct sem_undo *suptr = SEMU(i); 301 suptr->un_proc = NULL; 302 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 303 } 304 LIST_INIT(&semu_list); 305 mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 306 mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); 307 semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 308 EVENTHANDLER_PRI_ANY); 309 310 /* Set current prisons according to their allow.sysvipc. */ 311 sem_prison_slot = osd_jail_register(NULL, methods); 312 rsv = osd_reserve(sem_prison_slot); 313 prison_lock(&prison0); 314 (void)osd_jail_set_reserved(&prison0, sem_prison_slot, rsv, &prison0); 315 prison_unlock(&prison0); 316 rsv = NULL; 317 sx_slock(&allprison_lock); 318 TAILQ_FOREACH(pr, &allprison, pr_list) { 319 if (rsv == NULL) 320 rsv = osd_reserve(sem_prison_slot); 321 prison_lock(pr); 322 if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { 323 (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 324 &prison0); 325 rsv = NULL; 326 } 327 prison_unlock(pr); 328 } 329 if (rsv != NULL) 330 osd_free_reserved(rsv); 331 sx_sunlock(&allprison_lock); 332 333 error = syscall_helper_register(sem_syscalls, SY_THR_STATIC_KLD); 334 if (error != 0) 335 return (error); 336 #ifdef COMPAT_FREEBSD32 337 error = syscall32_helper_register(sem32_syscalls, SY_THR_STATIC_KLD); 338 if (error != 0) 339 return (error); 340 #endif 341 return (0); 342 } 343 344 static int 345 semunload(void) 346 { 347 int i; 348 349 /* XXXKIB */ 350 if (semtot != 0) 351 return (EBUSY); 352 353 #ifdef COMPAT_FREEBSD32 354 syscall32_helper_unregister(sem32_syscalls); 355 #endif 356 syscall_helper_unregister(sem_syscalls); 357 EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 358 if (sem_prison_slot != 0) 359 osd_jail_deregister(sem_prison_slot); 360 #ifdef MAC 361 for (i = 0; i < seminfo.semmni; i++) 362 mac_sysvsem_destroy(&sema[i]); 363 #endif 364 free(sem, M_SEM); 365 free(sema, M_SEM); 366 free(semu, M_SEM); 367 for (i = 0; i < seminfo.semmni; i++) 368 mtx_destroy(&sema_mtx[i]); 369 free(sema_mtx, M_SEM); 370 mtx_destroy(&sem_mtx); 371 mtx_destroy(&sem_undo_mtx); 372 return (0); 373 } 374 375 static int 376 sysvsem_modload(struct module *module, int cmd, void *arg) 377 { 378 int error = 0; 379 380 switch (cmd) { 381 case MOD_LOAD: 382 error = seminit(); 383 if (error != 0) 384 semunload(); 385 break; 386 case MOD_UNLOAD: 387 error = semunload(); 388 break; 389 case MOD_SHUTDOWN: 390 break; 391 default: 392 error = EINVAL; 393 break; 394 } 395 return (error); 396 } 397 398 static moduledata_t sysvsem_mod = { 399 "sysvsem", 400 &sysvsem_modload, 401 NULL 402 }; 403 404 DECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 405 MODULE_VERSION(sysvsem, 1); 406 407 /* 408 * Allocate a new sem_undo structure for a process 409 * (returns ptr to structure or NULL if no more room) 410 */ 411 412 static struct sem_undo * 413 semu_alloc(struct thread *td) 414 { 415 struct sem_undo *suptr; 416 417 SEMUNDO_LOCKASSERT(MA_OWNED); 418 if ((suptr = LIST_FIRST(&semu_free_list)) == NULL) 419 return (NULL); 420 LIST_REMOVE(suptr, un_next); 421 LIST_INSERT_HEAD(&semu_list, suptr, un_next); 422 suptr->un_cnt = 0; 423 suptr->un_proc = td->td_proc; 424 return (suptr); 425 } 426 427 static int 428 semu_try_free(struct sem_undo *suptr) 429 { 430 431 SEMUNDO_LOCKASSERT(MA_OWNED); 432 433 if (suptr->un_cnt != 0) 434 return (0); 435 LIST_REMOVE(suptr, un_next); 436 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 437 return (1); 438 } 439 440 /* 441 * Adjust a particular entry for a particular proc 442 */ 443 444 static int 445 semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, 446 int semseq, int semnum, int adjval) 447 { 448 struct proc *p = td->td_proc; 449 struct sem_undo *suptr; 450 struct undo *sunptr; 451 int i; 452 453 SEMUNDO_LOCKASSERT(MA_OWNED); 454 /* Look for and remember the sem_undo if the caller doesn't provide 455 it */ 456 457 suptr = *supptr; 458 if (suptr == NULL) { 459 LIST_FOREACH(suptr, &semu_list, un_next) { 460 if (suptr->un_proc == p) { 461 *supptr = suptr; 462 break; 463 } 464 } 465 if (suptr == NULL) { 466 if (adjval == 0) 467 return(0); 468 suptr = semu_alloc(td); 469 if (suptr == NULL) 470 return (ENOSPC); 471 *supptr = suptr; 472 } 473 } 474 475 /* 476 * Look for the requested entry and adjust it (delete if adjval becomes 477 * 0). 478 */ 479 sunptr = &suptr->un_ent[0]; 480 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 481 if (sunptr->un_id != semid || sunptr->un_num != semnum) 482 continue; 483 if (adjval != 0) { 484 adjval += sunptr->un_adjval; 485 if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 486 return (ERANGE); 487 } 488 sunptr->un_adjval = adjval; 489 if (sunptr->un_adjval == 0) { 490 suptr->un_cnt--; 491 if (i < suptr->un_cnt) 492 suptr->un_ent[i] = 493 suptr->un_ent[suptr->un_cnt]; 494 if (suptr->un_cnt == 0) 495 semu_try_free(suptr); 496 } 497 return (0); 498 } 499 500 /* Didn't find the right entry - create it */ 501 if (adjval == 0) 502 return (0); 503 if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 504 return (ERANGE); 505 if (suptr->un_cnt != seminfo.semume) { 506 sunptr = &suptr->un_ent[suptr->un_cnt]; 507 suptr->un_cnt++; 508 sunptr->un_adjval = adjval; 509 sunptr->un_id = semid; 510 sunptr->un_num = semnum; 511 sunptr->un_seq = semseq; 512 } else 513 return (EINVAL); 514 return (0); 515 } 516 517 static void 518 semundo_clear(int semid, int semnum) 519 { 520 struct sem_undo *suptr, *suptr1; 521 struct undo *sunptr; 522 int i; 523 524 SEMUNDO_LOCKASSERT(MA_OWNED); 525 LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { 526 sunptr = &suptr->un_ent[0]; 527 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 528 if (sunptr->un_id != semid) 529 continue; 530 if (semnum == -1 || sunptr->un_num == semnum) { 531 suptr->un_cnt--; 532 if (i < suptr->un_cnt) { 533 suptr->un_ent[i] = 534 suptr->un_ent[suptr->un_cnt]; 535 continue; 536 } 537 semu_try_free(suptr); 538 } 539 if (semnum != -1) 540 break; 541 } 542 } 543 } 544 545 static int 546 semvalid(int semid, struct prison *rpr, struct semid_kernel *semakptr) 547 { 548 549 return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 550 semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) || 551 sem_prison_cansee(rpr, semakptr) ? EINVAL : 0); 552 } 553 554 static void 555 sem_remove(int semidx, struct ucred *cred) 556 { 557 struct semid_kernel *semakptr; 558 int i; 559 560 KASSERT(semidx >= 0 && semidx < seminfo.semmni, 561 ("semidx out of bounds")); 562 semakptr = &sema[semidx]; 563 semakptr->u.sem_perm.cuid = cred ? cred->cr_uid : 0; 564 semakptr->u.sem_perm.uid = cred ? cred->cr_uid : 0; 565 semakptr->u.sem_perm.mode = 0; 566 racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); 567 crfree(semakptr->cred); 568 semakptr->cred = NULL; 569 SEMUNDO_LOCK(); 570 semundo_clear(semidx, -1); 571 SEMUNDO_UNLOCK(); 572 #ifdef MAC 573 mac_sysvsem_cleanup(semakptr); 574 #endif 575 wakeup(semakptr); 576 for (i = 0; i < seminfo.semmni; i++) { 577 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 578 sema[i].u.__sem_base > semakptr->u.__sem_base) 579 mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 580 } 581 for (i = semakptr->u.__sem_base - sem; i < semtot; i++) 582 sem[i] = sem[i + semakptr->u.sem_nsems]; 583 for (i = 0; i < seminfo.semmni; i++) { 584 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 585 sema[i].u.__sem_base > semakptr->u.__sem_base) { 586 sema[i].u.__sem_base -= semakptr->u.sem_nsems; 587 mtx_unlock(&sema_mtx[i]); 588 } 589 } 590 semtot -= semakptr->u.sem_nsems; 591 } 592 593 static struct prison * 594 sem_find_prison(struct ucred *cred) 595 { 596 struct prison *pr, *rpr; 597 598 pr = cred->cr_prison; 599 prison_lock(pr); 600 rpr = osd_jail_get(pr, sem_prison_slot); 601 prison_unlock(pr); 602 return rpr; 603 } 604 605 static int 606 sem_prison_cansee(struct prison *rpr, struct semid_kernel *semakptr) 607 { 608 609 if (semakptr->cred == NULL || 610 !(rpr == semakptr->cred->cr_prison || 611 prison_ischild(rpr, semakptr->cred->cr_prison))) 612 return (EINVAL); 613 return (0); 614 } 615 616 /* 617 * Note that the user-mode half of this passes a union, not a pointer. 618 */ 619 #ifndef _SYS_SYSPROTO_H_ 620 struct __semctl_args { 621 int semid; 622 int semnum; 623 int cmd; 624 union semun *arg; 625 }; 626 #endif 627 int 628 sys___semctl(struct thread *td, struct __semctl_args *uap) 629 { 630 struct semid_ds dsbuf; 631 union semun arg, semun; 632 register_t rval; 633 int error; 634 635 switch (uap->cmd) { 636 case SEM_STAT: 637 case IPC_SET: 638 case IPC_STAT: 639 case GETALL: 640 case SETVAL: 641 case SETALL: 642 error = copyin(uap->arg, &arg, sizeof(arg)); 643 if (error) 644 return (error); 645 break; 646 } 647 648 switch (uap->cmd) { 649 case SEM_STAT: 650 case IPC_STAT: 651 semun.buf = &dsbuf; 652 break; 653 case IPC_SET: 654 error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 655 if (error) 656 return (error); 657 semun.buf = &dsbuf; 658 break; 659 case GETALL: 660 case SETALL: 661 semun.array = arg.array; 662 break; 663 case SETVAL: 664 semun.val = arg.val; 665 break; 666 } 667 668 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 669 &rval); 670 if (error) 671 return (error); 672 673 switch (uap->cmd) { 674 case SEM_STAT: 675 case IPC_STAT: 676 error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 677 break; 678 } 679 680 if (error == 0) 681 td->td_retval[0] = rval; 682 return (error); 683 } 684 685 int 686 kern_semctl(struct thread *td, int semid, int semnum, int cmd, 687 union semun *arg, register_t *rval) 688 { 689 u_short *array; 690 struct ucred *cred = td->td_ucred; 691 int i, error; 692 struct prison *rpr; 693 struct semid_ds *sbuf; 694 struct semid_kernel *semakptr; 695 struct mtx *sema_mtxp; 696 u_short usval, count; 697 int semidx; 698 699 DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 700 semid, semnum, cmd, arg)); 701 702 AUDIT_ARG_SVIPC_CMD(cmd); 703 AUDIT_ARG_SVIPC_ID(semid); 704 705 rpr = sem_find_prison(td->td_ucred); 706 if (sem == NULL) 707 return (ENOSYS); 708 709 array = NULL; 710 711 switch(cmd) { 712 case SEM_STAT: 713 /* 714 * For this command we assume semid is an array index 715 * rather than an IPC id. 716 */ 717 if (semid < 0 || semid >= seminfo.semmni) 718 return (EINVAL); 719 semakptr = &sema[semid]; 720 sema_mtxp = &sema_mtx[semid]; 721 mtx_lock(sema_mtxp); 722 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 723 error = EINVAL; 724 goto done2; 725 } 726 if ((error = sem_prison_cansee(rpr, semakptr))) 727 goto done2; 728 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 729 goto done2; 730 #ifdef MAC 731 error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 732 if (error != 0) 733 goto done2; 734 #endif 735 bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 736 if (cred->cr_prison != semakptr->cred->cr_prison) 737 arg->buf->sem_perm.key = IPC_PRIVATE; 738 *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 739 mtx_unlock(sema_mtxp); 740 return (0); 741 } 742 743 semidx = IPCID_TO_IX(semid); 744 if (semidx < 0 || semidx >= seminfo.semmni) 745 return (EINVAL); 746 747 semakptr = &sema[semidx]; 748 sema_mtxp = &sema_mtx[semidx]; 749 if (cmd == IPC_RMID) 750 mtx_lock(&sem_mtx); 751 mtx_lock(sema_mtxp); 752 753 #ifdef MAC 754 error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 755 if (error != 0) 756 goto done2; 757 #endif 758 759 error = 0; 760 *rval = 0; 761 762 switch (cmd) { 763 case IPC_RMID: 764 if ((error = semvalid(semid, rpr, semakptr)) != 0) 765 goto done2; 766 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 767 goto done2; 768 sem_remove(semidx, cred); 769 break; 770 771 case IPC_SET: 772 AUDIT_ARG_SVIPC_PERM(&arg->buf->sem_perm); 773 if ((error = semvalid(semid, rpr, semakptr)) != 0) 774 goto done2; 775 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 776 goto done2; 777 sbuf = arg->buf; 778 semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 779 semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 780 semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 781 ~0777) | (sbuf->sem_perm.mode & 0777); 782 semakptr->u.sem_ctime = time_second; 783 break; 784 785 case IPC_STAT: 786 if ((error = semvalid(semid, rpr, semakptr)) != 0) 787 goto done2; 788 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 789 goto done2; 790 bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 791 if (cred->cr_prison != semakptr->cred->cr_prison) 792 arg->buf->sem_perm.key = IPC_PRIVATE; 793 break; 794 795 case GETNCNT: 796 if ((error = semvalid(semid, rpr, semakptr)) != 0) 797 goto done2; 798 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 799 goto done2; 800 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 801 error = EINVAL; 802 goto done2; 803 } 804 *rval = semakptr->u.__sem_base[semnum].semncnt; 805 break; 806 807 case GETPID: 808 if ((error = semvalid(semid, rpr, semakptr)) != 0) 809 goto done2; 810 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 811 goto done2; 812 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 813 error = EINVAL; 814 goto done2; 815 } 816 *rval = semakptr->u.__sem_base[semnum].sempid; 817 break; 818 819 case GETVAL: 820 if ((error = semvalid(semid, rpr, semakptr)) != 0) 821 goto done2; 822 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 823 goto done2; 824 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 825 error = EINVAL; 826 goto done2; 827 } 828 *rval = semakptr->u.__sem_base[semnum].semval; 829 break; 830 831 case GETALL: 832 /* 833 * Unfortunately, callers of this function don't know 834 * in advance how many semaphores are in this set. 835 * While we could just allocate the maximum size array 836 * and pass the actual size back to the caller, that 837 * won't work for SETALL since we can't copyin() more 838 * data than the user specified as we may return a 839 * spurious EFAULT. 840 * 841 * Note that the number of semaphores in a set is 842 * fixed for the life of that set. The only way that 843 * the 'count' could change while are blocked in 844 * malloc() is if this semaphore set were destroyed 845 * and a new one created with the same index. 846 * However, semvalid() will catch that due to the 847 * sequence number unless exactly 0x8000 (or a 848 * multiple thereof) semaphore sets for the same index 849 * are created and destroyed while we are in malloc! 850 * 851 */ 852 count = semakptr->u.sem_nsems; 853 mtx_unlock(sema_mtxp); 854 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 855 mtx_lock(sema_mtxp); 856 if ((error = semvalid(semid, rpr, semakptr)) != 0) 857 goto done2; 858 KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 859 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 860 goto done2; 861 for (i = 0; i < semakptr->u.sem_nsems; i++) 862 array[i] = semakptr->u.__sem_base[i].semval; 863 mtx_unlock(sema_mtxp); 864 error = copyout(array, arg->array, count * sizeof(*array)); 865 mtx_lock(sema_mtxp); 866 break; 867 868 case GETZCNT: 869 if ((error = semvalid(semid, rpr, semakptr)) != 0) 870 goto done2; 871 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 872 goto done2; 873 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 874 error = EINVAL; 875 goto done2; 876 } 877 *rval = semakptr->u.__sem_base[semnum].semzcnt; 878 break; 879 880 case SETVAL: 881 if ((error = semvalid(semid, rpr, semakptr)) != 0) 882 goto done2; 883 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 884 goto done2; 885 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 886 error = EINVAL; 887 goto done2; 888 } 889 if (arg->val < 0 || arg->val > seminfo.semvmx) { 890 error = ERANGE; 891 goto done2; 892 } 893 semakptr->u.__sem_base[semnum].semval = arg->val; 894 SEMUNDO_LOCK(); 895 semundo_clear(semidx, semnum); 896 SEMUNDO_UNLOCK(); 897 wakeup(semakptr); 898 break; 899 900 case SETALL: 901 /* 902 * See comment on GETALL for why 'count' shouldn't change 903 * and why we require a userland buffer. 904 */ 905 count = semakptr->u.sem_nsems; 906 mtx_unlock(sema_mtxp); 907 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 908 error = copyin(arg->array, array, count * sizeof(*array)); 909 mtx_lock(sema_mtxp); 910 if (error) 911 break; 912 if ((error = semvalid(semid, rpr, semakptr)) != 0) 913 goto done2; 914 KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 915 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 916 goto done2; 917 for (i = 0; i < semakptr->u.sem_nsems; i++) { 918 usval = array[i]; 919 if (usval > seminfo.semvmx) { 920 error = ERANGE; 921 break; 922 } 923 semakptr->u.__sem_base[i].semval = usval; 924 } 925 SEMUNDO_LOCK(); 926 semundo_clear(semidx, -1); 927 SEMUNDO_UNLOCK(); 928 wakeup(semakptr); 929 break; 930 931 default: 932 error = EINVAL; 933 break; 934 } 935 936 done2: 937 mtx_unlock(sema_mtxp); 938 if (cmd == IPC_RMID) 939 mtx_unlock(&sem_mtx); 940 if (array != NULL) 941 free(array, M_TEMP); 942 return(error); 943 } 944 945 #ifndef _SYS_SYSPROTO_H_ 946 struct semget_args { 947 key_t key; 948 int nsems; 949 int semflg; 950 }; 951 #endif 952 int 953 sys_semget(struct thread *td, struct semget_args *uap) 954 { 955 int semid, error = 0; 956 int key = uap->key; 957 int nsems = uap->nsems; 958 int semflg = uap->semflg; 959 struct ucred *cred = td->td_ucred; 960 961 DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 962 963 AUDIT_ARG_VALUE(semflg); 964 965 if (sem_find_prison(cred) == NULL) 966 return (ENOSYS); 967 968 mtx_lock(&sem_mtx); 969 if (key != IPC_PRIVATE) { 970 for (semid = 0; semid < seminfo.semmni; semid++) { 971 if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 972 sema[semid].cred != NULL && 973 sema[semid].cred->cr_prison == cred->cr_prison && 974 sema[semid].u.sem_perm.key == key) 975 break; 976 } 977 if (semid < seminfo.semmni) { 978 AUDIT_ARG_SVIPC_ID(semid); 979 DPRINTF(("found public key\n")); 980 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 981 DPRINTF(("not exclusive\n")); 982 error = EEXIST; 983 goto done2; 984 } 985 if ((error = ipcperm(td, &sema[semid].u.sem_perm, 986 semflg & 0700))) { 987 goto done2; 988 } 989 if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 990 DPRINTF(("too small\n")); 991 error = EINVAL; 992 goto done2; 993 } 994 #ifdef MAC 995 error = mac_sysvsem_check_semget(cred, &sema[semid]); 996 if (error != 0) 997 goto done2; 998 #endif 999 goto found; 1000 } 1001 } 1002 1003 DPRINTF(("need to allocate the semid_kernel\n")); 1004 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 1005 if (nsems <= 0 || nsems > seminfo.semmsl) { 1006 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 1007 seminfo.semmsl)); 1008 error = EINVAL; 1009 goto done2; 1010 } 1011 if (nsems > seminfo.semmns - semtot) { 1012 DPRINTF(( 1013 "not enough semaphores left (need %d, got %d)\n", 1014 nsems, seminfo.semmns - semtot)); 1015 error = ENOSPC; 1016 goto done2; 1017 } 1018 for (semid = 0; semid < seminfo.semmni; semid++) { 1019 if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 1020 break; 1021 } 1022 if (semid == seminfo.semmni) { 1023 DPRINTF(("no more semid_kernel's available\n")); 1024 error = ENOSPC; 1025 goto done2; 1026 } 1027 #ifdef RACCT 1028 if (racct_enable) { 1029 PROC_LOCK(td->td_proc); 1030 error = racct_add(td->td_proc, RACCT_NSEM, nsems); 1031 PROC_UNLOCK(td->td_proc); 1032 if (error != 0) { 1033 error = ENOSPC; 1034 goto done2; 1035 } 1036 } 1037 #endif 1038 DPRINTF(("semid %d is available\n", semid)); 1039 mtx_lock(&sema_mtx[semid]); 1040 KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 1041 ("Lost semaphore %d", semid)); 1042 sema[semid].u.sem_perm.key = key; 1043 sema[semid].u.sem_perm.cuid = cred->cr_uid; 1044 sema[semid].u.sem_perm.uid = cred->cr_uid; 1045 sema[semid].u.sem_perm.cgid = cred->cr_gid; 1046 sema[semid].u.sem_perm.gid = cred->cr_gid; 1047 sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 1048 sema[semid].cred = crhold(cred); 1049 sema[semid].u.sem_perm.seq = 1050 (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 1051 sema[semid].u.sem_nsems = nsems; 1052 sema[semid].u.sem_otime = 0; 1053 sema[semid].u.sem_ctime = time_second; 1054 sema[semid].u.__sem_base = &sem[semtot]; 1055 semtot += nsems; 1056 bzero(sema[semid].u.__sem_base, 1057 sizeof(sema[semid].u.__sem_base[0])*nsems); 1058 #ifdef MAC 1059 mac_sysvsem_create(cred, &sema[semid]); 1060 #endif 1061 mtx_unlock(&sema_mtx[semid]); 1062 DPRINTF(("sembase = %p, next = %p\n", 1063 sema[semid].u.__sem_base, &sem[semtot])); 1064 } else { 1065 DPRINTF(("didn't find it and wasn't asked to create it\n")); 1066 error = ENOENT; 1067 goto done2; 1068 } 1069 1070 found: 1071 td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 1072 done2: 1073 mtx_unlock(&sem_mtx); 1074 return (error); 1075 } 1076 1077 #ifndef _SYS_SYSPROTO_H_ 1078 struct semop_args { 1079 int semid; 1080 struct sembuf *sops; 1081 size_t nsops; 1082 }; 1083 #endif 1084 int 1085 sys_semop(struct thread *td, struct semop_args *uap) 1086 { 1087 #define SMALL_SOPS 8 1088 struct sembuf small_sops[SMALL_SOPS]; 1089 int semid = uap->semid; 1090 size_t nsops = uap->nsops; 1091 struct prison *rpr; 1092 struct sembuf *sops; 1093 struct semid_kernel *semakptr; 1094 struct sembuf *sopptr = NULL; 1095 struct sem *semptr = NULL; 1096 struct sem_undo *suptr; 1097 struct mtx *sema_mtxp; 1098 size_t i, j, k; 1099 int error; 1100 int do_wakeup, do_undos; 1101 unsigned short seq; 1102 1103 #ifdef SEM_DEBUG 1104 sops = NULL; 1105 #endif 1106 DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 1107 1108 AUDIT_ARG_SVIPC_ID(semid); 1109 1110 rpr = sem_find_prison(td->td_ucred); 1111 if (sem == NULL) 1112 return (ENOSYS); 1113 1114 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 1115 1116 if (semid < 0 || semid >= seminfo.semmni) 1117 return (EINVAL); 1118 1119 /* Allocate memory for sem_ops */ 1120 if (nsops <= SMALL_SOPS) 1121 sops = small_sops; 1122 else if (nsops > seminfo.semopm) { 1123 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1124 nsops)); 1125 return (E2BIG); 1126 } else { 1127 #ifdef RACCT 1128 if (racct_enable) { 1129 PROC_LOCK(td->td_proc); 1130 if (nsops > 1131 racct_get_available(td->td_proc, RACCT_NSEMOP)) { 1132 PROC_UNLOCK(td->td_proc); 1133 return (E2BIG); 1134 } 1135 PROC_UNLOCK(td->td_proc); 1136 } 1137 #endif 1138 1139 sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 1140 } 1141 if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1142 DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1143 uap->sops, sops, nsops * sizeof(sops[0]))); 1144 if (sops != small_sops) 1145 free(sops, M_SEM); 1146 return (error); 1147 } 1148 1149 semakptr = &sema[semid]; 1150 sema_mtxp = &sema_mtx[semid]; 1151 mtx_lock(sema_mtxp); 1152 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 1153 error = EINVAL; 1154 goto done2; 1155 } 1156 seq = semakptr->u.sem_perm.seq; 1157 if (seq != IPCID_TO_SEQ(uap->semid)) { 1158 error = EINVAL; 1159 goto done2; 1160 } 1161 if ((error = sem_prison_cansee(rpr, semakptr)) != 0) 1162 goto done2; 1163 /* 1164 * Initial pass through sops to see what permissions are needed. 1165 * Also perform any checks that don't need repeating on each 1166 * attempt to satisfy the request vector. 1167 */ 1168 j = 0; /* permission needed */ 1169 do_undos = 0; 1170 for (i = 0; i < nsops; i++) { 1171 sopptr = &sops[i]; 1172 if (sopptr->sem_num >= semakptr->u.sem_nsems) { 1173 error = EFBIG; 1174 goto done2; 1175 } 1176 if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 1177 do_undos = 1; 1178 j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 1179 } 1180 1181 if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1182 DPRINTF(("error = %d from ipaccess\n", error)); 1183 goto done2; 1184 } 1185 #ifdef MAC 1186 error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1187 if (error != 0) 1188 goto done2; 1189 #endif 1190 1191 /* 1192 * Loop trying to satisfy the vector of requests. 1193 * If we reach a point where we must wait, any requests already 1194 * performed are rolled back and we go to sleep until some other 1195 * process wakes us up. At this point, we start all over again. 1196 * 1197 * This ensures that from the perspective of other tasks, a set 1198 * of requests is atomic (never partially satisfied). 1199 */ 1200 for (;;) { 1201 do_wakeup = 0; 1202 error = 0; /* error return if necessary */ 1203 1204 for (i = 0; i < nsops; i++) { 1205 sopptr = &sops[i]; 1206 semptr = &semakptr->u.__sem_base[sopptr->sem_num]; 1207 1208 DPRINTF(( 1209 "semop: semakptr=%p, __sem_base=%p, " 1210 "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1211 semakptr, semakptr->u.__sem_base, semptr, 1212 sopptr->sem_num, semptr->semval, sopptr->sem_op, 1213 (sopptr->sem_flg & IPC_NOWAIT) ? 1214 "nowait" : "wait")); 1215 1216 if (sopptr->sem_op < 0) { 1217 if (semptr->semval + sopptr->sem_op < 0) { 1218 DPRINTF(("semop: can't do it now\n")); 1219 break; 1220 } else { 1221 semptr->semval += sopptr->sem_op; 1222 if (semptr->semval == 0 && 1223 semptr->semzcnt > 0) 1224 do_wakeup = 1; 1225 } 1226 } else if (sopptr->sem_op == 0) { 1227 if (semptr->semval != 0) { 1228 DPRINTF(("semop: not zero now\n")); 1229 break; 1230 } 1231 } else if (semptr->semval + sopptr->sem_op > 1232 seminfo.semvmx) { 1233 error = ERANGE; 1234 break; 1235 } else { 1236 if (semptr->semncnt > 0) 1237 do_wakeup = 1; 1238 semptr->semval += sopptr->sem_op; 1239 } 1240 } 1241 1242 /* 1243 * Did we get through the entire vector? 1244 */ 1245 if (i >= nsops) 1246 goto done; 1247 1248 /* 1249 * No ... rollback anything that we've already done 1250 */ 1251 DPRINTF(("semop: rollback 0 through %d\n", i-1)); 1252 for (j = 0; j < i; j++) 1253 semakptr->u.__sem_base[sops[j].sem_num].semval -= 1254 sops[j].sem_op; 1255 1256 /* If we detected an error, return it */ 1257 if (error != 0) 1258 goto done2; 1259 1260 /* 1261 * If the request that we couldn't satisfy has the 1262 * NOWAIT flag set then return with EAGAIN. 1263 */ 1264 if (sopptr->sem_flg & IPC_NOWAIT) { 1265 error = EAGAIN; 1266 goto done2; 1267 } 1268 1269 if (sopptr->sem_op == 0) 1270 semptr->semzcnt++; 1271 else 1272 semptr->semncnt++; 1273 1274 DPRINTF(("semop: good night!\n")); 1275 error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1276 "semwait", 0); 1277 DPRINTF(("semop: good morning (error=%d)!\n", error)); 1278 /* return code is checked below, after sem[nz]cnt-- */ 1279 1280 /* 1281 * Make sure that the semaphore still exists 1282 */ 1283 seq = semakptr->u.sem_perm.seq; 1284 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1285 seq != IPCID_TO_SEQ(uap->semid)) { 1286 error = EIDRM; 1287 goto done2; 1288 } 1289 1290 /* 1291 * Renew the semaphore's pointer after wakeup since 1292 * during msleep __sem_base may have been modified and semptr 1293 * is not valid any more 1294 */ 1295 semptr = &semakptr->u.__sem_base[sopptr->sem_num]; 1296 1297 /* 1298 * The semaphore is still alive. Readjust the count of 1299 * waiting processes. 1300 */ 1301 if (sopptr->sem_op == 0) 1302 semptr->semzcnt--; 1303 else 1304 semptr->semncnt--; 1305 1306 /* 1307 * Is it really morning, or was our sleep interrupted? 1308 * (Delayed check of msleep() return code because we 1309 * need to decrement sem[nz]cnt either way.) 1310 */ 1311 if (error != 0) { 1312 error = EINTR; 1313 goto done2; 1314 } 1315 DPRINTF(("semop: good morning!\n")); 1316 } 1317 1318 done: 1319 /* 1320 * Process any SEM_UNDO requests. 1321 */ 1322 if (do_undos) { 1323 SEMUNDO_LOCK(); 1324 suptr = NULL; 1325 for (i = 0; i < nsops; i++) { 1326 /* 1327 * We only need to deal with SEM_UNDO's for non-zero 1328 * op's. 1329 */ 1330 int adjval; 1331 1332 if ((sops[i].sem_flg & SEM_UNDO) == 0) 1333 continue; 1334 adjval = sops[i].sem_op; 1335 if (adjval == 0) 1336 continue; 1337 error = semundo_adjust(td, &suptr, semid, seq, 1338 sops[i].sem_num, -adjval); 1339 if (error == 0) 1340 continue; 1341 1342 /* 1343 * Oh-Oh! We ran out of either sem_undo's or undo's. 1344 * Rollback the adjustments to this point and then 1345 * rollback the semaphore ups and down so we can return 1346 * with an error with all structures restored. We 1347 * rollback the undo's in the exact reverse order that 1348 * we applied them. This guarantees that we won't run 1349 * out of space as we roll things back out. 1350 */ 1351 for (j = 0; j < i; j++) { 1352 k = i - j - 1; 1353 if ((sops[k].sem_flg & SEM_UNDO) == 0) 1354 continue; 1355 adjval = sops[k].sem_op; 1356 if (adjval == 0) 1357 continue; 1358 if (semundo_adjust(td, &suptr, semid, seq, 1359 sops[k].sem_num, adjval) != 0) 1360 panic("semop - can't undo undos"); 1361 } 1362 1363 for (j = 0; j < nsops; j++) 1364 semakptr->u.__sem_base[sops[j].sem_num].semval -= 1365 sops[j].sem_op; 1366 1367 DPRINTF(("error = %d from semundo_adjust\n", error)); 1368 SEMUNDO_UNLOCK(); 1369 goto done2; 1370 } /* loop through the sops */ 1371 SEMUNDO_UNLOCK(); 1372 } /* if (do_undos) */ 1373 1374 /* We're definitely done - set the sempid's and time */ 1375 for (i = 0; i < nsops; i++) { 1376 sopptr = &sops[i]; 1377 semptr = &semakptr->u.__sem_base[sopptr->sem_num]; 1378 semptr->sempid = td->td_proc->p_pid; 1379 } 1380 semakptr->u.sem_otime = time_second; 1381 1382 /* 1383 * Do a wakeup if any semaphore was up'd whilst something was 1384 * sleeping on it. 1385 */ 1386 if (do_wakeup) { 1387 DPRINTF(("semop: doing wakeup\n")); 1388 wakeup(semakptr); 1389 DPRINTF(("semop: back from wakeup\n")); 1390 } 1391 DPRINTF(("semop: done\n")); 1392 td->td_retval[0] = 0; 1393 done2: 1394 mtx_unlock(sema_mtxp); 1395 if (sops != small_sops) 1396 free(sops, M_SEM); 1397 return (error); 1398 } 1399 1400 /* 1401 * Go through the undo structures for this process and apply the adjustments to 1402 * semaphores. 1403 */ 1404 static void 1405 semexit_myhook(void *arg, struct proc *p) 1406 { 1407 struct sem_undo *suptr; 1408 struct semid_kernel *semakptr; 1409 struct mtx *sema_mtxp; 1410 int semid, semnum, adjval, ix; 1411 unsigned short seq; 1412 1413 /* 1414 * Go through the chain of undo vectors looking for one 1415 * associated with this process. 1416 */ 1417 if (LIST_EMPTY(&semu_list)) 1418 return; 1419 SEMUNDO_LOCK(); 1420 LIST_FOREACH(suptr, &semu_list, un_next) { 1421 if (suptr->un_proc == p) 1422 break; 1423 } 1424 if (suptr == NULL) { 1425 SEMUNDO_UNLOCK(); 1426 return; 1427 } 1428 LIST_REMOVE(suptr, un_next); 1429 1430 DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1431 suptr->un_cnt)); 1432 1433 /* 1434 * If there are any active undo elements then process them. 1435 */ 1436 if (suptr->un_cnt > 0) { 1437 SEMUNDO_UNLOCK(); 1438 for (ix = 0; ix < suptr->un_cnt; ix++) { 1439 semid = suptr->un_ent[ix].un_id; 1440 semnum = suptr->un_ent[ix].un_num; 1441 adjval = suptr->un_ent[ix].un_adjval; 1442 seq = suptr->un_ent[ix].un_seq; 1443 semakptr = &sema[semid]; 1444 sema_mtxp = &sema_mtx[semid]; 1445 1446 mtx_lock(sema_mtxp); 1447 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1448 (semakptr->u.sem_perm.seq != seq)) { 1449 mtx_unlock(sema_mtxp); 1450 continue; 1451 } 1452 if (semnum >= semakptr->u.sem_nsems) 1453 panic("semexit - semnum out of range"); 1454 1455 DPRINTF(( 1456 "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 1457 suptr->un_proc, suptr->un_ent[ix].un_id, 1458 suptr->un_ent[ix].un_num, 1459 suptr->un_ent[ix].un_adjval, 1460 semakptr->u.__sem_base[semnum].semval)); 1461 1462 if (adjval < 0 && semakptr->u.__sem_base[semnum].semval < 1463 -adjval) 1464 semakptr->u.__sem_base[semnum].semval = 0; 1465 else 1466 semakptr->u.__sem_base[semnum].semval += adjval; 1467 1468 wakeup(semakptr); 1469 DPRINTF(("semexit: back from wakeup\n")); 1470 mtx_unlock(sema_mtxp); 1471 } 1472 SEMUNDO_LOCK(); 1473 } 1474 1475 /* 1476 * Deallocate the undo vector. 1477 */ 1478 DPRINTF(("removing vector\n")); 1479 suptr->un_proc = NULL; 1480 suptr->un_cnt = 0; 1481 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1482 SEMUNDO_UNLOCK(); 1483 } 1484 1485 static int 1486 sysctl_sema(SYSCTL_HANDLER_ARGS) 1487 { 1488 struct prison *pr, *rpr; 1489 struct semid_kernel tsemak; 1490 #ifdef COMPAT_FREEBSD32 1491 struct semid_kernel32 tsemak32; 1492 #endif 1493 void *outaddr; 1494 size_t outsize; 1495 int error, i; 1496 1497 pr = req->td->td_ucred->cr_prison; 1498 rpr = sem_find_prison(req->td->td_ucred); 1499 error = 0; 1500 for (i = 0; i < seminfo.semmni; i++) { 1501 mtx_lock(&sema_mtx[i]); 1502 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) == 0 || 1503 rpr == NULL || sem_prison_cansee(rpr, &sema[i]) != 0) 1504 bzero(&tsemak, sizeof(tsemak)); 1505 else { 1506 tsemak = sema[i]; 1507 if (tsemak.cred->cr_prison != pr) 1508 tsemak.u.sem_perm.key = IPC_PRIVATE; 1509 } 1510 mtx_unlock(&sema_mtx[i]); 1511 #ifdef COMPAT_FREEBSD32 1512 if (SV_CURPROC_FLAG(SV_ILP32)) { 1513 bzero(&tsemak32, sizeof(tsemak32)); 1514 freebsd32_ipcperm_out(&tsemak.u.sem_perm, 1515 &tsemak32.u.sem_perm); 1516 /* Don't copy u.__sem_base */ 1517 CP(tsemak, tsemak32, u.sem_nsems); 1518 CP(tsemak, tsemak32, u.sem_otime); 1519 CP(tsemak, tsemak32, u.sem_ctime); 1520 /* Don't copy label or cred */ 1521 outaddr = &tsemak32; 1522 outsize = sizeof(tsemak32); 1523 } else 1524 #endif 1525 { 1526 tsemak.u.__sem_base = NULL; 1527 tsemak.label = NULL; 1528 tsemak.cred = NULL; 1529 outaddr = &tsemak; 1530 outsize = sizeof(tsemak); 1531 } 1532 error = SYSCTL_OUT(req, outaddr, outsize); 1533 if (error != 0) 1534 break; 1535 } 1536 return (error); 1537 } 1538 1539 static int 1540 sem_prison_check(void *obj, void *data) 1541 { 1542 struct prison *pr = obj; 1543 struct prison *prpr; 1544 struct vfsoptlist *opts = data; 1545 int error, jsys; 1546 1547 /* 1548 * sysvsem is a jailsys integer. 1549 * It must be "disable" if the parent jail is disabled. 1550 */ 1551 error = vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1552 if (error != ENOENT) { 1553 if (error != 0) 1554 return (error); 1555 switch (jsys) { 1556 case JAIL_SYS_DISABLE: 1557 break; 1558 case JAIL_SYS_NEW: 1559 case JAIL_SYS_INHERIT: 1560 prison_lock(pr->pr_parent); 1561 prpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1562 prison_unlock(pr->pr_parent); 1563 if (prpr == NULL) 1564 return (EPERM); 1565 break; 1566 default: 1567 return (EINVAL); 1568 } 1569 } 1570 1571 return (0); 1572 } 1573 1574 static int 1575 sem_prison_set(void *obj, void *data) 1576 { 1577 struct prison *pr = obj; 1578 struct prison *tpr, *orpr, *nrpr, *trpr; 1579 struct vfsoptlist *opts = data; 1580 void *rsv; 1581 int jsys, descend; 1582 1583 /* 1584 * sysvsem controls which jail is the root of the associated sems (this 1585 * jail or same as the parent), or if the feature is available at all. 1586 */ 1587 if (vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)) == ENOENT) 1588 jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0) 1589 ? JAIL_SYS_INHERIT 1590 : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0) 1591 ? JAIL_SYS_DISABLE 1592 : -1; 1593 if (jsys == JAIL_SYS_DISABLE) { 1594 prison_lock(pr); 1595 orpr = osd_jail_get(pr, sem_prison_slot); 1596 if (orpr != NULL) 1597 osd_jail_del(pr, sem_prison_slot); 1598 prison_unlock(pr); 1599 if (orpr != NULL) { 1600 if (orpr == pr) 1601 sem_prison_cleanup(pr); 1602 /* Disable all child jails as well. */ 1603 FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1604 prison_lock(tpr); 1605 trpr = osd_jail_get(tpr, sem_prison_slot); 1606 if (trpr != NULL) { 1607 osd_jail_del(tpr, sem_prison_slot); 1608 prison_unlock(tpr); 1609 if (trpr == tpr) 1610 sem_prison_cleanup(tpr); 1611 } else { 1612 prison_unlock(tpr); 1613 descend = 0; 1614 } 1615 } 1616 } 1617 } else if (jsys != -1) { 1618 if (jsys == JAIL_SYS_NEW) 1619 nrpr = pr; 1620 else { 1621 prison_lock(pr->pr_parent); 1622 nrpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1623 prison_unlock(pr->pr_parent); 1624 } 1625 rsv = osd_reserve(sem_prison_slot); 1626 prison_lock(pr); 1627 orpr = osd_jail_get(pr, sem_prison_slot); 1628 if (orpr != nrpr) 1629 (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 1630 nrpr); 1631 else 1632 osd_free_reserved(rsv); 1633 prison_unlock(pr); 1634 if (orpr != nrpr) { 1635 if (orpr == pr) 1636 sem_prison_cleanup(pr); 1637 if (orpr != NULL) { 1638 /* Change child jails matching the old root, */ 1639 FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1640 prison_lock(tpr); 1641 trpr = osd_jail_get(tpr, 1642 sem_prison_slot); 1643 if (trpr == orpr) { 1644 (void)osd_jail_set(tpr, 1645 sem_prison_slot, nrpr); 1646 prison_unlock(tpr); 1647 if (trpr == tpr) 1648 sem_prison_cleanup(tpr); 1649 } else { 1650 prison_unlock(tpr); 1651 descend = 0; 1652 } 1653 } 1654 } 1655 } 1656 } 1657 1658 return (0); 1659 } 1660 1661 static int 1662 sem_prison_get(void *obj, void *data) 1663 { 1664 struct prison *pr = obj; 1665 struct prison *rpr; 1666 struct vfsoptlist *opts = data; 1667 int error, jsys; 1668 1669 /* Set sysvsem based on the jail's root prison. */ 1670 prison_lock(pr); 1671 rpr = osd_jail_get(pr, sem_prison_slot); 1672 prison_unlock(pr); 1673 jsys = rpr == NULL ? JAIL_SYS_DISABLE 1674 : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 1675 error = vfs_setopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1676 if (error == ENOENT) 1677 error = 0; 1678 return (error); 1679 } 1680 1681 static int 1682 sem_prison_remove(void *obj, void *data __unused) 1683 { 1684 struct prison *pr = obj; 1685 struct prison *rpr; 1686 1687 prison_lock(pr); 1688 rpr = osd_jail_get(pr, sem_prison_slot); 1689 prison_unlock(pr); 1690 if (rpr == pr) 1691 sem_prison_cleanup(pr); 1692 return (0); 1693 } 1694 1695 static void 1696 sem_prison_cleanup(struct prison *pr) 1697 { 1698 int i; 1699 1700 /* Remove any sems that belong to this jail. */ 1701 mtx_lock(&sem_mtx); 1702 for (i = 0; i < seminfo.semmni; i++) { 1703 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 1704 sema[i].cred != NULL && sema[i].cred->cr_prison == pr) { 1705 mtx_lock(&sema_mtx[i]); 1706 sem_remove(i, NULL); 1707 mtx_unlock(&sema_mtx[i]); 1708 } 1709 } 1710 mtx_unlock(&sem_mtx); 1711 } 1712 1713 SYSCTL_JAIL_PARAM_SYS_NODE(sysvsem, CTLFLAG_RW, "SYSV semaphores"); 1714 1715 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1716 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1717 1718 /* XXX casting to (sy_call_t *) is bogus, as usual. */ 1719 static sy_call_t *semcalls[] = { 1720 (sy_call_t *)freebsd7___semctl, (sy_call_t *)sys_semget, 1721 (sy_call_t *)sys_semop 1722 }; 1723 1724 /* 1725 * Entry point for all SEM calls. 1726 */ 1727 int 1728 sys_semsys(td, uap) 1729 struct thread *td; 1730 /* XXX actually varargs. */ 1731 struct semsys_args /* { 1732 int which; 1733 int a2; 1734 int a3; 1735 int a4; 1736 int a5; 1737 } */ *uap; 1738 { 1739 int error; 1740 1741 AUDIT_ARG_SVIPC_WHICH(uap->which); 1742 if (uap->which < 0 || uap->which >= nitems(semcalls)) 1743 return (EINVAL); 1744 error = (*semcalls[uap->which])(td, &uap->a2); 1745 return (error); 1746 } 1747 1748 #ifndef CP 1749 #define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1750 #endif 1751 1752 #ifndef _SYS_SYSPROTO_H_ 1753 struct freebsd7___semctl_args { 1754 int semid; 1755 int semnum; 1756 int cmd; 1757 union semun_old *arg; 1758 }; 1759 #endif 1760 int 1761 freebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1762 { 1763 struct semid_ds_old dsold; 1764 struct semid_ds dsbuf; 1765 union semun_old arg; 1766 union semun semun; 1767 register_t rval; 1768 int error; 1769 1770 switch (uap->cmd) { 1771 case SEM_STAT: 1772 case IPC_SET: 1773 case IPC_STAT: 1774 case GETALL: 1775 case SETVAL: 1776 case SETALL: 1777 error = copyin(uap->arg, &arg, sizeof(arg)); 1778 if (error) 1779 return (error); 1780 break; 1781 } 1782 1783 switch (uap->cmd) { 1784 case SEM_STAT: 1785 case IPC_STAT: 1786 semun.buf = &dsbuf; 1787 break; 1788 case IPC_SET: 1789 error = copyin(arg.buf, &dsold, sizeof(dsold)); 1790 if (error) 1791 return (error); 1792 ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1793 CP(dsold, dsbuf, __sem_base); 1794 CP(dsold, dsbuf, sem_nsems); 1795 CP(dsold, dsbuf, sem_otime); 1796 CP(dsold, dsbuf, sem_ctime); 1797 semun.buf = &dsbuf; 1798 break; 1799 case GETALL: 1800 case SETALL: 1801 semun.array = arg.array; 1802 break; 1803 case SETVAL: 1804 semun.val = arg.val; 1805 break; 1806 } 1807 1808 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1809 &rval); 1810 if (error) 1811 return (error); 1812 1813 switch (uap->cmd) { 1814 case SEM_STAT: 1815 case IPC_STAT: 1816 bzero(&dsold, sizeof(dsold)); 1817 ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1818 CP(dsbuf, dsold, __sem_base); 1819 CP(dsbuf, dsold, sem_nsems); 1820 CP(dsbuf, dsold, sem_otime); 1821 CP(dsbuf, dsold, sem_ctime); 1822 error = copyout(&dsold, arg.buf, sizeof(dsold)); 1823 break; 1824 } 1825 1826 if (error == 0) 1827 td->td_retval[0] = rval; 1828 return (error); 1829 } 1830 1831 #endif /* COMPAT_FREEBSD{4,5,6,7} */ 1832 1833 #ifdef COMPAT_FREEBSD32 1834 1835 int 1836 freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1837 { 1838 1839 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1840 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1841 AUDIT_ARG_SVIPC_WHICH(uap->which); 1842 switch (uap->which) { 1843 case 0: 1844 return (freebsd7_freebsd32_semctl(td, 1845 (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1846 default: 1847 return (sys_semsys(td, (struct semsys_args *)uap)); 1848 } 1849 #else 1850 return (nosys(td, NULL)); 1851 #endif 1852 } 1853 1854 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1855 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1856 int 1857 freebsd7_freebsd32_semctl(struct thread *td, 1858 struct freebsd7_freebsd32_semctl_args *uap) 1859 { 1860 struct semid_ds32_old dsbuf32; 1861 struct semid_ds dsbuf; 1862 union semun semun; 1863 union semun32 arg; 1864 register_t rval; 1865 int error; 1866 1867 switch (uap->cmd) { 1868 case SEM_STAT: 1869 case IPC_SET: 1870 case IPC_STAT: 1871 case GETALL: 1872 case SETVAL: 1873 case SETALL: 1874 error = copyin(uap->arg, &arg, sizeof(arg)); 1875 if (error) 1876 return (error); 1877 break; 1878 } 1879 1880 switch (uap->cmd) { 1881 case SEM_STAT: 1882 case IPC_STAT: 1883 semun.buf = &dsbuf; 1884 break; 1885 case IPC_SET: 1886 error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1887 if (error) 1888 return (error); 1889 freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1890 PTRIN_CP(dsbuf32, dsbuf, __sem_base); 1891 CP(dsbuf32, dsbuf, sem_nsems); 1892 CP(dsbuf32, dsbuf, sem_otime); 1893 CP(dsbuf32, dsbuf, sem_ctime); 1894 semun.buf = &dsbuf; 1895 break; 1896 case GETALL: 1897 case SETALL: 1898 semun.array = PTRIN(arg.array); 1899 break; 1900 case SETVAL: 1901 semun.val = arg.val; 1902 break; 1903 } 1904 1905 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1906 &rval); 1907 if (error) 1908 return (error); 1909 1910 switch (uap->cmd) { 1911 case SEM_STAT: 1912 case IPC_STAT: 1913 bzero(&dsbuf32, sizeof(dsbuf32)); 1914 freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1915 PTROUT_CP(dsbuf, dsbuf32, __sem_base); 1916 CP(dsbuf, dsbuf32, sem_nsems); 1917 CP(dsbuf, dsbuf32, sem_otime); 1918 CP(dsbuf, dsbuf32, sem_ctime); 1919 error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1920 break; 1921 } 1922 1923 if (error == 0) 1924 td->td_retval[0] = rval; 1925 return (error); 1926 } 1927 #endif 1928 1929 int 1930 freebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1931 { 1932 struct semid_ds32 dsbuf32; 1933 struct semid_ds dsbuf; 1934 union semun semun; 1935 union semun32 arg; 1936 register_t rval; 1937 int error; 1938 1939 switch (uap->cmd) { 1940 case SEM_STAT: 1941 case IPC_SET: 1942 case IPC_STAT: 1943 case GETALL: 1944 case SETVAL: 1945 case SETALL: 1946 error = copyin(uap->arg, &arg, sizeof(arg)); 1947 if (error) 1948 return (error); 1949 break; 1950 } 1951 1952 switch (uap->cmd) { 1953 case SEM_STAT: 1954 case IPC_STAT: 1955 semun.buf = &dsbuf; 1956 break; 1957 case IPC_SET: 1958 error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1959 if (error) 1960 return (error); 1961 freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1962 PTRIN_CP(dsbuf32, dsbuf, __sem_base); 1963 CP(dsbuf32, dsbuf, sem_nsems); 1964 CP(dsbuf32, dsbuf, sem_otime); 1965 CP(dsbuf32, dsbuf, sem_ctime); 1966 semun.buf = &dsbuf; 1967 break; 1968 case GETALL: 1969 case SETALL: 1970 semun.array = PTRIN(arg.array); 1971 break; 1972 case SETVAL: 1973 semun.val = arg.val; 1974 break; 1975 } 1976 1977 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1978 &rval); 1979 if (error) 1980 return (error); 1981 1982 switch (uap->cmd) { 1983 case SEM_STAT: 1984 case IPC_STAT: 1985 bzero(&dsbuf32, sizeof(dsbuf32)); 1986 freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1987 PTROUT_CP(dsbuf, dsbuf32, __sem_base); 1988 CP(dsbuf, dsbuf32, sem_nsems); 1989 CP(dsbuf, dsbuf32, sem_otime); 1990 CP(dsbuf, dsbuf32, sem_ctime); 1991 error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1992 break; 1993 } 1994 1995 if (error == 0) 1996 td->td_retval[0] = rval; 1997 return (error); 1998 } 1999 2000 #endif /* COMPAT_FREEBSD32 */ 2001