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