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