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