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