50#include "opt_sysvipc.h"
54#include <sys/sysproto.h>
55#include <sys/abi_compat.h>
56#include <sys/eventhandler.h>
57#include <sys/kernel.h>
60#include <sys/module.h>
65#include <sys/syscall.h>
66#include <sys/syscallsubr.h>
67#include <sys/sysent.h>
68#include <sys/sysctl.h>
70#include <sys/malloc.h>
73#include <security/audit/audit.h>
74#include <security/mac/mac_framework.h>
76FEATURE(sysv_sem,
"System V semaphores support");
81#define DPRINTF(a) printf a
91static int semvalid(
int semid,
struct prison *rpr,
92 struct semid_kernel *semakptr);
93static void sem_remove(
int semidx,
struct ucred *cred);
102#ifndef _SYS_SYSPROTO_H_
113 int semid,
int semseq,
int semnum,
int adjval);
119static struct semid_kernel *
sema;
125static eventhandler_tag semexit_tag;
126static unsigned sem_prison_slot;
128#define SEMUNDO_MTX sem_undo_mtx
129#define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX);
130#define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX);
131#define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how));
145 struct proc *un_proc;
151 unsigned short un_seq;
187#define SEM_ALIGN(bytes) roundup2(bytes, sizeof(long))
190#define SEMUSZ(x) SEM_ALIGN(offsetof(struct sem_undo, un_ent[(x)]))
196 ((struct sem_undo *)(((intptr_t)semu) + (ix) * seminfo.semusz))
214 "Number of semaphore identifiers");
216 "Maximum number of semaphores in the system");
218 "Maximum number of undo structures in the system");
220 "Max semaphores per id");
222 "Max operations per semop call");
224 "Max undo entries per process");
226 "Size in bytes of undo structure");
228 "Semaphore maximum value");
230 "Adjust on exit max value");
232 CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
234 "Array of struct semid_kernel for each potential semaphore");
238 SYSCALL_INIT_HELPER(
semget),
239 SYSCALL_INIT_HELPER(
semop),
240#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
241 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
242 SYSCALL_INIT_HELPER(semsys),
243 SYSCALL_INIT_HELPER_COMPAT(freebsd7___semctl),
248#ifdef COMPAT_FREEBSD32
249#include <compat/freebsd32/freebsd32.h>
250#include <compat/freebsd32/freebsd32_ipc.h>
251#include <compat/freebsd32/freebsd32_proto.h>
252#include <compat/freebsd32/freebsd32_signal.h>
253#include <compat/freebsd32/freebsd32_syscall.h>
254#include <compat/freebsd32/freebsd32_util.h>
256static struct syscall_helper_data sem32_syscalls[] = {
257 SYSCALL32_INIT_HELPER(freebsd32___semctl),
258 SYSCALL32_INIT_HELPER_COMPAT(
semget),
259 SYSCALL32_INIT_HELPER_COMPAT(
semop),
260 SYSCALL32_INIT_HELPER(freebsd32_semsys),
261#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
262 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
263 SYSCALL32_INIT_HELPER(freebsd7_freebsd32___semctl),
275 osd_method_t methods[PR_MAXMETHOD] = {
290 for (i = 0; i <
seminfo.semmni; i++) {
291 sema[i].u.__sem_base = 0;
292 sema[i].u.sem_perm.mode = 0;
293 sema[i].u.sem_perm.seq = 0;
295 mac_sysvsem_init(&
sema[i]);
298 for (i = 0; i <
seminfo.semmni; i++)
299 mtx_init(&
sema_mtx[i],
"semid", NULL, MTX_DEF);
300 LIST_INIT(&semu_free_list);
301 for (i = 0; i <
seminfo.semmnu; i++) {
303 suptr->un_proc = NULL;
304 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
306 LIST_INIT(&semu_list);
307 mtx_init(&
sem_mtx,
"sem", NULL, MTX_DEF);
309 semexit_tag = EVENTHANDLER_REGISTER(process_exit,
semexit_myhook, NULL,
310 EVENTHANDLER_PRI_ANY);
313 sem_prison_slot = osd_jail_register(NULL, methods);
316 (void)osd_jail_set_reserved(&
prison0, sem_prison_slot, rsv, &
prison0);
324 if (
pr->pr_allow & PR_ALLOW_SYSVIPC) {
325 (void)osd_jail_set_reserved(
pr, sem_prison_slot, rsv,
338#ifdef COMPAT_FREEBSD32
339 error = syscall32_helper_register(sem32_syscalls, SY_THR_STATIC_KLD);
355#ifdef COMPAT_FREEBSD32
356 syscall32_helper_unregister(sem32_syscalls);
359 EVENTHANDLER_DEREGISTER(process_exit, semexit_tag);
360 if (sem_prison_slot != 0)
361 osd_jail_deregister(sem_prison_slot);
363 for (i = 0; i <
seminfo.semmni; i++)
364 mac_sysvsem_destroy(&
sema[i]);
369 for (i = 0; i <
seminfo.semmni; i++)
418 if ((suptr = LIST_FIRST(&semu_free_list)) == NULL)
420 LIST_REMOVE(suptr, un_next);
421 LIST_INSERT_HEAD(&semu_list, suptr, un_next);
423 suptr->un_proc = td->td_proc;
433 if (suptr->un_cnt != 0)
435 LIST_REMOVE(suptr, un_next);
436 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
446 int semseq,
int semnum,
int adjval)
448 struct proc *p = td->td_proc;
459 LIST_FOREACH(suptr, &semu_list, un_next) {
460 if (suptr->un_proc == p) {
479 sunptr = &suptr->
un_ent[0];
480 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
481 if (sunptr->un_id != semid || sunptr->un_num != semnum)
484 adjval += sunptr->un_adjval;
488 sunptr->un_adjval = adjval;
489 if (sunptr->un_adjval == 0) {
491 if (i < suptr->un_cnt)
493 suptr->
un_ent[suptr->un_cnt];
494 if (suptr->un_cnt == 0)
505 if (suptr->un_cnt !=
seminfo.semume) {
506 sunptr = &suptr->
un_ent[suptr->un_cnt];
508 sunptr->un_adjval = adjval;
509 sunptr->un_id = semid;
510 sunptr->un_num = semnum;
511 sunptr->un_seq = semseq;
525 LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) {
526 sunptr = &suptr->
un_ent[0];
527 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
528 if (sunptr->un_id != semid)
530 if (semnum == -1 || sunptr->un_num == semnum) {
532 if (i < suptr->un_cnt) {
534 suptr->
un_ent[suptr->un_cnt];
546semvalid(
int semid,
struct prison *rpr,
struct semid_kernel *semakptr)
549 return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
550 semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ||
557 struct semid_kernel *semakptr;
560 KASSERT(semidx >= 0 && semidx <
seminfo.semmni,
561 (
"semidx out of bounds"));
562 mtx_assert(&
sem_mtx, MA_OWNED);
563 semakptr = &
sema[semidx];
564 KASSERT(semakptr->u.__sem_base -
sem + semakptr->u.sem_nsems <=
semtot,
565 (
"sem_remove: sema %d corrupted sem pointer %p %p %d %d",
566 semidx, semakptr->u.__sem_base,
sem, semakptr->u.sem_nsems,
569 semakptr->u.sem_perm.cuid = cred ? cred->cr_uid : 0;
570 semakptr->u.sem_perm.uid = cred ? cred->cr_uid : 0;
571 semakptr->u.sem_perm.mode = 0;
572 racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems);
574 semakptr->cred = NULL;
579 mac_sysvsem_cleanup(semakptr);
582 for (i = 0; i <
seminfo.semmni; i++) {
583 if ((
sema[i].u.sem_perm.mode & SEM_ALLOC) &&
584 sema[i].u.__sem_base > semakptr->u.__sem_base)
585 mtx_lock_flags(&
sema_mtx[i], LOP_DUPOK);
587 for (i = semakptr->u.__sem_base -
sem + semakptr->u.sem_nsems;
589 sem[i - semakptr->u.sem_nsems] =
sem[i];
590 for (i = 0; i <
seminfo.semmni; i++) {
591 if ((
sema[i].u.sem_perm.mode & SEM_ALLOC) &&
592 sema[i].u.__sem_base > semakptr->u.__sem_base) {
593 sema[i].u.__sem_base -= semakptr->u.sem_nsems;
597 semtot -= semakptr->u.sem_nsems;
600static struct prison *
603 struct prison *
pr, *rpr;
605 pr = cred->cr_prison;
607 rpr = osd_jail_get(
pr, sem_prison_slot);
616 if (semakptr->cred == NULL ||
617 !(rpr == semakptr->cred->cr_prison ||
626#ifndef _SYS_SYSPROTO_H_
637 struct semid_ds dsbuf;
638 union semun arg, semun;
649 error = copyin(uap->
arg, &arg,
sizeof(arg));
661 error = copyin(arg.buf, &dsbuf,
sizeof(dsbuf));
668 semun.array = arg.array;
683 error = copyout(&dsbuf, arg.buf,
sizeof(dsbuf));
688 td->td_retval[0] = rval;
694 union semun *arg, register_t *rval)
697 struct ucred *cred = td->td_ucred;
700 struct semid_ds *sbuf;
701 struct semid_kernel *semakptr;
702 struct mtx *sema_mtxp;
703 u_short usval,
count;
706 DPRINTF((
"call to semctl(%d, %d, %d, 0x%p)\n",
707 semid, semnum, cmd, arg));
709 AUDIT_ARG_SVIPC_CMD(cmd);
710 AUDIT_ARG_SVIPC_ID(semid);
724 if (semid < 0 || semid >=
seminfo.semmni)
726 semakptr = &
sema[semid];
729 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
735 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
738 error = mac_sysvsem_check_semctl(cred, semakptr, cmd);
742 bcopy(&semakptr->u, arg->buf,
sizeof(
struct semid_ds));
743 if (cred->cr_prison != semakptr->cred->cr_prison)
744 arg->buf->sem_perm.key = IPC_PRIVATE;
745 *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm);
746 mtx_unlock(sema_mtxp);
750 semidx = IPCID_TO_IX(semid);
751 if (semidx < 0 || semidx >=
seminfo.semmni)
754 semakptr = &
sema[semidx];
761 error = mac_sysvsem_check_semctl(cred, semakptr, cmd);
771 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
773 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
779 AUDIT_ARG_SVIPC_PERM(&arg->buf->sem_perm);
780 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
782 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
785 semakptr->u.sem_perm.uid = sbuf->sem_perm.uid;
786 semakptr->u.sem_perm.gid = sbuf->sem_perm.gid;
787 semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode &
788 ~0777) | (sbuf->sem_perm.mode & 0777);
793 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
795 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
797 bcopy(&semakptr->u, arg->buf,
sizeof(
struct semid_ds));
798 if (cred->cr_prison != semakptr->cred->cr_prison)
799 arg->buf->sem_perm.key = IPC_PRIVATE;
806 arg->buf->__sem_base = NULL;
810 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
812 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
814 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
818 *rval = semakptr->u.__sem_base[semnum].semncnt;
822 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
824 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
826 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
830 *rval = semakptr->u.__sem_base[semnum].sempid;
834 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
836 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
838 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
842 *rval = semakptr->u.__sem_base[semnum].semval;
866 count = semakptr->u.sem_nsems;
867 mtx_unlock(sema_mtxp);
868 array =
malloc(
sizeof(*array) *
count, M_TEMP, M_WAITOK);
870 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
872 KASSERT(
count == semakptr->u.sem_nsems, (
"nsems changed"));
873 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
875 for (i = 0; i < semakptr->u.sem_nsems; i++)
876 array[i] = semakptr->u.__sem_base[i].semval;
877 mtx_unlock(sema_mtxp);
878 error = copyout(array, arg->array,
count *
sizeof(*array));
883 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
885 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
887 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
891 *rval = semakptr->u.__sem_base[semnum].semzcnt;
895 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
897 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
899 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
903 if (arg->val < 0 || arg->val >
seminfo.semvmx) {
907 semakptr->u.__sem_base[semnum].semval = arg->val;
919 count = semakptr->u.sem_nsems;
920 mtx_unlock(sema_mtxp);
921 array =
malloc(
sizeof(*array) *
count, M_TEMP, M_WAITOK);
922 error = copyin(arg->array, array,
count *
sizeof(*array));
926 if ((error =
semvalid(semid, rpr, semakptr)) != 0)
928 KASSERT(
count == semakptr->u.sem_nsems, (
"nsems changed"));
929 if ((error =
ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
931 for (i = 0; i < semakptr->u.sem_nsems; i++) {
937 semakptr->u.__sem_base[i].semval = usval;
951 mtx_unlock(sema_mtxp);
959#ifndef _SYS_SYSPROTO_H_
969 int semid, error = 0;
971 int nsems = uap->
nsems;
973 struct ucred *cred = td->td_ucred;
975 DPRINTF((
"semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
977 AUDIT_ARG_VALUE(semflg);
983 if (key != IPC_PRIVATE) {
984 for (semid = 0; semid <
seminfo.semmni; semid++) {
985 if ((
sema[semid].u.sem_perm.mode & SEM_ALLOC) &&
986 sema[semid].cred != NULL &&
987 sema[semid].cred->cr_prison == cred->cr_prison &&
988 sema[semid].u.sem_perm.key == key)
992 AUDIT_ARG_SVIPC_ID(semid);
993 DPRINTF((
"found public key\n"));
994 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
1003 if (nsems > 0 &&
sema[semid].u.sem_nsems < nsems) {
1009 error = mac_sysvsem_check_semget(cred, &
sema[semid]);
1017 DPRINTF((
"need to allocate the semid_kernel\n"));
1018 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
1019 if (nsems <= 0 || nsems >
seminfo.semmsl) {
1020 DPRINTF((
"nsems out of range (0<%d<=%d)\n", nsems,
1027 "not enough semaphores left (need %d, got %d)\n",
1032 for (semid = 0; semid <
seminfo.semmni; semid++) {
1033 if ((
sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0)
1036 if (semid ==
seminfo.semmni) {
1037 DPRINTF((
"no more semid_kernel's available\n"));
1043 PROC_LOCK(td->td_proc);
1044 error = racct_add(td->td_proc, RACCT_NSEM, nsems);
1045 PROC_UNLOCK(td->td_proc);
1052 DPRINTF((
"semid %d is available\n", semid));
1054 KASSERT((
sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0,
1055 (
"Lost semaphore %d", semid));
1056 sema[semid].u.sem_perm.key = key;
1057 sema[semid].u.sem_perm.cuid = cred->cr_uid;
1058 sema[semid].u.sem_perm.uid = cred->cr_uid;
1059 sema[semid].u.sem_perm.cgid = cred->cr_gid;
1060 sema[semid].u.sem_perm.gid = cred->cr_gid;
1061 sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
1063 sema[semid].u.sem_perm.seq =
1064 (
sema[semid].u.sem_perm.seq + 1) & 0x7fff;
1065 sema[semid].u.sem_nsems = nsems;
1066 sema[semid].u.sem_otime = 0;
1070 bzero(
sema[semid].u.__sem_base,
1071 sizeof(
sema[semid].u.__sem_base[0])*nsems);
1073 mac_sysvsem_create(cred, &
sema[semid]);
1076 DPRINTF((
"sembase = %p, next = %p\n",
1079 DPRINTF((
"didn't find it and wasn't asked to create it\n"));
1085 td->td_retval[0] = IXSEQ_TO_IPCID(semid,
sema[semid].u.sem_perm);
1091#ifndef _SYS_SYSPROTO_H_
1103 int semid = uap->
semid;
1104 size_t nsops = uap->
nsops;
1106 struct sembuf *sops;
1107 struct semid_kernel *semakptr;
1108 struct sembuf *sopptr = NULL;
1109 struct sem *semptr = NULL;
1111 struct mtx *sema_mtxp;
1114 int do_wakeup, do_undos;
1120 DPRINTF((
"call to semop(%d, %p, %u)\n", semid, sops, nsops));
1122 AUDIT_ARG_SVIPC_ID(semid);
1128 semid = IPCID_TO_IX(semid);
1130 if (semid < 0 || semid >=
seminfo.semmni)
1136 else if (nsops >
seminfo.semopm) {
1143 PROC_LOCK(td->td_proc);
1145 racct_get_available(td->td_proc, RACCT_NSEMOP)) {
1146 PROC_UNLOCK(td->td_proc);
1149 PROC_UNLOCK(td->td_proc);
1153 sops =
malloc(nsops *
sizeof(*sops), M_TEMP, M_WAITOK);
1155 if ((error = copyin(uap->
sops, sops, nsops *
sizeof(sops[0]))) != 0) {
1156 DPRINTF((
"error = %d from copyin(%p, %p, %d)\n", error,
1157 uap->
sops, sops, nsops *
sizeof(sops[0])));
1158 if (sops != small_sops)
1163 semakptr = &
sema[semid];
1165 mtx_lock(sema_mtxp);
1166 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
1170 seq = semakptr->u.sem_perm.seq;
1171 if (seq != IPCID_TO_SEQ(uap->
semid)) {
1184 for (i = 0; i < nsops; i++) {
1186 if (sopptr->sem_num >= semakptr->u.sem_nsems) {
1190 if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0)
1192 j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A;
1195 if ((error =
ipcperm(td, &semakptr->u.sem_perm, j))) {
1196 DPRINTF((
"error = %d from ipaccess\n", error));
1200 error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j);
1218 for (i = 0; i < nsops; i++) {
1220 semptr = &semakptr->u.__sem_base[sopptr->sem_num];
1223 "semop: semakptr=%p, __sem_base=%p, "
1224 "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n",
1225 semakptr, semakptr->u.__sem_base, semptr,
1226 sopptr->sem_num, semptr->semval, sopptr->sem_op,
1227 (sopptr->sem_flg & IPC_NOWAIT) ?
1228 "nowait" :
"wait"));
1230 if (sopptr->sem_op < 0) {
1231 if (semptr->semval + sopptr->sem_op < 0) {
1232 DPRINTF((
"semop: can't do it now\n"));
1235 semptr->semval += sopptr->sem_op;
1236 if (semptr->semval == 0 &&
1237 semptr->semzcnt > 0)
1240 }
else if (sopptr->sem_op == 0) {
1241 if (semptr->semval != 0) {
1242 DPRINTF((
"semop: not zero now\n"));
1245 }
else if (semptr->semval + sopptr->sem_op >
1250 if (semptr->semncnt > 0)
1252 semptr->semval += sopptr->sem_op;
1265 DPRINTF((
"semop: rollback 0 through %d\n", i-1));
1266 for (j = 0; j < i; j++)
1267 semakptr->u.__sem_base[sops[j].sem_num].semval -=
1278 if (sopptr->sem_flg & IPC_NOWAIT) {
1283 if (sopptr->sem_op == 0)
1288 DPRINTF((
"semop: good night!\n"));
1289 error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH,
1291 DPRINTF((
"semop: good morning (error=%d)!\n", error));
1297 seq = semakptr->u.sem_perm.seq;
1298 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
1299 seq != IPCID_TO_SEQ(uap->
semid)) {
1309 semptr = &semakptr->u.__sem_base[sopptr->sem_num];
1315 if (sopptr->sem_op == 0)
1329 DPRINTF((
"semop: good morning!\n"));
1339 for (i = 0; i < nsops; i++) {
1346 if ((sops[i].sem_flg & SEM_UNDO) == 0)
1348 adjval = sops[i].sem_op;
1352 sops[i].sem_num, -adjval);
1365 for (j = 0; j < i; j++) {
1367 if ((sops[k].sem_flg & SEM_UNDO) == 0)
1369 adjval = sops[k].sem_op;
1373 sops[k].sem_num, adjval) != 0)
1374 panic(
"semop - can't undo undos");
1377 for (j = 0; j < nsops; j++)
1378 semakptr->u.__sem_base[sops[j].sem_num].semval -=
1381 DPRINTF((
"error = %d from semundo_adjust\n", error));
1389 for (i = 0; i < nsops; i++) {
1391 semptr = &semakptr->u.__sem_base[sopptr->sem_num];
1392 semptr->sempid = td->td_proc->p_pid;
1401 DPRINTF((
"semop: doing wakeup\n"));
1403 DPRINTF((
"semop: back from wakeup\n"));
1406 td->td_retval[0] = 0;
1408 mtx_unlock(sema_mtxp);
1409 if (sops != small_sops)
1422 struct semid_kernel *semakptr;
1423 struct mtx *sema_mtxp;
1424 int semid, semnum, adjval, ix;
1431 if (LIST_EMPTY(&semu_list))
1434 LIST_FOREACH(suptr, &semu_list, un_next) {
1435 if (suptr->un_proc == p)
1438 if (suptr == NULL) {
1442 LIST_REMOVE(suptr, un_next);
1444 DPRINTF((
"proc @%p has undo structure with %d entries\n", p,
1450 if (suptr->un_cnt > 0) {
1452 for (ix = 0; ix < suptr->un_cnt; ix++) {
1453 semid = suptr->
un_ent[ix].un_id;
1454 semnum = suptr->
un_ent[ix].un_num;
1455 adjval = suptr->
un_ent[ix].un_adjval;
1456 seq = suptr->
un_ent[ix].un_seq;
1457 semakptr = &
sema[semid];
1460 mtx_lock(sema_mtxp);
1461 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
1462 (semakptr->u.sem_perm.seq != seq)) {
1463 mtx_unlock(sema_mtxp);
1466 if (semnum >= semakptr->u.sem_nsems)
1467 panic(
"semexit - semnum out of range");
1470 "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n",
1471 suptr->un_proc, suptr->
un_ent[ix].un_id,
1472 suptr->
un_ent[ix].un_num,
1473 suptr->
un_ent[ix].un_adjval,
1474 semakptr->u.__sem_base[semnum].semval));
1476 if (adjval < 0 && semakptr->u.__sem_base[semnum].semval <
1478 semakptr->u.__sem_base[semnum].semval = 0;
1480 semakptr->u.__sem_base[semnum].semval += adjval;
1483 DPRINTF((
"semexit: back from wakeup\n"));
1484 mtx_unlock(sema_mtxp);
1492 DPRINTF((
"removing vector\n"));
1493 suptr->un_proc = NULL;
1495 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
1502 struct prison *
pr, *rpr;
1503 struct semid_kernel tsemak;
1504#ifdef COMPAT_FREEBSD32
1505 struct semid_kernel32 tsemak32;
1511 pr = req->td->td_ucred->cr_prison;
1514 for (i = 0; i <
seminfo.semmni; i++) {
1516 if ((
sema[i].u.sem_perm.mode & SEM_ALLOC) == 0 ||
1518 bzero(&tsemak,
sizeof(tsemak));
1521 if (tsemak.cred->cr_prison !=
pr)
1522 tsemak.u.sem_perm.key = IPC_PRIVATE;
1525#ifdef COMPAT_FREEBSD32
1526 if (SV_CURPROC_FLAG(SV_ILP32)) {
1527 bzero(&tsemak32,
sizeof(tsemak32));
1528 freebsd32_ipcperm_out(&tsemak.u.sem_perm,
1529 &tsemak32.u.sem_perm);
1531 CP(tsemak, tsemak32, u.sem_nsems);
1532 CP(tsemak, tsemak32, u.sem_otime);
1533 CP(tsemak, tsemak32, u.sem_ctime);
1535 outaddr = &tsemak32;
1536 outsize =
sizeof(tsemak32);
1540 tsemak.u.__sem_base = NULL;
1541 tsemak.label = NULL;
1544 outsize =
sizeof(tsemak);
1546 error = SYSCTL_OUT(req, outaddr, outsize);
1556 struct prison *
pr = obj;
1557 struct prison *prpr;
1558 struct vfsoptlist *opts =
data;
1565 error =
vfs_copyopt(opts,
"sysvsem", &jsys,
sizeof(jsys));
1566 if (error != ENOENT) {
1570 case JAIL_SYS_DISABLE:
1573 case JAIL_SYS_INHERIT:
1574 prison_lock(
pr->pr_parent);
1575 prpr = osd_jail_get(
pr->pr_parent, sem_prison_slot);
1576 prison_unlock(
pr->pr_parent);
1591 struct prison *
pr = obj;
1592 struct prison *tpr, *orpr, *nrpr, *trpr;
1593 struct vfsoptlist *opts =
data;
1601 if (
vfs_copyopt(opts,
"sysvsem", &jsys,
sizeof(jsys)) == ENOENT)
1602 jsys =
vfs_flagopt(opts,
"allow.sysvipc", NULL, 0)
1607 if (jsys == JAIL_SYS_DISABLE) {
1609 orpr = osd_jail_get(
pr, sem_prison_slot);
1611 osd_jail_del(
pr, sem_prison_slot);
1617 FOREACH_PRISON_DESCENDANT(
pr, tpr, descend) {
1619 trpr = osd_jail_get(tpr, sem_prison_slot);
1621 osd_jail_del(tpr, sem_prison_slot);
1631 }
else if (jsys != -1) {
1632 if (jsys == JAIL_SYS_NEW)
1635 prison_lock(
pr->pr_parent);
1636 nrpr = osd_jail_get(
pr->pr_parent, sem_prison_slot);
1637 prison_unlock(
pr->pr_parent);
1641 orpr = osd_jail_get(
pr, sem_prison_slot);
1643 (void)osd_jail_set_reserved(
pr, sem_prison_slot, rsv,
1653 FOREACH_PRISON_DESCENDANT(
pr, tpr, descend) {
1655 trpr = osd_jail_get(tpr,
1658 (void)osd_jail_set(tpr,
1659 sem_prison_slot, nrpr);
1678 struct prison *
pr = obj;
1680 struct vfsoptlist *opts =
data;
1685 rpr = osd_jail_get(
pr, sem_prison_slot);
1687 jsys = rpr == NULL ? JAIL_SYS_DISABLE
1688 : rpr ==
pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
1689 error =
vfs_setopt(opts,
"sysvsem", &jsys,
sizeof(jsys));
1690 if (error == ENOENT)
1698 struct prison *
pr = obj;
1702 rpr = osd_jail_get(
pr, sem_prison_slot);
1716 for (i = 0; i <
seminfo.semmni; i++) {
1717 if ((
sema[i].u.sem_perm.mode & SEM_ALLOC) &&
1718 sema[i].cred != NULL &&
sema[i].cred->cr_prison ==
pr) {
1729#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1730 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1733static sy_call_t *semcalls[] = {
1734 (sy_call_t *)freebsd7___semctl, (sy_call_t *)
sys_semget,
1755 AUDIT_ARG_SVIPC_WHICH(uap->which);
1756 if (uap->which < 0 || uap->which >= nitems(semcalls))
1758 error = (*semcalls[uap->which])(td, &uap->a2);
1762#ifndef _SYS_SYSPROTO_H_
1763struct freebsd7___semctl_args {
1767 union semun_old *arg;
1771freebsd7___semctl(
struct thread *td,
struct freebsd7___semctl_args *uap)
1773 struct semid_ds_old dsold;
1774 struct semid_ds dsbuf;
1775 union semun_old arg;
1787 error = copyin(uap->arg, &arg,
sizeof(arg));
1799 error = copyin(arg.buf, &dsold,
sizeof(dsold));
1802 ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm);
1803 CP(dsold, dsbuf, __sem_base);
1804 CP(dsold, dsbuf, sem_nsems);
1805 CP(dsold, dsbuf, sem_otime);
1806 CP(dsold, dsbuf, sem_ctime);
1811 semun.array = arg.array;
1814 semun.val = arg.val;
1818 error =
kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
1826 bzero(&dsold,
sizeof(dsold));
1827 ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm);
1828 CP(dsbuf, dsold, __sem_base);
1829 CP(dsbuf, dsold, sem_nsems);
1830 CP(dsbuf, dsold, sem_otime);
1831 CP(dsbuf, dsold, sem_ctime);
1832 error = copyout(&dsold, arg.buf,
sizeof(dsold));
1837 td->td_retval[0] = rval;
1843#ifdef COMPAT_FREEBSD32
1846freebsd32_semsys(
struct thread *td,
struct freebsd32_semsys_args *uap)
1849#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1850 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1851 AUDIT_ARG_SVIPC_WHICH(uap->which);
1852 switch (uap->which) {
1854 return (freebsd7_freebsd32___semctl(td,
1855 (
struct freebsd7_freebsd32___semctl_args *)&uap->a2));
1857 return (sys_semsys(td, (
struct semsys_args *)uap));
1860 return (
nosys(td, NULL));
1864#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1865 defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1867freebsd7_freebsd32___semctl(
struct thread *td,
1868 struct freebsd7_freebsd32___semctl_args *uap)
1870 struct semid_ds_old32 dsbuf32;
1871 struct semid_ds dsbuf;
1873 union semun_old32 arg;
1884 error = copyin(uap->arg, &arg,
sizeof(arg));
1896 error = copyin(PTRIN(arg.buf), &dsbuf32,
sizeof(dsbuf32));
1899 freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm);
1900 PTRIN_CP(dsbuf32, dsbuf, __sem_base);
1901 CP(dsbuf32, dsbuf, sem_nsems);
1902 CP(dsbuf32, dsbuf, sem_otime);
1903 CP(dsbuf32, dsbuf, sem_ctime);
1908 semun.array = PTRIN(arg.array);
1911 semun.val = arg.val;
1915 error =
kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
1923 bzero(&dsbuf32,
sizeof(dsbuf32));
1924 freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm);
1925 PTROUT_CP(dsbuf, dsbuf32, __sem_base);
1926 CP(dsbuf, dsbuf32, sem_nsems);
1927 CP(dsbuf, dsbuf32, sem_otime);
1928 CP(dsbuf, dsbuf32, sem_ctime);
1929 error = copyout(&dsbuf32, PTRIN(arg.buf),
sizeof(dsbuf32));
1934 td->td_retval[0] = rval;
1940freebsd32___semctl(
struct thread *td,
struct freebsd32___semctl_args *uap)
1942 struct semid_ds32 dsbuf32;
1943 struct semid_ds dsbuf;
1956 error = copyin(uap->arg, &arg,
sizeof(arg));
1968 error = copyin(PTRIN(arg.buf), &dsbuf32,
sizeof(dsbuf32));
1971 freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm);
1972 PTRIN_CP(dsbuf32, dsbuf, __sem_base);
1973 CP(dsbuf32, dsbuf, sem_nsems);
1974 CP(dsbuf32, dsbuf, sem_otime);
1975 CP(dsbuf32, dsbuf, sem_ctime);
1980 semun.array = PTRIN(arg.array);
1983 semun.val = arg.val;
1987 error =
kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
1995 bzero(&dsbuf32,
sizeof(dsbuf32));
1996 freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm);
1997 PTROUT_CP(dsbuf, dsbuf32, __sem_base);
1998 CP(dsbuf, dsbuf32, sem_nsems);
1999 CP(dsbuf, dsbuf32, sem_otime);
2000 CP(dsbuf, dsbuf32, sem_ctime);
2001 error = copyout(&dsbuf32, PTRIN(arg.buf),
sizeof(dsbuf32));
2006 td->td_retval[0] = rval;
int prison_ischild(struct prison *pr1, struct prison *pr2)
struct prisonlist allprison
void *() malloc(size_t size, struct malloc_type *mtp, int flags)
void free(void *addr, struct malloc_type *mtp)
void osd_free_reserved(void **rsv)
void ** osd_reserve(u_int slot)
static struct pollrec pr[POLL_LIST_LEN]
struct ucred * crhold(struct ucred *cr)
void crfree(struct ucred *cr)
void panic(const char *fmt,...)
int nosys(struct thread *td, struct nosys_args *args)
void wakeup(const void *ident)
int syscall_helper_unregister(struct syscall_helper_data *sd)
int syscall_helper_register(struct syscall_helper_data *sd, int flags)
volatile time_t time_second
int ipcperm(struct thread *td, struct ipc_perm *perm, int acc_mode)
static int sysctl_sema(SYSCTL_HANDLER_ARGS)
SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, "Number of semaphore identifiers")
static int semu_try_free(struct sem_undo *suptr)
static int semunload(void)
MODULE_VERSION(sysvsem, 1)
static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores")
static struct prison * sem_find_prison(struct ucred *)
int semop(struct thread *td, struct semop_args *uap)
int kern_semctl(struct thread *td, int semid, int semnum, int cmd, union semun *arg, register_t *rval)
static int semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, int semseq, int semnum, int adjval)
SYSCTL_JAIL_PARAM_SYS_NODE(sysvsem, CTLFLAG_RW, "SYSV semaphores")
static int sem_prison_cansee(struct prison *, struct semid_kernel *)
int sys___semctl(struct thread *td, struct __semctl_args *uap)
static int sem_prison_check(void *, void *)
#define SEMUNDO_LOCKASSERT(how)
static struct mtx sem_undo_mtx
static moduledata_t sysvsem_mod
static struct semid_kernel * sema
static struct mtx sem_mtx
int semget(struct thread *td, struct semget_args *uap)
SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, 0, sysctl_sema, "", "Array of struct semid_kernel for each potential semaphore")
FEATURE(sysv_sem, "System V semaphores support")
static int semvalid(int semid, struct prison *rpr, struct semid_kernel *semakptr)
static void semexit_myhook(void *arg, struct proc *p)
int __semctl(struct thread *td, struct __semctl_args *uap)
static int sem_prison_get(void *, void *)
static void sem_prison_cleanup(struct prison *)
static void sem_remove(int semidx, struct ucred *cred)
static struct mtx * sema_mtx
static int sysvsem_modload(struct module *, int, void *)
int sys_semop(struct thread *td, struct semop_args *uap)
int sys_semget(struct thread *td, struct semget_args *uap)
static int sem_prison_remove(void *, void *)
DECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST)
static struct syscall_helper_data sem_syscalls[]
static struct sem_undo * semu_alloc(struct thread *td)
static void semundo_clear(int semid, int semnum)
static int sem_prison_set(void *, void *)
int vfs_copyopt(struct vfsoptlist *opts, const char *name, void *dest, int len)
int vfs_flagopt(struct vfsoptlist *opts, const char *name, uint64_t *w, uint64_t val)
int vfs_setopt(struct vfsoptlist *opts, const char *name, void *value, int len)