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