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/10/sys/kern/sysv_sem.c 329741 2018-02-21 18:32:57Z brooks $"); 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> 48112564Sjhb#include <sys/eventhandler.h> 492729Sdfr#include <sys/kernel.h> 502729Sdfr#include <sys/proc.h> 5182607Sdillon#include <sys/lock.h> 52129882Sphk#include <sys/module.h> 5382607Sdillon#include <sys/mutex.h> 54220398Strasz#include <sys/racct.h> 552729Sdfr#include <sys/sem.h> 56298835Sjamie#include <sys/sx.h> 5769449Salfred#include <sys/syscall.h> 58159991Sjhb#include <sys/syscallsubr.h> 5911626Sbde#include <sys/sysent.h> 6059839Speter#include <sys/sysctl.h> 61159991Sjhb#include <sys/uio.h> 6259839Speter#include <sys/malloc.h> 6368024Srwatson#include <sys/jail.h> 642729Sdfr 65163606Srwatson#include <security/mac/mac_framework.h> 66163606Srwatson 67219028SnetchildFEATURE(sysv_sem, "System V semaphores support"); 68219028Snetchild 6959839Speterstatic MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 7059839Speter 71100523Salfred#ifdef SEM_DEBUG 72100523Salfred#define DPRINTF(a) printf a 73100523Salfred#else 74100523Salfred#define DPRINTF(a) 75100523Salfred#endif 76100523Salfred 77205323Skibstatic int seminit(void); 7892723Salfredstatic int sysvsem_modload(struct module *, int, void *); 7992723Salfredstatic int semunload(void); 80112564Sjhbstatic void semexit_myhook(void *arg, struct proc *p); 8192723Salfredstatic int sysctl_sema(SYSCTL_HANDLER_ARGS); 82298835Sjamiestatic int semvalid(int semid, struct prison *rpr, 83298835Sjamie struct semid_kernel *semakptr); 84298835Sjamiestatic void sem_remove(int semidx, struct ucred *cred); 85298835Sjamiestatic struct prison *sem_find_prison(struct ucred *); 86298835Sjamiestatic int sem_prison_cansee(struct prison *, struct semid_kernel *); 87298835Sjamiestatic int sem_prison_check(void *, void *); 88298835Sjamiestatic int sem_prison_set(void *, void *); 89298835Sjamiestatic int sem_prison_get(void *, void *); 90298835Sjamiestatic int sem_prison_remove(void *, void *); 91298835Sjamiestatic void sem_prison_cleanup(struct prison *); 9210358Sjulian 9312866Speter#ifndef _SYS_SYSPROTO_H_ 9412866Speterstruct __semctl_args; 9592723Salfredint __semctl(struct thread *td, struct __semctl_args *uap); 9611626Sbdestruct semget_args; 9792723Salfredint semget(struct thread *td, struct semget_args *uap); 9811626Sbdestruct semop_args; 9992723Salfredint semop(struct thread *td, struct semop_args *uap); 10012866Speter#endif 10111626Sbde 10292723Salfredstatic struct sem_undo *semu_alloc(struct thread *td); 103122201Srwatsonstatic int semundo_adjust(struct thread *td, struct sem_undo **supptr, 104187223Skib int semid, int semseq, int semnum, int adjval); 10592723Salfredstatic void semundo_clear(int semid, int semnum); 10611626Sbde 107101774Salfredstatic struct mtx sem_mtx; /* semaphore global lock */ 108187223Skibstatic struct mtx sem_undo_mtx; 10912819Sphkstatic int semtot = 0; 110137613Srwatsonstatic struct semid_kernel *sema; /* semaphore id pool */ 111101774Salfredstatic struct mtx *sema_mtx; /* semaphore id pool mutexes*/ 11259839Speterstatic struct sem *sem; /* semaphore pool */ 113187223SkibLIST_HEAD(, sem_undo) semu_list; /* list of active undo structures */ 114187223SkibLIST_HEAD(, sem_undo) semu_free_list; /* list of free undo structures */ 11559839Speterstatic int *semu; /* undo structure pool */ 116112564Sjhbstatic eventhandler_tag semexit_tag; 117298835Sjamiestatic unsigned sem_prison_slot; /* prison OSD slot */ 1182729Sdfr 119187223Skib#define SEMUNDO_MTX sem_undo_mtx 120101774Salfred#define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX); 121101774Salfred#define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX); 122101774Salfred#define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how)); 123101774Salfred 12459839Speterstruct sem { 12559839Speter u_short semval; /* semaphore value */ 12659839Speter pid_t sempid; /* pid of last operation */ 12759839Speter u_short semncnt; /* # awaiting semval > cval */ 12859839Speter u_short semzcnt; /* # awaiting semval = 0 */ 12959839Speter}; 13059839Speter 13159839Speter/* 13259839Speter * Undo structure (one per process) 13359839Speter */ 13459839Speterstruct sem_undo { 135187223Skib LIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */ 13659839Speter struct proc *un_proc; /* owner of this structure */ 13759839Speter short un_cnt; /* # of active entries */ 13859839Speter struct undo { 13959839Speter short un_adjval; /* adjust on exit values */ 14059839Speter short un_num; /* semaphore # */ 14159839Speter int un_id; /* semid */ 142187223Skib unsigned short un_seq; 14359839Speter } un_ent[1]; /* undo entries */ 14459839Speter}; 14559839Speter 14659839Speter/* 14759839Speter * Configuration parameters 14859839Speter */ 14959839Speter#ifndef SEMMNI 150209037Sivoras#define SEMMNI 50 /* # of semaphore identifiers */ 15159839Speter#endif 15259839Speter#ifndef SEMMNS 153209037Sivoras#define SEMMNS 340 /* # of semaphores in system */ 15459839Speter#endif 15559839Speter#ifndef SEMUME 156209037Sivoras#define SEMUME 50 /* max # of undo entries per process */ 15759839Speter#endif 15859839Speter#ifndef SEMMNU 159209037Sivoras#define SEMMNU 150 /* # of undo structures in system */ 16059839Speter#endif 16159839Speter 16259839Speter/* shouldn't need tuning */ 16359839Speter#ifndef SEMMSL 16459839Speter#define SEMMSL SEMMNS /* max # of semaphores per id */ 16559839Speter#endif 16659839Speter#ifndef SEMOPM 16759839Speter#define SEMOPM 100 /* max # of operations per semop call */ 16859839Speter#endif 16959839Speter 17059839Speter#define SEMVMX 32767 /* semaphore maximum value */ 17159839Speter#define SEMAEM 16384 /* adjust on exit max value */ 17259839Speter 17359839Speter/* 17459839Speter * Due to the way semaphore memory is allocated, we have to ensure that 17559839Speter * SEMUSZ is properly aligned. 17659839Speter */ 17759839Speter 17859839Speter#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 17959839Speter 18059839Speter/* actual size of an undo structure */ 18159839Speter#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 18259839Speter 18359839Speter/* 18459839Speter * Macro to find a particular sem_undo vector 18559839Speter */ 186101350Salfred#define SEMU(ix) \ 187101350Salfred ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 18859839Speter 18959839Speter/* 19059839Speter * semaphore info struct 19159839Speter */ 19259839Speterstruct seminfo seminfo = { 19359839Speter SEMMNI, /* # of semaphore identifiers */ 19459839Speter SEMMNS, /* # of semaphores in system */ 19559839Speter SEMMNU, /* # of undo structures in system */ 19659839Speter SEMMSL, /* max # of semaphores per id */ 19759839Speter SEMOPM, /* max # of operations per semop call */ 19859839Speter SEMUME, /* max # of undo entries per process */ 19959839Speter SEMUSZ, /* size in bytes of undo structure */ 20059839Speter SEMVMX, /* semaphore maximum value */ 20159839Speter SEMAEM /* adjust on exit max value */ 20259839Speter}; 20359839Speter 204141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, 205141710Scsjp "Number of semaphore identifiers"); 206141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, 207141710Scsjp "Maximum number of semaphores in the system"); 208141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, 209141710Scsjp "Maximum number of undo structures in the system"); 210141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, 211141710Scsjp "Max semaphores per id"); 212141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, 213141710Scsjp "Max operations per semop call"); 214141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, 215141710Scsjp "Max undo entries per process"); 216141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0, 217141710Scsjp "Size in bytes of undo structure"); 218141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, 219141710Scsjp "Semaphore maximum value"); 220141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, 221141710Scsjp "Adjust on exit max value"); 222298835SjamieSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, 223298835Sjamie CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 224329741Sbrooks NULL, 0, sysctl_sema, "", 225329741Sbrooks "Array of struct semid_kernel for each potential semaphore"); 22659839Speter 227205323Skibstatic struct syscall_helper_data sem_syscalls[] = { 228205323Skib SYSCALL_INIT_HELPER(__semctl), 229205323Skib SYSCALL_INIT_HELPER(semget), 230205323Skib SYSCALL_INIT_HELPER(semop), 231205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 232205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 233205323Skib SYSCALL_INIT_HELPER(semsys), 234225617Skmacy SYSCALL_INIT_HELPER_COMPAT(freebsd7___semctl), 235205323Skib#endif 236205323Skib SYSCALL_INIT_LAST 237205323Skib}; 238205323Skib 239205323Skib#ifdef COMPAT_FREEBSD32 240205323Skib#include <compat/freebsd32/freebsd32.h> 241205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 242205323Skib#include <compat/freebsd32/freebsd32_proto.h> 243205323Skib#include <compat/freebsd32/freebsd32_signal.h> 244205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 245205323Skib#include <compat/freebsd32/freebsd32_util.h> 246205323Skib 247205323Skibstatic struct syscall_helper_data sem32_syscalls[] = { 248205323Skib SYSCALL32_INIT_HELPER(freebsd32_semctl), 249225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(semget), 250225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(semop), 251205323Skib SYSCALL32_INIT_HELPER(freebsd32_semsys), 252205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 253205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 254205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl), 255205323Skib#endif 256205323Skib SYSCALL_INIT_LAST 257205323Skib}; 258205323Skib#endif 259205323Skib 260205323Skibstatic int 26169449Salfredseminit(void) 2622729Sdfr{ 263298835Sjamie struct prison *pr; 264298835Sjamie void *rsv; 265205323Skib int i, error; 266298835Sjamie osd_method_t methods[PR_MAXMETHOD] = { 267298835Sjamie [PR_METHOD_CHECK] = sem_prison_check, 268298835Sjamie [PR_METHOD_SET] = sem_prison_set, 269298835Sjamie [PR_METHOD_GET] = sem_prison_get, 270298835Sjamie [PR_METHOD_REMOVE] = sem_prison_remove, 271298835Sjamie }; 2722729Sdfr 27383413Smr TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni); 27483413Smr TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns); 27583413Smr TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu); 27683413Smr TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl); 27783413Smr TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm); 27883413Smr TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume); 27983413Smr TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz); 28083413Smr TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx); 28183413Smr TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem); 28283413Smr 283111119Simp sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 284137613Srwatson sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 285111119Simp M_WAITOK); 286101774Salfred sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 287111119Simp M_WAITOK | M_ZERO); 288111119Simp semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 2892729Sdfr 2902729Sdfr for (i = 0; i < seminfo.semmni; i++) { 291137613Srwatson sema[i].u.sem_base = 0; 292137613Srwatson sema[i].u.sem_perm.mode = 0; 293137613Srwatson sema[i].u.sem_perm.seq = 0; 294140615Srwatson#ifdef MAC 295172930Srwatson mac_sysvsem_init(&sema[i]); 296140615Srwatson#endif 2972729Sdfr } 298101774Salfred for (i = 0; i < seminfo.semmni; i++) 299101774Salfred mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 300187223Skib LIST_INIT(&semu_free_list); 3012729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 302101350Salfred struct sem_undo *suptr = SEMU(i); 3032729Sdfr suptr->un_proc = NULL; 304187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 3052729Sdfr } 306187223Skib LIST_INIT(&semu_list); 307101774Salfred mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 308187223Skib mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); 309112564Sjhb semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 310112564Sjhb EVENTHANDLER_PRI_ANY); 311205323Skib 312298835Sjamie /* Set current prisons according to their allow.sysvipc. */ 313298835Sjamie sem_prison_slot = osd_jail_register(NULL, methods); 314298835Sjamie rsv = osd_reserve(sem_prison_slot); 315298835Sjamie prison_lock(&prison0); 316298835Sjamie (void)osd_jail_set_reserved(&prison0, sem_prison_slot, rsv, &prison0); 317298835Sjamie prison_unlock(&prison0); 318298835Sjamie rsv = NULL; 319298835Sjamie sx_slock(&allprison_lock); 320298835Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 321298835Sjamie if (rsv == NULL) 322298835Sjamie rsv = osd_reserve(sem_prison_slot); 323298835Sjamie prison_lock(pr); 324298835Sjamie if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { 325298835Sjamie (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 326298835Sjamie &prison0); 327298835Sjamie rsv = NULL; 328298835Sjamie } 329298835Sjamie prison_unlock(pr); 330298835Sjamie } 331298835Sjamie if (rsv != NULL) 332298835Sjamie osd_free_reserved(rsv); 333298835Sjamie sx_sunlock(&allprison_lock); 334298835Sjamie 335205323Skib error = syscall_helper_register(sem_syscalls); 336205323Skib if (error != 0) 337205323Skib return (error); 338205323Skib#ifdef COMPAT_FREEBSD32 339205323Skib error = syscall32_helper_register(sem32_syscalls); 340205323Skib if (error != 0) 341205323Skib return (error); 342205323Skib#endif 343205323Skib return (0); 3442729Sdfr} 3452729Sdfr 34669449Salfredstatic int 34769449Salfredsemunload(void) 34869449Salfred{ 349101774Salfred int i; 35069449Salfred 351187223Skib /* XXXKIB */ 35269449Salfred if (semtot != 0) 35369449Salfred return (EBUSY); 35469449Salfred 355205323Skib#ifdef COMPAT_FREEBSD32 356205323Skib syscall32_helper_unregister(sem32_syscalls); 357205323Skib#endif 358205323Skib syscall_helper_unregister(sem_syscalls); 359112564Sjhb EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 360298835Sjamie if (sem_prison_slot != 0) 361298835Sjamie osd_jail_deregister(sem_prison_slot); 362140615Srwatson#ifdef MAC 363140615Srwatson for (i = 0; i < seminfo.semmni; i++) 364172930Srwatson mac_sysvsem_destroy(&sema[i]); 365140615Srwatson#endif 36669449Salfred free(sem, M_SEM); 36769449Salfred free(sema, M_SEM); 36869449Salfred free(semu, M_SEM); 369101774Salfred for (i = 0; i < seminfo.semmni; i++) 370101774Salfred mtx_destroy(&sema_mtx[i]); 371190557Sbrueffer free(sema_mtx, M_SEM); 372101774Salfred mtx_destroy(&sem_mtx); 373187223Skib mtx_destroy(&sem_undo_mtx); 37469449Salfred return (0); 37569449Salfred} 37669449Salfred 37769449Salfredstatic int 37869449Salfredsysvsem_modload(struct module *module, int cmd, void *arg) 37969449Salfred{ 38069449Salfred int error = 0; 38169449Salfred 38269449Salfred switch (cmd) { 38369449Salfred case MOD_LOAD: 384205323Skib error = seminit(); 385205323Skib if (error != 0) 386205323Skib semunload(); 38769449Salfred break; 38869449Salfred case MOD_UNLOAD: 38969449Salfred error = semunload(); 39069449Salfred break; 39169449Salfred case MOD_SHUTDOWN: 39269449Salfred break; 39369449Salfred default: 39469449Salfred error = EINVAL; 39569449Salfred break; 39669449Salfred } 39769449Salfred return (error); 39869449Salfred} 39969449Salfred 40071038Sdesstatic moduledata_t sysvsem_mod = { 40171038Sdes "sysvsem", 40269449Salfred &sysvsem_modload, 40369449Salfred NULL 40469449Salfred}; 40569449Salfred 406194832SjhbDECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 40771038SdesMODULE_VERSION(sysvsem, 1); 40869449Salfred 4092729Sdfr/* 4102729Sdfr * Allocate a new sem_undo structure for a process 4112729Sdfr * (returns ptr to structure or NULL if no more room) 4122729Sdfr */ 4132729Sdfr 41412819Sphkstatic struct sem_undo * 415187223Skibsemu_alloc(struct thread *td) 4162729Sdfr{ 417101350Salfred struct sem_undo *suptr; 4182729Sdfr 419101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 420187223Skib if ((suptr = LIST_FIRST(&semu_free_list)) == NULL) 421187223Skib return (NULL); 422187223Skib LIST_REMOVE(suptr, un_next); 423187223Skib LIST_INSERT_HEAD(&semu_list, suptr, un_next); 424187223Skib suptr->un_cnt = 0; 425187223Skib suptr->un_proc = td->td_proc; 426187223Skib return (suptr); 427187223Skib} 4282729Sdfr 429187223Skibstatic int 430187223Skibsemu_try_free(struct sem_undo *suptr) 431187223Skib{ 4322729Sdfr 433187223Skib SEMUNDO_LOCKASSERT(MA_OWNED); 4342729Sdfr 435187223Skib if (suptr->un_cnt != 0) 436187223Skib return (0); 437187223Skib LIST_REMOVE(suptr, un_next); 438187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 439187223Skib return (1); 4402729Sdfr} 4412729Sdfr 4422729Sdfr/* 4432729Sdfr * Adjust a particular entry for a particular proc 4442729Sdfr */ 4452729Sdfr 44612819Sphkstatic int 447187223Skibsemundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, 448187223Skib int semseq, int semnum, int adjval) 4492729Sdfr{ 45083366Sjulian struct proc *p = td->td_proc; 451101350Salfred struct sem_undo *suptr; 452101350Salfred struct undo *sunptr; 4532729Sdfr int i; 4542729Sdfr 455101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 4562729Sdfr /* Look for and remember the sem_undo if the caller doesn't provide 4572729Sdfr it */ 4582729Sdfr 4592729Sdfr suptr = *supptr; 4602729Sdfr if (suptr == NULL) { 461187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 4622729Sdfr if (suptr->un_proc == p) { 4632729Sdfr *supptr = suptr; 4642729Sdfr break; 4652729Sdfr } 4662729Sdfr } 4672729Sdfr if (suptr == NULL) { 4682729Sdfr if (adjval == 0) 4692729Sdfr return(0); 47083366Sjulian suptr = semu_alloc(td); 4712729Sdfr if (suptr == NULL) 472187223Skib return (ENOSPC); 4732729Sdfr *supptr = suptr; 4742729Sdfr } 4752729Sdfr } 4762729Sdfr 4772729Sdfr /* 4782729Sdfr * Look for the requested entry and adjust it (delete if adjval becomes 4792729Sdfr * 0). 4802729Sdfr */ 4812729Sdfr sunptr = &suptr->un_ent[0]; 4822729Sdfr for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 4832729Sdfr if (sunptr->un_id != semid || sunptr->un_num != semnum) 4842729Sdfr continue; 48584789Smr if (adjval != 0) { 48684789Smr adjval += sunptr->un_adjval; 48784789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 48884789Smr return (ERANGE); 48984789Smr } 49084789Smr sunptr->un_adjval = adjval; 4912729Sdfr if (sunptr->un_adjval == 0) { 4922729Sdfr suptr->un_cnt--; 4932729Sdfr if (i < suptr->un_cnt) 4942729Sdfr suptr->un_ent[i] = 4952729Sdfr suptr->un_ent[suptr->un_cnt]; 496187223Skib if (suptr->un_cnt == 0) 497187223Skib semu_try_free(suptr); 4982729Sdfr } 499187223Skib return (0); 5002729Sdfr } 5012729Sdfr 5022729Sdfr /* Didn't find the right entry - create it */ 5032729Sdfr if (adjval == 0) 504187223Skib return (0); 50584789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 50684789Smr return (ERANGE); 50741774Sdillon if (suptr->un_cnt != seminfo.semume) { 5082729Sdfr sunptr = &suptr->un_ent[suptr->un_cnt]; 5092729Sdfr suptr->un_cnt++; 5102729Sdfr sunptr->un_adjval = adjval; 511187223Skib sunptr->un_id = semid; 512187223Skib sunptr->un_num = semnum; 513187223Skib sunptr->un_seq = semseq; 5142729Sdfr } else 515187223Skib return (EINVAL); 516187223Skib return (0); 5172729Sdfr} 5182729Sdfr 51912819Sphkstatic void 520187223Skibsemundo_clear(int semid, int semnum) 5212729Sdfr{ 522187223Skib struct sem_undo *suptr, *suptr1; 523187223Skib struct undo *sunptr; 524187223Skib int i; 5252729Sdfr 526101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 527187223Skib LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { 528187223Skib sunptr = &suptr->un_ent[0]; 529187223Skib for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 530187223Skib if (sunptr->un_id != semid) 531187223Skib continue; 532187223Skib if (semnum == -1 || sunptr->un_num == semnum) { 533187223Skib suptr->un_cnt--; 534187223Skib if (i < suptr->un_cnt) { 535187223Skib suptr->un_ent[i] = 536187223Skib suptr->un_ent[suptr->un_cnt]; 537187223Skib continue; 5382729Sdfr } 539187223Skib semu_try_free(suptr); 5402729Sdfr } 541187223Skib if (semnum != -1) 542187223Skib break; 5432729Sdfr } 5442729Sdfr } 5452729Sdfr} 5462729Sdfr 547101774Salfredstatic int 548298835Sjamiesemvalid(int semid, struct prison *rpr, struct semid_kernel *semakptr) 549101774Salfred{ 550101774Salfred 551137613Srwatson return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 552298835Sjamie semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) || 553298835Sjamie sem_prison_cansee(rpr, semakptr) ? EINVAL : 0); 554101774Salfred} 555101774Salfred 556298835Sjamiestatic void 557298835Sjamiesem_remove(int semidx, struct ucred *cred) 558298835Sjamie{ 559298835Sjamie struct semid_kernel *semakptr; 560298835Sjamie int i; 561298835Sjamie 562298835Sjamie KASSERT(semidx >= 0 && semidx < seminfo.semmni, 563298835Sjamie ("semidx out of bounds")); 564298835Sjamie semakptr = &sema[semidx]; 565298835Sjamie semakptr->u.sem_perm.cuid = cred ? cred->cr_uid : 0; 566298835Sjamie semakptr->u.sem_perm.uid = cred ? cred->cr_uid : 0; 567298835Sjamie semakptr->u.sem_perm.mode = 0; 568298835Sjamie racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); 569298835Sjamie crfree(semakptr->cred); 570298835Sjamie semakptr->cred = NULL; 571298835Sjamie SEMUNDO_LOCK(); 572298835Sjamie semundo_clear(semidx, -1); 573298835Sjamie SEMUNDO_UNLOCK(); 574298835Sjamie#ifdef MAC 575298835Sjamie mac_sysvsem_cleanup(semakptr); 576298835Sjamie#endif 577298835Sjamie wakeup(semakptr); 578298835Sjamie for (i = 0; i < seminfo.semmni; i++) { 579298835Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 580298835Sjamie sema[i].u.sem_base > semakptr->u.sem_base) 581298835Sjamie mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 582298835Sjamie } 583298835Sjamie for (i = semakptr->u.sem_base - sem; i < semtot; i++) 584298835Sjamie sem[i] = sem[i + semakptr->u.sem_nsems]; 585298835Sjamie for (i = 0; i < seminfo.semmni; i++) { 586298835Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 587298835Sjamie sema[i].u.sem_base > semakptr->u.sem_base) { 588298835Sjamie sema[i].u.sem_base -= semakptr->u.sem_nsems; 589298835Sjamie mtx_unlock(&sema_mtx[i]); 590298835Sjamie } 591298835Sjamie } 592298835Sjamie semtot -= semakptr->u.sem_nsems; 593298835Sjamie} 594298835Sjamie 595298835Sjamiestatic struct prison * 596298835Sjamiesem_find_prison(struct ucred *cred) 597298835Sjamie{ 598298835Sjamie struct prison *pr, *rpr; 599298835Sjamie 600298835Sjamie pr = cred->cr_prison; 601298835Sjamie prison_lock(pr); 602298835Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 603298835Sjamie prison_unlock(pr); 604298835Sjamie return rpr; 605298835Sjamie} 606298835Sjamie 607298835Sjamiestatic int 608298835Sjamiesem_prison_cansee(struct prison *rpr, struct semid_kernel *semakptr) 609298835Sjamie{ 610298835Sjamie 611298835Sjamie if (semakptr->cred == NULL || 612298835Sjamie !(rpr == semakptr->cred->cr_prison || 613298835Sjamie prison_ischild(rpr, semakptr->cred->cr_prison))) 614298835Sjamie return (EINVAL); 615298835Sjamie return (0); 616298835Sjamie} 617298835Sjamie 61812866Speter/* 619167211Srwatson * Note that the user-mode half of this passes a union, not a pointer. 62012866Speter */ 62112866Speter#ifndef _SYS_SYSPROTO_H_ 62212866Speterstruct __semctl_args { 6232729Sdfr int semid; 6242729Sdfr int semnum; 6252729Sdfr int cmd; 6262729Sdfr union semun *arg; 6272729Sdfr}; 62812866Speter#endif 62912866Speterint 630225617Skmacysys___semctl(struct thread *td, struct __semctl_args *uap) 6312729Sdfr{ 632160187Sjhb struct semid_ds dsbuf; 633160187Sjhb union semun arg, semun; 634160187Sjhb register_t rval; 635159991Sjhb int error; 636159991Sjhb 637159991Sjhb switch (uap->cmd) { 638159991Sjhb case SEM_STAT: 639159991Sjhb case IPC_SET: 640159991Sjhb case IPC_STAT: 641159991Sjhb case GETALL: 642159991Sjhb case SETVAL: 643159991Sjhb case SETALL: 644160187Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 645159991Sjhb if (error) 646159991Sjhb return (error); 647159991Sjhb break; 648160187Sjhb } 649160187Sjhb 650160187Sjhb switch (uap->cmd) { 651160187Sjhb case SEM_STAT: 652160187Sjhb case IPC_STAT: 653160187Sjhb semun.buf = &dsbuf; 654159991Sjhb break; 655160187Sjhb case IPC_SET: 656160187Sjhb error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 657160187Sjhb if (error) 658160187Sjhb return (error); 659160187Sjhb semun.buf = &dsbuf; 660160187Sjhb break; 661160187Sjhb case GETALL: 662160187Sjhb case SETALL: 663160187Sjhb semun.array = arg.array; 664160187Sjhb break; 665160187Sjhb case SETVAL: 666160187Sjhb semun.val = arg.val; 667160187Sjhb break; 668159991Sjhb } 669160187Sjhb 670160187Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 671160187Sjhb &rval); 672160187Sjhb if (error) 673160187Sjhb return (error); 674160187Sjhb 675160187Sjhb switch (uap->cmd) { 676160187Sjhb case SEM_STAT: 677160187Sjhb case IPC_STAT: 678160187Sjhb error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 679160187Sjhb break; 680160187Sjhb } 681160187Sjhb 682160187Sjhb if (error == 0) 683160187Sjhb td->td_retval[0] = rval; 684160187Sjhb return (error); 685159991Sjhb} 686159991Sjhb 687159991Sjhbint 688160187Sjhbkern_semctl(struct thread *td, int semid, int semnum, int cmd, 689160187Sjhb union semun *arg, register_t *rval) 690159991Sjhb{ 691101774Salfred u_short *array; 69291406Sjhb struct ucred *cred = td->td_ucred; 693160187Sjhb int i, error; 694298835Sjamie struct prison *rpr; 695160187Sjhb struct semid_ds *sbuf; 696137613Srwatson struct semid_kernel *semakptr; 697101774Salfred struct mtx *sema_mtxp; 698101774Salfred u_short usval, count; 699160028Sjhb int semidx; 7002729Sdfr 701160293Skib DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 702100523Salfred semid, semnum, cmd, arg)); 703298835Sjamie 704298835Sjamie rpr = sem_find_prison(td->td_ucred); 705298835Sjamie if (sem == NULL) 70691703Sjhb return (ENOSYS); 70791703Sjhb 708101774Salfred array = NULL; 709101774Salfred 71083414Smr switch(cmd) { 71183414Smr case SEM_STAT: 712160028Sjhb /* 713160028Sjhb * For this command we assume semid is an array index 714160028Sjhb * rather than an IPC id. 715160028Sjhb */ 71691744Smaxim if (semid < 0 || semid >= seminfo.semmni) 717101774Salfred return (EINVAL); 718137613Srwatson semakptr = &sema[semid]; 719101774Salfred sema_mtxp = &sema_mtx[semid]; 720101774Salfred mtx_lock(sema_mtxp); 721137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 722101774Salfred error = EINVAL; 723101774Salfred goto done2; 724101774Salfred } 725298835Sjamie if ((error = sem_prison_cansee(rpr, semakptr))) 726298835Sjamie goto done2; 727137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 728101774Salfred goto done2; 729140615Srwatson#ifdef MAC 730172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 731162468Srwatson if (error != 0) 732140615Srwatson goto done2; 733140615Srwatson#endif 734160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 735298835Sjamie if (cred->cr_prison != semakptr->cred->cr_prison) 736298835Sjamie arg->buf->sem_perm.key = IPC_PRIVATE; 737160187Sjhb *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 738101774Salfred mtx_unlock(sema_mtxp); 739160187Sjhb return (0); 74083414Smr } 74183414Smr 742160028Sjhb semidx = IPCID_TO_IX(semid); 743160028Sjhb if (semidx < 0 || semidx >= seminfo.semmni) 744101774Salfred return (EINVAL); 7452729Sdfr 746160028Sjhb semakptr = &sema[semidx]; 747160028Sjhb sema_mtxp = &sema_mtx[semidx]; 748187223Skib if (cmd == IPC_RMID) 749187223Skib mtx_lock(&sem_mtx); 750160187Sjhb mtx_lock(sema_mtxp); 751298835Sjamie 752140615Srwatson#ifdef MAC 753172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 754162468Srwatson if (error != 0) 755160187Sjhb goto done2; 756140615Srwatson#endif 757145230Srwatson 75882607Sdillon error = 0; 759160187Sjhb *rval = 0; 7602729Sdfr 7612729Sdfr switch (cmd) { 7622729Sdfr case IPC_RMID: 763298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 764101774Salfred goto done2; 765137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 76682607Sdillon goto done2; 767298835Sjamie sem_remove(semidx, cred); 7682729Sdfr break; 7692729Sdfr 7702729Sdfr case IPC_SET: 771298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 772101774Salfred goto done2; 773137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 774101774Salfred goto done2; 775160187Sjhb sbuf = arg->buf; 776160187Sjhb semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 777160187Sjhb semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 778137613Srwatson semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 779160187Sjhb ~0777) | (sbuf->sem_perm.mode & 0777); 780137613Srwatson semakptr->u.sem_ctime = time_second; 7812729Sdfr break; 7822729Sdfr 7832729Sdfr case IPC_STAT: 784298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 785101774Salfred goto done2; 786137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 78782607Sdillon goto done2; 788160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 789298835Sjamie if (cred->cr_prison != semakptr->cred->cr_prison) 790298835Sjamie arg->buf->sem_perm.key = IPC_PRIVATE; 7912729Sdfr break; 7922729Sdfr 7932729Sdfr case GETNCNT: 794298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 795101774Salfred goto done2; 796137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 79782607Sdillon goto done2; 798137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 79982607Sdillon error = EINVAL; 80082607Sdillon goto done2; 80182607Sdillon } 802160187Sjhb *rval = semakptr->u.sem_base[semnum].semncnt; 8032729Sdfr break; 8042729Sdfr 8052729Sdfr case GETPID: 806298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 807101774Salfred goto done2; 808137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 80982607Sdillon goto done2; 810137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 81182607Sdillon error = EINVAL; 81282607Sdillon goto done2; 81382607Sdillon } 814160187Sjhb *rval = semakptr->u.sem_base[semnum].sempid; 8152729Sdfr break; 8162729Sdfr 8172729Sdfr case GETVAL: 818298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 819101774Salfred goto done2; 820137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 82182607Sdillon goto done2; 822137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 82382607Sdillon error = EINVAL; 82482607Sdillon goto done2; 82582607Sdillon } 826160187Sjhb *rval = semakptr->u.sem_base[semnum].semval; 8272729Sdfr break; 8282729Sdfr 8292729Sdfr case GETALL: 830159991Sjhb /* 831160187Sjhb * Unfortunately, callers of this function don't know 832160187Sjhb * in advance how many semaphores are in this set. 833160187Sjhb * While we could just allocate the maximum size array 834160187Sjhb * and pass the actual size back to the caller, that 835160187Sjhb * won't work for SETALL since we can't copyin() more 836160187Sjhb * data than the user specified as we may return a 837160187Sjhb * spurious EFAULT. 838160187Sjhb * 839160187Sjhb * Note that the number of semaphores in a set is 840160187Sjhb * fixed for the life of that set. The only way that 841160187Sjhb * the 'count' could change while are blocked in 842160187Sjhb * malloc() is if this semaphore set were destroyed 843160187Sjhb * and a new one created with the same index. 844160187Sjhb * However, semvalid() will catch that due to the 845160187Sjhb * sequence number unless exactly 0x8000 (or a 846160187Sjhb * multiple thereof) semaphore sets for the same index 847160187Sjhb * are created and destroyed while we are in malloc! 848160187Sjhb * 849159991Sjhb */ 850160187Sjhb count = semakptr->u.sem_nsems; 851160187Sjhb mtx_unlock(sema_mtxp); 852160187Sjhb array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 853101774Salfred mtx_lock(sema_mtxp); 854298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 855101774Salfred goto done2; 856160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 857137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 85882607Sdillon goto done2; 859137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) 860137613Srwatson array[i] = semakptr->u.sem_base[i].semval; 861101774Salfred mtx_unlock(sema_mtxp); 862160187Sjhb error = copyout(array, arg->array, count * sizeof(*array)); 863160187Sjhb mtx_lock(sema_mtxp); 8642729Sdfr break; 8652729Sdfr 8662729Sdfr case GETZCNT: 867298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 868101774Salfred goto done2; 869137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 87082607Sdillon goto done2; 871137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 87282607Sdillon error = EINVAL; 87382607Sdillon goto done2; 87482607Sdillon } 875160187Sjhb *rval = semakptr->u.sem_base[semnum].semzcnt; 8762729Sdfr break; 8772729Sdfr 8782729Sdfr case SETVAL: 879298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 880101774Salfred goto done2; 881137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 88282607Sdillon goto done2; 883137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 88482607Sdillon error = EINVAL; 88582607Sdillon goto done2; 88682607Sdillon } 887159991Sjhb if (arg->val < 0 || arg->val > seminfo.semvmx) { 88884789Smr error = ERANGE; 88984789Smr goto done2; 89084789Smr } 891159991Sjhb semakptr->u.sem_base[semnum].semval = arg->val; 892101774Salfred SEMUNDO_LOCK(); 893160028Sjhb semundo_clear(semidx, semnum); 894101774Salfred SEMUNDO_UNLOCK(); 895137613Srwatson wakeup(semakptr); 8962729Sdfr break; 8972729Sdfr 8982729Sdfr case SETALL: 899159991Sjhb /* 900160187Sjhb * See comment on GETALL for why 'count' shouldn't change 901160187Sjhb * and why we require a userland buffer. 902159991Sjhb */ 903137613Srwatson count = semakptr->u.sem_nsems; 904160187Sjhb mtx_unlock(sema_mtxp); 905111119Simp array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 906159991Sjhb error = copyin(arg->array, array, count * sizeof(*array)); 907171179Skib mtx_lock(sema_mtxp); 908101774Salfred if (error) 909101774Salfred break; 910298835Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 911101774Salfred goto done2; 912160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 913137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 914101774Salfred goto done2; 915137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) { 916101774Salfred usval = array[i]; 91784789Smr if (usval > seminfo.semvmx) { 91884789Smr error = ERANGE; 91984789Smr break; 92084789Smr } 921137613Srwatson semakptr->u.sem_base[i].semval = usval; 9222729Sdfr } 923101774Salfred SEMUNDO_LOCK(); 924160028Sjhb semundo_clear(semidx, -1); 925101774Salfred SEMUNDO_UNLOCK(); 926137613Srwatson wakeup(semakptr); 9272729Sdfr break; 9282729Sdfr 9292729Sdfr default: 93082607Sdillon error = EINVAL; 93182607Sdillon break; 9322729Sdfr } 9332729Sdfr 93482607Sdillondone2: 935160187Sjhb mtx_unlock(sema_mtxp); 936187223Skib if (cmd == IPC_RMID) 937187223Skib mtx_unlock(&sem_mtx); 938101774Salfred if (array != NULL) 939101774Salfred free(array, M_TEMP); 94082607Sdillon return(error); 9412729Sdfr} 9422729Sdfr 94312866Speter#ifndef _SYS_SYSPROTO_H_ 9442729Sdfrstruct semget_args { 9452729Sdfr key_t key; 9462729Sdfr int nsems; 9472729Sdfr int semflg; 9482729Sdfr}; 94912866Speter#endif 95012866Speterint 951225617Skmacysys_semget(struct thread *td, struct semget_args *uap) 9522729Sdfr{ 95382607Sdillon int semid, error = 0; 9542729Sdfr int key = uap->key; 9552729Sdfr int nsems = uap->nsems; 9562729Sdfr int semflg = uap->semflg; 95791703Sjhb struct ucred *cred = td->td_ucred; 9582729Sdfr 959100523Salfred DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 960298835Sjamie 961298835Sjamie if (sem_find_prison(cred) == NULL) 96291703Sjhb return (ENOSYS); 96391703Sjhb 964187223Skib mtx_lock(&sem_mtx); 9652729Sdfr if (key != IPC_PRIVATE) { 9662729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 967137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 968298835Sjamie sema[semid].cred != NULL && 969298835Sjamie sema[semid].cred->cr_prison == cred->cr_prison && 970137613Srwatson sema[semid].u.sem_perm.key == key) 9712729Sdfr break; 9722729Sdfr } 9732729Sdfr if (semid < seminfo.semmni) { 974100523Salfred DPRINTF(("found public key\n")); 975297747Sjilles if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 976297747Sjilles DPRINTF(("not exclusive\n")); 977297747Sjilles error = EEXIST; 978297747Sjilles goto done2; 979297747Sjilles } 980137613Srwatson if ((error = ipcperm(td, &sema[semid].u.sem_perm, 98182607Sdillon semflg & 0700))) { 98282607Sdillon goto done2; 98382607Sdillon } 984137613Srwatson if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 985100523Salfred DPRINTF(("too small\n")); 98682607Sdillon error = EINVAL; 98782607Sdillon goto done2; 9882729Sdfr } 989140615Srwatson#ifdef MAC 990172930Srwatson error = mac_sysvsem_check_semget(cred, &sema[semid]); 991162468Srwatson if (error != 0) 992140615Srwatson goto done2; 993140615Srwatson#endif 9942729Sdfr goto found; 9952729Sdfr } 9962729Sdfr } 9972729Sdfr 998137613Srwatson DPRINTF(("need to allocate the semid_kernel\n")); 9992729Sdfr if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 10002729Sdfr if (nsems <= 0 || nsems > seminfo.semmsl) { 1001100523Salfred DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 1002100523Salfred seminfo.semmsl)); 100382607Sdillon error = EINVAL; 100482607Sdillon goto done2; 10052729Sdfr } 10062729Sdfr if (nsems > seminfo.semmns - semtot) { 1007100523Salfred DPRINTF(( 1008100523Salfred "not enough semaphores left (need %d, got %d)\n", 1009100523Salfred nsems, seminfo.semmns - semtot)); 101082607Sdillon error = ENOSPC; 101182607Sdillon goto done2; 10122729Sdfr } 10132729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 1014137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 10152729Sdfr break; 10162729Sdfr } 10172729Sdfr if (semid == seminfo.semmni) { 1018137613Srwatson DPRINTF(("no more semid_kernel's available\n")); 101982607Sdillon error = ENOSPC; 102082607Sdillon goto done2; 10212729Sdfr } 1022223825Strasz#ifdef RACCT 1023284665Strasz if (racct_enable) { 1024284665Strasz PROC_LOCK(td->td_proc); 1025284665Strasz error = racct_add(td->td_proc, RACCT_NSEM, nsems); 1026284665Strasz PROC_UNLOCK(td->td_proc); 1027284665Strasz if (error != 0) { 1028284665Strasz error = ENOSPC; 1029284665Strasz goto done2; 1030284665Strasz } 1031220398Strasz } 1032223825Strasz#endif 1033100523Salfred DPRINTF(("semid %d is available\n", semid)); 1034187298Skib mtx_lock(&sema_mtx[semid]); 1035187298Skib KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 1036187298Skib ("Lost semaphore %d", semid)); 1037137613Srwatson sema[semid].u.sem_perm.key = key; 1038137613Srwatson sema[semid].u.sem_perm.cuid = cred->cr_uid; 1039137613Srwatson sema[semid].u.sem_perm.uid = cred->cr_uid; 1040137613Srwatson sema[semid].u.sem_perm.cgid = cred->cr_gid; 1041137613Srwatson sema[semid].u.sem_perm.gid = cred->cr_gid; 1042137613Srwatson sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 1043220399Strasz sema[semid].cred = crhold(cred); 1044137613Srwatson sema[semid].u.sem_perm.seq = 1045137613Srwatson (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 1046137613Srwatson sema[semid].u.sem_nsems = nsems; 1047137613Srwatson sema[semid].u.sem_otime = 0; 1048137613Srwatson sema[semid].u.sem_ctime = time_second; 1049137613Srwatson sema[semid].u.sem_base = &sem[semtot]; 10502729Sdfr semtot += nsems; 1051137613Srwatson bzero(sema[semid].u.sem_base, 1052137613Srwatson sizeof(sema[semid].u.sem_base[0])*nsems); 1053140615Srwatson#ifdef MAC 1054172930Srwatson mac_sysvsem_create(cred, &sema[semid]); 1055140615Srwatson#endif 1056187298Skib mtx_unlock(&sema_mtx[semid]); 1057160293Skib DPRINTF(("sembase = %p, next = %p\n", 1058137613Srwatson sema[semid].u.sem_base, &sem[semtot])); 10592729Sdfr } else { 1060100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 106182607Sdillon error = ENOENT; 106282607Sdillon goto done2; 10632729Sdfr } 10642729Sdfr 10652729Sdfrfound: 1066137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 106782607Sdillondone2: 1068187223Skib mtx_unlock(&sem_mtx); 106982607Sdillon return (error); 10702729Sdfr} 10712729Sdfr 107212866Speter#ifndef _SYS_SYSPROTO_H_ 10732729Sdfrstruct semop_args { 10742729Sdfr int semid; 10752729Sdfr struct sembuf *sops; 1076109829Salfred size_t nsops; 10772729Sdfr}; 107812866Speter#endif 107912866Speterint 1080225617Skmacysys_semop(struct thread *td, struct semop_args *uap) 10812729Sdfr{ 1082123667Stjr#define SMALL_SOPS 8 1083123667Stjr struct sembuf small_sops[SMALL_SOPS]; 10842729Sdfr int semid = uap->semid; 1085109829Salfred size_t nsops = uap->nsops; 1086298835Sjamie struct prison *rpr; 1087105429Salfred struct sembuf *sops; 1088137613Srwatson struct semid_kernel *semakptr; 1089101350Salfred struct sembuf *sopptr = 0; 1090101350Salfred struct sem *semptr = 0; 109184789Smr struct sem_undo *suptr; 1092101774Salfred struct mtx *sema_mtxp; 1093110040Stjr size_t i, j, k; 1094109829Salfred int error; 10953308Sphk int do_wakeup, do_undos; 1096187223Skib unsigned short seq; 10972729Sdfr 1098160293Skib#ifdef SEM_DEBUG 1099160293Skib sops = NULL; 1100160293Skib#endif 1101160293Skib DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 11022729Sdfr 1103298835Sjamie rpr = sem_find_prison(td->td_ucred); 1104298835Sjamie if (sem == NULL) 110591703Sjhb return (ENOSYS); 110691703Sjhb 11072729Sdfr semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 11082729Sdfr 1109101774Salfred if (semid < 0 || semid >= seminfo.semmni) 1110137644Srwatson return (EINVAL); 1111101774Salfred 1112101774Salfred /* Allocate memory for sem_ops */ 1113123667Stjr if (nsops <= SMALL_SOPS) 1114123667Stjr sops = small_sops; 1115220398Strasz else if (nsops > seminfo.semopm) { 1116101774Salfred DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1117101774Salfred nsops)); 1118101774Salfred return (E2BIG); 1119220398Strasz } else { 1120223825Strasz#ifdef RACCT 1121284665Strasz if (racct_enable) { 1122284665Strasz PROC_LOCK(td->td_proc); 1123284665Strasz if (nsops > 1124284665Strasz racct_get_available(td->td_proc, RACCT_NSEMOP)) { 1125284665Strasz PROC_UNLOCK(td->td_proc); 1126284665Strasz return (E2BIG); 1127284665Strasz } 1128220398Strasz PROC_UNLOCK(td->td_proc); 1129220398Strasz } 1130223825Strasz#endif 1131220398Strasz 1132220398Strasz sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 113382607Sdillon } 1134101774Salfred if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1135160293Skib DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1136101774Salfred uap->sops, sops, nsops * sizeof(sops[0]))); 1137123667Stjr if (sops != small_sops) 1138123667Stjr free(sops, M_SEM); 1139101774Salfred return (error); 1140101774Salfred } 11412729Sdfr 1142137613Srwatson semakptr = &sema[semid]; 1143101774Salfred sema_mtxp = &sema_mtx[semid]; 1144101774Salfred mtx_lock(sema_mtxp); 1145137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 114682607Sdillon error = EINVAL; 114782607Sdillon goto done2; 114882607Sdillon } 1149187223Skib seq = semakptr->u.sem_perm.seq; 1150187223Skib if (seq != IPCID_TO_SEQ(uap->semid)) { 115182607Sdillon error = EINVAL; 115282607Sdillon goto done2; 115382607Sdillon } 1154298835Sjamie if ((error = sem_prison_cansee(rpr, semakptr)) != 0) 1155298835Sjamie goto done2; 115684789Smr /* 1157302234Sbdrewery * Initial pass through sops to see what permissions are needed. 115884789Smr * Also perform any checks that don't need repeating on each 115984789Smr * attempt to satisfy the request vector. 116084789Smr */ 116184789Smr j = 0; /* permission needed */ 116284789Smr do_undos = 0; 116384789Smr for (i = 0; i < nsops; i++) { 116484789Smr sopptr = &sops[i]; 1165137613Srwatson if (sopptr->sem_num >= semakptr->u.sem_nsems) { 116684789Smr error = EFBIG; 116784789Smr goto done2; 116884789Smr } 116984789Smr if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 117084789Smr do_undos = 1; 117184789Smr j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 117284789Smr } 117384789Smr 1174137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1175100523Salfred DPRINTF(("error = %d from ipaccess\n", error)); 117682607Sdillon goto done2; 11772729Sdfr } 1178140615Srwatson#ifdef MAC 1179172930Srwatson error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1180162468Srwatson if (error != 0) 1181140615Srwatson goto done2; 1182140615Srwatson#endif 11832729Sdfr 11848876Srgrimes /* 11852729Sdfr * Loop trying to satisfy the vector of requests. 11862729Sdfr * If we reach a point where we must wait, any requests already 11872729Sdfr * performed are rolled back and we go to sleep until some other 11882729Sdfr * process wakes us up. At this point, we start all over again. 11892729Sdfr * 11902729Sdfr * This ensures that from the perspective of other tasks, a set 11912729Sdfr * of requests is atomic (never partially satisfied). 11922729Sdfr */ 11932729Sdfr for (;;) { 11942729Sdfr do_wakeup = 0; 119584789Smr error = 0; /* error return if necessary */ 11962729Sdfr 11972729Sdfr for (i = 0; i < nsops; i++) { 11982729Sdfr sopptr = &sops[i]; 1199137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 12002729Sdfr 1201100523Salfred DPRINTF(( 1202160293Skib "semop: semakptr=%p, sem_base=%p, " 1203160293Skib "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1204137613Srwatson semakptr, semakptr->u.sem_base, semptr, 12052729Sdfr sopptr->sem_num, semptr->semval, sopptr->sem_op, 1206100523Salfred (sopptr->sem_flg & IPC_NOWAIT) ? 1207100523Salfred "nowait" : "wait")); 12082729Sdfr 12092729Sdfr if (sopptr->sem_op < 0) { 12102729Sdfr if (semptr->semval + sopptr->sem_op < 0) { 1211100523Salfred DPRINTF(("semop: can't do it now\n")); 12122729Sdfr break; 12132729Sdfr } else { 12142729Sdfr semptr->semval += sopptr->sem_op; 12152729Sdfr if (semptr->semval == 0 && 12162729Sdfr semptr->semzcnt > 0) 12172729Sdfr do_wakeup = 1; 12182729Sdfr } 12192729Sdfr } else if (sopptr->sem_op == 0) { 122084789Smr if (semptr->semval != 0) { 1221100523Salfred DPRINTF(("semop: not zero now\n")); 12222729Sdfr break; 12232729Sdfr } 122484789Smr } else if (semptr->semval + sopptr->sem_op > 122584789Smr seminfo.semvmx) { 122684789Smr error = ERANGE; 122784789Smr break; 12282729Sdfr } else { 12292729Sdfr if (semptr->semncnt > 0) 12302729Sdfr do_wakeup = 1; 12312729Sdfr semptr->semval += sopptr->sem_op; 12322729Sdfr } 12332729Sdfr } 12342729Sdfr 12352729Sdfr /* 12362729Sdfr * Did we get through the entire vector? 12372729Sdfr */ 12382729Sdfr if (i >= nsops) 12392729Sdfr goto done; 12402729Sdfr 12412729Sdfr /* 12422729Sdfr * No ... rollback anything that we've already done 12432729Sdfr */ 1244100523Salfred DPRINTF(("semop: rollback 0 through %d\n", i-1)); 12452729Sdfr for (j = 0; j < i; j++) 1246137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 12472729Sdfr sops[j].sem_op; 12482729Sdfr 124984789Smr /* If we detected an error, return it */ 125084789Smr if (error != 0) 125184789Smr goto done2; 125284789Smr 12532729Sdfr /* 12542729Sdfr * If the request that we couldn't satisfy has the 12552729Sdfr * NOWAIT flag set then return with EAGAIN. 12562729Sdfr */ 125782607Sdillon if (sopptr->sem_flg & IPC_NOWAIT) { 125882607Sdillon error = EAGAIN; 125982607Sdillon goto done2; 126082607Sdillon } 12612729Sdfr 12622729Sdfr if (sopptr->sem_op == 0) 12632729Sdfr semptr->semzcnt++; 12642729Sdfr else 12652729Sdfr semptr->semncnt++; 12662729Sdfr 1267100523Salfred DPRINTF(("semop: good night!\n")); 1268137613Srwatson error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1269101774Salfred "semwait", 0); 1270100523Salfred DPRINTF(("semop: good morning (error=%d)!\n", error)); 1271127108Scperciva /* return code is checked below, after sem[nz]cnt-- */ 12722729Sdfr 12732729Sdfr /* 12742729Sdfr * Make sure that the semaphore still exists 12752729Sdfr */ 1276187223Skib seq = semakptr->u.sem_perm.seq; 1277137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1278187223Skib seq != IPCID_TO_SEQ(uap->semid)) { 127982607Sdillon error = EIDRM; 128082607Sdillon goto done2; 128182607Sdillon } 12822729Sdfr 12832729Sdfr /* 1284179879Sgonzo * Renew the semaphore's pointer after wakeup since 1285179879Sgonzo * during msleep sem_base may have been modified and semptr 1286179879Sgonzo * is not valid any more 1287179879Sgonzo */ 1288179879Sgonzo semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1289179879Sgonzo 1290179879Sgonzo /* 12912729Sdfr * The semaphore is still alive. Readjust the count of 12922729Sdfr * waiting processes. 12932729Sdfr */ 12942729Sdfr if (sopptr->sem_op == 0) 12952729Sdfr semptr->semzcnt--; 12962729Sdfr else 12972729Sdfr semptr->semncnt--; 1298127108Scperciva 1299127108Scperciva /* 1300127108Scperciva * Is it really morning, or was our sleep interrupted? 1301127108Scperciva * (Delayed check of msleep() return code because we 1302127108Scperciva * need to decrement sem[nz]cnt either way.) 1303127108Scperciva */ 1304127108Scperciva if (error != 0) { 1305127108Scperciva error = EINTR; 1306127108Scperciva goto done2; 1307127108Scperciva } 1308127108Scperciva DPRINTF(("semop: good morning!\n")); 13092729Sdfr } 13102729Sdfr 13112729Sdfrdone: 13122729Sdfr /* 13132729Sdfr * Process any SEM_UNDO requests. 13142729Sdfr */ 13152729Sdfr if (do_undos) { 1316101774Salfred SEMUNDO_LOCK(); 131784789Smr suptr = NULL; 13182729Sdfr for (i = 0; i < nsops; i++) { 13192729Sdfr /* 13202729Sdfr * We only need to deal with SEM_UNDO's for non-zero 13212729Sdfr * op's. 13222729Sdfr */ 13232729Sdfr int adjval; 13242729Sdfr 13252729Sdfr if ((sops[i].sem_flg & SEM_UNDO) == 0) 13262729Sdfr continue; 13272729Sdfr adjval = sops[i].sem_op; 13282729Sdfr if (adjval == 0) 13292729Sdfr continue; 1330187223Skib error = semundo_adjust(td, &suptr, semid, seq, 13312729Sdfr sops[i].sem_num, -adjval); 133282607Sdillon if (error == 0) 13332729Sdfr continue; 13342729Sdfr 13352729Sdfr /* 13362729Sdfr * Oh-Oh! We ran out of either sem_undo's or undo's. 13372729Sdfr * Rollback the adjustments to this point and then 13382729Sdfr * rollback the semaphore ups and down so we can return 13392729Sdfr * with an error with all structures restored. We 13402729Sdfr * rollback the undo's in the exact reverse order that 13412729Sdfr * we applied them. This guarantees that we won't run 13422729Sdfr * out of space as we roll things back out. 13432729Sdfr */ 1344110040Stjr for (j = 0; j < i; j++) { 1345110040Stjr k = i - j - 1; 1346110040Stjr if ((sops[k].sem_flg & SEM_UNDO) == 0) 13472729Sdfr continue; 1348110040Stjr adjval = sops[k].sem_op; 13492729Sdfr if (adjval == 0) 13502729Sdfr continue; 1351187223Skib if (semundo_adjust(td, &suptr, semid, seq, 1352110040Stjr sops[k].sem_num, adjval) != 0) 13532729Sdfr panic("semop - can't undo undos"); 13542729Sdfr } 13552729Sdfr 13562729Sdfr for (j = 0; j < nsops; j++) 1357137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 13582729Sdfr sops[j].sem_op; 13592729Sdfr 1360100523Salfred DPRINTF(("error = %d from semundo_adjust\n", error)); 1361101774Salfred SEMUNDO_UNLOCK(); 136282607Sdillon goto done2; 13632729Sdfr } /* loop through the sops */ 1364101774Salfred SEMUNDO_UNLOCK(); 13652729Sdfr } /* if (do_undos) */ 13662729Sdfr 136784789Smr /* We're definitely done - set the sempid's and time */ 13682729Sdfr for (i = 0; i < nsops; i++) { 13692729Sdfr sopptr = &sops[i]; 1370137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 137183366Sjulian semptr->sempid = td->td_proc->p_pid; 13722729Sdfr } 1373137613Srwatson semakptr->u.sem_otime = time_second; 13742729Sdfr 137584789Smr /* 137684789Smr * Do a wakeup if any semaphore was up'd whilst something was 137784789Smr * sleeping on it. 137884789Smr */ 13792729Sdfr if (do_wakeup) { 1380100523Salfred DPRINTF(("semop: doing wakeup\n")); 1381137613Srwatson wakeup(semakptr); 1382100523Salfred DPRINTF(("semop: back from wakeup\n")); 13832729Sdfr } 1384100523Salfred DPRINTF(("semop: done\n")); 138583366Sjulian td->td_retval[0] = 0; 138682607Sdillondone2: 1387101774Salfred mtx_unlock(sema_mtxp); 1388123667Stjr if (sops != small_sops) 1389123667Stjr free(sops, M_SEM); 139082607Sdillon return (error); 13912729Sdfr} 13922729Sdfr 13932729Sdfr/* 13942729Sdfr * Go through the undo structures for this process and apply the adjustments to 13952729Sdfr * semaphores. 13962729Sdfr */ 139769449Salfredstatic void 1398187223Skibsemexit_myhook(void *arg, struct proc *p) 13992729Sdfr{ 1400101350Salfred struct sem_undo *suptr; 1401187223Skib struct semid_kernel *semakptr; 1402187223Skib struct mtx *sema_mtxp; 1403187223Skib int semid, semnum, adjval, ix; 1404187223Skib unsigned short seq; 14052729Sdfr 14062729Sdfr /* 14072729Sdfr * Go through the chain of undo vectors looking for one 14082729Sdfr * associated with this process. 14092729Sdfr */ 1410101774Salfred SEMUNDO_LOCK(); 1411187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 1412187223Skib if (suptr->un_proc == p) 14132729Sdfr break; 14142729Sdfr } 1415187223Skib if (suptr == NULL) { 1416187223Skib SEMUNDO_UNLOCK(); 141759828Speter return; 1418187223Skib } 1419187223Skib LIST_REMOVE(suptr, un_next); 14202729Sdfr 1421160293Skib DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1422100523Salfred suptr->un_cnt)); 14232729Sdfr 14242729Sdfr /* 14252729Sdfr * If there are any active undo elements then process them. 14262729Sdfr */ 14272729Sdfr if (suptr->un_cnt > 0) { 1428187223Skib SEMUNDO_UNLOCK(); 14292729Sdfr for (ix = 0; ix < suptr->un_cnt; ix++) { 1430187223Skib semid = suptr->un_ent[ix].un_id; 1431187223Skib semnum = suptr->un_ent[ix].un_num; 1432187223Skib adjval = suptr->un_ent[ix].un_adjval; 1433187223Skib seq = suptr->un_ent[ix].un_seq; 1434137613Srwatson semakptr = &sema[semid]; 1435101774Salfred sema_mtxp = &sema_mtx[semid]; 1436187223Skib 1437101774Salfred mtx_lock(sema_mtxp); 1438187223Skib if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1439187223Skib (semakptr->u.sem_perm.seq != seq)) { 1440187223Skib mtx_unlock(sema_mtxp); 1441187223Skib continue; 1442187223Skib } 1443137613Srwatson if (semnum >= semakptr->u.sem_nsems) 14442729Sdfr panic("semexit - semnum out of range"); 14452729Sdfr 1446100523Salfred DPRINTF(( 1447160293Skib "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 14482729Sdfr suptr->un_proc, suptr->un_ent[ix].un_id, 14492729Sdfr suptr->un_ent[ix].un_num, 14502729Sdfr suptr->un_ent[ix].un_adjval, 1451137613Srwatson semakptr->u.sem_base[semnum].semval)); 14522729Sdfr 1453187223Skib if (adjval < 0 && semakptr->u.sem_base[semnum].semval < 1454187223Skib -adjval) 1455187223Skib semakptr->u.sem_base[semnum].semval = 0; 1456187223Skib else 1457137613Srwatson semakptr->u.sem_base[semnum].semval += adjval; 14582729Sdfr 1459137613Srwatson wakeup(semakptr); 1460100523Salfred DPRINTF(("semexit: back from wakeup\n")); 1461101774Salfred mtx_unlock(sema_mtxp); 14622729Sdfr } 1463187223Skib SEMUNDO_LOCK(); 14642729Sdfr } 14652729Sdfr 14662729Sdfr /* 14672729Sdfr * Deallocate the undo vector. 14682729Sdfr */ 1469100523Salfred DPRINTF(("removing vector\n")); 14702729Sdfr suptr->un_proc = NULL; 1471187223Skib suptr->un_cnt = 0; 1472187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1473167904Semaste SEMUNDO_UNLOCK(); 14742729Sdfr} 147577461Sdd 147677461Sddstatic int 147777461Sddsysctl_sema(SYSCTL_HANDLER_ARGS) 147877461Sdd{ 1479298835Sjamie struct prison *pr, *rpr; 1480298835Sjamie struct semid_kernel tsemak; 1481298835Sjamie int error, i; 148277461Sdd 1483298835Sjamie pr = req->td->td_ucred->cr_prison; 1484298835Sjamie rpr = sem_find_prison(req->td->td_ucred); 1485298835Sjamie error = 0; 1486298835Sjamie for (i = 0; i < seminfo.semmni; i++) { 1487298835Sjamie mtx_lock(&sema_mtx[i]); 1488298835Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) == 0 || 1489298835Sjamie rpr == NULL || sem_prison_cansee(rpr, &sema[i]) != 0) 1490298835Sjamie bzero(&tsemak, sizeof(tsemak)); 1491298835Sjamie else { 1492298835Sjamie tsemak = sema[i]; 1493298835Sjamie if (tsemak.cred->cr_prison != pr) 1494298835Sjamie tsemak.u.sem_perm.key = IPC_PRIVATE; 1495298835Sjamie } 1496298835Sjamie mtx_unlock(&sema_mtx[i]); 1497298835Sjamie error = SYSCTL_OUT(req, &tsemak, sizeof(tsemak)); 1498298835Sjamie if (error != 0) 1499298835Sjamie break; 1500298835Sjamie } 1501298835Sjamie return (error); 150277461Sdd} 1503194894Sjhb 1504298835Sjamiestatic int 1505298835Sjamiesem_prison_check(void *obj, void *data) 1506298835Sjamie{ 1507298835Sjamie struct prison *pr = obj; 1508298835Sjamie struct prison *prpr; 1509298835Sjamie struct vfsoptlist *opts = data; 1510298835Sjamie int error, jsys; 1511298835Sjamie 1512298835Sjamie /* 1513298835Sjamie * sysvsem is a jailsys integer. 1514298835Sjamie * It must be "disable" if the parent jail is disabled. 1515298835Sjamie */ 1516298835Sjamie error = vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1517298835Sjamie if (error != ENOENT) { 1518298835Sjamie if (error != 0) 1519298835Sjamie return (error); 1520298835Sjamie switch (jsys) { 1521298835Sjamie case JAIL_SYS_DISABLE: 1522298835Sjamie break; 1523298835Sjamie case JAIL_SYS_NEW: 1524298835Sjamie case JAIL_SYS_INHERIT: 1525298835Sjamie prison_lock(pr->pr_parent); 1526298835Sjamie prpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1527298835Sjamie prison_unlock(pr->pr_parent); 1528298835Sjamie if (prpr == NULL) 1529298835Sjamie return (EPERM); 1530298835Sjamie break; 1531298835Sjamie default: 1532298835Sjamie return (EINVAL); 1533298835Sjamie } 1534298835Sjamie } 1535298835Sjamie 1536298835Sjamie return (0); 1537298835Sjamie} 1538298835Sjamie 1539298835Sjamiestatic int 1540298835Sjamiesem_prison_set(void *obj, void *data) 1541298835Sjamie{ 1542298835Sjamie struct prison *pr = obj; 1543298835Sjamie struct prison *tpr, *orpr, *nrpr, *trpr; 1544298835Sjamie struct vfsoptlist *opts = data; 1545298835Sjamie void *rsv; 1546298835Sjamie int jsys, descend; 1547298835Sjamie 1548298835Sjamie /* 1549298835Sjamie * sysvsem controls which jail is the root of the associated sems (this 1550298835Sjamie * jail or same as the parent), or if the feature is available at all. 1551298835Sjamie */ 1552298835Sjamie if (vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)) == ENOENT) 1553298835Sjamie jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0) 1554298835Sjamie ? JAIL_SYS_INHERIT 1555298835Sjamie : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0) 1556298835Sjamie ? JAIL_SYS_DISABLE 1557298835Sjamie : -1; 1558298835Sjamie if (jsys == JAIL_SYS_DISABLE) { 1559298835Sjamie prison_lock(pr); 1560298835Sjamie orpr = osd_jail_get(pr, sem_prison_slot); 1561298835Sjamie if (orpr != NULL) 1562298835Sjamie osd_jail_del(pr, sem_prison_slot); 1563298835Sjamie prison_unlock(pr); 1564298835Sjamie if (orpr != NULL) { 1565298835Sjamie if (orpr == pr) 1566298835Sjamie sem_prison_cleanup(pr); 1567298835Sjamie /* Disable all child jails as well. */ 1568298835Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1569298835Sjamie prison_lock(tpr); 1570298835Sjamie trpr = osd_jail_get(tpr, sem_prison_slot); 1571298835Sjamie if (trpr != NULL) { 1572298835Sjamie osd_jail_del(tpr, sem_prison_slot); 1573298835Sjamie prison_unlock(tpr); 1574298835Sjamie if (trpr == tpr) 1575298835Sjamie sem_prison_cleanup(tpr); 1576298835Sjamie } else { 1577298835Sjamie prison_unlock(tpr); 1578298835Sjamie descend = 0; 1579298835Sjamie } 1580298835Sjamie } 1581298835Sjamie } 1582298835Sjamie } else if (jsys != -1) { 1583298835Sjamie if (jsys == JAIL_SYS_NEW) 1584298835Sjamie nrpr = pr; 1585298835Sjamie else { 1586298835Sjamie prison_lock(pr->pr_parent); 1587298835Sjamie nrpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1588298835Sjamie prison_unlock(pr->pr_parent); 1589298835Sjamie } 1590298835Sjamie rsv = osd_reserve(sem_prison_slot); 1591298835Sjamie prison_lock(pr); 1592298835Sjamie orpr = osd_jail_get(pr, sem_prison_slot); 1593298835Sjamie if (orpr != nrpr) 1594298835Sjamie (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 1595298835Sjamie nrpr); 1596298835Sjamie else 1597298835Sjamie osd_free_reserved(rsv); 1598298835Sjamie prison_unlock(pr); 1599298835Sjamie if (orpr != nrpr) { 1600298835Sjamie if (orpr == pr) 1601298835Sjamie sem_prison_cleanup(pr); 1602298835Sjamie if (orpr != NULL) { 1603298835Sjamie /* Change child jails matching the old root, */ 1604298835Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1605298835Sjamie prison_lock(tpr); 1606298835Sjamie trpr = osd_jail_get(tpr, 1607298835Sjamie sem_prison_slot); 1608298835Sjamie if (trpr == orpr) { 1609298835Sjamie (void)osd_jail_set(tpr, 1610298835Sjamie sem_prison_slot, nrpr); 1611298835Sjamie prison_unlock(tpr); 1612298835Sjamie if (trpr == tpr) 1613298835Sjamie sem_prison_cleanup(tpr); 1614298835Sjamie } else { 1615298835Sjamie prison_unlock(tpr); 1616298835Sjamie descend = 0; 1617298835Sjamie } 1618298835Sjamie } 1619298835Sjamie } 1620298835Sjamie } 1621298835Sjamie } 1622298835Sjamie 1623298835Sjamie return (0); 1624298835Sjamie} 1625298835Sjamie 1626298835Sjamiestatic int 1627298835Sjamiesem_prison_get(void *obj, void *data) 1628298835Sjamie{ 1629298835Sjamie struct prison *pr = obj; 1630298835Sjamie struct prison *rpr; 1631298835Sjamie struct vfsoptlist *opts = data; 1632298835Sjamie int error, jsys; 1633298835Sjamie 1634298835Sjamie /* Set sysvsem based on the jail's root prison. */ 1635298835Sjamie prison_lock(pr); 1636298835Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 1637298835Sjamie prison_unlock(pr); 1638298835Sjamie jsys = rpr == NULL ? JAIL_SYS_DISABLE 1639298835Sjamie : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 1640298835Sjamie error = vfs_setopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1641298835Sjamie if (error == ENOENT) 1642298835Sjamie error = 0; 1643298835Sjamie return (error); 1644298835Sjamie} 1645298835Sjamie 1646298835Sjamiestatic int 1647298835Sjamiesem_prison_remove(void *obj, void *data __unused) 1648298835Sjamie{ 1649298835Sjamie struct prison *pr = obj; 1650298835Sjamie struct prison *rpr; 1651298835Sjamie 1652298835Sjamie prison_lock(pr); 1653298835Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 1654298835Sjamie prison_unlock(pr); 1655298835Sjamie if (rpr == pr) 1656298835Sjamie sem_prison_cleanup(pr); 1657298835Sjamie return (0); 1658298835Sjamie} 1659298835Sjamie 1660298835Sjamiestatic void 1661298835Sjamiesem_prison_cleanup(struct prison *pr) 1662298835Sjamie{ 1663298835Sjamie int i; 1664298835Sjamie 1665298835Sjamie /* Remove any sems that belong to this jail. */ 1666298835Sjamie mtx_lock(&sem_mtx); 1667298835Sjamie for (i = 0; i < seminfo.semmni; i++) { 1668298835Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 1669298835Sjamie sema[i].cred != NULL && sema[i].cred->cr_prison == pr) { 1670298835Sjamie mtx_lock(&sema_mtx[i]); 1671298835Sjamie sem_remove(i, NULL); 1672298835Sjamie mtx_unlock(&sema_mtx[i]); 1673298835Sjamie } 1674298835Sjamie } 1675298835Sjamie mtx_unlock(&sem_mtx); 1676298835Sjamie} 1677298835Sjamie 1678298835SjamieSYSCTL_JAIL_PARAM_SYS_NODE(sysvsem, CTLFLAG_RW, "SYSV semaphores"); 1679298835Sjamie 1680194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1681194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1682194894Sjhb 1683194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1684194894Sjhbstatic sy_call_t *semcalls[] = { 1685225617Skmacy (sy_call_t *)freebsd7___semctl, (sy_call_t *)sys_semget, 1686225617Skmacy (sy_call_t *)sys_semop 1687194894Sjhb}; 1688194894Sjhb 1689194894Sjhb/* 1690194894Sjhb * Entry point for all SEM calls. 1691194894Sjhb */ 1692194894Sjhbint 1693225617Skmacysys_semsys(td, uap) 1694194894Sjhb struct thread *td; 1695194894Sjhb /* XXX actually varargs. */ 1696194894Sjhb struct semsys_args /* { 1697194894Sjhb int which; 1698194894Sjhb int a2; 1699194894Sjhb int a3; 1700194894Sjhb int a4; 1701194894Sjhb int a5; 1702194894Sjhb } */ *uap; 1703194894Sjhb{ 1704194894Sjhb int error; 1705194894Sjhb 1706194894Sjhb if (uap->which < 0 || 1707194894Sjhb uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) 1708194894Sjhb return (EINVAL); 1709194894Sjhb error = (*semcalls[uap->which])(td, &uap->a2); 1710194894Sjhb return (error); 1711194894Sjhb} 1712194910Sjhb 1713205323Skib#ifndef CP 1714194910Sjhb#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1715205323Skib#endif 1716194910Sjhb 1717194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1718194910Sjhbstruct freebsd7___semctl_args { 1719194910Sjhb int semid; 1720194910Sjhb int semnum; 1721194910Sjhb int cmd; 1722194910Sjhb union semun_old *arg; 1723194910Sjhb}; 1724194910Sjhb#endif 1725194910Sjhbint 1726194910Sjhbfreebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1727194910Sjhb{ 1728194910Sjhb struct semid_ds_old dsold; 1729194910Sjhb struct semid_ds dsbuf; 1730194910Sjhb union semun_old arg; 1731194910Sjhb union semun semun; 1732194910Sjhb register_t rval; 1733194910Sjhb int error; 1734194910Sjhb 1735194910Sjhb switch (uap->cmd) { 1736194910Sjhb case SEM_STAT: 1737194910Sjhb case IPC_SET: 1738194910Sjhb case IPC_STAT: 1739194910Sjhb case GETALL: 1740194910Sjhb case SETVAL: 1741194910Sjhb case SETALL: 1742194910Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 1743194910Sjhb if (error) 1744194910Sjhb return (error); 1745194910Sjhb break; 1746194910Sjhb } 1747194910Sjhb 1748194910Sjhb switch (uap->cmd) { 1749194910Sjhb case SEM_STAT: 1750194910Sjhb case IPC_STAT: 1751194910Sjhb semun.buf = &dsbuf; 1752194910Sjhb break; 1753194910Sjhb case IPC_SET: 1754194910Sjhb error = copyin(arg.buf, &dsold, sizeof(dsold)); 1755194910Sjhb if (error) 1756194910Sjhb return (error); 1757194910Sjhb ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1758194910Sjhb CP(dsold, dsbuf, sem_base); 1759194910Sjhb CP(dsold, dsbuf, sem_nsems); 1760194910Sjhb CP(dsold, dsbuf, sem_otime); 1761194910Sjhb CP(dsold, dsbuf, sem_ctime); 1762194910Sjhb semun.buf = &dsbuf; 1763194910Sjhb break; 1764194910Sjhb case GETALL: 1765194910Sjhb case SETALL: 1766194910Sjhb semun.array = arg.array; 1767194910Sjhb break; 1768194910Sjhb case SETVAL: 1769194910Sjhb semun.val = arg.val; 1770194910Sjhb break; 1771194910Sjhb } 1772194910Sjhb 1773194910Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1774194910Sjhb &rval); 1775194910Sjhb if (error) 1776194910Sjhb return (error); 1777194910Sjhb 1778194910Sjhb switch (uap->cmd) { 1779194910Sjhb case SEM_STAT: 1780194910Sjhb case IPC_STAT: 1781194910Sjhb bzero(&dsold, sizeof(dsold)); 1782194910Sjhb ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1783194910Sjhb CP(dsbuf, dsold, sem_base); 1784194910Sjhb CP(dsbuf, dsold, sem_nsems); 1785194910Sjhb CP(dsbuf, dsold, sem_otime); 1786194910Sjhb CP(dsbuf, dsold, sem_ctime); 1787194910Sjhb error = copyout(&dsold, arg.buf, sizeof(dsold)); 1788194910Sjhb break; 1789194910Sjhb } 1790194910Sjhb 1791194910Sjhb if (error == 0) 1792194910Sjhb td->td_retval[0] = rval; 1793194910Sjhb return (error); 1794194910Sjhb} 1795194910Sjhb 1796205323Skib#endif /* COMPAT_FREEBSD{4,5,6,7} */ 1797194910Sjhb 1798205323Skib#ifdef COMPAT_FREEBSD32 1799205323Skib 1800205323Skibint 1801205323Skibfreebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1802205323Skib{ 1803205323Skib 1804205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1805205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1806205323Skib switch (uap->which) { 1807205323Skib case 0: 1808205323Skib return (freebsd7_freebsd32_semctl(td, 1809205323Skib (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1810205323Skib default: 1811225617Skmacy return (sys_semsys(td, (struct semsys_args *)uap)); 1812205323Skib } 1813205323Skib#else 1814205323Skib return (nosys(td, NULL)); 1815205323Skib#endif 1816205323Skib} 1817205323Skib 1818205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1819205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1820205323Skibint 1821205323Skibfreebsd7_freebsd32_semctl(struct thread *td, 1822205323Skib struct freebsd7_freebsd32_semctl_args *uap) 1823205323Skib{ 1824205323Skib struct semid_ds32_old dsbuf32; 1825205323Skib struct semid_ds dsbuf; 1826205323Skib union semun semun; 1827205323Skib union semun32 arg; 1828205323Skib register_t rval; 1829205323Skib int error; 1830205323Skib 1831205323Skib switch (uap->cmd) { 1832205323Skib case SEM_STAT: 1833205323Skib case IPC_SET: 1834205323Skib case IPC_STAT: 1835205323Skib case GETALL: 1836205323Skib case SETVAL: 1837205323Skib case SETALL: 1838205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1839205323Skib if (error) 1840205323Skib return (error); 1841205323Skib break; 1842205323Skib } 1843205323Skib 1844205323Skib switch (uap->cmd) { 1845205323Skib case SEM_STAT: 1846205323Skib case IPC_STAT: 1847205323Skib semun.buf = &dsbuf; 1848205323Skib break; 1849205323Skib case IPC_SET: 1850205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1851205323Skib if (error) 1852205323Skib return (error); 1853205323Skib freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1854205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1855205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1856205323Skib CP(dsbuf32, dsbuf, sem_otime); 1857205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1858205323Skib semun.buf = &dsbuf; 1859205323Skib break; 1860205323Skib case GETALL: 1861205323Skib case SETALL: 1862205323Skib semun.array = PTRIN(arg.array); 1863205323Skib break; 1864205323Skib case SETVAL: 1865205323Skib semun.val = arg.val; 1866205323Skib break; 1867205323Skib } 1868205323Skib 1869205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1870205323Skib &rval); 1871205323Skib if (error) 1872205323Skib return (error); 1873205323Skib 1874205323Skib switch (uap->cmd) { 1875205323Skib case SEM_STAT: 1876205323Skib case IPC_STAT: 1877205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1878205323Skib freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1879205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1880205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1881205323Skib CP(dsbuf, dsbuf32, sem_otime); 1882205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1883205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1884205323Skib break; 1885205323Skib } 1886205323Skib 1887205323Skib if (error == 0) 1888205323Skib td->td_retval[0] = rval; 1889205323Skib return (error); 1890205323Skib} 1891205323Skib#endif 1892205323Skib 1893205323Skibint 1894205323Skibfreebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1895205323Skib{ 1896205323Skib struct semid_ds32 dsbuf32; 1897205323Skib struct semid_ds dsbuf; 1898205323Skib union semun semun; 1899205323Skib union semun32 arg; 1900205323Skib register_t rval; 1901205323Skib int error; 1902205323Skib 1903205323Skib switch (uap->cmd) { 1904205323Skib case SEM_STAT: 1905205323Skib case IPC_SET: 1906205323Skib case IPC_STAT: 1907205323Skib case GETALL: 1908205323Skib case SETVAL: 1909205323Skib case SETALL: 1910205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1911205323Skib if (error) 1912205323Skib return (error); 1913205323Skib break; 1914205323Skib } 1915205323Skib 1916205323Skib switch (uap->cmd) { 1917205323Skib case SEM_STAT: 1918205323Skib case IPC_STAT: 1919205323Skib semun.buf = &dsbuf; 1920205323Skib break; 1921205323Skib case IPC_SET: 1922205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1923205323Skib if (error) 1924205323Skib return (error); 1925205323Skib freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1926205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1927205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1928205323Skib CP(dsbuf32, dsbuf, sem_otime); 1929205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1930205323Skib semun.buf = &dsbuf; 1931205323Skib break; 1932205323Skib case GETALL: 1933205323Skib case SETALL: 1934205323Skib semun.array = PTRIN(arg.array); 1935205323Skib break; 1936205323Skib case SETVAL: 1937205323Skib semun.val = arg.val; 1938205323Skib break; 1939205323Skib } 1940205323Skib 1941205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1942205323Skib &rval); 1943205323Skib if (error) 1944205323Skib return (error); 1945205323Skib 1946205323Skib switch (uap->cmd) { 1947205323Skib case SEM_STAT: 1948205323Skib case IPC_STAT: 1949205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1950205323Skib freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1951205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1952205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1953205323Skib CP(dsbuf, dsbuf32, sem_otime); 1954205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1955205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1956205323Skib break; 1957205323Skib } 1958205323Skib 1959205323Skib if (error == 0) 1960205323Skib td->td_retval[0] = rval; 1961205323Skib return (error); 1962205323Skib} 1963205323Skib 1964205323Skib#endif /* COMPAT_FREEBSD32 */ 1965