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