1139804Simp/*- 22729Sdfr * Implementation of SVID semaphores 32729Sdfr * 42729Sdfr * Author: Daniel Boulet 52729Sdfr * 62729Sdfr * This software is provided ``AS IS'' without any warranties of any kind. 72729Sdfr */ 8140615Srwatson/*- 9140615Srwatson * Copyright (c) 2003-2005 McAfee, Inc. 10140615Srwatson * All rights reserved. 11140615Srwatson * 12140615Srwatson * This software was developed for the FreeBSD Project in part by McAfee 13140615Srwatson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR 14140615Srwatson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research 15140615Srwatson * program. 16140615Srwatson * 17140615Srwatson * Redistribution and use in source and binary forms, with or without 18140615Srwatson * modification, are permitted provided that the following conditions 19140615Srwatson * are met: 20140615Srwatson * 1. Redistributions of source code must retain the above copyright 21140615Srwatson * notice, this list of conditions and the following disclaimer. 22140615Srwatson * 2. Redistributions in binary form must reproduce the above copyright 23140615Srwatson * notice, this list of conditions and the following disclaimer in the 24140615Srwatson * documentation and/or other materials provided with the distribution. 25140615Srwatson * 26140615Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27140615Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28140615Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29140615Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30140615Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31140615Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32140615Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33140615Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34140615Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35140615Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36140615Srwatson * SUCH DAMAGE. 37140615Srwatson */ 382729Sdfr 39116182Sobrien#include <sys/cdefs.h> 40116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/sysv_sem.c 367129 2020-10-29 11:19:47Z kib $"); 41116182Sobrien 42194894Sjhb#include "opt_compat.h" 4359839Speter#include "opt_sysvipc.h" 4459839Speter 452729Sdfr#include <sys/param.h> 462729Sdfr#include <sys/systm.h> 4711626Sbde#include <sys/sysproto.h> 48360451Sbrooks#include <sys/abi_compat.h> 49112564Sjhb#include <sys/eventhandler.h> 502729Sdfr#include <sys/kernel.h> 512729Sdfr#include <sys/proc.h> 5282607Sdillon#include <sys/lock.h> 53129882Sphk#include <sys/module.h> 5482607Sdillon#include <sys/mutex.h> 55220398Strasz#include <sys/racct.h> 562729Sdfr#include <sys/sem.h> 57298585Sjamie#include <sys/sx.h> 5869449Salfred#include <sys/syscall.h> 59159991Sjhb#include <sys/syscallsubr.h> 6011626Sbde#include <sys/sysent.h> 6159839Speter#include <sys/sysctl.h> 62159991Sjhb#include <sys/uio.h> 6359839Speter#include <sys/malloc.h> 6468024Srwatson#include <sys/jail.h> 652729Sdfr 66163606Srwatson#include <security/mac/mac_framework.h> 67163606Srwatson 68219028SnetchildFEATURE(sysv_sem, "System V semaphores support"); 69219028Snetchild 7059839Speterstatic MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 7159839Speter 72100523Salfred#ifdef SEM_DEBUG 73100523Salfred#define DPRINTF(a) printf a 74100523Salfred#else 75100523Salfred#define DPRINTF(a) 76100523Salfred#endif 77100523Salfred 78205323Skibstatic int seminit(void); 7992723Salfredstatic int sysvsem_modload(struct module *, int, void *); 8092723Salfredstatic int semunload(void); 81112564Sjhbstatic void semexit_myhook(void *arg, struct proc *p); 8292723Salfredstatic int sysctl_sema(SYSCTL_HANDLER_ARGS); 83298585Sjamiestatic int semvalid(int semid, struct prison *rpr, 84298585Sjamie struct semid_kernel *semakptr); 85298585Sjamiestatic void sem_remove(int semidx, struct ucred *cred); 86298585Sjamiestatic struct prison *sem_find_prison(struct ucred *); 87298585Sjamiestatic int sem_prison_cansee(struct prison *, struct semid_kernel *); 88298585Sjamiestatic int sem_prison_check(void *, void *); 89298585Sjamiestatic int sem_prison_set(void *, void *); 90298585Sjamiestatic int sem_prison_get(void *, void *); 91298585Sjamiestatic int sem_prison_remove(void *, void *); 92298585Sjamiestatic void sem_prison_cleanup(struct prison *); 9310358Sjulian 9412866Speter#ifndef _SYS_SYSPROTO_H_ 9512866Speterstruct __semctl_args; 9692723Salfredint __semctl(struct thread *td, struct __semctl_args *uap); 9711626Sbdestruct semget_args; 9892723Salfredint semget(struct thread *td, struct semget_args *uap); 9911626Sbdestruct semop_args; 10092723Salfredint semop(struct thread *td, struct semop_args *uap); 10112866Speter#endif 10211626Sbde 10392723Salfredstatic struct sem_undo *semu_alloc(struct thread *td); 104122201Srwatsonstatic int semundo_adjust(struct thread *td, struct sem_undo **supptr, 105187223Skib int semid, int semseq, int semnum, int adjval); 10692723Salfredstatic void semundo_clear(int semid, int semnum); 10711626Sbde 108101774Salfredstatic struct mtx sem_mtx; /* semaphore global lock */ 109187223Skibstatic struct mtx sem_undo_mtx; 11012819Sphkstatic int semtot = 0; 111137613Srwatsonstatic struct semid_kernel *sema; /* semaphore id pool */ 112101774Salfredstatic struct mtx *sema_mtx; /* semaphore id pool mutexes*/ 11359839Speterstatic struct sem *sem; /* semaphore pool */ 114187223SkibLIST_HEAD(, sem_undo) semu_list; /* list of active undo structures */ 115187223SkibLIST_HEAD(, sem_undo) semu_free_list; /* list of free undo structures */ 11659839Speterstatic int *semu; /* undo structure pool */ 117112564Sjhbstatic eventhandler_tag semexit_tag; 118298585Sjamiestatic unsigned sem_prison_slot; /* prison OSD slot */ 1192729Sdfr 120187223Skib#define SEMUNDO_MTX sem_undo_mtx 121101774Salfred#define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX); 122101774Salfred#define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX); 123101774Salfred#define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how)); 124101774Salfred 12559839Speterstruct sem { 12659839Speter u_short semval; /* semaphore value */ 12759839Speter pid_t sempid; /* pid of last operation */ 12859839Speter u_short semncnt; /* # awaiting semval > cval */ 12959839Speter u_short semzcnt; /* # awaiting semval = 0 */ 13059839Speter}; 13159839Speter 13259839Speter/* 13359839Speter * Undo structure (one per process) 13459839Speter */ 13559839Speterstruct sem_undo { 136187223Skib LIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */ 13759839Speter struct proc *un_proc; /* owner of this structure */ 13859839Speter short un_cnt; /* # of active entries */ 13959839Speter struct undo { 14059839Speter short un_adjval; /* adjust on exit values */ 14159839Speter short un_num; /* semaphore # */ 14259839Speter int un_id; /* semid */ 143187223Skib unsigned short un_seq; 14459839Speter } un_ent[1]; /* undo entries */ 14559839Speter}; 14659839Speter 14759839Speter/* 14859839Speter * Configuration parameters 14959839Speter */ 15059839Speter#ifndef SEMMNI 151209037Sivoras#define SEMMNI 50 /* # of semaphore identifiers */ 15259839Speter#endif 15359839Speter#ifndef SEMMNS 154209037Sivoras#define SEMMNS 340 /* # of semaphores in system */ 15559839Speter#endif 15659839Speter#ifndef SEMUME 157209037Sivoras#define SEMUME 50 /* max # of undo entries per process */ 15859839Speter#endif 15959839Speter#ifndef SEMMNU 160209037Sivoras#define SEMMNU 150 /* # of undo structures in system */ 16159839Speter#endif 16259839Speter 16359839Speter/* shouldn't need tuning */ 16459839Speter#ifndef SEMMSL 16559839Speter#define SEMMSL SEMMNS /* max # of semaphores per id */ 16659839Speter#endif 16759839Speter#ifndef SEMOPM 16859839Speter#define SEMOPM 100 /* max # of operations per semop call */ 16959839Speter#endif 17059839Speter 17159839Speter#define SEMVMX 32767 /* semaphore maximum value */ 17259839Speter#define SEMAEM 16384 /* adjust on exit max value */ 17359839Speter 17459839Speter/* 17559839Speter * Due to the way semaphore memory is allocated, we have to ensure that 17659839Speter * SEMUSZ is properly aligned. 17759839Speter */ 17859839Speter 179298433Spfg#define SEM_ALIGN(bytes) roundup2(bytes, sizeof(long)) 18059839Speter 18159839Speter/* actual size of an undo structure */ 182367129Skib#define SEMUSZ(x) SEM_ALIGN(offsetof(struct sem_undo, un_ent[(x)])) 18359839Speter 18459839Speter/* 18559839Speter * Macro to find a particular sem_undo vector 18659839Speter */ 187101350Salfred#define SEMU(ix) \ 188367129Skib ((struct sem_undo *)(((intptr_t)semu) + (ix) * seminfo.semusz)) 18959839Speter 19059839Speter/* 19159839Speter * semaphore info struct 19259839Speter */ 19359839Speterstruct seminfo seminfo = { 194358243Skib .semmni = SEMMNI, /* # of semaphore identifiers */ 195358243Skib .semmns = SEMMNS, /* # of semaphores in system */ 196358243Skib .semmnu = SEMMNU, /* # of undo structures in system */ 197358243Skib .semmsl = SEMMSL, /* max # of semaphores per id */ 198358243Skib .semopm = SEMOPM, /* max # of operations per semop call */ 199358243Skib .semume = SEMUME, /* max # of undo entries per process */ 200367129Skib .semusz = SEMUSZ(SEMUME), /* size in bytes of undo structure */ 201358243Skib .semvmx = SEMVMX, /* semaphore maximum value */ 202358243Skib .semaem = SEMAEM, /* adjust on exit max value */ 20359839Speter}; 20459839Speter 205141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, 206141710Scsjp "Number of semaphore identifiers"); 207141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, 208141710Scsjp "Maximum number of semaphores in the system"); 209141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, 210141710Scsjp "Maximum number of undo structures in the system"); 211267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RWTUN, &seminfo.semmsl, 0, 212141710Scsjp "Max semaphores per id"); 213141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, 214141710Scsjp "Max operations per semop call"); 215141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, 216141710Scsjp "Max undo entries per process"); 217367129SkibSYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, 218141710Scsjp "Size in bytes of undo structure"); 219267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RWTUN, &seminfo.semvmx, 0, 220141710Scsjp "Semaphore maximum value"); 221267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RWTUN, &seminfo.semaem, 0, 222141710Scsjp "Adjust on exit max value"); 223298656SjamieSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, 224298656Sjamie CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 225329739Sbrooks NULL, 0, sysctl_sema, "", 226329739Sbrooks "Array of struct semid_kernel for each potential semaphore"); 22759839Speter 228205323Skibstatic struct syscall_helper_data sem_syscalls[] = { 229205323Skib SYSCALL_INIT_HELPER(__semctl), 230205323Skib SYSCALL_INIT_HELPER(semget), 231205323Skib SYSCALL_INIT_HELPER(semop), 232205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 233205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 234205323Skib SYSCALL_INIT_HELPER(semsys), 235225617Skmacy SYSCALL_INIT_HELPER_COMPAT(freebsd7___semctl), 236205323Skib#endif 237205323Skib SYSCALL_INIT_LAST 238205323Skib}; 239205323Skib 240205323Skib#ifdef COMPAT_FREEBSD32 241205323Skib#include <compat/freebsd32/freebsd32.h> 242205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 243205323Skib#include <compat/freebsd32/freebsd32_proto.h> 244205323Skib#include <compat/freebsd32/freebsd32_signal.h> 245205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 246205323Skib#include <compat/freebsd32/freebsd32_util.h> 247205323Skib 248205323Skibstatic struct syscall_helper_data sem32_syscalls[] = { 249205323Skib SYSCALL32_INIT_HELPER(freebsd32_semctl), 250225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(semget), 251225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(semop), 252205323Skib SYSCALL32_INIT_HELPER(freebsd32_semsys), 253205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 254205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 255205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl), 256205323Skib#endif 257205323Skib SYSCALL_INIT_LAST 258205323Skib}; 259205323Skib#endif 260205323Skib 261205323Skibstatic int 26269449Salfredseminit(void) 2632729Sdfr{ 264298585Sjamie struct prison *pr; 265298661Scem void **rsv; 266205323Skib int i, error; 267298585Sjamie osd_method_t methods[PR_MAXMETHOD] = { 268298585Sjamie [PR_METHOD_CHECK] = sem_prison_check, 269298585Sjamie [PR_METHOD_SET] = sem_prison_set, 270298585Sjamie [PR_METHOD_GET] = sem_prison_get, 271298585Sjamie [PR_METHOD_REMOVE] = sem_prison_remove, 272298585Sjamie }; 2732729Sdfr 274111119Simp sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 275137613Srwatson sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 276329177Sbrooks M_WAITOK | M_ZERO); 277101774Salfred sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 278111119Simp M_WAITOK | M_ZERO); 279367129Skib seminfo.semusz = SEMUSZ(seminfo.semume); 280111119Simp semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 2812729Sdfr 2822729Sdfr for (i = 0; i < seminfo.semmni; i++) { 283137613Srwatson sema[i].u.sem_base = 0; 284137613Srwatson sema[i].u.sem_perm.mode = 0; 285137613Srwatson sema[i].u.sem_perm.seq = 0; 286140615Srwatson#ifdef MAC 287172930Srwatson mac_sysvsem_init(&sema[i]); 288140615Srwatson#endif 2892729Sdfr } 290101774Salfred for (i = 0; i < seminfo.semmni; i++) 291101774Salfred mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 292187223Skib LIST_INIT(&semu_free_list); 2932729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 294101350Salfred struct sem_undo *suptr = SEMU(i); 2952729Sdfr suptr->un_proc = NULL; 296187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 2972729Sdfr } 298187223Skib LIST_INIT(&semu_list); 299101774Salfred mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 300187223Skib mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); 301112564Sjhb semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 302112564Sjhb EVENTHANDLER_PRI_ANY); 303205323Skib 304298585Sjamie /* Set current prisons according to their allow.sysvipc. */ 305298585Sjamie sem_prison_slot = osd_jail_register(NULL, methods); 306298585Sjamie rsv = osd_reserve(sem_prison_slot); 307298585Sjamie prison_lock(&prison0); 308298585Sjamie (void)osd_jail_set_reserved(&prison0, sem_prison_slot, rsv, &prison0); 309298585Sjamie prison_unlock(&prison0); 310298585Sjamie rsv = NULL; 311298585Sjamie sx_slock(&allprison_lock); 312298585Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 313298585Sjamie if (rsv == NULL) 314298585Sjamie rsv = osd_reserve(sem_prison_slot); 315298585Sjamie prison_lock(pr); 316298585Sjamie if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { 317298585Sjamie (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 318298585Sjamie &prison0); 319298585Sjamie rsv = NULL; 320298585Sjamie } 321298585Sjamie prison_unlock(pr); 322298585Sjamie } 323298585Sjamie if (rsv != NULL) 324298585Sjamie osd_free_reserved(rsv); 325298585Sjamie sx_sunlock(&allprison_lock); 326298585Sjamie 327273707Smjg error = syscall_helper_register(sem_syscalls, SY_THR_STATIC_KLD); 328205323Skib if (error != 0) 329205323Skib return (error); 330205323Skib#ifdef COMPAT_FREEBSD32 331273707Smjg error = syscall32_helper_register(sem32_syscalls, SY_THR_STATIC_KLD); 332205323Skib if (error != 0) 333205323Skib return (error); 334205323Skib#endif 335205323Skib return (0); 3362729Sdfr} 3372729Sdfr 33869449Salfredstatic int 33969449Salfredsemunload(void) 34069449Salfred{ 341101774Salfred int i; 34269449Salfred 343187223Skib /* XXXKIB */ 34469449Salfred if (semtot != 0) 34569449Salfred return (EBUSY); 34669449Salfred 347205323Skib#ifdef COMPAT_FREEBSD32 348205323Skib syscall32_helper_unregister(sem32_syscalls); 349205323Skib#endif 350205323Skib syscall_helper_unregister(sem_syscalls); 351112564Sjhb EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 352298585Sjamie if (sem_prison_slot != 0) 353298585Sjamie osd_jail_deregister(sem_prison_slot); 354140615Srwatson#ifdef MAC 355140615Srwatson for (i = 0; i < seminfo.semmni; i++) 356172930Srwatson mac_sysvsem_destroy(&sema[i]); 357140615Srwatson#endif 35869449Salfred free(sem, M_SEM); 35969449Salfred free(sema, M_SEM); 36069449Salfred free(semu, M_SEM); 361101774Salfred for (i = 0; i < seminfo.semmni; i++) 362101774Salfred mtx_destroy(&sema_mtx[i]); 363190557Sbrueffer free(sema_mtx, M_SEM); 364101774Salfred mtx_destroy(&sem_mtx); 365187223Skib mtx_destroy(&sem_undo_mtx); 36669449Salfred return (0); 36769449Salfred} 36869449Salfred 36969449Salfredstatic int 37069449Salfredsysvsem_modload(struct module *module, int cmd, void *arg) 37169449Salfred{ 37269449Salfred int error = 0; 37369449Salfred 37469449Salfred switch (cmd) { 37569449Salfred case MOD_LOAD: 376205323Skib error = seminit(); 377205323Skib if (error != 0) 378205323Skib semunload(); 37969449Salfred break; 38069449Salfred case MOD_UNLOAD: 38169449Salfred error = semunload(); 38269449Salfred break; 38369449Salfred case MOD_SHUTDOWN: 38469449Salfred break; 38569449Salfred default: 38669449Salfred error = EINVAL; 38769449Salfred break; 38869449Salfred } 38969449Salfred return (error); 39069449Salfred} 39169449Salfred 39271038Sdesstatic moduledata_t sysvsem_mod = { 39371038Sdes "sysvsem", 39469449Salfred &sysvsem_modload, 39569449Salfred NULL 39669449Salfred}; 39769449Salfred 398194832SjhbDECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 39971038SdesMODULE_VERSION(sysvsem, 1); 40069449Salfred 4012729Sdfr/* 4022729Sdfr * Allocate a new sem_undo structure for a process 4032729Sdfr * (returns ptr to structure or NULL if no more room) 4042729Sdfr */ 4052729Sdfr 40612819Sphkstatic struct sem_undo * 407187223Skibsemu_alloc(struct thread *td) 4082729Sdfr{ 409101350Salfred struct sem_undo *suptr; 4102729Sdfr 411101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 412187223Skib if ((suptr = LIST_FIRST(&semu_free_list)) == NULL) 413187223Skib return (NULL); 414187223Skib LIST_REMOVE(suptr, un_next); 415187223Skib LIST_INSERT_HEAD(&semu_list, suptr, un_next); 416187223Skib suptr->un_cnt = 0; 417187223Skib suptr->un_proc = td->td_proc; 418187223Skib return (suptr); 419187223Skib} 4202729Sdfr 421187223Skibstatic int 422187223Skibsemu_try_free(struct sem_undo *suptr) 423187223Skib{ 4242729Sdfr 425187223Skib SEMUNDO_LOCKASSERT(MA_OWNED); 4262729Sdfr 427187223Skib if (suptr->un_cnt != 0) 428187223Skib return (0); 429187223Skib LIST_REMOVE(suptr, un_next); 430187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 431187223Skib return (1); 4322729Sdfr} 4332729Sdfr 4342729Sdfr/* 4352729Sdfr * Adjust a particular entry for a particular proc 4362729Sdfr */ 4372729Sdfr 43812819Sphkstatic int 439187223Skibsemundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, 440187223Skib int semseq, int semnum, int adjval) 4412729Sdfr{ 44283366Sjulian struct proc *p = td->td_proc; 443101350Salfred struct sem_undo *suptr; 444101350Salfred struct undo *sunptr; 4452729Sdfr int i; 4462729Sdfr 447101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 4482729Sdfr /* Look for and remember the sem_undo if the caller doesn't provide 4492729Sdfr it */ 4502729Sdfr 4512729Sdfr suptr = *supptr; 4522729Sdfr if (suptr == NULL) { 453187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 4542729Sdfr if (suptr->un_proc == p) { 4552729Sdfr *supptr = suptr; 4562729Sdfr break; 4572729Sdfr } 4582729Sdfr } 4592729Sdfr if (suptr == NULL) { 4602729Sdfr if (adjval == 0) 4612729Sdfr return(0); 46283366Sjulian suptr = semu_alloc(td); 4632729Sdfr if (suptr == NULL) 464187223Skib return (ENOSPC); 4652729Sdfr *supptr = suptr; 4662729Sdfr } 4672729Sdfr } 4682729Sdfr 4692729Sdfr /* 4702729Sdfr * Look for the requested entry and adjust it (delete if adjval becomes 4712729Sdfr * 0). 4722729Sdfr */ 4732729Sdfr sunptr = &suptr->un_ent[0]; 4742729Sdfr for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 4752729Sdfr if (sunptr->un_id != semid || sunptr->un_num != semnum) 4762729Sdfr continue; 47784789Smr if (adjval != 0) { 47884789Smr adjval += sunptr->un_adjval; 47984789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 48084789Smr return (ERANGE); 48184789Smr } 48284789Smr sunptr->un_adjval = adjval; 4832729Sdfr if (sunptr->un_adjval == 0) { 4842729Sdfr suptr->un_cnt--; 4852729Sdfr if (i < suptr->un_cnt) 4862729Sdfr suptr->un_ent[i] = 4872729Sdfr suptr->un_ent[suptr->un_cnt]; 488187223Skib if (suptr->un_cnt == 0) 489187223Skib semu_try_free(suptr); 4902729Sdfr } 491187223Skib return (0); 4922729Sdfr } 4932729Sdfr 4942729Sdfr /* Didn't find the right entry - create it */ 4952729Sdfr if (adjval == 0) 496187223Skib return (0); 49784789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 49884789Smr return (ERANGE); 49941774Sdillon if (suptr->un_cnt != seminfo.semume) { 5002729Sdfr sunptr = &suptr->un_ent[suptr->un_cnt]; 5012729Sdfr suptr->un_cnt++; 5022729Sdfr sunptr->un_adjval = adjval; 503187223Skib sunptr->un_id = semid; 504187223Skib sunptr->un_num = semnum; 505187223Skib sunptr->un_seq = semseq; 5062729Sdfr } else 507187223Skib return (EINVAL); 508187223Skib return (0); 5092729Sdfr} 5102729Sdfr 51112819Sphkstatic void 512187223Skibsemundo_clear(int semid, int semnum) 5132729Sdfr{ 514187223Skib struct sem_undo *suptr, *suptr1; 515187223Skib struct undo *sunptr; 516187223Skib int i; 5172729Sdfr 518101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 519187223Skib LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { 520187223Skib sunptr = &suptr->un_ent[0]; 521187223Skib for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 522187223Skib if (sunptr->un_id != semid) 523187223Skib continue; 524187223Skib if (semnum == -1 || sunptr->un_num == semnum) { 525187223Skib suptr->un_cnt--; 526187223Skib if (i < suptr->un_cnt) { 527187223Skib suptr->un_ent[i] = 528187223Skib suptr->un_ent[suptr->un_cnt]; 529187223Skib continue; 5302729Sdfr } 531187223Skib semu_try_free(suptr); 5322729Sdfr } 533187223Skib if (semnum != -1) 534187223Skib break; 5352729Sdfr } 5362729Sdfr } 5372729Sdfr} 5382729Sdfr 539101774Salfredstatic int 540298585Sjamiesemvalid(int semid, struct prison *rpr, struct semid_kernel *semakptr) 541101774Salfred{ 542101774Salfred 543137613Srwatson return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 544298585Sjamie semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) || 545298585Sjamie sem_prison_cansee(rpr, semakptr) ? EINVAL : 0); 546101774Salfred} 547101774Salfred 548298585Sjamiestatic void 549298585Sjamiesem_remove(int semidx, struct ucred *cred) 550298585Sjamie{ 551298585Sjamie struct semid_kernel *semakptr; 552298585Sjamie int i; 553298585Sjamie 554298585Sjamie KASSERT(semidx >= 0 && semidx < seminfo.semmni, 555358244Skib ("semidx out of bounds")); 556358244Skib mtx_assert(&sem_mtx, MA_OWNED); 557298585Sjamie semakptr = &sema[semidx]; 558358246Skib KASSERT(semakptr->u.sem_base - sem + semakptr->u.sem_nsems <= semtot, 559358244Skib ("sem_remove: sema %d corrupted sem pointer %p %p %d %d", 560358246Skib semidx, semakptr->u.sem_base, sem, semakptr->u.sem_nsems, 561358244Skib semtot)); 562358244Skib 563298585Sjamie semakptr->u.sem_perm.cuid = cred ? cred->cr_uid : 0; 564298585Sjamie semakptr->u.sem_perm.uid = cred ? cred->cr_uid : 0; 565298585Sjamie semakptr->u.sem_perm.mode = 0; 566298585Sjamie racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); 567298585Sjamie crfree(semakptr->cred); 568298585Sjamie semakptr->cred = NULL; 569298585Sjamie SEMUNDO_LOCK(); 570298585Sjamie semundo_clear(semidx, -1); 571298585Sjamie SEMUNDO_UNLOCK(); 572298585Sjamie#ifdef MAC 573298585Sjamie mac_sysvsem_cleanup(semakptr); 574298585Sjamie#endif 575298585Sjamie wakeup(semakptr); 576298585Sjamie for (i = 0; i < seminfo.semmni; i++) { 577298585Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 578298585Sjamie sema[i].u.sem_base > semakptr->u.sem_base) 579298585Sjamie mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 580298585Sjamie } 581358245Skib for (i = semakptr->u.sem_base - sem + semakptr->u.sem_nsems; 582358245Skib i < semtot; i++) 583358245Skib sem[i - semakptr->u.sem_nsems] = sem[i]; 584298585Sjamie for (i = 0; i < seminfo.semmni; i++) { 585298585Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 586298585Sjamie sema[i].u.sem_base > semakptr->u.sem_base) { 587298585Sjamie sema[i].u.sem_base -= semakptr->u.sem_nsems; 588298585Sjamie mtx_unlock(&sema_mtx[i]); 589298585Sjamie } 590298585Sjamie } 591298585Sjamie semtot -= semakptr->u.sem_nsems; 592298585Sjamie} 593298585Sjamie 594298585Sjamiestatic struct prison * 595298585Sjamiesem_find_prison(struct ucred *cred) 596298585Sjamie{ 597298585Sjamie struct prison *pr, *rpr; 598298585Sjamie 599298585Sjamie pr = cred->cr_prison; 600298585Sjamie prison_lock(pr); 601298585Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 602298585Sjamie prison_unlock(pr); 603298585Sjamie return rpr; 604298585Sjamie} 605298585Sjamie 606298585Sjamiestatic int 607298585Sjamiesem_prison_cansee(struct prison *rpr, struct semid_kernel *semakptr) 608298585Sjamie{ 609298585Sjamie 610298585Sjamie if (semakptr->cred == NULL || 611298585Sjamie !(rpr == semakptr->cred->cr_prison || 612298585Sjamie prison_ischild(rpr, semakptr->cred->cr_prison))) 613298585Sjamie return (EINVAL); 614298585Sjamie return (0); 615298585Sjamie} 616298585Sjamie 61712866Speter/* 618167211Srwatson * Note that the user-mode half of this passes a union, not a pointer. 61912866Speter */ 62012866Speter#ifndef _SYS_SYSPROTO_H_ 62112866Speterstruct __semctl_args { 6222729Sdfr int semid; 6232729Sdfr int semnum; 6242729Sdfr int cmd; 6252729Sdfr union semun *arg; 6262729Sdfr}; 62712866Speter#endif 62812866Speterint 629225617Skmacysys___semctl(struct thread *td, struct __semctl_args *uap) 6302729Sdfr{ 631160187Sjhb struct semid_ds dsbuf; 632160187Sjhb union semun arg, semun; 633160187Sjhb register_t rval; 634159991Sjhb int error; 635159991Sjhb 636159991Sjhb switch (uap->cmd) { 637159991Sjhb case SEM_STAT: 638159991Sjhb case IPC_SET: 639159991Sjhb case IPC_STAT: 640159991Sjhb case GETALL: 641159991Sjhb case SETVAL: 642159991Sjhb case SETALL: 643160187Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 644159991Sjhb if (error) 645159991Sjhb return (error); 646159991Sjhb break; 647160187Sjhb } 648160187Sjhb 649160187Sjhb switch (uap->cmd) { 650160187Sjhb case SEM_STAT: 651160187Sjhb case IPC_STAT: 652160187Sjhb semun.buf = &dsbuf; 653159991Sjhb break; 654160187Sjhb case IPC_SET: 655160187Sjhb error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 656160187Sjhb if (error) 657160187Sjhb return (error); 658160187Sjhb semun.buf = &dsbuf; 659160187Sjhb break; 660160187Sjhb case GETALL: 661160187Sjhb case SETALL: 662160187Sjhb semun.array = arg.array; 663160187Sjhb break; 664160187Sjhb case SETVAL: 665160187Sjhb semun.val = arg.val; 666160187Sjhb break; 667159991Sjhb } 668160187Sjhb 669160187Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 670160187Sjhb &rval); 671160187Sjhb if (error) 672160187Sjhb return (error); 673160187Sjhb 674160187Sjhb switch (uap->cmd) { 675160187Sjhb case SEM_STAT: 676160187Sjhb case IPC_STAT: 677160187Sjhb error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 678160187Sjhb break; 679160187Sjhb } 680160187Sjhb 681160187Sjhb if (error == 0) 682160187Sjhb td->td_retval[0] = rval; 683160187Sjhb return (error); 684159991Sjhb} 685159991Sjhb 686159991Sjhbint 687160187Sjhbkern_semctl(struct thread *td, int semid, int semnum, int cmd, 688160187Sjhb union semun *arg, register_t *rval) 689159991Sjhb{ 690101774Salfred u_short *array; 69191406Sjhb struct ucred *cred = td->td_ucred; 692160187Sjhb int i, error; 693298585Sjamie struct prison *rpr; 694160187Sjhb struct semid_ds *sbuf; 695137613Srwatson struct semid_kernel *semakptr; 696101774Salfred struct mtx *sema_mtxp; 697101774Salfred u_short usval, count; 698160028Sjhb int semidx; 6992729Sdfr 700160293Skib DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 701100523Salfred semid, semnum, cmd, arg)); 702298585Sjamie 703298585Sjamie rpr = sem_find_prison(td->td_ucred); 704298585Sjamie if (sem == NULL) 70591703Sjhb return (ENOSYS); 70691703Sjhb 707101774Salfred array = NULL; 708101774Salfred 70983414Smr switch(cmd) { 71083414Smr case SEM_STAT: 711160028Sjhb /* 712160028Sjhb * For this command we assume semid is an array index 713160028Sjhb * rather than an IPC id. 714160028Sjhb */ 71591744Smaxim if (semid < 0 || semid >= seminfo.semmni) 716101774Salfred return (EINVAL); 717137613Srwatson semakptr = &sema[semid]; 718101774Salfred sema_mtxp = &sema_mtx[semid]; 719101774Salfred mtx_lock(sema_mtxp); 720137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 721101774Salfred error = EINVAL; 722101774Salfred goto done2; 723101774Salfred } 724298585Sjamie if ((error = sem_prison_cansee(rpr, semakptr))) 725298585Sjamie goto done2; 726137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 727101774Salfred goto done2; 728140615Srwatson#ifdef MAC 729172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 730162468Srwatson if (error != 0) 731140615Srwatson goto done2; 732140615Srwatson#endif 733160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 734298585Sjamie if (cred->cr_prison != semakptr->cred->cr_prison) 735298585Sjamie arg->buf->sem_perm.key = IPC_PRIVATE; 736160187Sjhb *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 737101774Salfred mtx_unlock(sema_mtxp); 738160187Sjhb return (0); 73983414Smr } 74083414Smr 741160028Sjhb semidx = IPCID_TO_IX(semid); 742160028Sjhb if (semidx < 0 || semidx >= seminfo.semmni) 743101774Salfred return (EINVAL); 7442729Sdfr 745160028Sjhb semakptr = &sema[semidx]; 746160028Sjhb sema_mtxp = &sema_mtx[semidx]; 747187223Skib if (cmd == IPC_RMID) 748187223Skib mtx_lock(&sem_mtx); 749160187Sjhb mtx_lock(sema_mtxp); 750298585Sjamie 751140615Srwatson#ifdef MAC 752172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 753162468Srwatson if (error != 0) 754160187Sjhb goto done2; 755140615Srwatson#endif 756145230Srwatson 75782607Sdillon error = 0; 758160187Sjhb *rval = 0; 7592729Sdfr 7602729Sdfr switch (cmd) { 7612729Sdfr case IPC_RMID: 762298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 763101774Salfred goto done2; 764137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 76582607Sdillon goto done2; 766298585Sjamie sem_remove(semidx, cred); 7672729Sdfr break; 7682729Sdfr 7692729Sdfr case IPC_SET: 770298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 771101774Salfred goto done2; 772137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 773101774Salfred goto done2; 774160187Sjhb sbuf = arg->buf; 775160187Sjhb semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 776160187Sjhb semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 777137613Srwatson semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 778160187Sjhb ~0777) | (sbuf->sem_perm.mode & 0777); 779137613Srwatson semakptr->u.sem_ctime = time_second; 7802729Sdfr break; 7812729Sdfr 7822729Sdfr case IPC_STAT: 783298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 784101774Salfred goto done2; 785137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 78682607Sdillon goto done2; 787160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 788298585Sjamie if (cred->cr_prison != semakptr->cred->cr_prison) 789298585Sjamie arg->buf->sem_perm.key = IPC_PRIVATE; 7902729Sdfr break; 7912729Sdfr 7922729Sdfr case GETNCNT: 793298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 794101774Salfred goto done2; 795137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 79682607Sdillon goto done2; 797137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 79882607Sdillon error = EINVAL; 79982607Sdillon goto done2; 80082607Sdillon } 801160187Sjhb *rval = semakptr->u.sem_base[semnum].semncnt; 8022729Sdfr break; 8032729Sdfr 8042729Sdfr case GETPID: 805298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 806101774Salfred goto done2; 807137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 80882607Sdillon goto done2; 809137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 81082607Sdillon error = EINVAL; 81182607Sdillon goto done2; 81282607Sdillon } 813160187Sjhb *rval = semakptr->u.sem_base[semnum].sempid; 8142729Sdfr break; 8152729Sdfr 8162729Sdfr case GETVAL: 817298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 818101774Salfred goto done2; 819137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 82082607Sdillon goto done2; 821137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 82282607Sdillon error = EINVAL; 82382607Sdillon goto done2; 82482607Sdillon } 825160187Sjhb *rval = semakptr->u.sem_base[semnum].semval; 8262729Sdfr break; 8272729Sdfr 8282729Sdfr case GETALL: 829159991Sjhb /* 830160187Sjhb * Unfortunately, callers of this function don't know 831160187Sjhb * in advance how many semaphores are in this set. 832160187Sjhb * While we could just allocate the maximum size array 833160187Sjhb * and pass the actual size back to the caller, that 834160187Sjhb * won't work for SETALL since we can't copyin() more 835160187Sjhb * data than the user specified as we may return a 836160187Sjhb * spurious EFAULT. 837160187Sjhb * 838160187Sjhb * Note that the number of semaphores in a set is 839160187Sjhb * fixed for the life of that set. The only way that 840160187Sjhb * the 'count' could change while are blocked in 841160187Sjhb * malloc() is if this semaphore set were destroyed 842160187Sjhb * and a new one created with the same index. 843160187Sjhb * However, semvalid() will catch that due to the 844160187Sjhb * sequence number unless exactly 0x8000 (or a 845160187Sjhb * multiple thereof) semaphore sets for the same index 846160187Sjhb * are created and destroyed while we are in malloc! 847160187Sjhb * 848159991Sjhb */ 849160187Sjhb count = semakptr->u.sem_nsems; 850160187Sjhb mtx_unlock(sema_mtxp); 851160187Sjhb array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 852101774Salfred mtx_lock(sema_mtxp); 853298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 854101774Salfred goto done2; 855160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 856137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 85782607Sdillon goto done2; 858137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) 859137613Srwatson array[i] = semakptr->u.sem_base[i].semval; 860101774Salfred mtx_unlock(sema_mtxp); 861160187Sjhb error = copyout(array, arg->array, count * sizeof(*array)); 862160187Sjhb mtx_lock(sema_mtxp); 8632729Sdfr break; 8642729Sdfr 8652729Sdfr case GETZCNT: 866298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 867101774Salfred goto done2; 868137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 86982607Sdillon goto done2; 870137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 87182607Sdillon error = EINVAL; 87282607Sdillon goto done2; 87382607Sdillon } 874160187Sjhb *rval = semakptr->u.sem_base[semnum].semzcnt; 8752729Sdfr break; 8762729Sdfr 8772729Sdfr case SETVAL: 878298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 879101774Salfred goto done2; 880137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 88182607Sdillon goto done2; 882137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 88382607Sdillon error = EINVAL; 88482607Sdillon goto done2; 88582607Sdillon } 886159991Sjhb if (arg->val < 0 || arg->val > seminfo.semvmx) { 88784789Smr error = ERANGE; 88884789Smr goto done2; 88984789Smr } 890159991Sjhb semakptr->u.sem_base[semnum].semval = arg->val; 891101774Salfred SEMUNDO_LOCK(); 892160028Sjhb semundo_clear(semidx, semnum); 893101774Salfred SEMUNDO_UNLOCK(); 894137613Srwatson wakeup(semakptr); 8952729Sdfr break; 8962729Sdfr 8972729Sdfr case SETALL: 898159991Sjhb /* 899160187Sjhb * See comment on GETALL for why 'count' shouldn't change 900160187Sjhb * and why we require a userland buffer. 901159991Sjhb */ 902137613Srwatson count = semakptr->u.sem_nsems; 903160187Sjhb mtx_unlock(sema_mtxp); 904111119Simp array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 905159991Sjhb error = copyin(arg->array, array, count * sizeof(*array)); 906171179Skib mtx_lock(sema_mtxp); 907101774Salfred if (error) 908101774Salfred break; 909298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 910101774Salfred goto done2; 911160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 912137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 913101774Salfred goto done2; 914137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) { 915101774Salfred usval = array[i]; 91684789Smr if (usval > seminfo.semvmx) { 91784789Smr error = ERANGE; 91884789Smr break; 91984789Smr } 920137613Srwatson semakptr->u.sem_base[i].semval = usval; 9212729Sdfr } 922101774Salfred SEMUNDO_LOCK(); 923160028Sjhb semundo_clear(semidx, -1); 924101774Salfred SEMUNDO_UNLOCK(); 925137613Srwatson wakeup(semakptr); 9262729Sdfr break; 9272729Sdfr 9282729Sdfr default: 92982607Sdillon error = EINVAL; 93082607Sdillon break; 9312729Sdfr } 9322729Sdfr 93382607Sdillondone2: 934160187Sjhb mtx_unlock(sema_mtxp); 935187223Skib if (cmd == IPC_RMID) 936187223Skib mtx_unlock(&sem_mtx); 937101774Salfred if (array != NULL) 938101774Salfred free(array, M_TEMP); 93982607Sdillon return(error); 9402729Sdfr} 9412729Sdfr 94212866Speter#ifndef _SYS_SYSPROTO_H_ 9432729Sdfrstruct semget_args { 9442729Sdfr key_t key; 9452729Sdfr int nsems; 9462729Sdfr int semflg; 9472729Sdfr}; 94812866Speter#endif 94912866Speterint 950225617Skmacysys_semget(struct thread *td, struct semget_args *uap) 9512729Sdfr{ 95282607Sdillon int semid, error = 0; 9532729Sdfr int key = uap->key; 9542729Sdfr int nsems = uap->nsems; 9552729Sdfr int semflg = uap->semflg; 95691703Sjhb struct ucred *cred = td->td_ucred; 9572729Sdfr 958100523Salfred DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 959298585Sjamie 960298585Sjamie if (sem_find_prison(cred) == NULL) 96191703Sjhb return (ENOSYS); 96291703Sjhb 963187223Skib mtx_lock(&sem_mtx); 9642729Sdfr if (key != IPC_PRIVATE) { 9652729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 966137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 967298585Sjamie sema[semid].cred != NULL && 968298585Sjamie sema[semid].cred->cr_prison == cred->cr_prison && 969137613Srwatson sema[semid].u.sem_perm.key == key) 9702729Sdfr break; 9712729Sdfr } 9722729Sdfr if (semid < seminfo.semmni) { 973100523Salfred DPRINTF(("found public key\n")); 974295385Sjilles if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 975295385Sjilles DPRINTF(("not exclusive\n")); 976295385Sjilles error = EEXIST; 977295385Sjilles goto done2; 978295385Sjilles } 979137613Srwatson if ((error = ipcperm(td, &sema[semid].u.sem_perm, 98082607Sdillon semflg & 0700))) { 98182607Sdillon goto done2; 98282607Sdillon } 983137613Srwatson if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 984100523Salfred DPRINTF(("too small\n")); 98582607Sdillon error = EINVAL; 98682607Sdillon goto done2; 9872729Sdfr } 988140615Srwatson#ifdef MAC 989172930Srwatson error = mac_sysvsem_check_semget(cred, &sema[semid]); 990162468Srwatson if (error != 0) 991140615Srwatson goto done2; 992140615Srwatson#endif 9932729Sdfr goto found; 9942729Sdfr } 9952729Sdfr } 9962729Sdfr 997137613Srwatson DPRINTF(("need to allocate the semid_kernel\n")); 9982729Sdfr if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 9992729Sdfr if (nsems <= 0 || nsems > seminfo.semmsl) { 1000100523Salfred DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 1001100523Salfred seminfo.semmsl)); 100282607Sdillon error = EINVAL; 100382607Sdillon goto done2; 10042729Sdfr } 10052729Sdfr if (nsems > seminfo.semmns - semtot) { 1006100523Salfred DPRINTF(( 1007100523Salfred "not enough semaphores left (need %d, got %d)\n", 1008100523Salfred nsems, seminfo.semmns - semtot)); 100982607Sdillon error = ENOSPC; 101082607Sdillon goto done2; 10112729Sdfr } 10122729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 1013137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 10142729Sdfr break; 10152729Sdfr } 10162729Sdfr if (semid == seminfo.semmni) { 1017137613Srwatson DPRINTF(("no more semid_kernel's available\n")); 101882607Sdillon error = ENOSPC; 101982607Sdillon goto done2; 10202729Sdfr } 1021223825Strasz#ifdef RACCT 1022282213Strasz if (racct_enable) { 1023282213Strasz PROC_LOCK(td->td_proc); 1024282213Strasz error = racct_add(td->td_proc, RACCT_NSEM, nsems); 1025282213Strasz PROC_UNLOCK(td->td_proc); 1026282213Strasz if (error != 0) { 1027282213Strasz error = ENOSPC; 1028282213Strasz goto done2; 1029282213Strasz } 1030220398Strasz } 1031223825Strasz#endif 1032100523Salfred DPRINTF(("semid %d is available\n", semid)); 1033187298Skib mtx_lock(&sema_mtx[semid]); 1034187298Skib KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 1035187298Skib ("Lost semaphore %d", semid)); 1036137613Srwatson sema[semid].u.sem_perm.key = key; 1037137613Srwatson sema[semid].u.sem_perm.cuid = cred->cr_uid; 1038137613Srwatson sema[semid].u.sem_perm.uid = cred->cr_uid; 1039137613Srwatson sema[semid].u.sem_perm.cgid = cred->cr_gid; 1040137613Srwatson sema[semid].u.sem_perm.gid = cred->cr_gid; 1041137613Srwatson sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 1042220399Strasz sema[semid].cred = crhold(cred); 1043137613Srwatson sema[semid].u.sem_perm.seq = 1044137613Srwatson (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 1045137613Srwatson sema[semid].u.sem_nsems = nsems; 1046137613Srwatson sema[semid].u.sem_otime = 0; 1047137613Srwatson sema[semid].u.sem_ctime = time_second; 1048137613Srwatson sema[semid].u.sem_base = &sem[semtot]; 10492729Sdfr semtot += nsems; 1050137613Srwatson bzero(sema[semid].u.sem_base, 1051137613Srwatson sizeof(sema[semid].u.sem_base[0])*nsems); 1052140615Srwatson#ifdef MAC 1053172930Srwatson mac_sysvsem_create(cred, &sema[semid]); 1054140615Srwatson#endif 1055187298Skib mtx_unlock(&sema_mtx[semid]); 1056160293Skib DPRINTF(("sembase = %p, next = %p\n", 1057137613Srwatson sema[semid].u.sem_base, &sem[semtot])); 10582729Sdfr } else { 1059100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 106082607Sdillon error = ENOENT; 106182607Sdillon goto done2; 10622729Sdfr } 10632729Sdfr 10642729Sdfrfound: 1065137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 106682607Sdillondone2: 1067187223Skib mtx_unlock(&sem_mtx); 106882607Sdillon return (error); 10692729Sdfr} 10702729Sdfr 107112866Speter#ifndef _SYS_SYSPROTO_H_ 10722729Sdfrstruct semop_args { 10732729Sdfr int semid; 10742729Sdfr struct sembuf *sops; 1075109829Salfred size_t nsops; 10762729Sdfr}; 107712866Speter#endif 107812866Speterint 1079225617Skmacysys_semop(struct thread *td, struct semop_args *uap) 10802729Sdfr{ 1081123667Stjr#define SMALL_SOPS 8 1082123667Stjr struct sembuf small_sops[SMALL_SOPS]; 10832729Sdfr int semid = uap->semid; 1084109829Salfred size_t nsops = uap->nsops; 1085298585Sjamie struct prison *rpr; 1086105429Salfred struct sembuf *sops; 1087137613Srwatson struct semid_kernel *semakptr; 1088298069Spfg struct sembuf *sopptr = NULL; 1089298069Spfg struct sem *semptr = NULL; 109084789Smr struct sem_undo *suptr; 1091101774Salfred struct mtx *sema_mtxp; 1092110040Stjr size_t i, j, k; 1093109829Salfred int error; 10943308Sphk int do_wakeup, do_undos; 1095187223Skib unsigned short seq; 10962729Sdfr 1097160293Skib#ifdef SEM_DEBUG 1098160293Skib sops = NULL; 1099160293Skib#endif 1100160293Skib DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 11012729Sdfr 1102298585Sjamie rpr = sem_find_prison(td->td_ucred); 1103298585Sjamie if (sem == NULL) 110491703Sjhb return (ENOSYS); 110591703Sjhb 11062729Sdfr semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 11072729Sdfr 1108101774Salfred if (semid < 0 || semid >= seminfo.semmni) 1109137644Srwatson return (EINVAL); 1110101774Salfred 1111101774Salfred /* Allocate memory for sem_ops */ 1112123667Stjr if (nsops <= SMALL_SOPS) 1113123667Stjr sops = small_sops; 1114220398Strasz else if (nsops > seminfo.semopm) { 1115101774Salfred DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1116101774Salfred nsops)); 1117101774Salfred return (E2BIG); 1118220398Strasz } else { 1119223825Strasz#ifdef RACCT 1120282213Strasz if (racct_enable) { 1121282213Strasz PROC_LOCK(td->td_proc); 1122282213Strasz if (nsops > 1123282213Strasz racct_get_available(td->td_proc, RACCT_NSEMOP)) { 1124282213Strasz PROC_UNLOCK(td->td_proc); 1125282213Strasz return (E2BIG); 1126282213Strasz } 1127220398Strasz PROC_UNLOCK(td->td_proc); 1128220398Strasz } 1129223825Strasz#endif 1130220398Strasz 1131220398Strasz sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 113282607Sdillon } 1133101774Salfred if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1134160293Skib DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1135101774Salfred uap->sops, sops, nsops * sizeof(sops[0]))); 1136123667Stjr if (sops != small_sops) 1137123667Stjr free(sops, M_SEM); 1138101774Salfred return (error); 1139101774Salfred } 11402729Sdfr 1141137613Srwatson semakptr = &sema[semid]; 1142101774Salfred sema_mtxp = &sema_mtx[semid]; 1143101774Salfred mtx_lock(sema_mtxp); 1144137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 114582607Sdillon error = EINVAL; 114682607Sdillon goto done2; 114782607Sdillon } 1148187223Skib seq = semakptr->u.sem_perm.seq; 1149187223Skib if (seq != IPCID_TO_SEQ(uap->semid)) { 115082607Sdillon error = EINVAL; 115182607Sdillon goto done2; 115282607Sdillon } 1153298585Sjamie if ((error = sem_prison_cansee(rpr, semakptr)) != 0) 1154298585Sjamie goto done2; 115584789Smr /* 1156298819Spfg * Initial pass through sops to see what permissions are needed. 115784789Smr * Also perform any checks that don't need repeating on each 115884789Smr * attempt to satisfy the request vector. 115984789Smr */ 116084789Smr j = 0; /* permission needed */ 116184789Smr do_undos = 0; 116284789Smr for (i = 0; i < nsops; i++) { 116384789Smr sopptr = &sops[i]; 1164137613Srwatson if (sopptr->sem_num >= semakptr->u.sem_nsems) { 116584789Smr error = EFBIG; 116684789Smr goto done2; 116784789Smr } 116884789Smr if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 116984789Smr do_undos = 1; 117084789Smr j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 117184789Smr } 117284789Smr 1173137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1174100523Salfred DPRINTF(("error = %d from ipaccess\n", error)); 117582607Sdillon goto done2; 11762729Sdfr } 1177140615Srwatson#ifdef MAC 1178172930Srwatson error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1179162468Srwatson if (error != 0) 1180140615Srwatson goto done2; 1181140615Srwatson#endif 11822729Sdfr 11838876Srgrimes /* 11842729Sdfr * Loop trying to satisfy the vector of requests. 11852729Sdfr * If we reach a point where we must wait, any requests already 11862729Sdfr * performed are rolled back and we go to sleep until some other 11872729Sdfr * process wakes us up. At this point, we start all over again. 11882729Sdfr * 11892729Sdfr * This ensures that from the perspective of other tasks, a set 11902729Sdfr * of requests is atomic (never partially satisfied). 11912729Sdfr */ 11922729Sdfr for (;;) { 11932729Sdfr do_wakeup = 0; 119484789Smr error = 0; /* error return if necessary */ 11952729Sdfr 11962729Sdfr for (i = 0; i < nsops; i++) { 11972729Sdfr sopptr = &sops[i]; 1198137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 11992729Sdfr 1200100523Salfred DPRINTF(( 1201160293Skib "semop: semakptr=%p, sem_base=%p, " 1202160293Skib "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1203137613Srwatson semakptr, semakptr->u.sem_base, semptr, 12042729Sdfr sopptr->sem_num, semptr->semval, sopptr->sem_op, 1205100523Salfred (sopptr->sem_flg & IPC_NOWAIT) ? 1206100523Salfred "nowait" : "wait")); 12072729Sdfr 12082729Sdfr if (sopptr->sem_op < 0) { 12092729Sdfr if (semptr->semval + sopptr->sem_op < 0) { 1210100523Salfred DPRINTF(("semop: can't do it now\n")); 12112729Sdfr break; 12122729Sdfr } else { 12132729Sdfr semptr->semval += sopptr->sem_op; 12142729Sdfr if (semptr->semval == 0 && 12152729Sdfr semptr->semzcnt > 0) 12162729Sdfr do_wakeup = 1; 12172729Sdfr } 12182729Sdfr } else if (sopptr->sem_op == 0) { 121984789Smr if (semptr->semval != 0) { 1220100523Salfred DPRINTF(("semop: not zero now\n")); 12212729Sdfr break; 12222729Sdfr } 122384789Smr } else if (semptr->semval + sopptr->sem_op > 122484789Smr seminfo.semvmx) { 122584789Smr error = ERANGE; 122684789Smr break; 12272729Sdfr } else { 12282729Sdfr if (semptr->semncnt > 0) 12292729Sdfr do_wakeup = 1; 12302729Sdfr semptr->semval += sopptr->sem_op; 12312729Sdfr } 12322729Sdfr } 12332729Sdfr 12342729Sdfr /* 12352729Sdfr * Did we get through the entire vector? 12362729Sdfr */ 12372729Sdfr if (i >= nsops) 12382729Sdfr goto done; 12392729Sdfr 12402729Sdfr /* 12412729Sdfr * No ... rollback anything that we've already done 12422729Sdfr */ 1243100523Salfred DPRINTF(("semop: rollback 0 through %d\n", i-1)); 12442729Sdfr for (j = 0; j < i; j++) 1245137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 12462729Sdfr sops[j].sem_op; 12472729Sdfr 124884789Smr /* If we detected an error, return it */ 124984789Smr if (error != 0) 125084789Smr goto done2; 125184789Smr 12522729Sdfr /* 12532729Sdfr * If the request that we couldn't satisfy has the 12542729Sdfr * NOWAIT flag set then return with EAGAIN. 12552729Sdfr */ 125682607Sdillon if (sopptr->sem_flg & IPC_NOWAIT) { 125782607Sdillon error = EAGAIN; 125882607Sdillon goto done2; 125982607Sdillon } 12602729Sdfr 12612729Sdfr if (sopptr->sem_op == 0) 12622729Sdfr semptr->semzcnt++; 12632729Sdfr else 12642729Sdfr semptr->semncnt++; 12652729Sdfr 1266100523Salfred DPRINTF(("semop: good night!\n")); 1267137613Srwatson error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1268101774Salfred "semwait", 0); 1269100523Salfred DPRINTF(("semop: good morning (error=%d)!\n", error)); 1270127108Scperciva /* return code is checked below, after sem[nz]cnt-- */ 12712729Sdfr 12722729Sdfr /* 12732729Sdfr * Make sure that the semaphore still exists 12742729Sdfr */ 1275187223Skib seq = semakptr->u.sem_perm.seq; 1276137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1277187223Skib seq != IPCID_TO_SEQ(uap->semid)) { 127882607Sdillon error = EIDRM; 127982607Sdillon goto done2; 128082607Sdillon } 12812729Sdfr 12822729Sdfr /* 1283179879Sgonzo * Renew the semaphore's pointer after wakeup since 1284179879Sgonzo * during msleep sem_base may have been modified and semptr 1285179879Sgonzo * is not valid any more 1286179879Sgonzo */ 1287179879Sgonzo semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1288179879Sgonzo 1289179879Sgonzo /* 12902729Sdfr * The semaphore is still alive. Readjust the count of 12912729Sdfr * waiting processes. 12922729Sdfr */ 12932729Sdfr if (sopptr->sem_op == 0) 12942729Sdfr semptr->semzcnt--; 12952729Sdfr else 12962729Sdfr semptr->semncnt--; 1297127108Scperciva 1298127108Scperciva /* 1299127108Scperciva * Is it really morning, or was our sleep interrupted? 1300127108Scperciva * (Delayed check of msleep() return code because we 1301127108Scperciva * need to decrement sem[nz]cnt either way.) 1302127108Scperciva */ 1303127108Scperciva if (error != 0) { 1304127108Scperciva error = EINTR; 1305127108Scperciva goto done2; 1306127108Scperciva } 1307127108Scperciva DPRINTF(("semop: good morning!\n")); 13082729Sdfr } 13092729Sdfr 13102729Sdfrdone: 13112729Sdfr /* 13122729Sdfr * Process any SEM_UNDO requests. 13132729Sdfr */ 13142729Sdfr if (do_undos) { 1315101774Salfred SEMUNDO_LOCK(); 131684789Smr suptr = NULL; 13172729Sdfr for (i = 0; i < nsops; i++) { 13182729Sdfr /* 13192729Sdfr * We only need to deal with SEM_UNDO's for non-zero 13202729Sdfr * op's. 13212729Sdfr */ 13222729Sdfr int adjval; 13232729Sdfr 13242729Sdfr if ((sops[i].sem_flg & SEM_UNDO) == 0) 13252729Sdfr continue; 13262729Sdfr adjval = sops[i].sem_op; 13272729Sdfr if (adjval == 0) 13282729Sdfr continue; 1329187223Skib error = semundo_adjust(td, &suptr, semid, seq, 13302729Sdfr sops[i].sem_num, -adjval); 133182607Sdillon if (error == 0) 13322729Sdfr continue; 13332729Sdfr 13342729Sdfr /* 13352729Sdfr * Oh-Oh! We ran out of either sem_undo's or undo's. 13362729Sdfr * Rollback the adjustments to this point and then 13372729Sdfr * rollback the semaphore ups and down so we can return 13382729Sdfr * with an error with all structures restored. We 13392729Sdfr * rollback the undo's in the exact reverse order that 13402729Sdfr * we applied them. This guarantees that we won't run 13412729Sdfr * out of space as we roll things back out. 13422729Sdfr */ 1343110040Stjr for (j = 0; j < i; j++) { 1344110040Stjr k = i - j - 1; 1345110040Stjr if ((sops[k].sem_flg & SEM_UNDO) == 0) 13462729Sdfr continue; 1347110040Stjr adjval = sops[k].sem_op; 13482729Sdfr if (adjval == 0) 13492729Sdfr continue; 1350187223Skib if (semundo_adjust(td, &suptr, semid, seq, 1351110040Stjr sops[k].sem_num, adjval) != 0) 13522729Sdfr panic("semop - can't undo undos"); 13532729Sdfr } 13542729Sdfr 13552729Sdfr for (j = 0; j < nsops; j++) 1356137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 13572729Sdfr sops[j].sem_op; 13582729Sdfr 1359100523Salfred DPRINTF(("error = %d from semundo_adjust\n", error)); 1360101774Salfred SEMUNDO_UNLOCK(); 136182607Sdillon goto done2; 13622729Sdfr } /* loop through the sops */ 1363101774Salfred SEMUNDO_UNLOCK(); 13642729Sdfr } /* if (do_undos) */ 13652729Sdfr 136684789Smr /* We're definitely done - set the sempid's and time */ 13672729Sdfr for (i = 0; i < nsops; i++) { 13682729Sdfr sopptr = &sops[i]; 1369137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 137083366Sjulian semptr->sempid = td->td_proc->p_pid; 13712729Sdfr } 1372137613Srwatson semakptr->u.sem_otime = time_second; 13732729Sdfr 137484789Smr /* 137584789Smr * Do a wakeup if any semaphore was up'd whilst something was 137684789Smr * sleeping on it. 137784789Smr */ 13782729Sdfr if (do_wakeup) { 1379100523Salfred DPRINTF(("semop: doing wakeup\n")); 1380137613Srwatson wakeup(semakptr); 1381100523Salfred DPRINTF(("semop: back from wakeup\n")); 13822729Sdfr } 1383100523Salfred DPRINTF(("semop: done\n")); 138483366Sjulian td->td_retval[0] = 0; 138582607Sdillondone2: 1386101774Salfred mtx_unlock(sema_mtxp); 1387123667Stjr if (sops != small_sops) 1388123667Stjr free(sops, M_SEM); 138982607Sdillon return (error); 13902729Sdfr} 13912729Sdfr 13922729Sdfr/* 13932729Sdfr * Go through the undo structures for this process and apply the adjustments to 13942729Sdfr * semaphores. 13952729Sdfr */ 139669449Salfredstatic void 1397187223Skibsemexit_myhook(void *arg, struct proc *p) 13982729Sdfr{ 1399101350Salfred struct sem_undo *suptr; 1400187223Skib struct semid_kernel *semakptr; 1401187223Skib struct mtx *sema_mtxp; 1402187223Skib int semid, semnum, adjval, ix; 1403187223Skib unsigned short seq; 14042729Sdfr 14052729Sdfr /* 14062729Sdfr * Go through the chain of undo vectors looking for one 14072729Sdfr * associated with this process. 14082729Sdfr */ 1409101774Salfred SEMUNDO_LOCK(); 1410187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 1411187223Skib if (suptr->un_proc == p) 14122729Sdfr break; 14132729Sdfr } 1414187223Skib if (suptr == NULL) { 1415187223Skib SEMUNDO_UNLOCK(); 141659828Speter return; 1417187223Skib } 1418187223Skib LIST_REMOVE(suptr, un_next); 14192729Sdfr 1420160293Skib DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1421100523Salfred suptr->un_cnt)); 14222729Sdfr 14232729Sdfr /* 14242729Sdfr * If there are any active undo elements then process them. 14252729Sdfr */ 14262729Sdfr if (suptr->un_cnt > 0) { 1427187223Skib SEMUNDO_UNLOCK(); 14282729Sdfr for (ix = 0; ix < suptr->un_cnt; ix++) { 1429187223Skib semid = suptr->un_ent[ix].un_id; 1430187223Skib semnum = suptr->un_ent[ix].un_num; 1431187223Skib adjval = suptr->un_ent[ix].un_adjval; 1432187223Skib seq = suptr->un_ent[ix].un_seq; 1433137613Srwatson semakptr = &sema[semid]; 1434101774Salfred sema_mtxp = &sema_mtx[semid]; 1435187223Skib 1436101774Salfred mtx_lock(sema_mtxp); 1437187223Skib if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1438187223Skib (semakptr->u.sem_perm.seq != seq)) { 1439187223Skib mtx_unlock(sema_mtxp); 1440187223Skib continue; 1441187223Skib } 1442137613Srwatson if (semnum >= semakptr->u.sem_nsems) 14432729Sdfr panic("semexit - semnum out of range"); 14442729Sdfr 1445100523Salfred DPRINTF(( 1446160293Skib "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 14472729Sdfr suptr->un_proc, suptr->un_ent[ix].un_id, 14482729Sdfr suptr->un_ent[ix].un_num, 14492729Sdfr suptr->un_ent[ix].un_adjval, 1450137613Srwatson semakptr->u.sem_base[semnum].semval)); 14512729Sdfr 1452187223Skib if (adjval < 0 && semakptr->u.sem_base[semnum].semval < 1453187223Skib -adjval) 1454187223Skib semakptr->u.sem_base[semnum].semval = 0; 1455187223Skib else 1456137613Srwatson semakptr->u.sem_base[semnum].semval += adjval; 14572729Sdfr 1458137613Srwatson wakeup(semakptr); 1459100523Salfred DPRINTF(("semexit: back from wakeup\n")); 1460101774Salfred mtx_unlock(sema_mtxp); 14612729Sdfr } 1462187223Skib SEMUNDO_LOCK(); 14632729Sdfr } 14642729Sdfr 14652729Sdfr /* 14662729Sdfr * Deallocate the undo vector. 14672729Sdfr */ 1468100523Salfred DPRINTF(("removing vector\n")); 14692729Sdfr suptr->un_proc = NULL; 1470187223Skib suptr->un_cnt = 0; 1471187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1472167904Semaste SEMUNDO_UNLOCK(); 14732729Sdfr} 147477461Sdd 147577461Sddstatic int 147677461Sddsysctl_sema(SYSCTL_HANDLER_ARGS) 147777461Sdd{ 1478298656Sjamie struct prison *pr, *rpr; 1479298656Sjamie struct semid_kernel tsemak; 1480329177Sbrooks#ifdef COMPAT_FREEBSD32 1481329177Sbrooks struct semid_kernel32 tsemak32; 1482329177Sbrooks#endif 1483329177Sbrooks void *outaddr; 1484329177Sbrooks size_t outsize; 1485298585Sjamie int error, i; 148677461Sdd 1487298656Sjamie pr = req->td->td_ucred->cr_prison; 1488298585Sjamie rpr = sem_find_prison(req->td->td_ucred); 1489298656Sjamie error = 0; 1490298585Sjamie for (i = 0; i < seminfo.semmni; i++) { 1491298656Sjamie mtx_lock(&sema_mtx[i]); 1492298656Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) == 0 || 1493298656Sjamie rpr == NULL || sem_prison_cansee(rpr, &sema[i]) != 0) 1494298656Sjamie bzero(&tsemak, sizeof(tsemak)); 1495298656Sjamie else { 1496298656Sjamie tsemak = sema[i]; 1497298656Sjamie if (tsemak.cred->cr_prison != pr) 1498298656Sjamie tsemak.u.sem_perm.key = IPC_PRIVATE; 1499298585Sjamie } 1500298656Sjamie mtx_unlock(&sema_mtx[i]); 1501329177Sbrooks#ifdef COMPAT_FREEBSD32 1502329177Sbrooks if (SV_CURPROC_FLAG(SV_ILP32)) { 1503329177Sbrooks bzero(&tsemak32, sizeof(tsemak32)); 1504329177Sbrooks freebsd32_ipcperm_out(&tsemak.u.sem_perm, 1505329177Sbrooks &tsemak32.u.sem_perm); 1506329177Sbrooks /* Don't copy u.sem_base */ 1507329177Sbrooks CP(tsemak, tsemak32, u.sem_nsems); 1508329177Sbrooks CP(tsemak, tsemak32, u.sem_otime); 1509329177Sbrooks CP(tsemak, tsemak32, u.sem_ctime); 1510329177Sbrooks /* Don't copy label or cred */ 1511329177Sbrooks outaddr = &tsemak32; 1512329177Sbrooks outsize = sizeof(tsemak32); 1513329177Sbrooks } else 1514329177Sbrooks#endif 1515329177Sbrooks { 1516329177Sbrooks tsemak.u.sem_base = NULL; 1517329177Sbrooks tsemak.label = NULL; 1518329177Sbrooks tsemak.cred = NULL; 1519329177Sbrooks outaddr = &tsemak; 1520329177Sbrooks outsize = sizeof(tsemak); 1521329177Sbrooks } 1522329177Sbrooks error = SYSCTL_OUT(req, outaddr, outsize); 1523298656Sjamie if (error != 0) 1524298656Sjamie break; 1525298585Sjamie } 1526298585Sjamie return (error); 152777461Sdd} 1528194894Sjhb 1529298585Sjamiestatic int 1530298585Sjamiesem_prison_check(void *obj, void *data) 1531298585Sjamie{ 1532298585Sjamie struct prison *pr = obj; 1533298585Sjamie struct prison *prpr; 1534298585Sjamie struct vfsoptlist *opts = data; 1535298585Sjamie int error, jsys; 1536298585Sjamie 1537298585Sjamie /* 1538298585Sjamie * sysvsem is a jailsys integer. 1539298585Sjamie * It must be "disable" if the parent jail is disabled. 1540298585Sjamie */ 1541298585Sjamie error = vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1542298585Sjamie if (error != ENOENT) { 1543298585Sjamie if (error != 0) 1544298585Sjamie return (error); 1545298585Sjamie switch (jsys) { 1546298585Sjamie case JAIL_SYS_DISABLE: 1547298585Sjamie break; 1548298585Sjamie case JAIL_SYS_NEW: 1549298585Sjamie case JAIL_SYS_INHERIT: 1550298585Sjamie prison_lock(pr->pr_parent); 1551298585Sjamie prpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1552298585Sjamie prison_unlock(pr->pr_parent); 1553298585Sjamie if (prpr == NULL) 1554298585Sjamie return (EPERM); 1555298585Sjamie break; 1556298585Sjamie default: 1557298585Sjamie return (EINVAL); 1558298585Sjamie } 1559298585Sjamie } 1560298585Sjamie 1561298585Sjamie return (0); 1562298585Sjamie} 1563298585Sjamie 1564298585Sjamiestatic int 1565298585Sjamiesem_prison_set(void *obj, void *data) 1566298585Sjamie{ 1567298585Sjamie struct prison *pr = obj; 1568298585Sjamie struct prison *tpr, *orpr, *nrpr, *trpr; 1569298585Sjamie struct vfsoptlist *opts = data; 1570298585Sjamie void *rsv; 1571298585Sjamie int jsys, descend; 1572298585Sjamie 1573298585Sjamie /* 1574298585Sjamie * sysvsem controls which jail is the root of the associated sems (this 1575298585Sjamie * jail or same as the parent), or if the feature is available at all. 1576298585Sjamie */ 1577298585Sjamie if (vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)) == ENOENT) 1578298585Sjamie jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0) 1579298585Sjamie ? JAIL_SYS_INHERIT 1580298585Sjamie : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0) 1581298585Sjamie ? JAIL_SYS_DISABLE 1582298585Sjamie : -1; 1583298585Sjamie if (jsys == JAIL_SYS_DISABLE) { 1584298585Sjamie prison_lock(pr); 1585298585Sjamie orpr = osd_jail_get(pr, sem_prison_slot); 1586298585Sjamie if (orpr != NULL) 1587298585Sjamie osd_jail_del(pr, sem_prison_slot); 1588298585Sjamie prison_unlock(pr); 1589298585Sjamie if (orpr != NULL) { 1590298585Sjamie if (orpr == pr) 1591298585Sjamie sem_prison_cleanup(pr); 1592298585Sjamie /* Disable all child jails as well. */ 1593298585Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1594298585Sjamie prison_lock(tpr); 1595298585Sjamie trpr = osd_jail_get(tpr, sem_prison_slot); 1596298585Sjamie if (trpr != NULL) { 1597298585Sjamie osd_jail_del(tpr, sem_prison_slot); 1598298585Sjamie prison_unlock(tpr); 1599298585Sjamie if (trpr == tpr) 1600298585Sjamie sem_prison_cleanup(tpr); 1601298585Sjamie } else { 1602298585Sjamie prison_unlock(tpr); 1603298585Sjamie descend = 0; 1604298585Sjamie } 1605298585Sjamie } 1606298585Sjamie } 1607298585Sjamie } else if (jsys != -1) { 1608298585Sjamie if (jsys == JAIL_SYS_NEW) 1609298585Sjamie nrpr = pr; 1610298585Sjamie else { 1611298585Sjamie prison_lock(pr->pr_parent); 1612298585Sjamie nrpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1613298585Sjamie prison_unlock(pr->pr_parent); 1614298585Sjamie } 1615298585Sjamie rsv = osd_reserve(sem_prison_slot); 1616298585Sjamie prison_lock(pr); 1617298585Sjamie orpr = osd_jail_get(pr, sem_prison_slot); 1618298585Sjamie if (orpr != nrpr) 1619298585Sjamie (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 1620298585Sjamie nrpr); 1621298585Sjamie else 1622298585Sjamie osd_free_reserved(rsv); 1623298585Sjamie prison_unlock(pr); 1624298585Sjamie if (orpr != nrpr) { 1625298585Sjamie if (orpr == pr) 1626298585Sjamie sem_prison_cleanup(pr); 1627298585Sjamie if (orpr != NULL) { 1628298585Sjamie /* Change child jails matching the old root, */ 1629298585Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1630298585Sjamie prison_lock(tpr); 1631298585Sjamie trpr = osd_jail_get(tpr, 1632298585Sjamie sem_prison_slot); 1633298585Sjamie if (trpr == orpr) { 1634298585Sjamie (void)osd_jail_set(tpr, 1635298585Sjamie sem_prison_slot, nrpr); 1636298585Sjamie prison_unlock(tpr); 1637298585Sjamie if (trpr == tpr) 1638298585Sjamie sem_prison_cleanup(tpr); 1639298585Sjamie } else { 1640298585Sjamie prison_unlock(tpr); 1641298585Sjamie descend = 0; 1642298585Sjamie } 1643298585Sjamie } 1644298585Sjamie } 1645298585Sjamie } 1646298585Sjamie } 1647298585Sjamie 1648298585Sjamie return (0); 1649298585Sjamie} 1650298585Sjamie 1651298585Sjamiestatic int 1652298585Sjamiesem_prison_get(void *obj, void *data) 1653298585Sjamie{ 1654298585Sjamie struct prison *pr = obj; 1655298585Sjamie struct prison *rpr; 1656298585Sjamie struct vfsoptlist *opts = data; 1657298585Sjamie int error, jsys; 1658298585Sjamie 1659298585Sjamie /* Set sysvsem based on the jail's root prison. */ 1660298585Sjamie prison_lock(pr); 1661298585Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 1662298585Sjamie prison_unlock(pr); 1663298585Sjamie jsys = rpr == NULL ? JAIL_SYS_DISABLE 1664298585Sjamie : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 1665298585Sjamie error = vfs_setopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1666298585Sjamie if (error == ENOENT) 1667298585Sjamie error = 0; 1668298585Sjamie return (error); 1669298585Sjamie} 1670298585Sjamie 1671298585Sjamiestatic int 1672298585Sjamiesem_prison_remove(void *obj, void *data __unused) 1673298585Sjamie{ 1674298585Sjamie struct prison *pr = obj; 1675298585Sjamie struct prison *rpr; 1676298585Sjamie 1677298585Sjamie prison_lock(pr); 1678298585Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 1679298585Sjamie prison_unlock(pr); 1680298585Sjamie if (rpr == pr) 1681298585Sjamie sem_prison_cleanup(pr); 1682298585Sjamie return (0); 1683298585Sjamie} 1684298585Sjamie 1685298585Sjamiestatic void 1686298585Sjamiesem_prison_cleanup(struct prison *pr) 1687298585Sjamie{ 1688298585Sjamie int i; 1689298585Sjamie 1690298585Sjamie /* Remove any sems that belong to this jail. */ 1691298585Sjamie mtx_lock(&sem_mtx); 1692298585Sjamie for (i = 0; i < seminfo.semmni; i++) { 1693298585Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 1694298585Sjamie sema[i].cred != NULL && sema[i].cred->cr_prison == pr) { 1695298585Sjamie mtx_lock(&sema_mtx[i]); 1696298585Sjamie sem_remove(i, NULL); 1697298585Sjamie mtx_unlock(&sema_mtx[i]); 1698298585Sjamie } 1699298585Sjamie } 1700298585Sjamie mtx_unlock(&sem_mtx); 1701298585Sjamie} 1702298585Sjamie 1703298585SjamieSYSCTL_JAIL_PARAM_SYS_NODE(sysvsem, CTLFLAG_RW, "SYSV semaphores"); 1704298585Sjamie 1705194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1706194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1707194894Sjhb 1708194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1709194894Sjhbstatic sy_call_t *semcalls[] = { 1710225617Skmacy (sy_call_t *)freebsd7___semctl, (sy_call_t *)sys_semget, 1711225617Skmacy (sy_call_t *)sys_semop 1712194894Sjhb}; 1713194894Sjhb 1714194894Sjhb/* 1715194894Sjhb * Entry point for all SEM calls. 1716194894Sjhb */ 1717194894Sjhbint 1718225617Skmacysys_semsys(td, uap) 1719194894Sjhb struct thread *td; 1720194894Sjhb /* XXX actually varargs. */ 1721194894Sjhb struct semsys_args /* { 1722194894Sjhb int which; 1723194894Sjhb int a2; 1724194894Sjhb int a3; 1725194894Sjhb int a4; 1726194894Sjhb int a5; 1727194894Sjhb } */ *uap; 1728194894Sjhb{ 1729194894Sjhb int error; 1730194894Sjhb 1731298354Spfg if (uap->which < 0 || uap->which >= nitems(semcalls)) 1732194894Sjhb return (EINVAL); 1733194894Sjhb error = (*semcalls[uap->which])(td, &uap->a2); 1734194894Sjhb return (error); 1735194894Sjhb} 1736194910Sjhb 1737194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1738194910Sjhbstruct freebsd7___semctl_args { 1739194910Sjhb int semid; 1740194910Sjhb int semnum; 1741194910Sjhb int cmd; 1742194910Sjhb union semun_old *arg; 1743194910Sjhb}; 1744194910Sjhb#endif 1745194910Sjhbint 1746194910Sjhbfreebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1747194910Sjhb{ 1748194910Sjhb struct semid_ds_old dsold; 1749194910Sjhb struct semid_ds dsbuf; 1750194910Sjhb union semun_old arg; 1751194910Sjhb union semun semun; 1752194910Sjhb register_t rval; 1753194910Sjhb int error; 1754194910Sjhb 1755194910Sjhb switch (uap->cmd) { 1756194910Sjhb case SEM_STAT: 1757194910Sjhb case IPC_SET: 1758194910Sjhb case IPC_STAT: 1759194910Sjhb case GETALL: 1760194910Sjhb case SETVAL: 1761194910Sjhb case SETALL: 1762194910Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 1763194910Sjhb if (error) 1764194910Sjhb return (error); 1765194910Sjhb break; 1766194910Sjhb } 1767194910Sjhb 1768194910Sjhb switch (uap->cmd) { 1769194910Sjhb case SEM_STAT: 1770194910Sjhb case IPC_STAT: 1771194910Sjhb semun.buf = &dsbuf; 1772194910Sjhb break; 1773194910Sjhb case IPC_SET: 1774194910Sjhb error = copyin(arg.buf, &dsold, sizeof(dsold)); 1775194910Sjhb if (error) 1776194910Sjhb return (error); 1777194910Sjhb ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1778194910Sjhb CP(dsold, dsbuf, sem_base); 1779194910Sjhb CP(dsold, dsbuf, sem_nsems); 1780194910Sjhb CP(dsold, dsbuf, sem_otime); 1781194910Sjhb CP(dsold, dsbuf, sem_ctime); 1782194910Sjhb semun.buf = &dsbuf; 1783194910Sjhb break; 1784194910Sjhb case GETALL: 1785194910Sjhb case SETALL: 1786194910Sjhb semun.array = arg.array; 1787194910Sjhb break; 1788194910Sjhb case SETVAL: 1789194910Sjhb semun.val = arg.val; 1790194910Sjhb break; 1791194910Sjhb } 1792194910Sjhb 1793194910Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1794194910Sjhb &rval); 1795194910Sjhb if (error) 1796194910Sjhb return (error); 1797194910Sjhb 1798194910Sjhb switch (uap->cmd) { 1799194910Sjhb case SEM_STAT: 1800194910Sjhb case IPC_STAT: 1801194910Sjhb bzero(&dsold, sizeof(dsold)); 1802194910Sjhb ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1803194910Sjhb CP(dsbuf, dsold, sem_base); 1804194910Sjhb CP(dsbuf, dsold, sem_nsems); 1805194910Sjhb CP(dsbuf, dsold, sem_otime); 1806194910Sjhb CP(dsbuf, dsold, sem_ctime); 1807194910Sjhb error = copyout(&dsold, arg.buf, sizeof(dsold)); 1808194910Sjhb break; 1809194910Sjhb } 1810194910Sjhb 1811194910Sjhb if (error == 0) 1812194910Sjhb td->td_retval[0] = rval; 1813194910Sjhb return (error); 1814194910Sjhb} 1815194910Sjhb 1816205323Skib#endif /* COMPAT_FREEBSD{4,5,6,7} */ 1817194910Sjhb 1818205323Skib#ifdef COMPAT_FREEBSD32 1819205323Skib 1820205323Skibint 1821205323Skibfreebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1822205323Skib{ 1823205323Skib 1824205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1825205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1826205323Skib switch (uap->which) { 1827205323Skib case 0: 1828205323Skib return (freebsd7_freebsd32_semctl(td, 1829205323Skib (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1830205323Skib default: 1831225617Skmacy return (sys_semsys(td, (struct semsys_args *)uap)); 1832205323Skib } 1833205323Skib#else 1834205323Skib return (nosys(td, NULL)); 1835205323Skib#endif 1836205323Skib} 1837205323Skib 1838205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1839205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1840205323Skibint 1841205323Skibfreebsd7_freebsd32_semctl(struct thread *td, 1842205323Skib struct freebsd7_freebsd32_semctl_args *uap) 1843205323Skib{ 1844205323Skib struct semid_ds32_old dsbuf32; 1845205323Skib struct semid_ds dsbuf; 1846205323Skib union semun semun; 1847205323Skib union semun32 arg; 1848205323Skib register_t rval; 1849205323Skib int error; 1850205323Skib 1851205323Skib switch (uap->cmd) { 1852205323Skib case SEM_STAT: 1853205323Skib case IPC_SET: 1854205323Skib case IPC_STAT: 1855205323Skib case GETALL: 1856205323Skib case SETVAL: 1857205323Skib case SETALL: 1858205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1859205323Skib if (error) 1860205323Skib return (error); 1861205323Skib break; 1862205323Skib } 1863205323Skib 1864205323Skib switch (uap->cmd) { 1865205323Skib case SEM_STAT: 1866205323Skib case IPC_STAT: 1867205323Skib semun.buf = &dsbuf; 1868205323Skib break; 1869205323Skib case IPC_SET: 1870205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1871205323Skib if (error) 1872205323Skib return (error); 1873205323Skib freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1874205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1875205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1876205323Skib CP(dsbuf32, dsbuf, sem_otime); 1877205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1878205323Skib semun.buf = &dsbuf; 1879205323Skib break; 1880205323Skib case GETALL: 1881205323Skib case SETALL: 1882205323Skib semun.array = PTRIN(arg.array); 1883205323Skib break; 1884205323Skib case SETVAL: 1885205323Skib semun.val = arg.val; 1886205323Skib break; 1887205323Skib } 1888205323Skib 1889205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1890205323Skib &rval); 1891205323Skib if (error) 1892205323Skib return (error); 1893205323Skib 1894205323Skib switch (uap->cmd) { 1895205323Skib case SEM_STAT: 1896205323Skib case IPC_STAT: 1897205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1898205323Skib freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1899205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1900205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1901205323Skib CP(dsbuf, dsbuf32, sem_otime); 1902205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1903205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1904205323Skib break; 1905205323Skib } 1906205323Skib 1907205323Skib if (error == 0) 1908205323Skib td->td_retval[0] = rval; 1909205323Skib return (error); 1910205323Skib} 1911205323Skib#endif 1912205323Skib 1913205323Skibint 1914205323Skibfreebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1915205323Skib{ 1916205323Skib struct semid_ds32 dsbuf32; 1917205323Skib struct semid_ds dsbuf; 1918205323Skib union semun semun; 1919205323Skib union semun32 arg; 1920205323Skib register_t rval; 1921205323Skib int error; 1922205323Skib 1923205323Skib switch (uap->cmd) { 1924205323Skib case SEM_STAT: 1925205323Skib case IPC_SET: 1926205323Skib case IPC_STAT: 1927205323Skib case GETALL: 1928205323Skib case SETVAL: 1929205323Skib case SETALL: 1930205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1931205323Skib if (error) 1932205323Skib return (error); 1933205323Skib break; 1934205323Skib } 1935205323Skib 1936205323Skib switch (uap->cmd) { 1937205323Skib case SEM_STAT: 1938205323Skib case IPC_STAT: 1939205323Skib semun.buf = &dsbuf; 1940205323Skib break; 1941205323Skib case IPC_SET: 1942205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1943205323Skib if (error) 1944205323Skib return (error); 1945205323Skib freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1946205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1947205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1948205323Skib CP(dsbuf32, dsbuf, sem_otime); 1949205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1950205323Skib semun.buf = &dsbuf; 1951205323Skib break; 1952205323Skib case GETALL: 1953205323Skib case SETALL: 1954205323Skib semun.array = PTRIN(arg.array); 1955205323Skib break; 1956205323Skib case SETVAL: 1957205323Skib semun.val = arg.val; 1958205323Skib break; 1959205323Skib } 1960205323Skib 1961205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1962205323Skib &rval); 1963205323Skib if (error) 1964205323Skib return (error); 1965205323Skib 1966205323Skib switch (uap->cmd) { 1967205323Skib case SEM_STAT: 1968205323Skib case IPC_STAT: 1969205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1970205323Skib freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1971205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1972205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1973205323Skib CP(dsbuf, dsbuf32, sem_otime); 1974205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1975205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1976205323Skib break; 1977205323Skib } 1978205323Skib 1979205323Skib if (error == 0) 1980205323Skib td->td_retval[0] = rval; 1981205323Skib return (error); 1982205323Skib} 1983205323Skib 1984205323Skib#endif /* COMPAT_FREEBSD32 */ 1985