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