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