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: releng/11.0/sys/kern/sysv_sem.c 298819 2016-04-29 22:15:33Z pfg $"); 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> 56298585Sjamie#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); 82298585Sjamiestatic int semvalid(int semid, struct prison *rpr, 83298585Sjamie struct semid_kernel *semakptr); 84298585Sjamiestatic void sem_remove(int semidx, struct ucred *cred); 85298585Sjamiestatic struct prison *sem_find_prison(struct ucred *); 86298585Sjamiestatic int sem_prison_cansee(struct prison *, struct semid_kernel *); 87298585Sjamiestatic int sem_prison_check(void *, void *); 88298585Sjamiestatic int sem_prison_set(void *, void *); 89298585Sjamiestatic int sem_prison_get(void *, void *); 90298585Sjamiestatic int sem_prison_remove(void *, void *); 91298585Sjamiestatic 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; 117298585Sjamiestatic 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 178298433Spfg#define SEM_ALIGN(bytes) roundup2(bytes, sizeof(long)) 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"); 210267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RWTUN, &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"); 218267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RWTUN, &seminfo.semvmx, 0, 219141710Scsjp "Semaphore maximum value"); 220267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RWTUN, &seminfo.semaem, 0, 221141710Scsjp "Adjust on exit max value"); 222298656SjamieSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, 223298656Sjamie CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 224215281Sbrucec NULL, 0, sysctl_sema, "", "Semaphore id pool"); 22559839Speter 226205323Skibstatic struct syscall_helper_data sem_syscalls[] = { 227205323Skib SYSCALL_INIT_HELPER(__semctl), 228205323Skib SYSCALL_INIT_HELPER(semget), 229205323Skib SYSCALL_INIT_HELPER(semop), 230205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 231205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 232205323Skib SYSCALL_INIT_HELPER(semsys), 233225617Skmacy SYSCALL_INIT_HELPER_COMPAT(freebsd7___semctl), 234205323Skib#endif 235205323Skib SYSCALL_INIT_LAST 236205323Skib}; 237205323Skib 238205323Skib#ifdef COMPAT_FREEBSD32 239205323Skib#include <compat/freebsd32/freebsd32.h> 240205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 241205323Skib#include <compat/freebsd32/freebsd32_proto.h> 242205323Skib#include <compat/freebsd32/freebsd32_signal.h> 243205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 244205323Skib#include <compat/freebsd32/freebsd32_util.h> 245205323Skib 246205323Skibstatic struct syscall_helper_data sem32_syscalls[] = { 247205323Skib SYSCALL32_INIT_HELPER(freebsd32_semctl), 248225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(semget), 249225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(semop), 250205323Skib SYSCALL32_INIT_HELPER(freebsd32_semsys), 251205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 252205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 253205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl), 254205323Skib#endif 255205323Skib SYSCALL_INIT_LAST 256205323Skib}; 257205323Skib#endif 258205323Skib 259205323Skibstatic int 26069449Salfredseminit(void) 2612729Sdfr{ 262298585Sjamie struct prison *pr; 263298661Scem void **rsv; 264205323Skib int i, error; 265298585Sjamie osd_method_t methods[PR_MAXMETHOD] = { 266298585Sjamie [PR_METHOD_CHECK] = sem_prison_check, 267298585Sjamie [PR_METHOD_SET] = sem_prison_set, 268298585Sjamie [PR_METHOD_GET] = sem_prison_get, 269298585Sjamie [PR_METHOD_REMOVE] = sem_prison_remove, 270298585Sjamie }; 2712729Sdfr 272111119Simp sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 273137613Srwatson sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 274111119Simp M_WAITOK); 275101774Salfred sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 276111119Simp M_WAITOK | M_ZERO); 277111119Simp semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 2782729Sdfr 2792729Sdfr for (i = 0; i < seminfo.semmni; i++) { 280137613Srwatson sema[i].u.sem_base = 0; 281137613Srwatson sema[i].u.sem_perm.mode = 0; 282137613Srwatson sema[i].u.sem_perm.seq = 0; 283140615Srwatson#ifdef MAC 284172930Srwatson mac_sysvsem_init(&sema[i]); 285140615Srwatson#endif 2862729Sdfr } 287101774Salfred for (i = 0; i < seminfo.semmni; i++) 288101774Salfred mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 289187223Skib LIST_INIT(&semu_free_list); 2902729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 291101350Salfred struct sem_undo *suptr = SEMU(i); 2922729Sdfr suptr->un_proc = NULL; 293187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 2942729Sdfr } 295187223Skib LIST_INIT(&semu_list); 296101774Salfred mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 297187223Skib mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); 298112564Sjhb semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 299112564Sjhb EVENTHANDLER_PRI_ANY); 300205323Skib 301298585Sjamie /* Set current prisons according to their allow.sysvipc. */ 302298585Sjamie sem_prison_slot = osd_jail_register(NULL, methods); 303298585Sjamie rsv = osd_reserve(sem_prison_slot); 304298585Sjamie prison_lock(&prison0); 305298585Sjamie (void)osd_jail_set_reserved(&prison0, sem_prison_slot, rsv, &prison0); 306298585Sjamie prison_unlock(&prison0); 307298585Sjamie rsv = NULL; 308298585Sjamie sx_slock(&allprison_lock); 309298585Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 310298585Sjamie if (rsv == NULL) 311298585Sjamie rsv = osd_reserve(sem_prison_slot); 312298585Sjamie prison_lock(pr); 313298585Sjamie if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { 314298585Sjamie (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 315298585Sjamie &prison0); 316298585Sjamie rsv = NULL; 317298585Sjamie } 318298585Sjamie prison_unlock(pr); 319298585Sjamie } 320298585Sjamie if (rsv != NULL) 321298585Sjamie osd_free_reserved(rsv); 322298585Sjamie sx_sunlock(&allprison_lock); 323298585Sjamie 324273707Smjg error = syscall_helper_register(sem_syscalls, SY_THR_STATIC_KLD); 325205323Skib if (error != 0) 326205323Skib return (error); 327205323Skib#ifdef COMPAT_FREEBSD32 328273707Smjg error = syscall32_helper_register(sem32_syscalls, SY_THR_STATIC_KLD); 329205323Skib if (error != 0) 330205323Skib return (error); 331205323Skib#endif 332205323Skib return (0); 3332729Sdfr} 3342729Sdfr 33569449Salfredstatic int 33669449Salfredsemunload(void) 33769449Salfred{ 338101774Salfred int i; 33969449Salfred 340187223Skib /* XXXKIB */ 34169449Salfred if (semtot != 0) 34269449Salfred return (EBUSY); 34369449Salfred 344205323Skib#ifdef COMPAT_FREEBSD32 345205323Skib syscall32_helper_unregister(sem32_syscalls); 346205323Skib#endif 347205323Skib syscall_helper_unregister(sem_syscalls); 348112564Sjhb EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 349298585Sjamie if (sem_prison_slot != 0) 350298585Sjamie osd_jail_deregister(sem_prison_slot); 351140615Srwatson#ifdef MAC 352140615Srwatson for (i = 0; i < seminfo.semmni; i++) 353172930Srwatson mac_sysvsem_destroy(&sema[i]); 354140615Srwatson#endif 35569449Salfred free(sem, M_SEM); 35669449Salfred free(sema, M_SEM); 35769449Salfred free(semu, M_SEM); 358101774Salfred for (i = 0; i < seminfo.semmni; i++) 359101774Salfred mtx_destroy(&sema_mtx[i]); 360190557Sbrueffer free(sema_mtx, M_SEM); 361101774Salfred mtx_destroy(&sem_mtx); 362187223Skib mtx_destroy(&sem_undo_mtx); 36369449Salfred return (0); 36469449Salfred} 36569449Salfred 36669449Salfredstatic int 36769449Salfredsysvsem_modload(struct module *module, int cmd, void *arg) 36869449Salfred{ 36969449Salfred int error = 0; 37069449Salfred 37169449Salfred switch (cmd) { 37269449Salfred case MOD_LOAD: 373205323Skib error = seminit(); 374205323Skib if (error != 0) 375205323Skib semunload(); 37669449Salfred break; 37769449Salfred case MOD_UNLOAD: 37869449Salfred error = semunload(); 37969449Salfred break; 38069449Salfred case MOD_SHUTDOWN: 38169449Salfred break; 38269449Salfred default: 38369449Salfred error = EINVAL; 38469449Salfred break; 38569449Salfred } 38669449Salfred return (error); 38769449Salfred} 38869449Salfred 38971038Sdesstatic moduledata_t sysvsem_mod = { 39071038Sdes "sysvsem", 39169449Salfred &sysvsem_modload, 39269449Salfred NULL 39369449Salfred}; 39469449Salfred 395194832SjhbDECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 39671038SdesMODULE_VERSION(sysvsem, 1); 39769449Salfred 3982729Sdfr/* 3992729Sdfr * Allocate a new sem_undo structure for a process 4002729Sdfr * (returns ptr to structure or NULL if no more room) 4012729Sdfr */ 4022729Sdfr 40312819Sphkstatic struct sem_undo * 404187223Skibsemu_alloc(struct thread *td) 4052729Sdfr{ 406101350Salfred struct sem_undo *suptr; 4072729Sdfr 408101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 409187223Skib if ((suptr = LIST_FIRST(&semu_free_list)) == NULL) 410187223Skib return (NULL); 411187223Skib LIST_REMOVE(suptr, un_next); 412187223Skib LIST_INSERT_HEAD(&semu_list, suptr, un_next); 413187223Skib suptr->un_cnt = 0; 414187223Skib suptr->un_proc = td->td_proc; 415187223Skib return (suptr); 416187223Skib} 4172729Sdfr 418187223Skibstatic int 419187223Skibsemu_try_free(struct sem_undo *suptr) 420187223Skib{ 4212729Sdfr 422187223Skib SEMUNDO_LOCKASSERT(MA_OWNED); 4232729Sdfr 424187223Skib if (suptr->un_cnt != 0) 425187223Skib return (0); 426187223Skib LIST_REMOVE(suptr, un_next); 427187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 428187223Skib return (1); 4292729Sdfr} 4302729Sdfr 4312729Sdfr/* 4322729Sdfr * Adjust a particular entry for a particular proc 4332729Sdfr */ 4342729Sdfr 43512819Sphkstatic int 436187223Skibsemundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, 437187223Skib int semseq, int semnum, int adjval) 4382729Sdfr{ 43983366Sjulian struct proc *p = td->td_proc; 440101350Salfred struct sem_undo *suptr; 441101350Salfred struct undo *sunptr; 4422729Sdfr int i; 4432729Sdfr 444101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 4452729Sdfr /* Look for and remember the sem_undo if the caller doesn't provide 4462729Sdfr it */ 4472729Sdfr 4482729Sdfr suptr = *supptr; 4492729Sdfr if (suptr == NULL) { 450187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 4512729Sdfr if (suptr->un_proc == p) { 4522729Sdfr *supptr = suptr; 4532729Sdfr break; 4542729Sdfr } 4552729Sdfr } 4562729Sdfr if (suptr == NULL) { 4572729Sdfr if (adjval == 0) 4582729Sdfr return(0); 45983366Sjulian suptr = semu_alloc(td); 4602729Sdfr if (suptr == NULL) 461187223Skib return (ENOSPC); 4622729Sdfr *supptr = suptr; 4632729Sdfr } 4642729Sdfr } 4652729Sdfr 4662729Sdfr /* 4672729Sdfr * Look for the requested entry and adjust it (delete if adjval becomes 4682729Sdfr * 0). 4692729Sdfr */ 4702729Sdfr sunptr = &suptr->un_ent[0]; 4712729Sdfr for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 4722729Sdfr if (sunptr->un_id != semid || sunptr->un_num != semnum) 4732729Sdfr continue; 47484789Smr if (adjval != 0) { 47584789Smr adjval += sunptr->un_adjval; 47684789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 47784789Smr return (ERANGE); 47884789Smr } 47984789Smr sunptr->un_adjval = adjval; 4802729Sdfr if (sunptr->un_adjval == 0) { 4812729Sdfr suptr->un_cnt--; 4822729Sdfr if (i < suptr->un_cnt) 4832729Sdfr suptr->un_ent[i] = 4842729Sdfr suptr->un_ent[suptr->un_cnt]; 485187223Skib if (suptr->un_cnt == 0) 486187223Skib semu_try_free(suptr); 4872729Sdfr } 488187223Skib return (0); 4892729Sdfr } 4902729Sdfr 4912729Sdfr /* Didn't find the right entry - create it */ 4922729Sdfr if (adjval == 0) 493187223Skib return (0); 49484789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 49584789Smr return (ERANGE); 49641774Sdillon if (suptr->un_cnt != seminfo.semume) { 4972729Sdfr sunptr = &suptr->un_ent[suptr->un_cnt]; 4982729Sdfr suptr->un_cnt++; 4992729Sdfr sunptr->un_adjval = adjval; 500187223Skib sunptr->un_id = semid; 501187223Skib sunptr->un_num = semnum; 502187223Skib sunptr->un_seq = semseq; 5032729Sdfr } else 504187223Skib return (EINVAL); 505187223Skib return (0); 5062729Sdfr} 5072729Sdfr 50812819Sphkstatic void 509187223Skibsemundo_clear(int semid, int semnum) 5102729Sdfr{ 511187223Skib struct sem_undo *suptr, *suptr1; 512187223Skib struct undo *sunptr; 513187223Skib int i; 5142729Sdfr 515101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 516187223Skib LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { 517187223Skib sunptr = &suptr->un_ent[0]; 518187223Skib for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 519187223Skib if (sunptr->un_id != semid) 520187223Skib continue; 521187223Skib if (semnum == -1 || sunptr->un_num == semnum) { 522187223Skib suptr->un_cnt--; 523187223Skib if (i < suptr->un_cnt) { 524187223Skib suptr->un_ent[i] = 525187223Skib suptr->un_ent[suptr->un_cnt]; 526187223Skib continue; 5272729Sdfr } 528187223Skib semu_try_free(suptr); 5292729Sdfr } 530187223Skib if (semnum != -1) 531187223Skib break; 5322729Sdfr } 5332729Sdfr } 5342729Sdfr} 5352729Sdfr 536101774Salfredstatic int 537298585Sjamiesemvalid(int semid, struct prison *rpr, struct semid_kernel *semakptr) 538101774Salfred{ 539101774Salfred 540137613Srwatson return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 541298585Sjamie semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) || 542298585Sjamie sem_prison_cansee(rpr, semakptr) ? EINVAL : 0); 543101774Salfred} 544101774Salfred 545298585Sjamiestatic void 546298585Sjamiesem_remove(int semidx, struct ucred *cred) 547298585Sjamie{ 548298585Sjamie struct semid_kernel *semakptr; 549298585Sjamie int i; 550298585Sjamie 551298585Sjamie KASSERT(semidx >= 0 && semidx < seminfo.semmni, 552298585Sjamie ("semidx out of bounds")); 553298585Sjamie semakptr = &sema[semidx]; 554298585Sjamie semakptr->u.sem_perm.cuid = cred ? cred->cr_uid : 0; 555298585Sjamie semakptr->u.sem_perm.uid = cred ? cred->cr_uid : 0; 556298585Sjamie semakptr->u.sem_perm.mode = 0; 557298585Sjamie racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); 558298585Sjamie crfree(semakptr->cred); 559298585Sjamie semakptr->cred = NULL; 560298585Sjamie SEMUNDO_LOCK(); 561298585Sjamie semundo_clear(semidx, -1); 562298585Sjamie SEMUNDO_UNLOCK(); 563298585Sjamie#ifdef MAC 564298585Sjamie mac_sysvsem_cleanup(semakptr); 565298585Sjamie#endif 566298585Sjamie wakeup(semakptr); 567298585Sjamie for (i = 0; i < seminfo.semmni; i++) { 568298585Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 569298585Sjamie sema[i].u.sem_base > semakptr->u.sem_base) 570298585Sjamie mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 571298585Sjamie } 572298585Sjamie for (i = semakptr->u.sem_base - sem; i < semtot; i++) 573298585Sjamie sem[i] = sem[i + semakptr->u.sem_nsems]; 574298585Sjamie for (i = 0; i < seminfo.semmni; i++) { 575298585Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 576298585Sjamie sema[i].u.sem_base > semakptr->u.sem_base) { 577298585Sjamie sema[i].u.sem_base -= semakptr->u.sem_nsems; 578298585Sjamie mtx_unlock(&sema_mtx[i]); 579298585Sjamie } 580298585Sjamie } 581298585Sjamie semtot -= semakptr->u.sem_nsems; 582298585Sjamie} 583298585Sjamie 584298585Sjamiestatic struct prison * 585298585Sjamiesem_find_prison(struct ucred *cred) 586298585Sjamie{ 587298585Sjamie struct prison *pr, *rpr; 588298585Sjamie 589298585Sjamie pr = cred->cr_prison; 590298585Sjamie prison_lock(pr); 591298585Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 592298585Sjamie prison_unlock(pr); 593298585Sjamie return rpr; 594298585Sjamie} 595298585Sjamie 596298585Sjamiestatic int 597298585Sjamiesem_prison_cansee(struct prison *rpr, struct semid_kernel *semakptr) 598298585Sjamie{ 599298585Sjamie 600298585Sjamie if (semakptr->cred == NULL || 601298585Sjamie !(rpr == semakptr->cred->cr_prison || 602298585Sjamie prison_ischild(rpr, semakptr->cred->cr_prison))) 603298585Sjamie return (EINVAL); 604298585Sjamie return (0); 605298585Sjamie} 606298585Sjamie 60712866Speter/* 608167211Srwatson * Note that the user-mode half of this passes a union, not a pointer. 60912866Speter */ 61012866Speter#ifndef _SYS_SYSPROTO_H_ 61112866Speterstruct __semctl_args { 6122729Sdfr int semid; 6132729Sdfr int semnum; 6142729Sdfr int cmd; 6152729Sdfr union semun *arg; 6162729Sdfr}; 61712866Speter#endif 61812866Speterint 619225617Skmacysys___semctl(struct thread *td, struct __semctl_args *uap) 6202729Sdfr{ 621160187Sjhb struct semid_ds dsbuf; 622160187Sjhb union semun arg, semun; 623160187Sjhb register_t rval; 624159991Sjhb int error; 625159991Sjhb 626159991Sjhb switch (uap->cmd) { 627159991Sjhb case SEM_STAT: 628159991Sjhb case IPC_SET: 629159991Sjhb case IPC_STAT: 630159991Sjhb case GETALL: 631159991Sjhb case SETVAL: 632159991Sjhb case SETALL: 633160187Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 634159991Sjhb if (error) 635159991Sjhb return (error); 636159991Sjhb break; 637160187Sjhb } 638160187Sjhb 639160187Sjhb switch (uap->cmd) { 640160187Sjhb case SEM_STAT: 641160187Sjhb case IPC_STAT: 642160187Sjhb semun.buf = &dsbuf; 643159991Sjhb break; 644160187Sjhb case IPC_SET: 645160187Sjhb error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 646160187Sjhb if (error) 647160187Sjhb return (error); 648160187Sjhb semun.buf = &dsbuf; 649160187Sjhb break; 650160187Sjhb case GETALL: 651160187Sjhb case SETALL: 652160187Sjhb semun.array = arg.array; 653160187Sjhb break; 654160187Sjhb case SETVAL: 655160187Sjhb semun.val = arg.val; 656160187Sjhb break; 657159991Sjhb } 658160187Sjhb 659160187Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 660160187Sjhb &rval); 661160187Sjhb if (error) 662160187Sjhb return (error); 663160187Sjhb 664160187Sjhb switch (uap->cmd) { 665160187Sjhb case SEM_STAT: 666160187Sjhb case IPC_STAT: 667160187Sjhb error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 668160187Sjhb break; 669160187Sjhb } 670160187Sjhb 671160187Sjhb if (error == 0) 672160187Sjhb td->td_retval[0] = rval; 673160187Sjhb return (error); 674159991Sjhb} 675159991Sjhb 676159991Sjhbint 677160187Sjhbkern_semctl(struct thread *td, int semid, int semnum, int cmd, 678160187Sjhb union semun *arg, register_t *rval) 679159991Sjhb{ 680101774Salfred u_short *array; 68191406Sjhb struct ucred *cred = td->td_ucred; 682160187Sjhb int i, error; 683298585Sjamie struct prison *rpr; 684160187Sjhb struct semid_ds *sbuf; 685137613Srwatson struct semid_kernel *semakptr; 686101774Salfred struct mtx *sema_mtxp; 687101774Salfred u_short usval, count; 688160028Sjhb int semidx; 6892729Sdfr 690160293Skib DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 691100523Salfred semid, semnum, cmd, arg)); 692298585Sjamie 693298585Sjamie rpr = sem_find_prison(td->td_ucred); 694298585Sjamie if (sem == NULL) 69591703Sjhb return (ENOSYS); 69691703Sjhb 697101774Salfred array = NULL; 698101774Salfred 69983414Smr switch(cmd) { 70083414Smr case SEM_STAT: 701160028Sjhb /* 702160028Sjhb * For this command we assume semid is an array index 703160028Sjhb * rather than an IPC id. 704160028Sjhb */ 70591744Smaxim if (semid < 0 || semid >= seminfo.semmni) 706101774Salfred return (EINVAL); 707137613Srwatson semakptr = &sema[semid]; 708101774Salfred sema_mtxp = &sema_mtx[semid]; 709101774Salfred mtx_lock(sema_mtxp); 710137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 711101774Salfred error = EINVAL; 712101774Salfred goto done2; 713101774Salfred } 714298585Sjamie if ((error = sem_prison_cansee(rpr, semakptr))) 715298585Sjamie goto done2; 716137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 717101774Salfred goto done2; 718140615Srwatson#ifdef MAC 719172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 720162468Srwatson if (error != 0) 721140615Srwatson goto done2; 722140615Srwatson#endif 723160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 724298585Sjamie if (cred->cr_prison != semakptr->cred->cr_prison) 725298585Sjamie arg->buf->sem_perm.key = IPC_PRIVATE; 726160187Sjhb *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 727101774Salfred mtx_unlock(sema_mtxp); 728160187Sjhb return (0); 72983414Smr } 73083414Smr 731160028Sjhb semidx = IPCID_TO_IX(semid); 732160028Sjhb if (semidx < 0 || semidx >= seminfo.semmni) 733101774Salfred return (EINVAL); 7342729Sdfr 735160028Sjhb semakptr = &sema[semidx]; 736160028Sjhb sema_mtxp = &sema_mtx[semidx]; 737187223Skib if (cmd == IPC_RMID) 738187223Skib mtx_lock(&sem_mtx); 739160187Sjhb mtx_lock(sema_mtxp); 740298585Sjamie 741140615Srwatson#ifdef MAC 742172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 743162468Srwatson if (error != 0) 744160187Sjhb goto done2; 745140615Srwatson#endif 746145230Srwatson 74782607Sdillon error = 0; 748160187Sjhb *rval = 0; 7492729Sdfr 7502729Sdfr switch (cmd) { 7512729Sdfr case IPC_RMID: 752298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 753101774Salfred goto done2; 754137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 75582607Sdillon goto done2; 756298585Sjamie sem_remove(semidx, cred); 7572729Sdfr break; 7582729Sdfr 7592729Sdfr case IPC_SET: 760298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 761101774Salfred goto done2; 762137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 763101774Salfred goto done2; 764160187Sjhb sbuf = arg->buf; 765160187Sjhb semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 766160187Sjhb semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 767137613Srwatson semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 768160187Sjhb ~0777) | (sbuf->sem_perm.mode & 0777); 769137613Srwatson semakptr->u.sem_ctime = time_second; 7702729Sdfr break; 7712729Sdfr 7722729Sdfr case IPC_STAT: 773298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 774101774Salfred goto done2; 775137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 77682607Sdillon goto done2; 777160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 778298585Sjamie if (cred->cr_prison != semakptr->cred->cr_prison) 779298585Sjamie arg->buf->sem_perm.key = IPC_PRIVATE; 7802729Sdfr break; 7812729Sdfr 7822729Sdfr case GETNCNT: 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; 787137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 78882607Sdillon error = EINVAL; 78982607Sdillon goto done2; 79082607Sdillon } 791160187Sjhb *rval = semakptr->u.sem_base[semnum].semncnt; 7922729Sdfr break; 7932729Sdfr 7942729Sdfr case GETPID: 795298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 796101774Salfred goto done2; 797137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 79882607Sdillon goto done2; 799137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 80082607Sdillon error = EINVAL; 80182607Sdillon goto done2; 80282607Sdillon } 803160187Sjhb *rval = semakptr->u.sem_base[semnum].sempid; 8042729Sdfr break; 8052729Sdfr 8062729Sdfr case GETVAL: 807298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 808101774Salfred goto done2; 809137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 81082607Sdillon goto done2; 811137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 81282607Sdillon error = EINVAL; 81382607Sdillon goto done2; 81482607Sdillon } 815160187Sjhb *rval = semakptr->u.sem_base[semnum].semval; 8162729Sdfr break; 8172729Sdfr 8182729Sdfr case GETALL: 819159991Sjhb /* 820160187Sjhb * Unfortunately, callers of this function don't know 821160187Sjhb * in advance how many semaphores are in this set. 822160187Sjhb * While we could just allocate the maximum size array 823160187Sjhb * and pass the actual size back to the caller, that 824160187Sjhb * won't work for SETALL since we can't copyin() more 825160187Sjhb * data than the user specified as we may return a 826160187Sjhb * spurious EFAULT. 827160187Sjhb * 828160187Sjhb * Note that the number of semaphores in a set is 829160187Sjhb * fixed for the life of that set. The only way that 830160187Sjhb * the 'count' could change while are blocked in 831160187Sjhb * malloc() is if this semaphore set were destroyed 832160187Sjhb * and a new one created with the same index. 833160187Sjhb * However, semvalid() will catch that due to the 834160187Sjhb * sequence number unless exactly 0x8000 (or a 835160187Sjhb * multiple thereof) semaphore sets for the same index 836160187Sjhb * are created and destroyed while we are in malloc! 837160187Sjhb * 838159991Sjhb */ 839160187Sjhb count = semakptr->u.sem_nsems; 840160187Sjhb mtx_unlock(sema_mtxp); 841160187Sjhb array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 842101774Salfred mtx_lock(sema_mtxp); 843298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 844101774Salfred goto done2; 845160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 846137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 84782607Sdillon goto done2; 848137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) 849137613Srwatson array[i] = semakptr->u.sem_base[i].semval; 850101774Salfred mtx_unlock(sema_mtxp); 851160187Sjhb error = copyout(array, arg->array, count * sizeof(*array)); 852160187Sjhb mtx_lock(sema_mtxp); 8532729Sdfr break; 8542729Sdfr 8552729Sdfr case GETZCNT: 856298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 857101774Salfred goto done2; 858137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 85982607Sdillon goto done2; 860137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 86182607Sdillon error = EINVAL; 86282607Sdillon goto done2; 86382607Sdillon } 864160187Sjhb *rval = semakptr->u.sem_base[semnum].semzcnt; 8652729Sdfr break; 8662729Sdfr 8672729Sdfr case SETVAL: 868298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 869101774Salfred goto done2; 870137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 87182607Sdillon goto done2; 872137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 87382607Sdillon error = EINVAL; 87482607Sdillon goto done2; 87582607Sdillon } 876159991Sjhb if (arg->val < 0 || arg->val > seminfo.semvmx) { 87784789Smr error = ERANGE; 87884789Smr goto done2; 87984789Smr } 880159991Sjhb semakptr->u.sem_base[semnum].semval = arg->val; 881101774Salfred SEMUNDO_LOCK(); 882160028Sjhb semundo_clear(semidx, semnum); 883101774Salfred SEMUNDO_UNLOCK(); 884137613Srwatson wakeup(semakptr); 8852729Sdfr break; 8862729Sdfr 8872729Sdfr case SETALL: 888159991Sjhb /* 889160187Sjhb * See comment on GETALL for why 'count' shouldn't change 890160187Sjhb * and why we require a userland buffer. 891159991Sjhb */ 892137613Srwatson count = semakptr->u.sem_nsems; 893160187Sjhb mtx_unlock(sema_mtxp); 894111119Simp array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 895159991Sjhb error = copyin(arg->array, array, count * sizeof(*array)); 896171179Skib mtx_lock(sema_mtxp); 897101774Salfred if (error) 898101774Salfred break; 899298585Sjamie if ((error = semvalid(semid, rpr, semakptr)) != 0) 900101774Salfred goto done2; 901160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 902137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 903101774Salfred goto done2; 904137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) { 905101774Salfred usval = array[i]; 90684789Smr if (usval > seminfo.semvmx) { 90784789Smr error = ERANGE; 90884789Smr break; 90984789Smr } 910137613Srwatson semakptr->u.sem_base[i].semval = usval; 9112729Sdfr } 912101774Salfred SEMUNDO_LOCK(); 913160028Sjhb semundo_clear(semidx, -1); 914101774Salfred SEMUNDO_UNLOCK(); 915137613Srwatson wakeup(semakptr); 9162729Sdfr break; 9172729Sdfr 9182729Sdfr default: 91982607Sdillon error = EINVAL; 92082607Sdillon break; 9212729Sdfr } 9222729Sdfr 92382607Sdillondone2: 924160187Sjhb mtx_unlock(sema_mtxp); 925187223Skib if (cmd == IPC_RMID) 926187223Skib mtx_unlock(&sem_mtx); 927101774Salfred if (array != NULL) 928101774Salfred free(array, M_TEMP); 92982607Sdillon return(error); 9302729Sdfr} 9312729Sdfr 93212866Speter#ifndef _SYS_SYSPROTO_H_ 9332729Sdfrstruct semget_args { 9342729Sdfr key_t key; 9352729Sdfr int nsems; 9362729Sdfr int semflg; 9372729Sdfr}; 93812866Speter#endif 93912866Speterint 940225617Skmacysys_semget(struct thread *td, struct semget_args *uap) 9412729Sdfr{ 94282607Sdillon int semid, error = 0; 9432729Sdfr int key = uap->key; 9442729Sdfr int nsems = uap->nsems; 9452729Sdfr int semflg = uap->semflg; 94691703Sjhb struct ucred *cred = td->td_ucred; 9472729Sdfr 948100523Salfred DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 949298585Sjamie 950298585Sjamie if (sem_find_prison(cred) == NULL) 95191703Sjhb return (ENOSYS); 95291703Sjhb 953187223Skib mtx_lock(&sem_mtx); 9542729Sdfr if (key != IPC_PRIVATE) { 9552729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 956137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 957298585Sjamie sema[semid].cred != NULL && 958298585Sjamie sema[semid].cred->cr_prison == cred->cr_prison && 959137613Srwatson sema[semid].u.sem_perm.key == key) 9602729Sdfr break; 9612729Sdfr } 9622729Sdfr if (semid < seminfo.semmni) { 963100523Salfred DPRINTF(("found public key\n")); 964295385Sjilles if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 965295385Sjilles DPRINTF(("not exclusive\n")); 966295385Sjilles error = EEXIST; 967295385Sjilles goto done2; 968295385Sjilles } 969137613Srwatson if ((error = ipcperm(td, &sema[semid].u.sem_perm, 97082607Sdillon semflg & 0700))) { 97182607Sdillon goto done2; 97282607Sdillon } 973137613Srwatson if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 974100523Salfred DPRINTF(("too small\n")); 97582607Sdillon error = EINVAL; 97682607Sdillon goto done2; 9772729Sdfr } 978140615Srwatson#ifdef MAC 979172930Srwatson error = mac_sysvsem_check_semget(cred, &sema[semid]); 980162468Srwatson if (error != 0) 981140615Srwatson goto done2; 982140615Srwatson#endif 9832729Sdfr goto found; 9842729Sdfr } 9852729Sdfr } 9862729Sdfr 987137613Srwatson DPRINTF(("need to allocate the semid_kernel\n")); 9882729Sdfr if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 9892729Sdfr if (nsems <= 0 || nsems > seminfo.semmsl) { 990100523Salfred DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 991100523Salfred seminfo.semmsl)); 99282607Sdillon error = EINVAL; 99382607Sdillon goto done2; 9942729Sdfr } 9952729Sdfr if (nsems > seminfo.semmns - semtot) { 996100523Salfred DPRINTF(( 997100523Salfred "not enough semaphores left (need %d, got %d)\n", 998100523Salfred nsems, seminfo.semmns - semtot)); 99982607Sdillon error = ENOSPC; 100082607Sdillon goto done2; 10012729Sdfr } 10022729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 1003137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 10042729Sdfr break; 10052729Sdfr } 10062729Sdfr if (semid == seminfo.semmni) { 1007137613Srwatson DPRINTF(("no more semid_kernel's available\n")); 100882607Sdillon error = ENOSPC; 100982607Sdillon goto done2; 10102729Sdfr } 1011223825Strasz#ifdef RACCT 1012282213Strasz if (racct_enable) { 1013282213Strasz PROC_LOCK(td->td_proc); 1014282213Strasz error = racct_add(td->td_proc, RACCT_NSEM, nsems); 1015282213Strasz PROC_UNLOCK(td->td_proc); 1016282213Strasz if (error != 0) { 1017282213Strasz error = ENOSPC; 1018282213Strasz goto done2; 1019282213Strasz } 1020220398Strasz } 1021223825Strasz#endif 1022100523Salfred DPRINTF(("semid %d is available\n", semid)); 1023187298Skib mtx_lock(&sema_mtx[semid]); 1024187298Skib KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 1025187298Skib ("Lost semaphore %d", semid)); 1026137613Srwatson sema[semid].u.sem_perm.key = key; 1027137613Srwatson sema[semid].u.sem_perm.cuid = cred->cr_uid; 1028137613Srwatson sema[semid].u.sem_perm.uid = cred->cr_uid; 1029137613Srwatson sema[semid].u.sem_perm.cgid = cred->cr_gid; 1030137613Srwatson sema[semid].u.sem_perm.gid = cred->cr_gid; 1031137613Srwatson sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 1032220399Strasz sema[semid].cred = crhold(cred); 1033137613Srwatson sema[semid].u.sem_perm.seq = 1034137613Srwatson (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 1035137613Srwatson sema[semid].u.sem_nsems = nsems; 1036137613Srwatson sema[semid].u.sem_otime = 0; 1037137613Srwatson sema[semid].u.sem_ctime = time_second; 1038137613Srwatson sema[semid].u.sem_base = &sem[semtot]; 10392729Sdfr semtot += nsems; 1040137613Srwatson bzero(sema[semid].u.sem_base, 1041137613Srwatson sizeof(sema[semid].u.sem_base[0])*nsems); 1042140615Srwatson#ifdef MAC 1043172930Srwatson mac_sysvsem_create(cred, &sema[semid]); 1044140615Srwatson#endif 1045187298Skib mtx_unlock(&sema_mtx[semid]); 1046160293Skib DPRINTF(("sembase = %p, next = %p\n", 1047137613Srwatson sema[semid].u.sem_base, &sem[semtot])); 10482729Sdfr } else { 1049100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 105082607Sdillon error = ENOENT; 105182607Sdillon goto done2; 10522729Sdfr } 10532729Sdfr 10542729Sdfrfound: 1055137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 105682607Sdillondone2: 1057187223Skib mtx_unlock(&sem_mtx); 105882607Sdillon return (error); 10592729Sdfr} 10602729Sdfr 106112866Speter#ifndef _SYS_SYSPROTO_H_ 10622729Sdfrstruct semop_args { 10632729Sdfr int semid; 10642729Sdfr struct sembuf *sops; 1065109829Salfred size_t nsops; 10662729Sdfr}; 106712866Speter#endif 106812866Speterint 1069225617Skmacysys_semop(struct thread *td, struct semop_args *uap) 10702729Sdfr{ 1071123667Stjr#define SMALL_SOPS 8 1072123667Stjr struct sembuf small_sops[SMALL_SOPS]; 10732729Sdfr int semid = uap->semid; 1074109829Salfred size_t nsops = uap->nsops; 1075298585Sjamie struct prison *rpr; 1076105429Salfred struct sembuf *sops; 1077137613Srwatson struct semid_kernel *semakptr; 1078298069Spfg struct sembuf *sopptr = NULL; 1079298069Spfg struct sem *semptr = NULL; 108084789Smr struct sem_undo *suptr; 1081101774Salfred struct mtx *sema_mtxp; 1082110040Stjr size_t i, j, k; 1083109829Salfred int error; 10843308Sphk int do_wakeup, do_undos; 1085187223Skib unsigned short seq; 10862729Sdfr 1087160293Skib#ifdef SEM_DEBUG 1088160293Skib sops = NULL; 1089160293Skib#endif 1090160293Skib DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 10912729Sdfr 1092298585Sjamie rpr = sem_find_prison(td->td_ucred); 1093298585Sjamie if (sem == NULL) 109491703Sjhb return (ENOSYS); 109591703Sjhb 10962729Sdfr semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 10972729Sdfr 1098101774Salfred if (semid < 0 || semid >= seminfo.semmni) 1099137644Srwatson return (EINVAL); 1100101774Salfred 1101101774Salfred /* Allocate memory for sem_ops */ 1102123667Stjr if (nsops <= SMALL_SOPS) 1103123667Stjr sops = small_sops; 1104220398Strasz else if (nsops > seminfo.semopm) { 1105101774Salfred DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1106101774Salfred nsops)); 1107101774Salfred return (E2BIG); 1108220398Strasz } else { 1109223825Strasz#ifdef RACCT 1110282213Strasz if (racct_enable) { 1111282213Strasz PROC_LOCK(td->td_proc); 1112282213Strasz if (nsops > 1113282213Strasz racct_get_available(td->td_proc, RACCT_NSEMOP)) { 1114282213Strasz PROC_UNLOCK(td->td_proc); 1115282213Strasz return (E2BIG); 1116282213Strasz } 1117220398Strasz PROC_UNLOCK(td->td_proc); 1118220398Strasz } 1119223825Strasz#endif 1120220398Strasz 1121220398Strasz sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 112282607Sdillon } 1123101774Salfred if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1124160293Skib DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1125101774Salfred uap->sops, sops, nsops * sizeof(sops[0]))); 1126123667Stjr if (sops != small_sops) 1127123667Stjr free(sops, M_SEM); 1128101774Salfred return (error); 1129101774Salfred } 11302729Sdfr 1131137613Srwatson semakptr = &sema[semid]; 1132101774Salfred sema_mtxp = &sema_mtx[semid]; 1133101774Salfred mtx_lock(sema_mtxp); 1134137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 113582607Sdillon error = EINVAL; 113682607Sdillon goto done2; 113782607Sdillon } 1138187223Skib seq = semakptr->u.sem_perm.seq; 1139187223Skib if (seq != IPCID_TO_SEQ(uap->semid)) { 114082607Sdillon error = EINVAL; 114182607Sdillon goto done2; 114282607Sdillon } 1143298585Sjamie if ((error = sem_prison_cansee(rpr, semakptr)) != 0) 1144298585Sjamie goto done2; 114584789Smr /* 1146298819Spfg * Initial pass through sops to see what permissions are needed. 114784789Smr * Also perform any checks that don't need repeating on each 114884789Smr * attempt to satisfy the request vector. 114984789Smr */ 115084789Smr j = 0; /* permission needed */ 115184789Smr do_undos = 0; 115284789Smr for (i = 0; i < nsops; i++) { 115384789Smr sopptr = &sops[i]; 1154137613Srwatson if (sopptr->sem_num >= semakptr->u.sem_nsems) { 115584789Smr error = EFBIG; 115684789Smr goto done2; 115784789Smr } 115884789Smr if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 115984789Smr do_undos = 1; 116084789Smr j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 116184789Smr } 116284789Smr 1163137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1164100523Salfred DPRINTF(("error = %d from ipaccess\n", error)); 116582607Sdillon goto done2; 11662729Sdfr } 1167140615Srwatson#ifdef MAC 1168172930Srwatson error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1169162468Srwatson if (error != 0) 1170140615Srwatson goto done2; 1171140615Srwatson#endif 11722729Sdfr 11738876Srgrimes /* 11742729Sdfr * Loop trying to satisfy the vector of requests. 11752729Sdfr * If we reach a point where we must wait, any requests already 11762729Sdfr * performed are rolled back and we go to sleep until some other 11772729Sdfr * process wakes us up. At this point, we start all over again. 11782729Sdfr * 11792729Sdfr * This ensures that from the perspective of other tasks, a set 11802729Sdfr * of requests is atomic (never partially satisfied). 11812729Sdfr */ 11822729Sdfr for (;;) { 11832729Sdfr do_wakeup = 0; 118484789Smr error = 0; /* error return if necessary */ 11852729Sdfr 11862729Sdfr for (i = 0; i < nsops; i++) { 11872729Sdfr sopptr = &sops[i]; 1188137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 11892729Sdfr 1190100523Salfred DPRINTF(( 1191160293Skib "semop: semakptr=%p, sem_base=%p, " 1192160293Skib "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1193137613Srwatson semakptr, semakptr->u.sem_base, semptr, 11942729Sdfr sopptr->sem_num, semptr->semval, sopptr->sem_op, 1195100523Salfred (sopptr->sem_flg & IPC_NOWAIT) ? 1196100523Salfred "nowait" : "wait")); 11972729Sdfr 11982729Sdfr if (sopptr->sem_op < 0) { 11992729Sdfr if (semptr->semval + sopptr->sem_op < 0) { 1200100523Salfred DPRINTF(("semop: can't do it now\n")); 12012729Sdfr break; 12022729Sdfr } else { 12032729Sdfr semptr->semval += sopptr->sem_op; 12042729Sdfr if (semptr->semval == 0 && 12052729Sdfr semptr->semzcnt > 0) 12062729Sdfr do_wakeup = 1; 12072729Sdfr } 12082729Sdfr } else if (sopptr->sem_op == 0) { 120984789Smr if (semptr->semval != 0) { 1210100523Salfred DPRINTF(("semop: not zero now\n")); 12112729Sdfr break; 12122729Sdfr } 121384789Smr } else if (semptr->semval + sopptr->sem_op > 121484789Smr seminfo.semvmx) { 121584789Smr error = ERANGE; 121684789Smr break; 12172729Sdfr } else { 12182729Sdfr if (semptr->semncnt > 0) 12192729Sdfr do_wakeup = 1; 12202729Sdfr semptr->semval += sopptr->sem_op; 12212729Sdfr } 12222729Sdfr } 12232729Sdfr 12242729Sdfr /* 12252729Sdfr * Did we get through the entire vector? 12262729Sdfr */ 12272729Sdfr if (i >= nsops) 12282729Sdfr goto done; 12292729Sdfr 12302729Sdfr /* 12312729Sdfr * No ... rollback anything that we've already done 12322729Sdfr */ 1233100523Salfred DPRINTF(("semop: rollback 0 through %d\n", i-1)); 12342729Sdfr for (j = 0; j < i; j++) 1235137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 12362729Sdfr sops[j].sem_op; 12372729Sdfr 123884789Smr /* If we detected an error, return it */ 123984789Smr if (error != 0) 124084789Smr goto done2; 124184789Smr 12422729Sdfr /* 12432729Sdfr * If the request that we couldn't satisfy has the 12442729Sdfr * NOWAIT flag set then return with EAGAIN. 12452729Sdfr */ 124682607Sdillon if (sopptr->sem_flg & IPC_NOWAIT) { 124782607Sdillon error = EAGAIN; 124882607Sdillon goto done2; 124982607Sdillon } 12502729Sdfr 12512729Sdfr if (sopptr->sem_op == 0) 12522729Sdfr semptr->semzcnt++; 12532729Sdfr else 12542729Sdfr semptr->semncnt++; 12552729Sdfr 1256100523Salfred DPRINTF(("semop: good night!\n")); 1257137613Srwatson error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1258101774Salfred "semwait", 0); 1259100523Salfred DPRINTF(("semop: good morning (error=%d)!\n", error)); 1260127108Scperciva /* return code is checked below, after sem[nz]cnt-- */ 12612729Sdfr 12622729Sdfr /* 12632729Sdfr * Make sure that the semaphore still exists 12642729Sdfr */ 1265187223Skib seq = semakptr->u.sem_perm.seq; 1266137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1267187223Skib seq != IPCID_TO_SEQ(uap->semid)) { 126882607Sdillon error = EIDRM; 126982607Sdillon goto done2; 127082607Sdillon } 12712729Sdfr 12722729Sdfr /* 1273179879Sgonzo * Renew the semaphore's pointer after wakeup since 1274179879Sgonzo * during msleep sem_base may have been modified and semptr 1275179879Sgonzo * is not valid any more 1276179879Sgonzo */ 1277179879Sgonzo semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1278179879Sgonzo 1279179879Sgonzo /* 12802729Sdfr * The semaphore is still alive. Readjust the count of 12812729Sdfr * waiting processes. 12822729Sdfr */ 12832729Sdfr if (sopptr->sem_op == 0) 12842729Sdfr semptr->semzcnt--; 12852729Sdfr else 12862729Sdfr semptr->semncnt--; 1287127108Scperciva 1288127108Scperciva /* 1289127108Scperciva * Is it really morning, or was our sleep interrupted? 1290127108Scperciva * (Delayed check of msleep() return code because we 1291127108Scperciva * need to decrement sem[nz]cnt either way.) 1292127108Scperciva */ 1293127108Scperciva if (error != 0) { 1294127108Scperciva error = EINTR; 1295127108Scperciva goto done2; 1296127108Scperciva } 1297127108Scperciva DPRINTF(("semop: good morning!\n")); 12982729Sdfr } 12992729Sdfr 13002729Sdfrdone: 13012729Sdfr /* 13022729Sdfr * Process any SEM_UNDO requests. 13032729Sdfr */ 13042729Sdfr if (do_undos) { 1305101774Salfred SEMUNDO_LOCK(); 130684789Smr suptr = NULL; 13072729Sdfr for (i = 0; i < nsops; i++) { 13082729Sdfr /* 13092729Sdfr * We only need to deal with SEM_UNDO's for non-zero 13102729Sdfr * op's. 13112729Sdfr */ 13122729Sdfr int adjval; 13132729Sdfr 13142729Sdfr if ((sops[i].sem_flg & SEM_UNDO) == 0) 13152729Sdfr continue; 13162729Sdfr adjval = sops[i].sem_op; 13172729Sdfr if (adjval == 0) 13182729Sdfr continue; 1319187223Skib error = semundo_adjust(td, &suptr, semid, seq, 13202729Sdfr sops[i].sem_num, -adjval); 132182607Sdillon if (error == 0) 13222729Sdfr continue; 13232729Sdfr 13242729Sdfr /* 13252729Sdfr * Oh-Oh! We ran out of either sem_undo's or undo's. 13262729Sdfr * Rollback the adjustments to this point and then 13272729Sdfr * rollback the semaphore ups and down so we can return 13282729Sdfr * with an error with all structures restored. We 13292729Sdfr * rollback the undo's in the exact reverse order that 13302729Sdfr * we applied them. This guarantees that we won't run 13312729Sdfr * out of space as we roll things back out. 13322729Sdfr */ 1333110040Stjr for (j = 0; j < i; j++) { 1334110040Stjr k = i - j - 1; 1335110040Stjr if ((sops[k].sem_flg & SEM_UNDO) == 0) 13362729Sdfr continue; 1337110040Stjr adjval = sops[k].sem_op; 13382729Sdfr if (adjval == 0) 13392729Sdfr continue; 1340187223Skib if (semundo_adjust(td, &suptr, semid, seq, 1341110040Stjr sops[k].sem_num, adjval) != 0) 13422729Sdfr panic("semop - can't undo undos"); 13432729Sdfr } 13442729Sdfr 13452729Sdfr for (j = 0; j < nsops; j++) 1346137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 13472729Sdfr sops[j].sem_op; 13482729Sdfr 1349100523Salfred DPRINTF(("error = %d from semundo_adjust\n", error)); 1350101774Salfred SEMUNDO_UNLOCK(); 135182607Sdillon goto done2; 13522729Sdfr } /* loop through the sops */ 1353101774Salfred SEMUNDO_UNLOCK(); 13542729Sdfr } /* if (do_undos) */ 13552729Sdfr 135684789Smr /* We're definitely done - set the sempid's and time */ 13572729Sdfr for (i = 0; i < nsops; i++) { 13582729Sdfr sopptr = &sops[i]; 1359137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 136083366Sjulian semptr->sempid = td->td_proc->p_pid; 13612729Sdfr } 1362137613Srwatson semakptr->u.sem_otime = time_second; 13632729Sdfr 136484789Smr /* 136584789Smr * Do a wakeup if any semaphore was up'd whilst something was 136684789Smr * sleeping on it. 136784789Smr */ 13682729Sdfr if (do_wakeup) { 1369100523Salfred DPRINTF(("semop: doing wakeup\n")); 1370137613Srwatson wakeup(semakptr); 1371100523Salfred DPRINTF(("semop: back from wakeup\n")); 13722729Sdfr } 1373100523Salfred DPRINTF(("semop: done\n")); 137483366Sjulian td->td_retval[0] = 0; 137582607Sdillondone2: 1376101774Salfred mtx_unlock(sema_mtxp); 1377123667Stjr if (sops != small_sops) 1378123667Stjr free(sops, M_SEM); 137982607Sdillon return (error); 13802729Sdfr} 13812729Sdfr 13822729Sdfr/* 13832729Sdfr * Go through the undo structures for this process and apply the adjustments to 13842729Sdfr * semaphores. 13852729Sdfr */ 138669449Salfredstatic void 1387187223Skibsemexit_myhook(void *arg, struct proc *p) 13882729Sdfr{ 1389101350Salfred struct sem_undo *suptr; 1390187223Skib struct semid_kernel *semakptr; 1391187223Skib struct mtx *sema_mtxp; 1392187223Skib int semid, semnum, adjval, ix; 1393187223Skib unsigned short seq; 13942729Sdfr 13952729Sdfr /* 13962729Sdfr * Go through the chain of undo vectors looking for one 13972729Sdfr * associated with this process. 13982729Sdfr */ 1399101774Salfred SEMUNDO_LOCK(); 1400187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 1401187223Skib if (suptr->un_proc == p) 14022729Sdfr break; 14032729Sdfr } 1404187223Skib if (suptr == NULL) { 1405187223Skib SEMUNDO_UNLOCK(); 140659828Speter return; 1407187223Skib } 1408187223Skib LIST_REMOVE(suptr, un_next); 14092729Sdfr 1410160293Skib DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1411100523Salfred suptr->un_cnt)); 14122729Sdfr 14132729Sdfr /* 14142729Sdfr * If there are any active undo elements then process them. 14152729Sdfr */ 14162729Sdfr if (suptr->un_cnt > 0) { 1417187223Skib SEMUNDO_UNLOCK(); 14182729Sdfr for (ix = 0; ix < suptr->un_cnt; ix++) { 1419187223Skib semid = suptr->un_ent[ix].un_id; 1420187223Skib semnum = suptr->un_ent[ix].un_num; 1421187223Skib adjval = suptr->un_ent[ix].un_adjval; 1422187223Skib seq = suptr->un_ent[ix].un_seq; 1423137613Srwatson semakptr = &sema[semid]; 1424101774Salfred sema_mtxp = &sema_mtx[semid]; 1425187223Skib 1426101774Salfred mtx_lock(sema_mtxp); 1427187223Skib if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1428187223Skib (semakptr->u.sem_perm.seq != seq)) { 1429187223Skib mtx_unlock(sema_mtxp); 1430187223Skib continue; 1431187223Skib } 1432137613Srwatson if (semnum >= semakptr->u.sem_nsems) 14332729Sdfr panic("semexit - semnum out of range"); 14342729Sdfr 1435100523Salfred DPRINTF(( 1436160293Skib "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 14372729Sdfr suptr->un_proc, suptr->un_ent[ix].un_id, 14382729Sdfr suptr->un_ent[ix].un_num, 14392729Sdfr suptr->un_ent[ix].un_adjval, 1440137613Srwatson semakptr->u.sem_base[semnum].semval)); 14412729Sdfr 1442187223Skib if (adjval < 0 && semakptr->u.sem_base[semnum].semval < 1443187223Skib -adjval) 1444187223Skib semakptr->u.sem_base[semnum].semval = 0; 1445187223Skib else 1446137613Srwatson semakptr->u.sem_base[semnum].semval += adjval; 14472729Sdfr 1448137613Srwatson wakeup(semakptr); 1449100523Salfred DPRINTF(("semexit: back from wakeup\n")); 1450101774Salfred mtx_unlock(sema_mtxp); 14512729Sdfr } 1452187223Skib SEMUNDO_LOCK(); 14532729Sdfr } 14542729Sdfr 14552729Sdfr /* 14562729Sdfr * Deallocate the undo vector. 14572729Sdfr */ 1458100523Salfred DPRINTF(("removing vector\n")); 14592729Sdfr suptr->un_proc = NULL; 1460187223Skib suptr->un_cnt = 0; 1461187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1462167904Semaste SEMUNDO_UNLOCK(); 14632729Sdfr} 146477461Sdd 146577461Sddstatic int 146677461Sddsysctl_sema(SYSCTL_HANDLER_ARGS) 146777461Sdd{ 1468298656Sjamie struct prison *pr, *rpr; 1469298656Sjamie struct semid_kernel tsemak; 1470298585Sjamie int error, i; 147177461Sdd 1472298656Sjamie pr = req->td->td_ucred->cr_prison; 1473298585Sjamie rpr = sem_find_prison(req->td->td_ucred); 1474298656Sjamie error = 0; 1475298585Sjamie for (i = 0; i < seminfo.semmni; i++) { 1476298656Sjamie mtx_lock(&sema_mtx[i]); 1477298656Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) == 0 || 1478298656Sjamie rpr == NULL || sem_prison_cansee(rpr, &sema[i]) != 0) 1479298656Sjamie bzero(&tsemak, sizeof(tsemak)); 1480298656Sjamie else { 1481298656Sjamie tsemak = sema[i]; 1482298656Sjamie if (tsemak.cred->cr_prison != pr) 1483298656Sjamie tsemak.u.sem_perm.key = IPC_PRIVATE; 1484298585Sjamie } 1485298656Sjamie mtx_unlock(&sema_mtx[i]); 1486298656Sjamie error = SYSCTL_OUT(req, &tsemak, sizeof(tsemak)); 1487298656Sjamie if (error != 0) 1488298656Sjamie break; 1489298585Sjamie } 1490298585Sjamie return (error); 149177461Sdd} 1492194894Sjhb 1493298585Sjamiestatic int 1494298585Sjamiesem_prison_check(void *obj, void *data) 1495298585Sjamie{ 1496298585Sjamie struct prison *pr = obj; 1497298585Sjamie struct prison *prpr; 1498298585Sjamie struct vfsoptlist *opts = data; 1499298585Sjamie int error, jsys; 1500298585Sjamie 1501298585Sjamie /* 1502298585Sjamie * sysvsem is a jailsys integer. 1503298585Sjamie * It must be "disable" if the parent jail is disabled. 1504298585Sjamie */ 1505298585Sjamie error = vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1506298585Sjamie if (error != ENOENT) { 1507298585Sjamie if (error != 0) 1508298585Sjamie return (error); 1509298585Sjamie switch (jsys) { 1510298585Sjamie case JAIL_SYS_DISABLE: 1511298585Sjamie break; 1512298585Sjamie case JAIL_SYS_NEW: 1513298585Sjamie case JAIL_SYS_INHERIT: 1514298585Sjamie prison_lock(pr->pr_parent); 1515298585Sjamie prpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1516298585Sjamie prison_unlock(pr->pr_parent); 1517298585Sjamie if (prpr == NULL) 1518298585Sjamie return (EPERM); 1519298585Sjamie break; 1520298585Sjamie default: 1521298585Sjamie return (EINVAL); 1522298585Sjamie } 1523298585Sjamie } 1524298585Sjamie 1525298585Sjamie return (0); 1526298585Sjamie} 1527298585Sjamie 1528298585Sjamiestatic int 1529298585Sjamiesem_prison_set(void *obj, void *data) 1530298585Sjamie{ 1531298585Sjamie struct prison *pr = obj; 1532298585Sjamie struct prison *tpr, *orpr, *nrpr, *trpr; 1533298585Sjamie struct vfsoptlist *opts = data; 1534298585Sjamie void *rsv; 1535298585Sjamie int jsys, descend; 1536298585Sjamie 1537298585Sjamie /* 1538298585Sjamie * sysvsem controls which jail is the root of the associated sems (this 1539298585Sjamie * jail or same as the parent), or if the feature is available at all. 1540298585Sjamie */ 1541298585Sjamie if (vfs_copyopt(opts, "sysvsem", &jsys, sizeof(jsys)) == ENOENT) 1542298585Sjamie jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0) 1543298585Sjamie ? JAIL_SYS_INHERIT 1544298585Sjamie : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0) 1545298585Sjamie ? JAIL_SYS_DISABLE 1546298585Sjamie : -1; 1547298585Sjamie if (jsys == JAIL_SYS_DISABLE) { 1548298585Sjamie prison_lock(pr); 1549298585Sjamie orpr = osd_jail_get(pr, sem_prison_slot); 1550298585Sjamie if (orpr != NULL) 1551298585Sjamie osd_jail_del(pr, sem_prison_slot); 1552298585Sjamie prison_unlock(pr); 1553298585Sjamie if (orpr != NULL) { 1554298585Sjamie if (orpr == pr) 1555298585Sjamie sem_prison_cleanup(pr); 1556298585Sjamie /* Disable all child jails as well. */ 1557298585Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1558298585Sjamie prison_lock(tpr); 1559298585Sjamie trpr = osd_jail_get(tpr, sem_prison_slot); 1560298585Sjamie if (trpr != NULL) { 1561298585Sjamie osd_jail_del(tpr, sem_prison_slot); 1562298585Sjamie prison_unlock(tpr); 1563298585Sjamie if (trpr == tpr) 1564298585Sjamie sem_prison_cleanup(tpr); 1565298585Sjamie } else { 1566298585Sjamie prison_unlock(tpr); 1567298585Sjamie descend = 0; 1568298585Sjamie } 1569298585Sjamie } 1570298585Sjamie } 1571298585Sjamie } else if (jsys != -1) { 1572298585Sjamie if (jsys == JAIL_SYS_NEW) 1573298585Sjamie nrpr = pr; 1574298585Sjamie else { 1575298585Sjamie prison_lock(pr->pr_parent); 1576298585Sjamie nrpr = osd_jail_get(pr->pr_parent, sem_prison_slot); 1577298585Sjamie prison_unlock(pr->pr_parent); 1578298585Sjamie } 1579298585Sjamie rsv = osd_reserve(sem_prison_slot); 1580298585Sjamie prison_lock(pr); 1581298585Sjamie orpr = osd_jail_get(pr, sem_prison_slot); 1582298585Sjamie if (orpr != nrpr) 1583298585Sjamie (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, 1584298585Sjamie nrpr); 1585298585Sjamie else 1586298585Sjamie osd_free_reserved(rsv); 1587298585Sjamie prison_unlock(pr); 1588298585Sjamie if (orpr != nrpr) { 1589298585Sjamie if (orpr == pr) 1590298585Sjamie sem_prison_cleanup(pr); 1591298585Sjamie if (orpr != NULL) { 1592298585Sjamie /* Change child jails matching the old root, */ 1593298585Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1594298585Sjamie prison_lock(tpr); 1595298585Sjamie trpr = osd_jail_get(tpr, 1596298585Sjamie sem_prison_slot); 1597298585Sjamie if (trpr == orpr) { 1598298585Sjamie (void)osd_jail_set(tpr, 1599298585Sjamie sem_prison_slot, nrpr); 1600298585Sjamie prison_unlock(tpr); 1601298585Sjamie if (trpr == tpr) 1602298585Sjamie sem_prison_cleanup(tpr); 1603298585Sjamie } else { 1604298585Sjamie prison_unlock(tpr); 1605298585Sjamie descend = 0; 1606298585Sjamie } 1607298585Sjamie } 1608298585Sjamie } 1609298585Sjamie } 1610298585Sjamie } 1611298585Sjamie 1612298585Sjamie return (0); 1613298585Sjamie} 1614298585Sjamie 1615298585Sjamiestatic int 1616298585Sjamiesem_prison_get(void *obj, void *data) 1617298585Sjamie{ 1618298585Sjamie struct prison *pr = obj; 1619298585Sjamie struct prison *rpr; 1620298585Sjamie struct vfsoptlist *opts = data; 1621298585Sjamie int error, jsys; 1622298585Sjamie 1623298585Sjamie /* Set sysvsem based on the jail's root prison. */ 1624298585Sjamie prison_lock(pr); 1625298585Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 1626298585Sjamie prison_unlock(pr); 1627298585Sjamie jsys = rpr == NULL ? JAIL_SYS_DISABLE 1628298585Sjamie : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 1629298585Sjamie error = vfs_setopt(opts, "sysvsem", &jsys, sizeof(jsys)); 1630298585Sjamie if (error == ENOENT) 1631298585Sjamie error = 0; 1632298585Sjamie return (error); 1633298585Sjamie} 1634298585Sjamie 1635298585Sjamiestatic int 1636298585Sjamiesem_prison_remove(void *obj, void *data __unused) 1637298585Sjamie{ 1638298585Sjamie struct prison *pr = obj; 1639298585Sjamie struct prison *rpr; 1640298585Sjamie 1641298585Sjamie prison_lock(pr); 1642298585Sjamie rpr = osd_jail_get(pr, sem_prison_slot); 1643298585Sjamie prison_unlock(pr); 1644298585Sjamie if (rpr == pr) 1645298585Sjamie sem_prison_cleanup(pr); 1646298585Sjamie return (0); 1647298585Sjamie} 1648298585Sjamie 1649298585Sjamiestatic void 1650298585Sjamiesem_prison_cleanup(struct prison *pr) 1651298585Sjamie{ 1652298585Sjamie int i; 1653298585Sjamie 1654298585Sjamie /* Remove any sems that belong to this jail. */ 1655298585Sjamie mtx_lock(&sem_mtx); 1656298585Sjamie for (i = 0; i < seminfo.semmni; i++) { 1657298585Sjamie if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 1658298585Sjamie sema[i].cred != NULL && sema[i].cred->cr_prison == pr) { 1659298585Sjamie mtx_lock(&sema_mtx[i]); 1660298585Sjamie sem_remove(i, NULL); 1661298585Sjamie mtx_unlock(&sema_mtx[i]); 1662298585Sjamie } 1663298585Sjamie } 1664298585Sjamie mtx_unlock(&sem_mtx); 1665298585Sjamie} 1666298585Sjamie 1667298585SjamieSYSCTL_JAIL_PARAM_SYS_NODE(sysvsem, CTLFLAG_RW, "SYSV semaphores"); 1668298585Sjamie 1669194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1670194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1671194894Sjhb 1672194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1673194894Sjhbstatic sy_call_t *semcalls[] = { 1674225617Skmacy (sy_call_t *)freebsd7___semctl, (sy_call_t *)sys_semget, 1675225617Skmacy (sy_call_t *)sys_semop 1676194894Sjhb}; 1677194894Sjhb 1678194894Sjhb/* 1679194894Sjhb * Entry point for all SEM calls. 1680194894Sjhb */ 1681194894Sjhbint 1682225617Skmacysys_semsys(td, uap) 1683194894Sjhb struct thread *td; 1684194894Sjhb /* XXX actually varargs. */ 1685194894Sjhb struct semsys_args /* { 1686194894Sjhb int which; 1687194894Sjhb int a2; 1688194894Sjhb int a3; 1689194894Sjhb int a4; 1690194894Sjhb int a5; 1691194894Sjhb } */ *uap; 1692194894Sjhb{ 1693194894Sjhb int error; 1694194894Sjhb 1695298354Spfg if (uap->which < 0 || uap->which >= nitems(semcalls)) 1696194894Sjhb return (EINVAL); 1697194894Sjhb error = (*semcalls[uap->which])(td, &uap->a2); 1698194894Sjhb return (error); 1699194894Sjhb} 1700194910Sjhb 1701205323Skib#ifndef CP 1702194910Sjhb#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1703205323Skib#endif 1704194910Sjhb 1705194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1706194910Sjhbstruct freebsd7___semctl_args { 1707194910Sjhb int semid; 1708194910Sjhb int semnum; 1709194910Sjhb int cmd; 1710194910Sjhb union semun_old *arg; 1711194910Sjhb}; 1712194910Sjhb#endif 1713194910Sjhbint 1714194910Sjhbfreebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1715194910Sjhb{ 1716194910Sjhb struct semid_ds_old dsold; 1717194910Sjhb struct semid_ds dsbuf; 1718194910Sjhb union semun_old arg; 1719194910Sjhb union semun semun; 1720194910Sjhb register_t rval; 1721194910Sjhb int error; 1722194910Sjhb 1723194910Sjhb switch (uap->cmd) { 1724194910Sjhb case SEM_STAT: 1725194910Sjhb case IPC_SET: 1726194910Sjhb case IPC_STAT: 1727194910Sjhb case GETALL: 1728194910Sjhb case SETVAL: 1729194910Sjhb case SETALL: 1730194910Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 1731194910Sjhb if (error) 1732194910Sjhb return (error); 1733194910Sjhb break; 1734194910Sjhb } 1735194910Sjhb 1736194910Sjhb switch (uap->cmd) { 1737194910Sjhb case SEM_STAT: 1738194910Sjhb case IPC_STAT: 1739194910Sjhb semun.buf = &dsbuf; 1740194910Sjhb break; 1741194910Sjhb case IPC_SET: 1742194910Sjhb error = copyin(arg.buf, &dsold, sizeof(dsold)); 1743194910Sjhb if (error) 1744194910Sjhb return (error); 1745194910Sjhb ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1746194910Sjhb CP(dsold, dsbuf, sem_base); 1747194910Sjhb CP(dsold, dsbuf, sem_nsems); 1748194910Sjhb CP(dsold, dsbuf, sem_otime); 1749194910Sjhb CP(dsold, dsbuf, sem_ctime); 1750194910Sjhb semun.buf = &dsbuf; 1751194910Sjhb break; 1752194910Sjhb case GETALL: 1753194910Sjhb case SETALL: 1754194910Sjhb semun.array = arg.array; 1755194910Sjhb break; 1756194910Sjhb case SETVAL: 1757194910Sjhb semun.val = arg.val; 1758194910Sjhb break; 1759194910Sjhb } 1760194910Sjhb 1761194910Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1762194910Sjhb &rval); 1763194910Sjhb if (error) 1764194910Sjhb return (error); 1765194910Sjhb 1766194910Sjhb switch (uap->cmd) { 1767194910Sjhb case SEM_STAT: 1768194910Sjhb case IPC_STAT: 1769194910Sjhb bzero(&dsold, sizeof(dsold)); 1770194910Sjhb ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1771194910Sjhb CP(dsbuf, dsold, sem_base); 1772194910Sjhb CP(dsbuf, dsold, sem_nsems); 1773194910Sjhb CP(dsbuf, dsold, sem_otime); 1774194910Sjhb CP(dsbuf, dsold, sem_ctime); 1775194910Sjhb error = copyout(&dsold, arg.buf, sizeof(dsold)); 1776194910Sjhb break; 1777194910Sjhb } 1778194910Sjhb 1779194910Sjhb if (error == 0) 1780194910Sjhb td->td_retval[0] = rval; 1781194910Sjhb return (error); 1782194910Sjhb} 1783194910Sjhb 1784205323Skib#endif /* COMPAT_FREEBSD{4,5,6,7} */ 1785194910Sjhb 1786205323Skib#ifdef COMPAT_FREEBSD32 1787205323Skib 1788205323Skibint 1789205323Skibfreebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1790205323Skib{ 1791205323Skib 1792205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1793205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1794205323Skib switch (uap->which) { 1795205323Skib case 0: 1796205323Skib return (freebsd7_freebsd32_semctl(td, 1797205323Skib (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1798205323Skib default: 1799225617Skmacy return (sys_semsys(td, (struct semsys_args *)uap)); 1800205323Skib } 1801205323Skib#else 1802205323Skib return (nosys(td, NULL)); 1803205323Skib#endif 1804205323Skib} 1805205323Skib 1806205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1807205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1808205323Skibint 1809205323Skibfreebsd7_freebsd32_semctl(struct thread *td, 1810205323Skib struct freebsd7_freebsd32_semctl_args *uap) 1811205323Skib{ 1812205323Skib struct semid_ds32_old dsbuf32; 1813205323Skib struct semid_ds dsbuf; 1814205323Skib union semun semun; 1815205323Skib union semun32 arg; 1816205323Skib register_t rval; 1817205323Skib int error; 1818205323Skib 1819205323Skib switch (uap->cmd) { 1820205323Skib case SEM_STAT: 1821205323Skib case IPC_SET: 1822205323Skib case IPC_STAT: 1823205323Skib case GETALL: 1824205323Skib case SETVAL: 1825205323Skib case SETALL: 1826205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1827205323Skib if (error) 1828205323Skib return (error); 1829205323Skib break; 1830205323Skib } 1831205323Skib 1832205323Skib switch (uap->cmd) { 1833205323Skib case SEM_STAT: 1834205323Skib case IPC_STAT: 1835205323Skib semun.buf = &dsbuf; 1836205323Skib break; 1837205323Skib case IPC_SET: 1838205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1839205323Skib if (error) 1840205323Skib return (error); 1841205323Skib freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1842205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1843205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1844205323Skib CP(dsbuf32, dsbuf, sem_otime); 1845205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1846205323Skib semun.buf = &dsbuf; 1847205323Skib break; 1848205323Skib case GETALL: 1849205323Skib case SETALL: 1850205323Skib semun.array = PTRIN(arg.array); 1851205323Skib break; 1852205323Skib case SETVAL: 1853205323Skib semun.val = arg.val; 1854205323Skib break; 1855205323Skib } 1856205323Skib 1857205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1858205323Skib &rval); 1859205323Skib if (error) 1860205323Skib return (error); 1861205323Skib 1862205323Skib switch (uap->cmd) { 1863205323Skib case SEM_STAT: 1864205323Skib case IPC_STAT: 1865205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1866205323Skib freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1867205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1868205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1869205323Skib CP(dsbuf, dsbuf32, sem_otime); 1870205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1871205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1872205323Skib break; 1873205323Skib } 1874205323Skib 1875205323Skib if (error == 0) 1876205323Skib td->td_retval[0] = rval; 1877205323Skib return (error); 1878205323Skib} 1879205323Skib#endif 1880205323Skib 1881205323Skibint 1882205323Skibfreebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1883205323Skib{ 1884205323Skib struct semid_ds32 dsbuf32; 1885205323Skib struct semid_ds dsbuf; 1886205323Skib union semun semun; 1887205323Skib union semun32 arg; 1888205323Skib register_t rval; 1889205323Skib int error; 1890205323Skib 1891205323Skib switch (uap->cmd) { 1892205323Skib case SEM_STAT: 1893205323Skib case IPC_SET: 1894205323Skib case IPC_STAT: 1895205323Skib case GETALL: 1896205323Skib case SETVAL: 1897205323Skib case SETALL: 1898205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1899205323Skib if (error) 1900205323Skib return (error); 1901205323Skib break; 1902205323Skib } 1903205323Skib 1904205323Skib switch (uap->cmd) { 1905205323Skib case SEM_STAT: 1906205323Skib case IPC_STAT: 1907205323Skib semun.buf = &dsbuf; 1908205323Skib break; 1909205323Skib case IPC_SET: 1910205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1911205323Skib if (error) 1912205323Skib return (error); 1913205323Skib freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1914205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1915205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1916205323Skib CP(dsbuf32, dsbuf, sem_otime); 1917205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1918205323Skib semun.buf = &dsbuf; 1919205323Skib break; 1920205323Skib case GETALL: 1921205323Skib case SETALL: 1922205323Skib semun.array = PTRIN(arg.array); 1923205323Skib break; 1924205323Skib case SETVAL: 1925205323Skib semun.val = arg.val; 1926205323Skib break; 1927205323Skib } 1928205323Skib 1929205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1930205323Skib &rval); 1931205323Skib if (error) 1932205323Skib return (error); 1933205323Skib 1934205323Skib switch (uap->cmd) { 1935205323Skib case SEM_STAT: 1936205323Skib case IPC_STAT: 1937205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1938205323Skib freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1939205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1940205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1941205323Skib CP(dsbuf, dsbuf32, sem_otime); 1942205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1943205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1944205323Skib break; 1945205323Skib } 1946205323Skib 1947205323Skib if (error == 0) 1948205323Skib td->td_retval[0] = rval; 1949205323Skib return (error); 1950205323Skib} 1951205323Skib 1952205323Skib#endif /* COMPAT_FREEBSD32 */ 1953