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