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 if (racct_enable) { 919 PROC_LOCK(td->td_proc); 920 error = racct_add(td->td_proc, RACCT_NSEM, nsems); 921 PROC_UNLOCK(td->td_proc); 922 if (error != 0) { 923 error = ENOSPC; 924 goto done2; 925 } 926 } 927 #endif 928 DPRINTF(("semid %d is available\n", semid)); 929 mtx_lock(&sema_mtx[semid]); 930 KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 931 ("Lost semaphore %d", semid)); 932 sema[semid].u.sem_perm.key = key; 933 sema[semid].u.sem_perm.cuid = cred->cr_uid; 934 sema[semid].u.sem_perm.uid = cred->cr_uid; 935 sema[semid].u.sem_perm.cgid = cred->cr_gid; 936 sema[semid].u.sem_perm.gid = cred->cr_gid; 937 sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 938 sema[semid].cred = crhold(cred); 939 sema[semid].u.sem_perm.seq = 940 (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 941 sema[semid].u.sem_nsems = nsems; 942 sema[semid].u.sem_otime = 0; 943 sema[semid].u.sem_ctime = time_second; 944 sema[semid].u.sem_base = &sem[semtot]; 945 semtot += nsems; 946 bzero(sema[semid].u.sem_base, 947 sizeof(sema[semid].u.sem_base[0])*nsems); 948 #ifdef MAC 949 mac_sysvsem_create(cred, &sema[semid]); 950 #endif 951 mtx_unlock(&sema_mtx[semid]); 952 DPRINTF(("sembase = %p, next = %p\n", 953 sema[semid].u.sem_base, &sem[semtot])); 954 } else { 955 DPRINTF(("didn't find it and wasn't asked to create it\n")); 956 error = ENOENT; 957 goto done2; 958 } 959 960 found: 961 td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 962 done2: 963 mtx_unlock(&sem_mtx); 964 return (error); 965 } 966 967 #ifndef _SYS_SYSPROTO_H_ 968 struct semop_args { 969 int semid; 970 struct sembuf *sops; 971 size_t nsops; 972 }; 973 #endif 974 int 975 sys_semop(struct thread *td, struct semop_args *uap) 976 { 977 #define SMALL_SOPS 8 978 struct sembuf small_sops[SMALL_SOPS]; 979 int semid = uap->semid; 980 size_t nsops = uap->nsops; 981 struct sembuf *sops; 982 struct semid_kernel *semakptr; 983 struct sembuf *sopptr = 0; 984 struct sem *semptr = 0; 985 struct sem_undo *suptr; 986 struct mtx *sema_mtxp; 987 size_t i, j, k; 988 int error; 989 int do_wakeup, do_undos; 990 unsigned short seq; 991 992 #ifdef SEM_DEBUG 993 sops = NULL; 994 #endif 995 DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 996 997 if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 998 return (ENOSYS); 999 1000 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 1001 1002 if (semid < 0 || semid >= seminfo.semmni) 1003 return (EINVAL); 1004 1005 /* Allocate memory for sem_ops */ 1006 if (nsops <= SMALL_SOPS) 1007 sops = small_sops; 1008 else if (nsops > seminfo.semopm) { 1009 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1010 nsops)); 1011 return (E2BIG); 1012 } else { 1013 #ifdef RACCT 1014 if (racct_enable) { 1015 PROC_LOCK(td->td_proc); 1016 if (nsops > 1017 racct_get_available(td->td_proc, RACCT_NSEMOP)) { 1018 PROC_UNLOCK(td->td_proc); 1019 return (E2BIG); 1020 } 1021 PROC_UNLOCK(td->td_proc); 1022 } 1023 #endif 1024 1025 sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 1026 } 1027 if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1028 DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1029 uap->sops, sops, nsops * sizeof(sops[0]))); 1030 if (sops != small_sops) 1031 free(sops, M_SEM); 1032 return (error); 1033 } 1034 1035 semakptr = &sema[semid]; 1036 sema_mtxp = &sema_mtx[semid]; 1037 mtx_lock(sema_mtxp); 1038 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 1039 error = EINVAL; 1040 goto done2; 1041 } 1042 seq = semakptr->u.sem_perm.seq; 1043 if (seq != IPCID_TO_SEQ(uap->semid)) { 1044 error = EINVAL; 1045 goto done2; 1046 } 1047 /* 1048 * Initial pass thru sops to see what permissions are needed. 1049 * Also perform any checks that don't need repeating on each 1050 * attempt to satisfy the request vector. 1051 */ 1052 j = 0; /* permission needed */ 1053 do_undos = 0; 1054 for (i = 0; i < nsops; i++) { 1055 sopptr = &sops[i]; 1056 if (sopptr->sem_num >= semakptr->u.sem_nsems) { 1057 error = EFBIG; 1058 goto done2; 1059 } 1060 if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 1061 do_undos = 1; 1062 j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 1063 } 1064 1065 if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1066 DPRINTF(("error = %d from ipaccess\n", error)); 1067 goto done2; 1068 } 1069 #ifdef MAC 1070 error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1071 if (error != 0) 1072 goto done2; 1073 #endif 1074 1075 /* 1076 * Loop trying to satisfy the vector of requests. 1077 * If we reach a point where we must wait, any requests already 1078 * performed are rolled back and we go to sleep until some other 1079 * process wakes us up. At this point, we start all over again. 1080 * 1081 * This ensures that from the perspective of other tasks, a set 1082 * of requests is atomic (never partially satisfied). 1083 */ 1084 for (;;) { 1085 do_wakeup = 0; 1086 error = 0; /* error return if necessary */ 1087 1088 for (i = 0; i < nsops; i++) { 1089 sopptr = &sops[i]; 1090 semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1091 1092 DPRINTF(( 1093 "semop: semakptr=%p, sem_base=%p, " 1094 "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1095 semakptr, semakptr->u.sem_base, semptr, 1096 sopptr->sem_num, semptr->semval, sopptr->sem_op, 1097 (sopptr->sem_flg & IPC_NOWAIT) ? 1098 "nowait" : "wait")); 1099 1100 if (sopptr->sem_op < 0) { 1101 if (semptr->semval + sopptr->sem_op < 0) { 1102 DPRINTF(("semop: can't do it now\n")); 1103 break; 1104 } else { 1105 semptr->semval += sopptr->sem_op; 1106 if (semptr->semval == 0 && 1107 semptr->semzcnt > 0) 1108 do_wakeup = 1; 1109 } 1110 } else if (sopptr->sem_op == 0) { 1111 if (semptr->semval != 0) { 1112 DPRINTF(("semop: not zero now\n")); 1113 break; 1114 } 1115 } else if (semptr->semval + sopptr->sem_op > 1116 seminfo.semvmx) { 1117 error = ERANGE; 1118 break; 1119 } else { 1120 if (semptr->semncnt > 0) 1121 do_wakeup = 1; 1122 semptr->semval += sopptr->sem_op; 1123 } 1124 } 1125 1126 /* 1127 * Did we get through the entire vector? 1128 */ 1129 if (i >= nsops) 1130 goto done; 1131 1132 /* 1133 * No ... rollback anything that we've already done 1134 */ 1135 DPRINTF(("semop: rollback 0 through %d\n", i-1)); 1136 for (j = 0; j < i; j++) 1137 semakptr->u.sem_base[sops[j].sem_num].semval -= 1138 sops[j].sem_op; 1139 1140 /* If we detected an error, return it */ 1141 if (error != 0) 1142 goto done2; 1143 1144 /* 1145 * If the request that we couldn't satisfy has the 1146 * NOWAIT flag set then return with EAGAIN. 1147 */ 1148 if (sopptr->sem_flg & IPC_NOWAIT) { 1149 error = EAGAIN; 1150 goto done2; 1151 } 1152 1153 if (sopptr->sem_op == 0) 1154 semptr->semzcnt++; 1155 else 1156 semptr->semncnt++; 1157 1158 DPRINTF(("semop: good night!\n")); 1159 error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1160 "semwait", 0); 1161 DPRINTF(("semop: good morning (error=%d)!\n", error)); 1162 /* return code is checked below, after sem[nz]cnt-- */ 1163 1164 /* 1165 * Make sure that the semaphore still exists 1166 */ 1167 seq = semakptr->u.sem_perm.seq; 1168 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1169 seq != IPCID_TO_SEQ(uap->semid)) { 1170 error = EIDRM; 1171 goto done2; 1172 } 1173 1174 /* 1175 * Renew the semaphore's pointer after wakeup since 1176 * during msleep sem_base may have been modified and semptr 1177 * is not valid any more 1178 */ 1179 semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1180 1181 /* 1182 * The semaphore is still alive. Readjust the count of 1183 * waiting processes. 1184 */ 1185 if (sopptr->sem_op == 0) 1186 semptr->semzcnt--; 1187 else 1188 semptr->semncnt--; 1189 1190 /* 1191 * Is it really morning, or was our sleep interrupted? 1192 * (Delayed check of msleep() return code because we 1193 * need to decrement sem[nz]cnt either way.) 1194 */ 1195 if (error != 0) { 1196 error = EINTR; 1197 goto done2; 1198 } 1199 DPRINTF(("semop: good morning!\n")); 1200 } 1201 1202 done: 1203 /* 1204 * Process any SEM_UNDO requests. 1205 */ 1206 if (do_undos) { 1207 SEMUNDO_LOCK(); 1208 suptr = NULL; 1209 for (i = 0; i < nsops; i++) { 1210 /* 1211 * We only need to deal with SEM_UNDO's for non-zero 1212 * op's. 1213 */ 1214 int adjval; 1215 1216 if ((sops[i].sem_flg & SEM_UNDO) == 0) 1217 continue; 1218 adjval = sops[i].sem_op; 1219 if (adjval == 0) 1220 continue; 1221 error = semundo_adjust(td, &suptr, semid, seq, 1222 sops[i].sem_num, -adjval); 1223 if (error == 0) 1224 continue; 1225 1226 /* 1227 * Oh-Oh! We ran out of either sem_undo's or undo's. 1228 * Rollback the adjustments to this point and then 1229 * rollback the semaphore ups and down so we can return 1230 * with an error with all structures restored. We 1231 * rollback the undo's in the exact reverse order that 1232 * we applied them. This guarantees that we won't run 1233 * out of space as we roll things back out. 1234 */ 1235 for (j = 0; j < i; j++) { 1236 k = i - j - 1; 1237 if ((sops[k].sem_flg & SEM_UNDO) == 0) 1238 continue; 1239 adjval = sops[k].sem_op; 1240 if (adjval == 0) 1241 continue; 1242 if (semundo_adjust(td, &suptr, semid, seq, 1243 sops[k].sem_num, adjval) != 0) 1244 panic("semop - can't undo undos"); 1245 } 1246 1247 for (j = 0; j < nsops; j++) 1248 semakptr->u.sem_base[sops[j].sem_num].semval -= 1249 sops[j].sem_op; 1250 1251 DPRINTF(("error = %d from semundo_adjust\n", error)); 1252 SEMUNDO_UNLOCK(); 1253 goto done2; 1254 } /* loop through the sops */ 1255 SEMUNDO_UNLOCK(); 1256 } /* if (do_undos) */ 1257 1258 /* We're definitely done - set the sempid's and time */ 1259 for (i = 0; i < nsops; i++) { 1260 sopptr = &sops[i]; 1261 semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1262 semptr->sempid = td->td_proc->p_pid; 1263 } 1264 semakptr->u.sem_otime = time_second; 1265 1266 /* 1267 * Do a wakeup if any semaphore was up'd whilst something was 1268 * sleeping on it. 1269 */ 1270 if (do_wakeup) { 1271 DPRINTF(("semop: doing wakeup\n")); 1272 wakeup(semakptr); 1273 DPRINTF(("semop: back from wakeup\n")); 1274 } 1275 DPRINTF(("semop: done\n")); 1276 td->td_retval[0] = 0; 1277 done2: 1278 mtx_unlock(sema_mtxp); 1279 if (sops != small_sops) 1280 free(sops, M_SEM); 1281 return (error); 1282 } 1283 1284 /* 1285 * Go through the undo structures for this process and apply the adjustments to 1286 * semaphores. 1287 */ 1288 static void 1289 semexit_myhook(void *arg, struct proc *p) 1290 { 1291 struct sem_undo *suptr; 1292 struct semid_kernel *semakptr; 1293 struct mtx *sema_mtxp; 1294 int semid, semnum, adjval, ix; 1295 unsigned short seq; 1296 1297 /* 1298 * Go through the chain of undo vectors looking for one 1299 * associated with this process. 1300 */ 1301 SEMUNDO_LOCK(); 1302 LIST_FOREACH(suptr, &semu_list, un_next) { 1303 if (suptr->un_proc == p) 1304 break; 1305 } 1306 if (suptr == NULL) { 1307 SEMUNDO_UNLOCK(); 1308 return; 1309 } 1310 LIST_REMOVE(suptr, un_next); 1311 1312 DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1313 suptr->un_cnt)); 1314 1315 /* 1316 * If there are any active undo elements then process them. 1317 */ 1318 if (suptr->un_cnt > 0) { 1319 SEMUNDO_UNLOCK(); 1320 for (ix = 0; ix < suptr->un_cnt; ix++) { 1321 semid = suptr->un_ent[ix].un_id; 1322 semnum = suptr->un_ent[ix].un_num; 1323 adjval = suptr->un_ent[ix].un_adjval; 1324 seq = suptr->un_ent[ix].un_seq; 1325 semakptr = &sema[semid]; 1326 sema_mtxp = &sema_mtx[semid]; 1327 1328 mtx_lock(sema_mtxp); 1329 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1330 (semakptr->u.sem_perm.seq != seq)) { 1331 mtx_unlock(sema_mtxp); 1332 continue; 1333 } 1334 if (semnum >= semakptr->u.sem_nsems) 1335 panic("semexit - semnum out of range"); 1336 1337 DPRINTF(( 1338 "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 1339 suptr->un_proc, suptr->un_ent[ix].un_id, 1340 suptr->un_ent[ix].un_num, 1341 suptr->un_ent[ix].un_adjval, 1342 semakptr->u.sem_base[semnum].semval)); 1343 1344 if (adjval < 0 && semakptr->u.sem_base[semnum].semval < 1345 -adjval) 1346 semakptr->u.sem_base[semnum].semval = 0; 1347 else 1348 semakptr->u.sem_base[semnum].semval += adjval; 1349 1350 wakeup(semakptr); 1351 DPRINTF(("semexit: back from wakeup\n")); 1352 mtx_unlock(sema_mtxp); 1353 } 1354 SEMUNDO_LOCK(); 1355 } 1356 1357 /* 1358 * Deallocate the undo vector. 1359 */ 1360 DPRINTF(("removing vector\n")); 1361 suptr->un_proc = NULL; 1362 suptr->un_cnt = 0; 1363 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1364 SEMUNDO_UNLOCK(); 1365 } 1366 1367 static int 1368 sysctl_sema(SYSCTL_HANDLER_ARGS) 1369 { 1370 1371 return (SYSCTL_OUT(req, sema, 1372 sizeof(struct semid_kernel) * seminfo.semmni)); 1373 } 1374 1375 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1376 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1377 1378 /* XXX casting to (sy_call_t *) is bogus, as usual. */ 1379 static sy_call_t *semcalls[] = { 1380 (sy_call_t *)freebsd7___semctl, (sy_call_t *)sys_semget, 1381 (sy_call_t *)sys_semop 1382 }; 1383 1384 /* 1385 * Entry point for all SEM calls. 1386 */ 1387 int 1388 sys_semsys(td, uap) 1389 struct thread *td; 1390 /* XXX actually varargs. */ 1391 struct semsys_args /* { 1392 int which; 1393 int a2; 1394 int a3; 1395 int a4; 1396 int a5; 1397 } */ *uap; 1398 { 1399 int error; 1400 1401 if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 1402 return (ENOSYS); 1403 if (uap->which < 0 || 1404 uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) 1405 return (EINVAL); 1406 error = (*semcalls[uap->which])(td, &uap->a2); 1407 return (error); 1408 } 1409 1410 #ifndef CP 1411 #define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1412 #endif 1413 1414 #ifndef _SYS_SYSPROTO_H_ 1415 struct freebsd7___semctl_args { 1416 int semid; 1417 int semnum; 1418 int cmd; 1419 union semun_old *arg; 1420 }; 1421 #endif 1422 int 1423 freebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1424 { 1425 struct semid_ds_old dsold; 1426 struct semid_ds dsbuf; 1427 union semun_old arg; 1428 union semun semun; 1429 register_t rval; 1430 int error; 1431 1432 switch (uap->cmd) { 1433 case SEM_STAT: 1434 case IPC_SET: 1435 case IPC_STAT: 1436 case GETALL: 1437 case SETVAL: 1438 case SETALL: 1439 error = copyin(uap->arg, &arg, sizeof(arg)); 1440 if (error) 1441 return (error); 1442 break; 1443 } 1444 1445 switch (uap->cmd) { 1446 case SEM_STAT: 1447 case IPC_STAT: 1448 semun.buf = &dsbuf; 1449 break; 1450 case IPC_SET: 1451 error = copyin(arg.buf, &dsold, sizeof(dsold)); 1452 if (error) 1453 return (error); 1454 ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1455 CP(dsold, dsbuf, sem_base); 1456 CP(dsold, dsbuf, sem_nsems); 1457 CP(dsold, dsbuf, sem_otime); 1458 CP(dsold, dsbuf, sem_ctime); 1459 semun.buf = &dsbuf; 1460 break; 1461 case GETALL: 1462 case SETALL: 1463 semun.array = arg.array; 1464 break; 1465 case SETVAL: 1466 semun.val = arg.val; 1467 break; 1468 } 1469 1470 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1471 &rval); 1472 if (error) 1473 return (error); 1474 1475 switch (uap->cmd) { 1476 case SEM_STAT: 1477 case IPC_STAT: 1478 bzero(&dsold, sizeof(dsold)); 1479 ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1480 CP(dsbuf, dsold, sem_base); 1481 CP(dsbuf, dsold, sem_nsems); 1482 CP(dsbuf, dsold, sem_otime); 1483 CP(dsbuf, dsold, sem_ctime); 1484 error = copyout(&dsold, arg.buf, sizeof(dsold)); 1485 break; 1486 } 1487 1488 if (error == 0) 1489 td->td_retval[0] = rval; 1490 return (error); 1491 } 1492 1493 #endif /* COMPAT_FREEBSD{4,5,6,7} */ 1494 1495 #ifdef COMPAT_FREEBSD32 1496 1497 int 1498 freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1499 { 1500 1501 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1502 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1503 switch (uap->which) { 1504 case 0: 1505 return (freebsd7_freebsd32_semctl(td, 1506 (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1507 default: 1508 return (sys_semsys(td, (struct semsys_args *)uap)); 1509 } 1510 #else 1511 return (nosys(td, NULL)); 1512 #endif 1513 } 1514 1515 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1516 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1517 int 1518 freebsd7_freebsd32_semctl(struct thread *td, 1519 struct freebsd7_freebsd32_semctl_args *uap) 1520 { 1521 struct semid_ds32_old dsbuf32; 1522 struct semid_ds dsbuf; 1523 union semun semun; 1524 union semun32 arg; 1525 register_t rval; 1526 int error; 1527 1528 switch (uap->cmd) { 1529 case SEM_STAT: 1530 case IPC_SET: 1531 case IPC_STAT: 1532 case GETALL: 1533 case SETVAL: 1534 case SETALL: 1535 error = copyin(uap->arg, &arg, sizeof(arg)); 1536 if (error) 1537 return (error); 1538 break; 1539 } 1540 1541 switch (uap->cmd) { 1542 case SEM_STAT: 1543 case IPC_STAT: 1544 semun.buf = &dsbuf; 1545 break; 1546 case IPC_SET: 1547 error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1548 if (error) 1549 return (error); 1550 freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1551 PTRIN_CP(dsbuf32, dsbuf, sem_base); 1552 CP(dsbuf32, dsbuf, sem_nsems); 1553 CP(dsbuf32, dsbuf, sem_otime); 1554 CP(dsbuf32, dsbuf, sem_ctime); 1555 semun.buf = &dsbuf; 1556 break; 1557 case GETALL: 1558 case SETALL: 1559 semun.array = PTRIN(arg.array); 1560 break; 1561 case SETVAL: 1562 semun.val = arg.val; 1563 break; 1564 } 1565 1566 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1567 &rval); 1568 if (error) 1569 return (error); 1570 1571 switch (uap->cmd) { 1572 case SEM_STAT: 1573 case IPC_STAT: 1574 bzero(&dsbuf32, sizeof(dsbuf32)); 1575 freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1576 PTROUT_CP(dsbuf, dsbuf32, sem_base); 1577 CP(dsbuf, dsbuf32, sem_nsems); 1578 CP(dsbuf, dsbuf32, sem_otime); 1579 CP(dsbuf, dsbuf32, sem_ctime); 1580 error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1581 break; 1582 } 1583 1584 if (error == 0) 1585 td->td_retval[0] = rval; 1586 return (error); 1587 } 1588 #endif 1589 1590 int 1591 freebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1592 { 1593 struct semid_ds32 dsbuf32; 1594 struct semid_ds dsbuf; 1595 union semun semun; 1596 union semun32 arg; 1597 register_t rval; 1598 int error; 1599 1600 switch (uap->cmd) { 1601 case SEM_STAT: 1602 case IPC_SET: 1603 case IPC_STAT: 1604 case GETALL: 1605 case SETVAL: 1606 case SETALL: 1607 error = copyin(uap->arg, &arg, sizeof(arg)); 1608 if (error) 1609 return (error); 1610 break; 1611 } 1612 1613 switch (uap->cmd) { 1614 case SEM_STAT: 1615 case IPC_STAT: 1616 semun.buf = &dsbuf; 1617 break; 1618 case IPC_SET: 1619 error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1620 if (error) 1621 return (error); 1622 freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1623 PTRIN_CP(dsbuf32, dsbuf, sem_base); 1624 CP(dsbuf32, dsbuf, sem_nsems); 1625 CP(dsbuf32, dsbuf, sem_otime); 1626 CP(dsbuf32, dsbuf, sem_ctime); 1627 semun.buf = &dsbuf; 1628 break; 1629 case GETALL: 1630 case SETALL: 1631 semun.array = PTRIN(arg.array); 1632 break; 1633 case SETVAL: 1634 semun.val = arg.val; 1635 break; 1636 } 1637 1638 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1639 &rval); 1640 if (error) 1641 return (error); 1642 1643 switch (uap->cmd) { 1644 case SEM_STAT: 1645 case IPC_STAT: 1646 bzero(&dsbuf32, sizeof(dsbuf32)); 1647 freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1648 PTROUT_CP(dsbuf, dsbuf32, sem_base); 1649 CP(dsbuf, dsbuf32, sem_nsems); 1650 CP(dsbuf, dsbuf32, sem_otime); 1651 CP(dsbuf, dsbuf32, sem_ctime); 1652 error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1653 break; 1654 } 1655 1656 if (error == 0) 1657 td->td_retval[0] = rval; 1658 return (error); 1659 } 1660 1661 #endif /* COMPAT_FREEBSD32 */ 1662