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