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 = SEMMNI, /* # of semaphore identifiers */ 202 .semmns = SEMMNS, /* # of semaphores in system */ 203 .semmnu = SEMMNU, /* # of undo structures in system */ 204 .semmsl = SEMMSL, /* max # of semaphores per id */ 205 .semopm = SEMOPM, /* max # of operations per semop call */ 206 .semume = SEMUME, /* max # of undo entries per process */ 207 .semusz = SEMUSZ, /* size in bytes of undo structure */ 208 .semvmx = SEMVMX, /* semaphore maximum value */ 209 .semaem = 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 mtx_assert(&sem_mtx, MA_OWNED); 563 semakptr = &sema[semidx]; 564 KASSERT(semakptr->u.__sem_base - sem + semakptr->u.sem_nsems <= semtot, 565 ("sem_remove: sema %d corrupted sem pointer %p %p %d %d", 566 semidx, semakptr->u.__sem_base, sem, semakptr->u.sem_nsems, 567 semtot)); 568 569 semakptr->u.sem_perm.cuid = cred ? cred->cr_uid : 0; 570 semakptr->u.sem_perm.uid = cred ? cred->cr_uid : 0; 571 semakptr->u.sem_perm.mode = 0; 572 racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); 573 crfree(semakptr->cred); 574 semakptr->cred = NULL; 575 SEMUNDO_LOCK(); 576 semundo_clear(semidx, -1); 577 SEMUNDO_UNLOCK(); 578 #ifdef MAC 579 mac_sysvsem_cleanup(semakptr); 580 #endif 581 wakeup(semakptr); 582 for (i = 0; i < seminfo.semmni; i++) { 583 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 584 sema[i].u.__sem_base > semakptr->u.__sem_base) 585 mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 586 } 587 for (i = semakptr->u.__sem_base - sem + semakptr->u.sem_nsems; 588 i < semtot; i++) 589 sem[i - semakptr->u.sem_nsems] = sem[i]; 590 for (i = 0; i < seminfo.semmni; i++) { 591 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 592 sema[i].u.__sem_base > semakptr->u.__sem_base) { 593 sema[i].u.__sem_base -= semakptr->u.sem_nsems; 594 mtx_unlock(&sema_mtx[i]); 595 } 596 } 597 semtot -= semakptr->u.sem_nsems; 598 } 599 600 static struct prison * 601 sem_find_prison(struct ucred *cred) 602 { 603 struct prison *pr, *rpr; 604 605 pr = cred->cr_prison; 606 prison_lock(pr); 607 rpr = osd_jail_get(pr, sem_prison_slot); 608 prison_unlock(pr); 609 return rpr; 610 } 611 612 static int 613 sem_prison_cansee(struct prison *rpr, struct semid_kernel *semakptr) 614 { 615 616 if (semakptr->cred == NULL || 617 !(rpr == semakptr->cred->cr_prison || 618 prison_ischild(rpr, semakptr->cred->cr_prison))) 619 return (EINVAL); 620 return (0); 621 } 622 623 /* 624 * Note that the user-mode half of this passes a union, not a pointer. 625 */ 626 #ifndef _SYS_SYSPROTO_H_ 627 struct __semctl_args { 628 int semid; 629 int semnum; 630 int cmd; 631 union semun *arg; 632 }; 633 #endif 634 int 635 sys___semctl(struct thread *td, struct __semctl_args *uap) 636 { 637 struct semid_ds dsbuf; 638 union semun arg, semun; 639 register_t rval; 640 int error; 641 642 switch (uap->cmd) { 643 case SEM_STAT: 644 case IPC_SET: 645 case IPC_STAT: 646 case GETALL: 647 case SETVAL: 648 case SETALL: 649 error = copyin(uap->arg, &arg, sizeof(arg)); 650 if (error) 651 return (error); 652 break; 653 } 654 655 switch (uap->cmd) { 656 case SEM_STAT: 657 case IPC_STAT: 658 semun.buf = &dsbuf; 659 break; 660 case IPC_SET: 661 error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 662 if (error) 663 return (error); 664 semun.buf = &dsbuf; 665 break; 666 case GETALL: 667 case SETALL: 668 semun.array = arg.array; 669 break; 670 case SETVAL: 671 semun.val = arg.val; 672 break; 673 } 674 675 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 676 &rval); 677 if (error) 678 return (error); 679 680 switch (uap->cmd) { 681 case SEM_STAT: 682 case IPC_STAT: 683 error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 684 break; 685 } 686 687 if (error == 0) 688 td->td_retval[0] = rval; 689 return (error); 690 } 691 692 int 693 kern_semctl(struct thread *td, int semid, int semnum, int cmd, 694 union semun *arg, register_t *rval) 695 { 696 u_short *array; 697 struct ucred *cred = td->td_ucred; 698 int i, error; 699 struct prison *rpr; 700 struct semid_ds *sbuf; 701 struct semid_kernel *semakptr; 702 struct mtx *sema_mtxp; 703 u_short usval, count; 704 int semidx; 705 706 DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 707 semid, semnum, cmd, arg)); 708 709 AUDIT_ARG_SVIPC_CMD(cmd); 710 AUDIT_ARG_SVIPC_ID(semid); 711 712 rpr = sem_find_prison(td->td_ucred); 713 if (sem == NULL) 714 return (ENOSYS); 715 716 array = NULL; 717 718 switch(cmd) { 719 case SEM_STAT: 720 /* 721 * For this command we assume semid is an array index 722 * rather than an IPC id. 723 */ 724 if (semid < 0 || semid >= seminfo.semmni) 725 return (EINVAL); 726 semakptr = &sema[semid]; 727 sema_mtxp = &sema_mtx[semid]; 728 mtx_lock(sema_mtxp); 729 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 730 error = EINVAL; 731 goto done2; 732 } 733 if ((error = sem_prison_cansee(rpr, semakptr))) 734 goto done2; 735 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 736 goto done2; 737 #ifdef MAC 738 error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 739 if (error != 0) 740 goto done2; 741 #endif 742 bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 743 if (cred->cr_prison != semakptr->cred->cr_prison) 744 arg->buf->sem_perm.key = IPC_PRIVATE; 745 *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 746 mtx_unlock(sema_mtxp); 747 return (0); 748 } 749 750 semidx = IPCID_TO_IX(semid); 751 if (semidx < 0 || semidx >= seminfo.semmni) 752 return (EINVAL); 753 754 semakptr = &sema[semidx]; 755 sema_mtxp = &sema_mtx[semidx]; 756 if (cmd == IPC_RMID) 757 mtx_lock(&sem_mtx); 758 mtx_lock(sema_mtxp); 759 760 #ifdef MAC 761 error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 762 if (error != 0) 763 goto done2; 764 #endif 765 766 error = 0; 767 *rval = 0; 768 769 switch (cmd) { 770 case IPC_RMID: 771 if ((error = semvalid(semid, rpr, semakptr)) != 0) 772 goto done2; 773 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 774 goto done2; 775 sem_remove(semidx, cred); 776 break; 777 778 case IPC_SET: 779 AUDIT_ARG_SVIPC_PERM(&arg->buf->sem_perm); 780 if ((error = semvalid(semid, rpr, semakptr)) != 0) 781 goto done2; 782 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 783 goto done2; 784 sbuf = arg->buf; 785 semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 786 semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 787 semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 788 ~0777) | (sbuf->sem_perm.mode & 0777); 789 semakptr->u.sem_ctime = time_second; 790 break; 791 792 case IPC_STAT: 793 if ((error = semvalid(semid, rpr, semakptr)) != 0) 794 goto done2; 795 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 796 goto done2; 797 bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 798 if (cred->cr_prison != semakptr->cred->cr_prison) 799 arg->buf->sem_perm.key = IPC_PRIVATE; 800 break; 801 802 case GETNCNT: 803 if ((error = semvalid(semid, rpr, semakptr)) != 0) 804 goto done2; 805 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 806 goto done2; 807 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 808 error = EINVAL; 809 goto done2; 810 } 811 *rval = semakptr->u.__sem_base[semnum].semncnt; 812 break; 813 814 case GETPID: 815 if ((error = semvalid(semid, rpr, semakptr)) != 0) 816 goto done2; 817 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 818 goto done2; 819 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 820 error = EINVAL; 821 goto done2; 822 } 823 *rval = semakptr->u.__sem_base[semnum].sempid; 824 break; 825 826 case GETVAL: 827 if ((error = semvalid(semid, rpr, semakptr)) != 0) 828 goto done2; 829 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 830 goto done2; 831 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 832 error = EINVAL; 833 goto done2; 834 } 835 *rval = semakptr->u.__sem_base[semnum].semval; 836 break; 837 838 case GETALL: 839 /* 840 * Unfortunately, callers of this function don't know 841 * in advance how many semaphores are in this set. 842 * While we could just allocate the maximum size array 843 * and pass the actual size back to the caller, that 844 * won't work for SETALL since we can't copyin() more 845 * data than the user specified as we may return a 846 * spurious EFAULT. 847 * 848 * Note that the number of semaphores in a set is 849 * fixed for the life of that set. The only way that 850 * the 'count' could change while are blocked in 851 * malloc() is if this semaphore set were destroyed 852 * and a new one created with the same index. 853 * However, semvalid() will catch that due to the 854 * sequence number unless exactly 0x8000 (or a 855 * multiple thereof) semaphore sets for the same index 856 * are created and destroyed while we are in malloc! 857 * 858 */ 859 count = semakptr->u.sem_nsems; 860 mtx_unlock(sema_mtxp); 861 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 862 mtx_lock(sema_mtxp); 863 if ((error = semvalid(semid, rpr, semakptr)) != 0) 864 goto done2; 865 KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 866 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 867 goto done2; 868 for (i = 0; i < semakptr->u.sem_nsems; i++) 869 array[i] = semakptr->u.__sem_base[i].semval; 870 mtx_unlock(sema_mtxp); 871 error = copyout(array, arg->array, count * sizeof(*array)); 872 mtx_lock(sema_mtxp); 873 break; 874 875 case GETZCNT: 876 if ((error = semvalid(semid, rpr, semakptr)) != 0) 877 goto done2; 878 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 879 goto done2; 880 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 881 error = EINVAL; 882 goto done2; 883 } 884 *rval = semakptr->u.__sem_base[semnum].semzcnt; 885 break; 886 887 case SETVAL: 888 if ((error = semvalid(semid, rpr, semakptr)) != 0) 889 goto done2; 890 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 891 goto done2; 892 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 893 error = EINVAL; 894 goto done2; 895 } 896 if (arg->val < 0 || arg->val > seminfo.semvmx) { 897 error = ERANGE; 898 goto done2; 899 } 900 semakptr->u.__sem_base[semnum].semval = arg->val; 901 SEMUNDO_LOCK(); 902 semundo_clear(semidx, semnum); 903 SEMUNDO_UNLOCK(); 904 wakeup(semakptr); 905 break; 906 907 case SETALL: 908 /* 909 * See comment on GETALL for why 'count' shouldn't change 910 * and why we require a userland buffer. 911 */ 912 count = semakptr->u.sem_nsems; 913 mtx_unlock(sema_mtxp); 914 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 915 error = copyin(arg->array, array, count * sizeof(*array)); 916 mtx_lock(sema_mtxp); 917 if (error) 918 break; 919 if ((error = semvalid(semid, rpr, semakptr)) != 0) 920 goto done2; 921 KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 922 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 923 goto done2; 924 for (i = 0; i < semakptr->u.sem_nsems; i++) { 925 usval = array[i]; 926 if (usval > seminfo.semvmx) { 927 error = ERANGE; 928 break; 929 } 930 semakptr->u.__sem_base[i].semval = usval; 931 } 932 SEMUNDO_LOCK(); 933 semundo_clear(semidx, -1); 934 SEMUNDO_UNLOCK(); 935 wakeup(semakptr); 936 break; 937 938 default: 939 error = EINVAL; 940 break; 941 } 942 943 done2: 944 mtx_unlock(sema_mtxp); 945 if (cmd == IPC_RMID) 946 mtx_unlock(&sem_mtx); 947 if (array != NULL) 948 free(array, M_TEMP); 949 return(error); 950 } 951 952 #ifndef _SYS_SYSPROTO_H_ 953 struct semget_args { 954 key_t key; 955 int nsems; 956 int semflg; 957 }; 958 #endif 959 int 960 sys_semget(struct thread *td, struct semget_args *uap) 961 { 962 int semid, error = 0; 963 int key = uap->key; 964 int nsems = uap->nsems; 965 int semflg = uap->semflg; 966 struct ucred *cred = td->td_ucred; 967 968 DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 969 970 AUDIT_ARG_VALUE(semflg); 971 972 if (sem_find_prison(cred) == NULL) 973 return (ENOSYS); 974 975 mtx_lock(&sem_mtx); 976 if (key != IPC_PRIVATE) { 977 for (semid = 0; semid < seminfo.semmni; semid++) { 978 if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 979 sema[semid].cred != NULL && 980 sema[semid].cred->cr_prison == cred->cr_prison && 981 sema[semid].u.sem_perm.key == key) 982 break; 983 } 984 if (semid < seminfo.semmni) { 985 AUDIT_ARG_SVIPC_ID(semid); 986 DPRINTF(("found public key\n")); 987 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 988 DPRINTF(("not exclusive\n")); 989 error = EEXIST; 990 goto done2; 991 } 992 if ((error = ipcperm(td, &sema[semid].u.sem_perm, 993 semflg & 0700))) { 994 goto done2; 995 } 996 if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 997 DPRINTF(("too small\n")); 998 error = EINVAL; 999 goto done2; 1000 } 1001 #ifdef MAC 1002 error = mac_sysvsem_check_semget(cred, &sema[semid]); 1003 if (error != 0) 1004 goto done2; 1005 #endif 1006 goto found; 1007 } 1008 } 1009 1010 DPRINTF(("need to allocate the semid_kernel\n")); 1011 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 1012 if (nsems <= 0 || nsems > seminfo.semmsl) { 1013 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 1014 seminfo.semmsl)); 1015 error = EINVAL; 1016 goto done2; 1017 } 1018 if (nsems > seminfo.semmns - semtot) { 1019 DPRINTF(( 1020 "not enough semaphores left (need %d, got %d)\n", 1021 nsems, seminfo.semmns - semtot)); 1022 error = ENOSPC; 1023 goto done2; 1024 } 1025 for (semid = 0; semid < seminfo.semmni; semid++) { 1026 if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 1027 break; 1028 } 1029 if (semid == seminfo.semmni) { 1030 DPRINTF(("no more semid_kernel's available\n")); 1031 error = ENOSPC; 1032 goto done2; 1033 } 1034 #ifdef RACCT 1035 if (racct_enable) { 1036 PROC_LOCK(td->td_proc); 1037 error = racct_add(td->td_proc, RACCT_NSEM, nsems); 1038 PROC_UNLOCK(td->td_proc); 1039 if (error != 0) { 1040 error = ENOSPC; 1041 goto done2; 1042 } 1043 } 1044 #endif 1045 DPRINTF(("semid %d is available\n", semid)); 1046 mtx_lock(&sema_mtx[semid]); 1047 KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 1048 ("Lost semaphore %d", semid)); 1049 sema[semid].u.sem_perm.key = key; 1050 sema[semid].u.sem_perm.cuid = cred->cr_uid; 1051 sema[semid].u.sem_perm.uid = cred->cr_uid; 1052 sema[semid].u.sem_perm.cgid = cred->cr_gid; 1053 sema[semid].u.sem_perm.gid = cred->cr_gid; 1054 sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 1055 sema[semid].cred = crhold(cred); 1056 sema[semid].u.sem_perm.seq = 1057 (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 1058 sema[semid].u.sem_nsems = nsems; 1059 sema[semid].u.sem_otime = 0; 1060 sema[semid].u.sem_ctime = time_second; 1061 sema[semid].u.__sem_base = &sem[semtot]; 1062 semtot += nsems; 1063 bzero(sema[semid].u.__sem_base, 1064 sizeof(sema[semid].u.__sem_base[0])*nsems); 1065 #ifdef MAC 1066 mac_sysvsem_create(cred, &sema[semid]); 1067 #endif 1068 mtx_unlock(&sema_mtx[semid]); 1069 DPRINTF(("sembase = %p, next = %p\n", 1070 sema[semid].u.__sem_base, &sem[semtot])); 1071 } else { 1072 DPRINTF(("didn't find it and wasn't asked to create it\n")); 1073 error = ENOENT; 1074 goto done2; 1075 } 1076 1077 found: 1078 td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 1079 done2: 1080 mtx_unlock(&sem_mtx); 1081 return (error); 1082 } 1083 1084 #ifndef _SYS_SYSPROTO_H_ 1085 struct semop_args { 1086 int semid; 1087 struct sembuf *sops; 1088 size_t nsops; 1089 }; 1090 #endif 1091 int 1092 sys_semop(struct thread *td, struct semop_args *uap) 1093 { 1094 #define SMALL_SOPS 8 1095 struct sembuf small_sops[SMALL_SOPS]; 1096 int semid = uap->semid; 1097 size_t nsops = uap->nsops; 1098 struct prison *rpr; 1099 struct sembuf *sops; 1100 struct semid_kernel *semakptr; 1101 struct sembuf *sopptr = NULL; 1102 struct sem *semptr = NULL; 1103 struct sem_undo *suptr; 1104 struct mtx *sema_mtxp; 1105 size_t i, j, k; 1106 int error; 1107 int do_wakeup, do_undos; 1108 unsigned short seq; 1109 1110 #ifdef SEM_DEBUG 1111 sops = NULL; 1112 #endif 1113 DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 1114 1115 AUDIT_ARG_SVIPC_ID(semid); 1116 1117 rpr = sem_find_prison(td->td_ucred); 1118 if (sem == NULL) 1119 return (ENOSYS); 1120 1121 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 1122 1123 if (semid < 0 || semid >= seminfo.semmni) 1124 return (EINVAL); 1125 1126 /* Allocate memory for sem_ops */ 1127 if (nsops <= SMALL_SOPS) 1128 sops = small_sops; 1129 else if (nsops > seminfo.semopm) { 1130 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1131 nsops)); 1132 return (E2BIG); 1133 } else { 1134 #ifdef RACCT 1135 if (racct_enable) { 1136 PROC_LOCK(td->td_proc); 1137 if (nsops > 1138 racct_get_available(td->td_proc, RACCT_NSEMOP)) { 1139 PROC_UNLOCK(td->td_proc); 1140 return (E2BIG); 1141 } 1142 PROC_UNLOCK(td->td_proc); 1143 } 1144 #endif 1145 1146 sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 1147 } 1148 if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1149 DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1150 uap->sops, sops, nsops * sizeof(sops[0]))); 1151 if (sops != small_sops) 1152 free(sops, M_TEMP); 1153 return (error); 1154 } 1155 1156 semakptr = &sema[semid]; 1157 sema_mtxp = &sema_mtx[semid]; 1158 mtx_lock(sema_mtxp); 1159 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 1160 error = EINVAL; 1161 goto done2; 1162 } 1163 seq = semakptr->u.sem_perm.seq; 1164 if (seq != IPCID_TO_SEQ(uap->semid)) { 1165 error = EINVAL; 1166 goto done2; 1167 } 1168 if ((error = sem_prison_cansee(rpr, semakptr)) != 0) 1169 goto done2; 1170 /* 1171 * Initial pass through sops to see what permissions are needed. 1172 * Also perform any checks that don't need repeating on each 1173 * attempt to satisfy the request vector. 1174 */ 1175 j = 0; /* permission needed */ 1176 do_undos = 0; 1177 for (i = 0; i < nsops; i++) { 1178 sopptr = &sops[i]; 1179 if (sopptr->sem_num >= semakptr->u.sem_nsems) { 1180 error = EFBIG; 1181 goto done2; 1182 } 1183 if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 1184 do_undos = 1; 1185 j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 1186 } 1187 1188 if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1189 DPRINTF(("error = %d from ipaccess\n", error)); 1190 goto done2; 1191 } 1192 #ifdef MAC 1193 error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1194 if (error != 0) 1195 goto done2; 1196 #endif 1197 1198 /* 1199 * Loop trying to satisfy the vector of requests. 1200 * If we reach a point where we must wait, any requests already 1201 * performed are rolled back and we go to sleep until some other 1202 * process wakes us up. At this point, we start all over again. 1203 * 1204 * This ensures that from the perspective of other tasks, a set 1205 * of requests is atomic (never partially satisfied). 1206 */ 1207 for (;;) { 1208 do_wakeup = 0; 1209 error = 0; /* error return if necessary */ 1210 1211 for (i = 0; i < nsops; i++) { 1212 sopptr = &sops[i]; 1213 semptr = &semakptr->u.__sem_base[sopptr->sem_num]; 1214 1215 DPRINTF(( 1216 "semop: semakptr=%p, __sem_base=%p, " 1217 "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1218 semakptr, semakptr->u.__sem_base, semptr, 1219 sopptr->sem_num, semptr->semval, sopptr->sem_op, 1220 (sopptr->sem_flg & IPC_NOWAIT) ? 1221 "nowait" : "wait")); 1222 1223 if (sopptr->sem_op < 0) { 1224 if (semptr->semval + sopptr->sem_op < 0) { 1225 DPRINTF(("semop: can't do it now\n")); 1226 break; 1227 } else { 1228 semptr->semval += sopptr->sem_op; 1229 if (semptr->semval == 0 && 1230 semptr->semzcnt > 0) 1231 do_wakeup = 1; 1232 } 1233 } else if (sopptr->sem_op == 0) { 1234 if (semptr->semval != 0) { 1235 DPRINTF(("semop: not zero now\n")); 1236 break; 1237 } 1238 } else if (semptr->semval + sopptr->sem_op > 1239 seminfo.semvmx) { 1240 error = ERANGE; 1241 break; 1242 } else { 1243 if (semptr->semncnt > 0) 1244 do_wakeup = 1; 1245 semptr->semval += sopptr->sem_op; 1246 } 1247 } 1248 1249 /* 1250 * Did we get through the entire vector? 1251 */ 1252 if (i >= nsops) 1253 goto done; 1254 1255 /* 1256 * No ... rollback anything that we've already done 1257 */ 1258 DPRINTF(("semop: rollback 0 through %d\n", i-1)); 1259 for (j = 0; j < i; j++) 1260 semakptr->u.__sem_base[sops[j].sem_num].semval -= 1261 sops[j].sem_op; 1262 1263 /* If we detected an error, return it */ 1264 if (error != 0) 1265 goto done2; 1266 1267 /* 1268 * If the request that we couldn't satisfy has the 1269 * NOWAIT flag set then return with EAGAIN. 1270 */ 1271 if (sopptr->sem_flg & IPC_NOWAIT) { 1272 error = EAGAIN; 1273 goto done2; 1274 } 1275 1276 if (sopptr->sem_op == 0) 1277 semptr->semzcnt++; 1278 else 1279 semptr->semncnt++; 1280 1281 DPRINTF(("semop: good night!\n")); 1282 error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1283 "semwait", 0); 1284 DPRINTF(("semop: good morning (error=%d)!\n", error)); 1285 /* return code is checked below, after sem[nz]cnt-- */ 1286 1287 /* 1288 * Make sure that the semaphore still exists 1289 */ 1290 seq = semakptr->u.sem_perm.seq; 1291 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1292 seq != IPCID_TO_SEQ(uap->semid)) { 1293 error = EIDRM; 1294 goto done2; 1295 } 1296 1297 /* 1298 * Renew the semaphore's pointer after wakeup since 1299 * during msleep __sem_base may have been modified and semptr 1300 * is not valid any more 1301 */ 1302 semptr = &semakptr->u.__sem_base[sopptr->sem_num]; 1303 1304 /* 1305 * The semaphore is still alive. Readjust the count of 1306 * waiting processes. 1307 */ 1308 if (sopptr->sem_op == 0) 1309 semptr->semzcnt--; 1310 else 1311 semptr->semncnt--; 1312 1313 /* 1314 * Is it really morning, or was our sleep interrupted? 1315 * (Delayed check of msleep() return code because we 1316 * need to decrement sem[nz]cnt either way.) 1317 */ 1318 if (error != 0) { 1319 error = EINTR; 1320 goto done2; 1321 } 1322 DPRINTF(("semop: good morning!\n")); 1323 } 1324 1325 done: 1326 /* 1327 * Process any SEM_UNDO requests. 1328 */ 1329 if (do_undos) { 1330 SEMUNDO_LOCK(); 1331 suptr = NULL; 1332 for (i = 0; i < nsops; i++) { 1333 /* 1334 * We only need to deal with SEM_UNDO's for non-zero 1335 * op's. 1336 */ 1337 int adjval; 1338 1339 if ((sops[i].sem_flg & SEM_UNDO) == 0) 1340 continue; 1341 adjval = sops[i].sem_op; 1342 if (adjval == 0) 1343 continue; 1344 error = semundo_adjust(td, &suptr, semid, seq, 1345 sops[i].sem_num, -adjval); 1346 if (error == 0) 1347 continue; 1348 1349 /* 1350 * Oh-Oh! We ran out of either sem_undo's or undo's. 1351 * Rollback the adjustments to this point and then 1352 * rollback the semaphore ups and down so we can return 1353 * with an error with all structures restored. We 1354 * rollback the undo's in the exact reverse order that 1355 * we applied them. This guarantees that we won't run 1356 * out of space as we roll things back out. 1357 */ 1358 for (j = 0; j < i; j++) { 1359 k = i - j - 1; 1360 if ((sops[k].sem_flg & SEM_UNDO) == 0) 1361 continue; 1362 adjval = sops[k].sem_op; 1363 if (adjval == 0) 1364 continue; 1365 if (semundo_adjust(td, &suptr, semid, seq, 1366 sops[k].sem_num, adjval) != 0) 1367 panic("semop - can't undo undos"); 1368 } 1369 1370 for (j = 0; j < nsops; j++) 1371 semakptr->u.__sem_base[sops[j].sem_num].semval -= 1372 sops[j].sem_op; 1373 1374 DPRINTF(("error = %d from semundo_adjust\n", error)); 1375 SEMUNDO_UNLOCK(); 1376 goto done2; 1377 } /* loop through the sops */ 1378 SEMUNDO_UNLOCK(); 1379 } /* if (do_undos) */ 1380 1381 /* We're definitely done - set the sempid's and time */ 1382 for (i = 0; i < nsops; i++) { 1383 sopptr = &sops[i]; 1384 semptr = &semakptr->u.__sem_base[sopptr->sem_num]; 1385 semptr->sempid = td->td_proc->p_pid; 1386 } 1387 semakptr->u.sem_otime = time_second; 1388 1389 /* 1390 * Do a wakeup if any semaphore was up'd whilst something was 1391 * sleeping on it. 1392 */ 1393 if (do_wakeup) { 1394 DPRINTF(("semop: doing wakeup\n")); 1395 wakeup(semakptr); 1396 DPRINTF(("semop: back from wakeup\n")); 1397 } 1398 DPRINTF(("semop: done\n")); 1399 td->td_retval[0] = 0; 1400 done2: 1401 mtx_unlock(sema_mtxp); 1402 if (sops != small_sops) 1403 free(sops, M_TEMP); 1404 return (error); 1405 } 1406 1407 /* 1408 * Go through the undo structures for this process and apply the adjustments to 1409 * semaphores. 1410 */ 1411 static void 1412 semexit_myhook(void *arg, struct proc *p) 1413 { 1414 struct sem_undo *suptr; 1415 struct semid_kernel *semakptr; 1416 struct mtx *sema_mtxp; 1417 int semid, semnum, adjval, ix; 1418 unsigned short seq; 1419 1420 /* 1421 * Go through the chain of undo vectors looking for one 1422 * associated with this process. 1423 */ 1424 if (LIST_EMPTY(&semu_list)) 1425 return; 1426 SEMUNDO_LOCK(); 1427 LIST_FOREACH(suptr, &semu_list, un_next) { 1428 if (suptr->un_proc == p) 1429 break; 1430 } 1431 if (suptr == NULL) { 1432 SEMUNDO_UNLOCK(); 1433 return; 1434 } 1435 LIST_REMOVE(suptr, un_next); 1436 1437 DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1438 suptr->un_cnt)); 1439 1440 /* 1441 * If there are any active undo elements then process them. 1442 */ 1443 if (suptr->un_cnt > 0) { 1444 SEMUNDO_UNLOCK(); 1445 for (ix = 0; ix < suptr->un_cnt; ix++) { 1446 semid = suptr->un_ent[ix].un_id; 1447 semnum = suptr->un_ent[ix].un_num; 1448 adjval = suptr->un_ent[ix].un_adjval; 1449 seq = suptr->un_ent[ix].un_seq; 1450 semakptr = &sema[semid]; 1451 sema_mtxp = &sema_mtx[semid]; 1452 1453 mtx_lock(sema_mtxp); 1454 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1455 (semakptr->u.sem_perm.seq != seq)) { 1456 mtx_unlock(sema_mtxp); 1457 continue; 1458 } 1459 if (semnum >= semakptr->u.sem_nsems) 1460 panic("semexit - semnum out of range"); 1461 1462 DPRINTF(( 1463 "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 1464 suptr->un_proc, suptr->un_ent[ix].un_id, 1465 suptr->un_ent[ix].un_num, 1466 suptr->un_ent[ix].un_adjval, 1467 semakptr->u.__sem_base[semnum].semval)); 1468 1469 if (adjval < 0 && semakptr->u.__sem_base[semnum].semval < 1470 -adjval) 1471 semakptr->u.__sem_base[semnum].semval = 0; 1472 else 1473 semakptr->u.__sem_base[semnum].semval += adjval; 1474 1475 wakeup(semakptr); 1476 DPRINTF(("semexit: back from wakeup\n")); 1477 mtx_unlock(sema_mtxp); 1478 } 1479 SEMUNDO_LOCK(); 1480 } 1481 1482 /* 1483 * Deallocate the undo vector. 1484 */ 1485 DPRINTF(("removing vector\n")); 1486 suptr->un_proc = NULL; 1487 suptr->un_cnt = 0; 1488 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1489 SEMUNDO_UNLOCK(); 1490 } 1491 1492 static int 1493 sysctl_sema(SYSCTL_HANDLER_ARGS) 1494 { 1495 struct prison *pr, *rpr; 1496 struct semid_kernel tsemak; 1497 #ifdef COMPAT_FREEBSD32 1498 struct semid_kernel32 tsemak32; 1499 #endif 1500 void *outaddr; 1501 size_t outsize; 1502 int error, i; 1503 1504 pr = req->td->td_ucred->cr_prison; 1505 rpr = sem_find_prison(req->td->td_ucred); 1506 error = 0; 1507 for (i = 0; i < seminfo.semmni; i++) { 1508 mtx_lock(&sema_mtx[i]); 1509 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) == 0 || 1510 rpr == NULL || sem_prison_cansee(rpr, &sema[i]) != 0) 1511 bzero(&tsemak, sizeof(tsemak)); 1512 else { 1513 tsemak = sema[i]; 1514 if (tsemak.cred->cr_prison != pr) 1515 tsemak.u.sem_perm.key = IPC_PRIVATE; 1516 } 1517 mtx_unlock(&sema_mtx[i]); 1518 #ifdef COMPAT_FREEBSD32 1519 if (SV_CURPROC_FLAG(SV_ILP32)) { 1520 bzero(&tsemak32, sizeof(tsemak32)); 1521 freebsd32_ipcperm_out(&tsemak.u.sem_perm, 1522 &tsemak32.u.sem_perm); 1523 /* Don't copy u.__sem_base */ 1524 CP(tsemak, tsemak32, u.sem_nsems); 1525 CP(tsemak, tsemak32, u.sem_otime); 1526 CP(tsemak, tsemak32, u.sem_ctime); 1527 /* Don't copy label or cred */ 1528 outaddr = &tsemak32; 1529 outsize = sizeof(tsemak32); 1530 } else 1531 #endif 1532 { 1533 tsemak.u.__sem_base = NULL; 1534 tsemak.label = NULL; 1535 tsemak.cred = NULL; 1536 outaddr = &tsemak; 1537 outsize = sizeof(tsemak); 1538 } 1539 error = SYSCTL_OUT(req, outaddr, outsize); 1540 if (error != 0) 1541 break; 1542 } 1543 return (error); 1544 } 1545 1546 static int 1547 sem_prison_check(void *obj, void *data) 1548 { 1549 struct prison *pr = obj; 1550 struct prison *prpr; 1551 struct vfsoptlist *opts = data; 1552 int error, jsys; 1553 1554 /* 1555 * sysvsem is a jailsys integer. 1556 * It must be "disable" if the parent jail is disabled. 1557 */ 1558 error = vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1559 if (error != ENOENT) { 1560 if (error != 0) 1561 return (error); 1562 switch (jsys) { 1563 case JAIL_SYS_DISABLE: 1564 break; 1565 case JAIL_SYS_NEW: 1566 case JAIL_SYS_INHERIT: 1567 prison_lock(pr->pr_parent); 1568 prpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1569 prison_unlock(pr->pr_parent); 1570 if (prpr == NULL) 1571 return (EPERM); 1572 break; 1573 default: 1574 return (EINVAL); 1575 } 1576 } 1577 1578 return (0); 1579 } 1580 1581 static int 1582 sem_prison_set(void *obj, void *data) 1583 { 1584 struct prison *pr = obj; 1585 struct prison *tpr, *orpr, *nrpr, *trpr; 1586 struct vfsoptlist *opts = data; 1587 void *rsv; 1588 int jsys, descend; 1589 1590 /* 1591 * sysvsem controls which jail is the root of the associated sems (this 1592 * jail or same as the parent), or if the feature is available at all. 1593 */ 1594 if (vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)) == ENOENT) 1595 jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0) 1596 ? JAIL_SYS_INHERIT 1597 : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0) 1598 ? JAIL_SYS_DISABLE 1599 : -1; 1600 if (jsys == JAIL_SYS_DISABLE) { 1601 prison_lock(pr); 1602 orpr = osd_jail_get(pr, sem_prison_slot); 1603 if (orpr != NULL) 1604 osd_jail_del(pr, sem_prison_slot); 1605 prison_unlock(pr); 1606 if (orpr != NULL) { 1607 if (orpr == pr) 1608 sem_prison_cleanup(pr); 1609 /* Disable all child jails as well. */ 1610 FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1611 prison_lock(tpr); 1612 trpr = osd_jail_get(tpr, sem_prison_slot); 1613 if (trpr != NULL) { 1614 osd_jail_del(tpr, sem_prison_slot); 1615 prison_unlock(tpr); 1616 if (trpr == tpr) 1617 sem_prison_cleanup(tpr); 1618 } else { 1619 prison_unlock(tpr); 1620 descend = 0; 1621 } 1622 } 1623 } 1624 } else if (jsys != -1) { 1625 if (jsys == JAIL_SYS_NEW) 1626 nrpr = pr; 1627 else { 1628 prison_lock(pr->pr_parent); 1629 nrpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1630 prison_unlock(pr->pr_parent); 1631 } 1632 rsv = osd_reserve(sem_prison_slot); 1633 prison_lock(pr); 1634 orpr = osd_jail_get(pr, sem_prison_slot); 1635 if (orpr != nrpr) 1636 (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 1637 nrpr); 1638 else 1639 osd_free_reserved(rsv); 1640 prison_unlock(pr); 1641 if (orpr != nrpr) { 1642 if (orpr == pr) 1643 sem_prison_cleanup(pr); 1644 if (orpr != NULL) { 1645 /* Change child jails matching the old root, */ 1646 FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1647 prison_lock(tpr); 1648 trpr = osd_jail_get(tpr, 1649 sem_prison_slot); 1650 if (trpr == orpr) { 1651 (void)osd_jail_set(tpr, 1652 sem_prison_slot, nrpr); 1653 prison_unlock(tpr); 1654 if (trpr == tpr) 1655 sem_prison_cleanup(tpr); 1656 } else { 1657 prison_unlock(tpr); 1658 descend = 0; 1659 } 1660 } 1661 } 1662 } 1663 } 1664 1665 return (0); 1666 } 1667 1668 static int 1669 sem_prison_get(void *obj, void *data) 1670 { 1671 struct prison *pr = obj; 1672 struct prison *rpr; 1673 struct vfsoptlist *opts = data; 1674 int error, jsys; 1675 1676 /* Set sysvsem based on the jail's root prison. */ 1677 prison_lock(pr); 1678 rpr = osd_jail_get(pr, sem_prison_slot); 1679 prison_unlock(pr); 1680 jsys = rpr == NULL ? JAIL_SYS_DISABLE 1681 : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 1682 error = vfs_setopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1683 if (error == ENOENT) 1684 error = 0; 1685 return (error); 1686 } 1687 1688 static int 1689 sem_prison_remove(void *obj, void *data __unused) 1690 { 1691 struct prison *pr = obj; 1692 struct prison *rpr; 1693 1694 prison_lock(pr); 1695 rpr = osd_jail_get(pr, sem_prison_slot); 1696 prison_unlock(pr); 1697 if (rpr == pr) 1698 sem_prison_cleanup(pr); 1699 return (0); 1700 } 1701 1702 static void 1703 sem_prison_cleanup(struct prison *pr) 1704 { 1705 int i; 1706 1707 /* Remove any sems that belong to this jail. */ 1708 mtx_lock(&sem_mtx); 1709 for (i = 0; i < seminfo.semmni; i++) { 1710 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 1711 sema[i].cred != NULL && sema[i].cred->cr_prison == pr) { 1712 mtx_lock(&sema_mtx[i]); 1713 sem_remove(i, NULL); 1714 mtx_unlock(&sema_mtx[i]); 1715 } 1716 } 1717 mtx_unlock(&sem_mtx); 1718 } 1719 1720 SYSCTL_JAIL_PARAM_SYS_NODE(sysvsem, CTLFLAG_RW, "SYSV semaphores"); 1721 1722 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1723 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1724 1725 /* XXX casting to (sy_call_t *) is bogus, as usual. */ 1726 static sy_call_t *semcalls[] = { 1727 (sy_call_t *)freebsd7___semctl, (sy_call_t *)sys_semget, 1728 (sy_call_t *)sys_semop 1729 }; 1730 1731 /* 1732 * Entry point for all SEM calls. 1733 */ 1734 int 1735 sys_semsys(td, uap) 1736 struct thread *td; 1737 /* XXX actually varargs. */ 1738 struct semsys_args /* { 1739 int which; 1740 int a2; 1741 int a3; 1742 int a4; 1743 int a5; 1744 } */ *uap; 1745 { 1746 int error; 1747 1748 AUDIT_ARG_SVIPC_WHICH(uap->which); 1749 if (uap->which < 0 || uap->which >= nitems(semcalls)) 1750 return (EINVAL); 1751 error = (*semcalls[uap->which])(td, &uap->a2); 1752 return (error); 1753 } 1754 1755 #ifndef CP 1756 #define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1757 #endif 1758 1759 #ifndef _SYS_SYSPROTO_H_ 1760 struct freebsd7___semctl_args { 1761 int semid; 1762 int semnum; 1763 int cmd; 1764 union semun_old *arg; 1765 }; 1766 #endif 1767 int 1768 freebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1769 { 1770 struct semid_ds_old dsold; 1771 struct semid_ds dsbuf; 1772 union semun_old arg; 1773 union semun semun; 1774 register_t rval; 1775 int error; 1776 1777 switch (uap->cmd) { 1778 case SEM_STAT: 1779 case IPC_SET: 1780 case IPC_STAT: 1781 case GETALL: 1782 case SETVAL: 1783 case SETALL: 1784 error = copyin(uap->arg, &arg, sizeof(arg)); 1785 if (error) 1786 return (error); 1787 break; 1788 } 1789 1790 switch (uap->cmd) { 1791 case SEM_STAT: 1792 case IPC_STAT: 1793 semun.buf = &dsbuf; 1794 break; 1795 case IPC_SET: 1796 error = copyin(arg.buf, &dsold, sizeof(dsold)); 1797 if (error) 1798 return (error); 1799 ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1800 CP(dsold, dsbuf, __sem_base); 1801 CP(dsold, dsbuf, sem_nsems); 1802 CP(dsold, dsbuf, sem_otime); 1803 CP(dsold, dsbuf, sem_ctime); 1804 semun.buf = &dsbuf; 1805 break; 1806 case GETALL: 1807 case SETALL: 1808 semun.array = arg.array; 1809 break; 1810 case SETVAL: 1811 semun.val = arg.val; 1812 break; 1813 } 1814 1815 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1816 &rval); 1817 if (error) 1818 return (error); 1819 1820 switch (uap->cmd) { 1821 case SEM_STAT: 1822 case IPC_STAT: 1823 bzero(&dsold, sizeof(dsold)); 1824 ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1825 CP(dsbuf, dsold, __sem_base); 1826 CP(dsbuf, dsold, sem_nsems); 1827 CP(dsbuf, dsold, sem_otime); 1828 CP(dsbuf, dsold, sem_ctime); 1829 error = copyout(&dsold, arg.buf, sizeof(dsold)); 1830 break; 1831 } 1832 1833 if (error == 0) 1834 td->td_retval[0] = rval; 1835 return (error); 1836 } 1837 1838 #endif /* COMPAT_FREEBSD{4,5,6,7} */ 1839 1840 #ifdef COMPAT_FREEBSD32 1841 1842 int 1843 freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1844 { 1845 1846 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1847 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1848 AUDIT_ARG_SVIPC_WHICH(uap->which); 1849 switch (uap->which) { 1850 case 0: 1851 return (freebsd7_freebsd32_semctl(td, 1852 (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1853 default: 1854 return (sys_semsys(td, (struct semsys_args *)uap)); 1855 } 1856 #else 1857 return (nosys(td, NULL)); 1858 #endif 1859 } 1860 1861 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1862 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1863 int 1864 freebsd7_freebsd32_semctl(struct thread *td, 1865 struct freebsd7_freebsd32_semctl_args *uap) 1866 { 1867 struct semid_ds32_old dsbuf32; 1868 struct semid_ds dsbuf; 1869 union semun semun; 1870 union semun32 arg; 1871 register_t rval; 1872 int error; 1873 1874 switch (uap->cmd) { 1875 case SEM_STAT: 1876 case IPC_SET: 1877 case IPC_STAT: 1878 case GETALL: 1879 case SETVAL: 1880 case SETALL: 1881 error = copyin(uap->arg, &arg, sizeof(arg)); 1882 if (error) 1883 return (error); 1884 break; 1885 } 1886 1887 switch (uap->cmd) { 1888 case SEM_STAT: 1889 case IPC_STAT: 1890 semun.buf = &dsbuf; 1891 break; 1892 case IPC_SET: 1893 error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1894 if (error) 1895 return (error); 1896 freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1897 PTRIN_CP(dsbuf32, dsbuf, __sem_base); 1898 CP(dsbuf32, dsbuf, sem_nsems); 1899 CP(dsbuf32, dsbuf, sem_otime); 1900 CP(dsbuf32, dsbuf, sem_ctime); 1901 semun.buf = &dsbuf; 1902 break; 1903 case GETALL: 1904 case SETALL: 1905 semun.array = PTRIN(arg.array); 1906 break; 1907 case SETVAL: 1908 semun.val = arg.val; 1909 break; 1910 } 1911 1912 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1913 &rval); 1914 if (error) 1915 return (error); 1916 1917 switch (uap->cmd) { 1918 case SEM_STAT: 1919 case IPC_STAT: 1920 bzero(&dsbuf32, sizeof(dsbuf32)); 1921 freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1922 PTROUT_CP(dsbuf, dsbuf32, __sem_base); 1923 CP(dsbuf, dsbuf32, sem_nsems); 1924 CP(dsbuf, dsbuf32, sem_otime); 1925 CP(dsbuf, dsbuf32, sem_ctime); 1926 error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1927 break; 1928 } 1929 1930 if (error == 0) 1931 td->td_retval[0] = rval; 1932 return (error); 1933 } 1934 #endif 1935 1936 int 1937 freebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1938 { 1939 struct semid_ds32 dsbuf32; 1940 struct semid_ds dsbuf; 1941 union semun semun; 1942 union semun32 arg; 1943 register_t rval; 1944 int error; 1945 1946 switch (uap->cmd) { 1947 case SEM_STAT: 1948 case IPC_SET: 1949 case IPC_STAT: 1950 case GETALL: 1951 case SETVAL: 1952 case SETALL: 1953 error = copyin(uap->arg, &arg, sizeof(arg)); 1954 if (error) 1955 return (error); 1956 break; 1957 } 1958 1959 switch (uap->cmd) { 1960 case SEM_STAT: 1961 case IPC_STAT: 1962 semun.buf = &dsbuf; 1963 break; 1964 case IPC_SET: 1965 error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1966 if (error) 1967 return (error); 1968 freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1969 PTRIN_CP(dsbuf32, dsbuf, __sem_base); 1970 CP(dsbuf32, dsbuf, sem_nsems); 1971 CP(dsbuf32, dsbuf, sem_otime); 1972 CP(dsbuf32, dsbuf, sem_ctime); 1973 semun.buf = &dsbuf; 1974 break; 1975 case GETALL: 1976 case SETALL: 1977 semun.array = PTRIN(arg.array); 1978 break; 1979 case SETVAL: 1980 semun.val = arg.val; 1981 break; 1982 } 1983 1984 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1985 &rval); 1986 if (error) 1987 return (error); 1988 1989 switch (uap->cmd) { 1990 case SEM_STAT: 1991 case IPC_STAT: 1992 bzero(&dsbuf32, sizeof(dsbuf32)); 1993 freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1994 PTROUT_CP(dsbuf, dsbuf32, __sem_base); 1995 CP(dsbuf, dsbuf32, sem_nsems); 1996 CP(dsbuf, dsbuf32, sem_otime); 1997 CP(dsbuf, dsbuf32, sem_ctime); 1998 error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1999 break; 2000 } 2001 2002 if (error == 0) 2003 td->td_retval[0] = rval; 2004 return (error); 2005 } 2006 2007 #endif /* COMPAT_FREEBSD32 */ 2008