1 /* $NetBSD: sysv_sem.c,v 1.97 2019/04/10 10:03:50 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center, and by Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Implementation of SVID semaphores 35 * 36 * Author: Daniel Boulet 37 * 38 * This software is provided ``AS IS'' without any warranties of any kind. 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: sysv_sem.c,v 1.97 2019/04/10 10:03:50 pgoyette Exp $"); 43 44 #ifdef _KERNEL_OPT 45 #include "opt_sysv.h" 46 #endif 47 48 #include <sys/param.h> 49 #include <sys/kernel.h> 50 #include <sys/sem.h> 51 #include <sys/sysctl.h> 52 #include <sys/kmem.h> 53 #include <sys/mount.h> /* XXX for <sys/syscallargs.h> */ 54 #include <sys/syscallargs.h> 55 #include <sys/kauth.h> 56 #include <sys/once.h> 57 58 /* 59 * Memory areas: 60 * 1st: Pool of semaphore identifiers 61 * 2nd: Semaphores 62 * 3rd: Conditional variables 63 * 4th: Undo structures 64 */ 65 struct semid_ds * sema __read_mostly; 66 static struct __sem * sem __read_mostly; 67 static kcondvar_t * semcv __read_mostly; 68 static int * semu __read_mostly; 69 70 static kmutex_t semlock __cacheline_aligned; 71 static bool sem_realloc_state __read_mostly; 72 static kcondvar_t sem_realloc_cv; 73 74 /* 75 * List of active undo structures, total number of semaphores, 76 * and total number of semop waiters. 77 */ 78 static struct sem_undo *semu_list __read_mostly; 79 static u_int semtot __cacheline_aligned; 80 static u_int sem_waiters __cacheline_aligned; 81 82 /* Macro to find a particular sem_undo vector */ 83 #define SEMU(s, ix) ((struct sem_undo *)(((long)s) + ix * seminfo.semusz)) 84 85 #ifdef SEM_DEBUG 86 #define SEM_PRINTF(a) printf a 87 #else 88 #define SEM_PRINTF(a) 89 #endif 90 91 void *hook; /* cookie from exithook_establish() */ 92 93 extern int kern_has_sysvsem; 94 95 SYSCTL_SETUP_PROTO(sysctl_ipc_sem_setup); 96 97 struct sem_undo *semu_alloc(struct proc *); 98 int semundo_adjust(struct proc *, struct sem_undo **, int, int, int); 99 void semundo_clear(int, int); 100 101 static ONCE_DECL(exithook_control); 102 static int seminit_exithook(void); 103 104 int 105 seminit(struct sysctllog **clog) 106 { 107 int i, sz; 108 vaddr_t v; 109 110 mutex_init(&semlock, MUTEX_DEFAULT, IPL_NONE); 111 cv_init(&sem_realloc_cv, "semrealc"); 112 sem_realloc_state = false; 113 semtot = 0; 114 sem_waiters = 0; 115 116 /* Allocate the wired memory for our structures */ 117 sz = ALIGN(seminfo.semmni * sizeof(struct semid_ds)) + 118 ALIGN(seminfo.semmns * sizeof(struct __sem)) + 119 ALIGN(seminfo.semmni * sizeof(kcondvar_t)) + 120 ALIGN(seminfo.semmnu * seminfo.semusz); 121 sz = round_page(sz); 122 v = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_WIRED|UVM_KMF_ZERO); 123 if (v == 0) { 124 printf("sysv_sem: cannot allocate memory"); 125 return ENOMEM; 126 } 127 sema = (void *)v; 128 sem = (void *)((uintptr_t)sema + 129 ALIGN(seminfo.semmni * sizeof(struct semid_ds))); 130 semcv = (void *)((uintptr_t)sem + 131 ALIGN(seminfo.semmns * sizeof(struct __sem))); 132 semu = (void *)((uintptr_t)semcv + 133 ALIGN(seminfo.semmni * sizeof(kcondvar_t))); 134 135 for (i = 0; i < seminfo.semmni; i++) { 136 sema[i]._sem_base = 0; 137 sema[i].sem_perm.mode = 0; 138 cv_init(&semcv[i], "semwait"); 139 } 140 for (i = 0; i < seminfo.semmnu; i++) { 141 struct sem_undo *suptr = SEMU(semu, i); 142 suptr->un_proc = NULL; 143 } 144 semu_list = NULL; 145 146 kern_has_sysvsem = 1; 147 148 #ifdef _MODULE 149 if (clog) 150 sysctl_ipc_sem_setup(clog); 151 #endif 152 return 0; 153 } 154 155 static int 156 seminit_exithook(void) 157 { 158 159 hook = exithook_establish(semexit, NULL); 160 return 0; 161 } 162 163 int 164 semfini(void) 165 { 166 int i, sz; 167 vaddr_t v = (vaddr_t)sema; 168 169 /* Don't allow module unload if we're busy */ 170 mutex_enter(&semlock); 171 if (semtot) { 172 mutex_exit(&semlock); 173 return 1; 174 } 175 176 /* Remove the exit hook */ 177 if (hook) 178 exithook_disestablish(hook); 179 180 /* Destroy all our condvars */ 181 for (i = 0; i < seminfo.semmni; i++) { 182 cv_destroy(&semcv[i]); 183 } 184 185 /* Free the wired memory that we allocated */ 186 sz = ALIGN(seminfo.semmni * sizeof(struct semid_ds)) + 187 ALIGN(seminfo.semmns * sizeof(struct __sem)) + 188 ALIGN(seminfo.semmni * sizeof(kcondvar_t)) + 189 ALIGN(seminfo.semmnu * seminfo.semusz); 190 sz = round_page(sz); 191 uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED); 192 193 /* Destroy the last cv and mutex */ 194 cv_destroy(&sem_realloc_cv); 195 mutex_exit(&semlock); 196 mutex_destroy(&semlock); 197 198 kern_has_sysvsem = 0; 199 200 return 0; 201 } 202 203 static int 204 semrealloc(int newsemmni, int newsemmns, int newsemmnu) 205 { 206 struct semid_ds *new_sema, *old_sema; 207 struct __sem *new_sem; 208 struct sem_undo *new_semu_list, *suptr, *nsuptr; 209 int *new_semu; 210 kcondvar_t *new_semcv; 211 vaddr_t v; 212 int i, j, lsemid, nmnus, sz; 213 214 if (newsemmni < 1 || newsemmns < 1 || newsemmnu < 1) 215 return EINVAL; 216 217 /* Allocate the wired memory for our structures */ 218 sz = ALIGN(newsemmni * sizeof(struct semid_ds)) + 219 ALIGN(newsemmns * sizeof(struct __sem)) + 220 ALIGN(newsemmni * sizeof(kcondvar_t)) + 221 ALIGN(newsemmnu * seminfo.semusz); 222 sz = round_page(sz); 223 v = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_WIRED|UVM_KMF_ZERO); 224 if (v == 0) 225 return ENOMEM; 226 227 mutex_enter(&semlock); 228 if (sem_realloc_state) { 229 mutex_exit(&semlock); 230 uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED); 231 return EBUSY; 232 } 233 sem_realloc_state = true; 234 if (sem_waiters) { 235 /* 236 * Mark reallocation state, wake-up all waiters, 237 * and wait while they will all exit. 238 */ 239 for (i = 0; i < seminfo.semmni; i++) 240 cv_broadcast(&semcv[i]); 241 while (sem_waiters) 242 cv_wait(&sem_realloc_cv, &semlock); 243 } 244 old_sema = sema; 245 246 /* Get the number of last slot */ 247 lsemid = 0; 248 for (i = 0; i < seminfo.semmni; i++) 249 if (sema[i].sem_perm.mode & SEM_ALLOC) 250 lsemid = i; 251 252 /* Get the number of currently used undo structures */ 253 nmnus = 0; 254 for (i = 0; i < seminfo.semmnu; i++) { 255 suptr = SEMU(semu, i); 256 if (suptr->un_proc == NULL) 257 continue; 258 nmnus++; 259 } 260 261 /* We cannot reallocate less memory than we use */ 262 if (lsemid >= newsemmni || semtot > newsemmns || nmnus > newsemmnu) { 263 mutex_exit(&semlock); 264 uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED); 265 return EBUSY; 266 } 267 268 new_sema = (void *)v; 269 new_sem = (void *)((uintptr_t)new_sema + 270 ALIGN(newsemmni * sizeof(struct semid_ds))); 271 new_semcv = (void *)((uintptr_t)new_sem + 272 ALIGN(newsemmns * sizeof(struct __sem))); 273 new_semu = (void *)((uintptr_t)new_semcv + 274 ALIGN(newsemmni * sizeof(kcondvar_t))); 275 276 /* Initialize all semaphore identifiers and condvars */ 277 for (i = 0; i < newsemmni; i++) { 278 new_sema[i]._sem_base = 0; 279 new_sema[i].sem_perm.mode = 0; 280 cv_init(&new_semcv[i], "semwait"); 281 } 282 for (i = 0; i < newsemmnu; i++) { 283 nsuptr = SEMU(new_semu, i); 284 nsuptr->un_proc = NULL; 285 } 286 287 /* 288 * Copy all identifiers, semaphores and list of the 289 * undo structures to the new memory allocation. 290 */ 291 j = 0; 292 for (i = 0; i <= lsemid; i++) { 293 if ((sema[i].sem_perm.mode & SEM_ALLOC) == 0) 294 continue; 295 memcpy(&new_sema[i], &sema[i], sizeof(struct semid_ds)); 296 new_sema[i]._sem_base = &new_sem[j]; 297 memcpy(new_sema[i]._sem_base, sema[i]._sem_base, 298 (sizeof(struct __sem) * sema[i].sem_nsems)); 299 j += sema[i].sem_nsems; 300 } 301 KASSERT(j == semtot); 302 303 j = 0; 304 new_semu_list = NULL; 305 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { 306 KASSERT(j < newsemmnu); 307 nsuptr = SEMU(new_semu, j); 308 memcpy(nsuptr, suptr, SEMUSZ); 309 nsuptr->un_next = new_semu_list; 310 new_semu_list = nsuptr; 311 j++; 312 } 313 314 for (i = 0; i < seminfo.semmni; i++) { 315 KASSERT(cv_has_waiters(&semcv[i]) == false); 316 cv_destroy(&semcv[i]); 317 } 318 319 sz = ALIGN(seminfo.semmni * sizeof(struct semid_ds)) + 320 ALIGN(seminfo.semmns * sizeof(struct __sem)) + 321 ALIGN(seminfo.semmni * sizeof(kcondvar_t)) + 322 ALIGN(seminfo.semmnu * seminfo.semusz); 323 sz = round_page(sz); 324 325 /* Set the pointers and update the new values */ 326 sema = new_sema; 327 sem = new_sem; 328 semcv = new_semcv; 329 semu = new_semu; 330 semu_list = new_semu_list; 331 332 seminfo.semmni = newsemmni; 333 seminfo.semmns = newsemmns; 334 seminfo.semmnu = newsemmnu; 335 336 /* Reallocation completed - notify all waiters, if any */ 337 sem_realloc_state = false; 338 cv_broadcast(&sem_realloc_cv); 339 mutex_exit(&semlock); 340 341 uvm_km_free(kernel_map, (vaddr_t)old_sema, sz, UVM_KMF_WIRED); 342 return 0; 343 } 344 345 /* 346 * Placebo. 347 */ 348 349 int 350 sys_semconfig(struct lwp *l, const struct sys_semconfig_args *uap, register_t *retval) 351 { 352 353 RUN_ONCE(&exithook_control, seminit_exithook); 354 355 *retval = 0; 356 return 0; 357 } 358 359 /* 360 * Allocate a new sem_undo structure for a process. 361 * => Returns NULL on failure. 362 */ 363 struct sem_undo * 364 semu_alloc(struct proc *p) 365 { 366 struct sem_undo *suptr, **supptr; 367 bool attempted = false; 368 int i; 369 370 KASSERT(mutex_owned(&semlock)); 371 again: 372 /* Look for a free structure. */ 373 for (i = 0; i < seminfo.semmnu; i++) { 374 suptr = SEMU(semu, i); 375 if (suptr->un_proc == NULL) { 376 /* Found. Fill it in and return. */ 377 suptr->un_next = semu_list; 378 semu_list = suptr; 379 suptr->un_cnt = 0; 380 suptr->un_proc = p; 381 return suptr; 382 } 383 } 384 385 /* Not found. Attempt to free some structures. */ 386 if (!attempted) { 387 bool freed = false; 388 389 attempted = true; 390 supptr = &semu_list; 391 while ((suptr = *supptr) != NULL) { 392 if (suptr->un_cnt == 0) { 393 suptr->un_proc = NULL; 394 *supptr = suptr->un_next; 395 freed = true; 396 } else { 397 supptr = &suptr->un_next; 398 } 399 } 400 if (freed) { 401 goto again; 402 } 403 } 404 return NULL; 405 } 406 407 /* 408 * Adjust a particular entry for a particular proc 409 */ 410 411 int 412 semundo_adjust(struct proc *p, struct sem_undo **supptr, int semid, int semnum, 413 int adjval) 414 { 415 struct sem_undo *suptr; 416 struct sem_undo_entry *sunptr; 417 int i; 418 419 KASSERT(mutex_owned(&semlock)); 420 421 /* 422 * Look for and remember the sem_undo if the caller doesn't 423 * provide it 424 */ 425 426 suptr = *supptr; 427 if (suptr == NULL) { 428 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) 429 if (suptr->un_proc == p) 430 break; 431 432 if (suptr == NULL) { 433 suptr = semu_alloc(p); 434 if (suptr == NULL) 435 return (ENOSPC); 436 } 437 *supptr = suptr; 438 } 439 440 /* 441 * Look for the requested entry and adjust it (delete if 442 * adjval becomes 0). 443 */ 444 sunptr = &suptr->un_ent[0]; 445 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 446 if (sunptr->un_id != semid || sunptr->un_num != semnum) 447 continue; 448 sunptr->un_adjval += adjval; 449 if (sunptr->un_adjval == 0) { 450 suptr->un_cnt--; 451 if (i < suptr->un_cnt) 452 suptr->un_ent[i] = 453 suptr->un_ent[suptr->un_cnt]; 454 } 455 return (0); 456 } 457 458 /* Didn't find the right entry - create it */ 459 if (suptr->un_cnt == SEMUME) 460 return (EINVAL); 461 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 return (0); 468 } 469 470 void 471 semundo_clear(int semid, int semnum) 472 { 473 struct sem_undo *suptr; 474 struct sem_undo_entry *sunptr, *sunend; 475 476 KASSERT(mutex_owned(&semlock)); 477 478 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) 479 for (sunptr = &suptr->un_ent[0], 480 sunend = sunptr + suptr->un_cnt; sunptr < sunend;) { 481 if (sunptr->un_id == semid) { 482 if (semnum == -1 || sunptr->un_num == semnum) { 483 suptr->un_cnt--; 484 sunend--; 485 if (sunptr != sunend) 486 *sunptr = *sunend; 487 if (semnum != -1) 488 break; 489 else 490 continue; 491 } 492 } 493 sunptr++; 494 } 495 } 496 497 int 498 sys_____semctl50(struct lwp *l, const struct sys_____semctl50_args *uap, 499 register_t *retval) 500 { 501 /* { 502 syscallarg(int) semid; 503 syscallarg(int) semnum; 504 syscallarg(int) cmd; 505 syscallarg(union __semun *) arg; 506 } */ 507 struct semid_ds sembuf; 508 int cmd, error; 509 void *pass_arg; 510 union __semun karg; 511 512 RUN_ONCE(&exithook_control, seminit_exithook); 513 514 cmd = SCARG(uap, cmd); 515 516 pass_arg = get_semctl_arg(cmd, &sembuf, &karg); 517 518 if (pass_arg) { 519 error = copyin(SCARG(uap, arg), &karg, sizeof(karg)); 520 if (error) 521 return error; 522 if (cmd == IPC_SET) { 523 error = copyin(karg.buf, &sembuf, sizeof(sembuf)); 524 if (error) 525 return (error); 526 } 527 } 528 529 error = semctl1(l, SCARG(uap, semid), SCARG(uap, semnum), cmd, 530 pass_arg, retval); 531 532 if (error == 0 && cmd == IPC_STAT) 533 error = copyout(&sembuf, karg.buf, sizeof(sembuf)); 534 535 return (error); 536 } 537 538 int 539 semctl1(struct lwp *l, int semid, int semnum, int cmd, void *v, 540 register_t *retval) 541 { 542 kauth_cred_t cred = l->l_cred; 543 union __semun *arg = v; 544 struct semid_ds *sembuf = v, *semaptr; 545 int i, error, ix; 546 547 SEM_PRINTF(("call to semctl(%d, %d, %d, %p)\n", 548 semid, semnum, cmd, v)); 549 550 mutex_enter(&semlock); 551 552 ix = IPCID_TO_IX(semid); 553 if (ix < 0 || ix >= seminfo.semmni) { 554 mutex_exit(&semlock); 555 return (EINVAL); 556 } 557 558 semaptr = &sema[ix]; 559 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 560 semaptr->sem_perm._seq != IPCID_TO_SEQ(semid)) { 561 mutex_exit(&semlock); 562 return (EINVAL); 563 } 564 565 switch (cmd) { 566 case IPC_RMID: 567 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)) != 0) 568 break; 569 semaptr->sem_perm.cuid = kauth_cred_geteuid(cred); 570 semaptr->sem_perm.uid = kauth_cred_geteuid(cred); 571 semtot -= semaptr->sem_nsems; 572 for (i = semaptr->_sem_base - sem; i < semtot; i++) 573 sem[i] = sem[i + semaptr->sem_nsems]; 574 for (i = 0; i < seminfo.semmni; i++) { 575 if ((sema[i].sem_perm.mode & SEM_ALLOC) && 576 sema[i]._sem_base > semaptr->_sem_base) 577 sema[i]._sem_base -= semaptr->sem_nsems; 578 } 579 semaptr->sem_perm.mode = 0; 580 semundo_clear(ix, -1); 581 cv_broadcast(&semcv[ix]); 582 break; 583 584 case IPC_SET: 585 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M))) 586 break; 587 KASSERT(sembuf != NULL); 588 semaptr->sem_perm.uid = sembuf->sem_perm.uid; 589 semaptr->sem_perm.gid = sembuf->sem_perm.gid; 590 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | 591 (sembuf->sem_perm.mode & 0777); 592 semaptr->sem_ctime = time_second; 593 break; 594 595 case IPC_STAT: 596 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 597 break; 598 KASSERT(sembuf != NULL); 599 memset(sembuf, 0, sizeof *sembuf); 600 sembuf->sem_perm = semaptr->sem_perm; 601 sembuf->sem_perm.mode &= 0777; 602 sembuf->sem_nsems = semaptr->sem_nsems; 603 sembuf->sem_otime = semaptr->sem_otime; 604 sembuf->sem_ctime = semaptr->sem_ctime; 605 break; 606 607 case GETNCNT: 608 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 609 break; 610 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 611 error = EINVAL; 612 break; 613 } 614 *retval = semaptr->_sem_base[semnum].semncnt; 615 break; 616 617 case GETPID: 618 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 619 break; 620 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 621 error = EINVAL; 622 break; 623 } 624 *retval = semaptr->_sem_base[semnum].sempid; 625 break; 626 627 case GETVAL: 628 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 629 break; 630 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 631 error = EINVAL; 632 break; 633 } 634 *retval = semaptr->_sem_base[semnum].semval; 635 break; 636 637 case GETALL: 638 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 639 break; 640 KASSERT(arg != NULL); 641 for (i = 0; i < semaptr->sem_nsems; i++) { 642 error = copyout(&semaptr->_sem_base[i].semval, 643 &arg->array[i], sizeof(arg->array[i])); 644 if (error != 0) 645 break; 646 } 647 break; 648 649 case GETZCNT: 650 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 651 break; 652 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 653 error = EINVAL; 654 break; 655 } 656 *retval = semaptr->_sem_base[semnum].semzcnt; 657 break; 658 659 case SETVAL: 660 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 661 break; 662 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 663 error = EINVAL; 664 break; 665 } 666 KASSERT(arg != NULL); 667 if ((unsigned int)arg->val > seminfo.semvmx) { 668 error = ERANGE; 669 break; 670 } 671 semaptr->_sem_base[semnum].semval = arg->val; 672 semundo_clear(ix, semnum); 673 cv_broadcast(&semcv[ix]); 674 break; 675 676 case SETALL: 677 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 678 break; 679 KASSERT(arg != NULL); 680 for (i = 0; i < semaptr->sem_nsems; i++) { 681 unsigned short semval; 682 error = copyin(&arg->array[i], &semval, 683 sizeof(arg->array[i])); 684 if (error != 0) 685 break; 686 if ((unsigned int)semval > seminfo.semvmx) { 687 error = ERANGE; 688 break; 689 } 690 semaptr->_sem_base[i].semval = semval; 691 } 692 semundo_clear(ix, -1); 693 cv_broadcast(&semcv[ix]); 694 break; 695 696 default: 697 error = EINVAL; 698 break; 699 } 700 701 mutex_exit(&semlock); 702 return (error); 703 } 704 705 int 706 sys_semget(struct lwp *l, const struct sys_semget_args *uap, register_t *retval) 707 { 708 /* { 709 syscallarg(key_t) key; 710 syscallarg(int) nsems; 711 syscallarg(int) semflg; 712 } */ 713 int semid, error = 0; 714 int key = SCARG(uap, key); 715 int nsems = SCARG(uap, nsems); 716 int semflg = SCARG(uap, semflg); 717 kauth_cred_t cred = l->l_cred; 718 719 RUN_ONCE(&exithook_control, seminit_exithook); 720 721 SEM_PRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 722 723 mutex_enter(&semlock); 724 725 if (key != IPC_PRIVATE) { 726 for (semid = 0; semid < seminfo.semmni; semid++) { 727 if ((sema[semid].sem_perm.mode & SEM_ALLOC) && 728 sema[semid].sem_perm._key == key) 729 break; 730 } 731 if (semid < seminfo.semmni) { 732 SEM_PRINTF(("found public key\n")); 733 if ((error = ipcperm(cred, &sema[semid].sem_perm, 734 semflg & 0700))) 735 goto out; 736 if (nsems > 0 && sema[semid].sem_nsems < nsems) { 737 SEM_PRINTF(("too small\n")); 738 error = EINVAL; 739 goto out; 740 } 741 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 742 SEM_PRINTF(("not exclusive\n")); 743 error = EEXIST; 744 goto out; 745 } 746 goto found; 747 } 748 } 749 750 SEM_PRINTF(("need to allocate the semid_ds\n")); 751 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 752 if (nsems <= 0 || nsems > seminfo.semmsl) { 753 SEM_PRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 754 seminfo.semmsl)); 755 error = EINVAL; 756 goto out; 757 } 758 if (nsems > seminfo.semmns - semtot) { 759 SEM_PRINTF(("not enough semaphores left " 760 "(need %d, got %d)\n", 761 nsems, seminfo.semmns - semtot)); 762 error = ENOSPC; 763 goto out; 764 } 765 for (semid = 0; semid < seminfo.semmni; semid++) { 766 if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0) 767 break; 768 } 769 if (semid == seminfo.semmni) { 770 SEM_PRINTF(("no more semid_ds's available\n")); 771 error = ENOSPC; 772 goto out; 773 } 774 SEM_PRINTF(("semid %d is available\n", semid)); 775 sema[semid].sem_perm._key = key; 776 sema[semid].sem_perm.cuid = kauth_cred_geteuid(cred); 777 sema[semid].sem_perm.uid = kauth_cred_geteuid(cred); 778 sema[semid].sem_perm.cgid = kauth_cred_getegid(cred); 779 sema[semid].sem_perm.gid = kauth_cred_getegid(cred); 780 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 781 sema[semid].sem_perm._seq = 782 (sema[semid].sem_perm._seq + 1) & 0x7fff; 783 sema[semid].sem_nsems = nsems; 784 sema[semid].sem_otime = 0; 785 sema[semid].sem_ctime = time_second; 786 sema[semid]._sem_base = &sem[semtot]; 787 semtot += nsems; 788 memset(sema[semid]._sem_base, 0, 789 sizeof(sema[semid]._sem_base[0]) * nsems); 790 SEM_PRINTF(("sembase = %p, next = %p\n", sema[semid]._sem_base, 791 &sem[semtot])); 792 } else { 793 SEM_PRINTF(("didn't find it and wasn't asked to create it\n")); 794 error = ENOENT; 795 goto out; 796 } 797 798 found: 799 *retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); 800 out: 801 mutex_exit(&semlock); 802 return (error); 803 } 804 805 #define SMALL_SOPS 8 806 807 int 808 sys_semop(struct lwp *l, const struct sys_semop_args *uap, register_t *retval) 809 { 810 /* { 811 syscallarg(int) semid; 812 syscallarg(struct sembuf *) sops; 813 syscallarg(size_t) nsops; 814 } */ 815 struct proc *p = l->l_proc; 816 int semid = SCARG(uap, semid), seq; 817 size_t nsops = SCARG(uap, nsops); 818 struct sembuf small_sops[SMALL_SOPS]; 819 struct sembuf *sops; 820 struct semid_ds *semaptr; 821 struct sembuf *sopptr = NULL; 822 struct __sem *semptr = NULL; 823 struct sem_undo *suptr = NULL; 824 kauth_cred_t cred = l->l_cred; 825 int i, error; 826 int do_wakeup, do_undos; 827 828 RUN_ONCE(&exithook_control, seminit_exithook); 829 830 SEM_PRINTF(("call to semop(%d, %p, %zd)\n", semid, SCARG(uap,sops), nsops)); 831 832 if (__predict_false((p->p_flag & PK_SYSVSEM) == 0)) { 833 mutex_enter(p->p_lock); 834 p->p_flag |= PK_SYSVSEM; 835 mutex_exit(p->p_lock); 836 } 837 838 restart: 839 if (nsops <= SMALL_SOPS) { 840 sops = small_sops; 841 } else if (nsops <= seminfo.semopm) { 842 sops = kmem_alloc(nsops * sizeof(*sops), KM_SLEEP); 843 } else { 844 SEM_PRINTF(("too many sops (max=%d, nsops=%zd)\n", 845 seminfo.semopm, nsops)); 846 return (E2BIG); 847 } 848 849 error = copyin(SCARG(uap, sops), sops, nsops * sizeof(sops[0])); 850 if (error) { 851 SEM_PRINTF(("error = %d from copyin(%p, %p, %zd)\n", error, 852 SCARG(uap, sops), &sops, nsops * sizeof(sops[0]))); 853 if (sops != small_sops) 854 kmem_free(sops, nsops * sizeof(*sops)); 855 return error; 856 } 857 858 mutex_enter(&semlock); 859 /* In case of reallocation, we will wait for completion */ 860 while (__predict_false(sem_realloc_state)) 861 cv_wait(&sem_realloc_cv, &semlock); 862 863 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 864 if (semid < 0 || semid >= seminfo.semmni) { 865 error = EINVAL; 866 goto out; 867 } 868 869 semaptr = &sema[semid]; 870 seq = IPCID_TO_SEQ(SCARG(uap, semid)); 871 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 872 semaptr->sem_perm._seq != seq) { 873 error = EINVAL; 874 goto out; 875 } 876 877 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) { 878 SEM_PRINTF(("error = %d from ipaccess\n", error)); 879 goto out; 880 } 881 882 for (i = 0; i < nsops; i++) 883 if (sops[i].sem_num >= semaptr->sem_nsems) { 884 error = EFBIG; 885 goto out; 886 } 887 888 /* 889 * Loop trying to satisfy the vector of requests. 890 * If we reach a point where we must wait, any requests already 891 * performed are rolled back and we go to sleep until some other 892 * process wakes us up. At this point, we start all over again. 893 * 894 * This ensures that from the perspective of other tasks, a set 895 * of requests is atomic (never partially satisfied). 896 */ 897 do_undos = 0; 898 899 for (;;) { 900 do_wakeup = 0; 901 902 for (i = 0; i < nsops; i++) { 903 sopptr = &sops[i]; 904 semptr = &semaptr->_sem_base[sopptr->sem_num]; 905 906 SEM_PRINTF(("semop: semaptr=%p, sem_base=%p, " 907 "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 908 semaptr, semaptr->_sem_base, semptr, 909 sopptr->sem_num, semptr->semval, sopptr->sem_op, 910 (sopptr->sem_flg & IPC_NOWAIT) ? 911 "nowait" : "wait")); 912 913 if (sopptr->sem_op < 0) { 914 if ((int)(semptr->semval + 915 sopptr->sem_op) < 0) { 916 SEM_PRINTF(("semop: " 917 "can't do it now\n")); 918 break; 919 } else { 920 semptr->semval += sopptr->sem_op; 921 if (semptr->semval == 0 && 922 semptr->semzcnt > 0) 923 do_wakeup = 1; 924 } 925 if (sopptr->sem_flg & SEM_UNDO) 926 do_undos = 1; 927 } else if (sopptr->sem_op == 0) { 928 if (semptr->semval > 0) { 929 SEM_PRINTF(("semop: not zero now\n")); 930 break; 931 } 932 } else { 933 if (semptr->semncnt > 0) 934 do_wakeup = 1; 935 semptr->semval += sopptr->sem_op; 936 if (sopptr->sem_flg & SEM_UNDO) 937 do_undos = 1; 938 } 939 } 940 941 /* 942 * Did we get through the entire vector? 943 */ 944 if (i >= nsops) 945 goto done; 946 947 /* 948 * No ... rollback anything that we've already done 949 */ 950 SEM_PRINTF(("semop: rollback 0 through %d\n", i - 1)); 951 while (i-- > 0) 952 semaptr->_sem_base[sops[i].sem_num].semval -= 953 sops[i].sem_op; 954 955 /* 956 * If the request that we couldn't satisfy has the 957 * NOWAIT flag set then return with EAGAIN. 958 */ 959 if (sopptr->sem_flg & IPC_NOWAIT) { 960 error = EAGAIN; 961 goto out; 962 } 963 964 if (sopptr->sem_op == 0) 965 semptr->semzcnt++; 966 else 967 semptr->semncnt++; 968 969 sem_waiters++; 970 SEM_PRINTF(("semop: good night!\n")); 971 error = cv_wait_sig(&semcv[semid], &semlock); 972 SEM_PRINTF(("semop: good morning (error=%d)!\n", error)); 973 sem_waiters--; 974 975 /* Notify reallocator, if it is waiting */ 976 cv_broadcast(&sem_realloc_cv); 977 978 /* 979 * Make sure that the semaphore still exists 980 */ 981 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 982 semaptr->sem_perm._seq != seq) { 983 error = EIDRM; 984 goto out; 985 } 986 987 /* 988 * The semaphore is still alive. Readjust the count of 989 * waiting processes. 990 */ 991 semptr = &semaptr->_sem_base[sopptr->sem_num]; 992 if (sopptr->sem_op == 0) 993 semptr->semzcnt--; 994 else 995 semptr->semncnt--; 996 997 /* In case of such state, restart the call */ 998 if (sem_realloc_state) { 999 mutex_exit(&semlock); 1000 goto restart; 1001 } 1002 1003 /* Is it really morning, or was our sleep interrupted? */ 1004 if (error != 0) { 1005 error = EINTR; 1006 goto out; 1007 } 1008 SEM_PRINTF(("semop: good morning!\n")); 1009 } 1010 1011 done: 1012 /* 1013 * Process any SEM_UNDO requests. 1014 */ 1015 if (do_undos) { 1016 for (i = 0; i < nsops; i++) { 1017 /* 1018 * We only need to deal with SEM_UNDO's for non-zero 1019 * op's. 1020 */ 1021 int adjval; 1022 1023 if ((sops[i].sem_flg & SEM_UNDO) == 0) 1024 continue; 1025 adjval = sops[i].sem_op; 1026 if (adjval == 0) 1027 continue; 1028 error = semundo_adjust(p, &suptr, semid, 1029 sops[i].sem_num, -adjval); 1030 if (error == 0) 1031 continue; 1032 1033 /* 1034 * Oh-Oh! We ran out of either sem_undo's or undo's. 1035 * Rollback the adjustments to this point and then 1036 * rollback the semaphore ups and down so we can return 1037 * with an error with all structures restored. We 1038 * rollback the undo's in the exact reverse order that 1039 * we applied them. This guarantees that we won't run 1040 * out of space as we roll things back out. 1041 */ 1042 while (i-- > 0) { 1043 if ((sops[i].sem_flg & SEM_UNDO) == 0) 1044 continue; 1045 adjval = sops[i].sem_op; 1046 if (adjval == 0) 1047 continue; 1048 if (semundo_adjust(p, &suptr, semid, 1049 sops[i].sem_num, adjval) != 0) 1050 panic("semop - can't undo undos"); 1051 } 1052 1053 for (i = 0; i < nsops; i++) 1054 semaptr->_sem_base[sops[i].sem_num].semval -= 1055 sops[i].sem_op; 1056 1057 SEM_PRINTF(("error = %d from semundo_adjust\n", error)); 1058 goto out; 1059 } /* loop through the sops */ 1060 } /* if (do_undos) */ 1061 1062 /* We're definitely done - set the sempid's */ 1063 for (i = 0; i < nsops; i++) { 1064 sopptr = &sops[i]; 1065 semptr = &semaptr->_sem_base[sopptr->sem_num]; 1066 semptr->sempid = p->p_pid; 1067 } 1068 1069 /* Update sem_otime */ 1070 semaptr->sem_otime = time_second; 1071 1072 /* Do a wakeup if any semaphore was up'd. */ 1073 if (do_wakeup) { 1074 SEM_PRINTF(("semop: doing wakeup\n")); 1075 cv_broadcast(&semcv[semid]); 1076 SEM_PRINTF(("semop: back from wakeup\n")); 1077 } 1078 SEM_PRINTF(("semop: done\n")); 1079 *retval = 0; 1080 1081 out: 1082 mutex_exit(&semlock); 1083 if (sops != small_sops) 1084 kmem_free(sops, nsops * sizeof(*sops)); 1085 return error; 1086 } 1087 1088 /* 1089 * Go through the undo structures for this process and apply the 1090 * adjustments to semaphores. 1091 */ 1092 /*ARGSUSED*/ 1093 void 1094 semexit(struct proc *p, void *v) 1095 { 1096 struct sem_undo *suptr; 1097 struct sem_undo **supptr; 1098 1099 if ((p->p_flag & PK_SYSVSEM) == 0) 1100 return; 1101 1102 mutex_enter(&semlock); 1103 1104 /* 1105 * Go through the chain of undo vectors looking for one 1106 * associated with this process. 1107 */ 1108 1109 for (supptr = &semu_list; (suptr = *supptr) != NULL; 1110 supptr = &suptr->un_next) { 1111 if (suptr->un_proc == p) 1112 break; 1113 } 1114 1115 /* 1116 * If there is no undo vector, skip to the end. 1117 */ 1118 1119 if (suptr == NULL) { 1120 mutex_exit(&semlock); 1121 return; 1122 } 1123 1124 /* 1125 * We now have an undo vector for this process. 1126 */ 1127 1128 SEM_PRINTF(("proc @%p has undo structure with %d entries\n", p, 1129 suptr->un_cnt)); 1130 1131 /* 1132 * If there are any active undo elements then process them. 1133 */ 1134 if (suptr->un_cnt > 0) { 1135 int ix; 1136 1137 for (ix = 0; ix < suptr->un_cnt; ix++) { 1138 int semid = suptr->un_ent[ix].un_id; 1139 int semnum = suptr->un_ent[ix].un_num; 1140 int adjval = suptr->un_ent[ix].un_adjval; 1141 struct semid_ds *semaptr; 1142 1143 semaptr = &sema[semid]; 1144 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) 1145 if (semnum >= semaptr->sem_nsems) 1146 panic("semexit - semnum out of range"); 1147 1148 SEM_PRINTF(("semexit: %p id=%d num=%d(adj=%d) ; " 1149 "sem=%d\n", 1150 suptr->un_proc, suptr->un_ent[ix].un_id, 1151 suptr->un_ent[ix].un_num, 1152 suptr->un_ent[ix].un_adjval, 1153 semaptr->_sem_base[semnum].semval)); 1154 1155 if (adjval < 0 && 1156 semaptr->_sem_base[semnum].semval < -adjval) 1157 semaptr->_sem_base[semnum].semval = 0; 1158 else 1159 semaptr->_sem_base[semnum].semval += adjval; 1160 1161 cv_broadcast(&semcv[semid]); 1162 SEM_PRINTF(("semexit: back from wakeup\n")); 1163 } 1164 } 1165 1166 /* 1167 * Deallocate the undo vector. 1168 */ 1169 SEM_PRINTF(("removing vector\n")); 1170 suptr->un_proc = NULL; 1171 *supptr = suptr->un_next; 1172 mutex_exit(&semlock); 1173 } 1174 1175 /* 1176 * Sysctl initialization and nodes. 1177 */ 1178 1179 static int 1180 sysctl_ipc_semmni(SYSCTLFN_ARGS) 1181 { 1182 int newsize, error; 1183 struct sysctlnode node; 1184 node = *rnode; 1185 node.sysctl_data = &newsize; 1186 1187 newsize = seminfo.semmni; 1188 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1189 if (error || newp == NULL) 1190 return error; 1191 1192 return semrealloc(newsize, seminfo.semmns, seminfo.semmnu); 1193 } 1194 1195 static int 1196 sysctl_ipc_semmns(SYSCTLFN_ARGS) 1197 { 1198 int newsize, error; 1199 struct sysctlnode node; 1200 node = *rnode; 1201 node.sysctl_data = &newsize; 1202 1203 newsize = seminfo.semmns; 1204 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1205 if (error || newp == NULL) 1206 return error; 1207 1208 return semrealloc(seminfo.semmni, newsize, seminfo.semmnu); 1209 } 1210 1211 static int 1212 sysctl_ipc_semmnu(SYSCTLFN_ARGS) 1213 { 1214 int newsize, error; 1215 struct sysctlnode node; 1216 node = *rnode; 1217 node.sysctl_data = &newsize; 1218 1219 newsize = seminfo.semmnu; 1220 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1221 if (error || newp == NULL) 1222 return error; 1223 1224 return semrealloc(seminfo.semmni, seminfo.semmns, newsize); 1225 } 1226 1227 SYSCTL_SETUP(sysctl_ipc_sem_setup, "sysctl kern.ipc subtree setup") 1228 { 1229 const struct sysctlnode *node = NULL; 1230 1231 sysctl_createv(clog, 0, NULL, &node, 1232 CTLFLAG_PERMANENT, 1233 CTLTYPE_NODE, "ipc", 1234 SYSCTL_DESCR("SysV IPC options"), 1235 NULL, 0, NULL, 0, 1236 CTL_KERN, KERN_SYSVIPC, CTL_EOL); 1237 1238 if (node == NULL) 1239 return; 1240 1241 sysctl_createv(clog, 0, &node, NULL, 1242 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1243 CTLTYPE_INT, "semmni", 1244 SYSCTL_DESCR("Max number of number of semaphore identifiers"), 1245 sysctl_ipc_semmni, 0, &seminfo.semmni, 0, 1246 CTL_CREATE, CTL_EOL); 1247 sysctl_createv(clog, 0, &node, NULL, 1248 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1249 CTLTYPE_INT, "semmns", 1250 SYSCTL_DESCR("Max number of number of semaphores in system"), 1251 sysctl_ipc_semmns, 0, &seminfo.semmns, 0, 1252 CTL_CREATE, CTL_EOL); 1253 sysctl_createv(clog, 0, &node, NULL, 1254 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1255 CTLTYPE_INT, "semmnu", 1256 SYSCTL_DESCR("Max number of undo structures in system"), 1257 sysctl_ipc_semmnu, 0, &seminfo.semmnu, 0, 1258 CTL_CREATE, CTL_EOL); 1259 } 1260