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