#include <security/mac_framework.h>
#endif
-#include <bsm/audit_kernel.h>
+#include <security/audit/audit.h>
#if SYSV_SEM
* NOTE: Source and target may *NOT* overlap! (target is smaller)
*/
static void
-semid_ds_64to32(struct user_semid_ds *in, struct semid_ds *out)
+semid_ds_kernelto32(struct user_semid_ds *in, struct user32_semid_ds *out)
{
out->sem_perm = in->sem_perm;
- out->sem_base = (__int32_t)in->sem_base;
+ out->sem_base = CAST_DOWN_EXPLICIT(__int32_t,in->sem_base);
+ out->sem_nsems = in->sem_nsems;
+ out->sem_otime = in->sem_otime; /* XXX loses precision */
+ out->sem_ctime = in->sem_ctime; /* XXX loses precision */
+}
+
+static void
+semid_ds_kernelto64(struct user_semid_ds *in, struct user64_semid_ds *out)
+{
+ out->sem_perm = in->sem_perm;
+ out->sem_base = CAST_DOWN_EXPLICIT(__int32_t,in->sem_base);
out->sem_nsems = in->sem_nsems;
out->sem_otime = in->sem_otime; /* XXX loses precision */
out->sem_ctime = in->sem_ctime; /* XXX loses precision */
* XXX is the same.
*/
static void
-semid_ds_32to64(struct semid_ds *in, struct user_semid_ds *out)
+semid_ds_32tokernel(struct user32_semid_ds *in, struct user_semid_ds *out)
{
out->sem_ctime = in->sem_ctime;
out->sem_otime = in->sem_otime;
out->sem_nsems = in->sem_nsems;
- out->sem_base = (void *)in->sem_base;
+ out->sem_base = (void *)(uintptr_t)in->sem_base;
+ out->sem_perm = in->sem_perm;
+}
+
+static void
+semid_ds_64tokernel(struct user64_semid_ds *in, struct user_semid_ds *out)
+{
+ out->sem_ctime = in->sem_ctime;
+ out->sem_otime = in->sem_otime;
+ out->sem_nsems = in->sem_nsems;
+ out->sem_base = (void *)(uintptr_t)in->sem_base;
out->sem_perm = in->sem_perm;
}
/*
- * Entry point for all SEM calls
+ * semsys
+ *
+ * Entry point for all SEM calls: semctl, semget, semop
+ *
+ * Parameters: p Process requesting the call
+ * uap User argument descriptor (see below)
+ * retval Return value of the selected sem call
+ *
+ * Indirect parameters: uap->which sem call to invoke (index in array of sem calls)
+ * uap->a2 User argument descriptor
+ *
+ * Returns: 0 Success
+ * !0 Not success
+ *
+ * Implicit returns: retval Return value of the selected sem call
+ *
+ * DEPRECATED: This interface should not be used to call the other SEM
+ * functions (semctl, semget, semop). The correct usage is
+ * to call the other SEM functions directly.
*
- * In Darwin this is no longer the entry point. It will be removed after
- * the code has been tested better.
*/
-/* XXX actually varargs. */
int
-semsys(struct proc *p, struct semsys_args *uap, register_t *retval)
+semsys(struct proc *p, struct semsys_args *uap, int32_t *retval)
{
/* The individual calls handling the locking now */
/* Update our id structures to point to the new semaphores */
for(i = 0; i < seminfo.semmni; i++) {
if (sema[i].u.sem_perm.mode & SEM_ALLOC) /* ID in use */
- sema[i].u.sem_base += (new_sem_pool - sem_pool);
+ sema[i].u.sem_base = new_sem_pool +
+ (sema[i].u.sem_base - sem_pool);
}
sem_free = sem_pool;
* because the alignment is the same in user and kernel space.
*/
int
-semctl(struct proc *p, struct semctl_args *uap, register_t *retval)
+semctl(struct proc *p, struct semctl_args *uap, int32_t *retval)
{
int semid = uap->semid;
int semnum = uap->semnum;
int i, rval, eval;
struct user_semid_ds sbuf;
struct semid_kernel *semakptr;
- struct user_semid_ds uds;
AUDIT_ARG(svipc_cmd, cmd);
goto semctlout;
if (IS_64BIT_PROCESS(p)) {
- eval = copyin(user_arg.buf, &sbuf, sizeof(struct user_semid_ds));
+ struct user64_semid_ds ds64;
+ eval = copyin(user_arg.buf, &ds64, sizeof(ds64));
+ semid_ds_64tokernel(&ds64, &sbuf);
} else {
- eval = copyin(user_arg.buf, &sbuf, sizeof(struct semid_ds));
- /* convert in place; ugly, but safe */
- semid_ds_32to64((struct semid_ds *)&sbuf, &sbuf);
+ struct user32_semid_ds ds32;
+ eval = copyin(user_arg.buf, &ds32, sizeof(ds32));
+ semid_ds_32tokernel(&ds32, &sbuf);
}
if (eval != 0) {
case IPC_STAT:
if ((eval = ipcperm(cred, &semakptr->u.sem_perm, IPC_R)))
goto semctlout;
- bcopy((caddr_t)&semakptr->u, &uds, sizeof(struct user_semid_ds));
+
if (IS_64BIT_PROCESS(p)) {
- eval = copyout(&uds, user_arg.buf, sizeof(struct user_semid_ds));
+ struct user64_semid_ds semid_ds64;
+ bzero(&semid_ds64, sizeof(semid_ds64));
+ semid_ds_kernelto64(&semakptr->u, &semid_ds64);
+ eval = copyout(&semid_ds64, user_arg.buf, sizeof(semid_ds64));
} else {
- struct semid_ds semid_ds32;
- semid_ds_64to32(&uds, &semid_ds32);
- eval = copyout(&semid_ds32, user_arg.buf, sizeof(struct semid_ds));
+ struct user32_semid_ds semid_ds32;
+ bzero(&semid_ds32, sizeof(semid_ds32));
+ semid_ds_kernelto32(&semakptr->u, &semid_ds32);
+ eval = copyout(&semid_ds32, user_arg.buf, sizeof(semid_ds32));
}
break;
eval = EINVAL;
goto semctlout;
}
+
/*
* Cast down a pointer instead of using 'val' member directly
* to avoid introducing endieness and a pad field into the
* header file. Ugly, but it works.
*/
- semakptr->u.sem_base[semnum].semval = CAST_DOWN(int,user_arg.buf);
+ u_int newsemval = CAST_DOWN_EXPLICIT(u_int, user_arg.buf);
+
+ /*
+ * The check is being performed as unsigned values to match
+ * eventual destination
+ */
+ if (newsemval > (u_int)seminfo.semvmx)
+ {
+#ifdef SEM_DEBUG
+ printf("Out of range sem value for set\n");
+#endif
+ eval = ERANGE;
+ goto semctlout;
+ }
+ semakptr->u.sem_base[semnum].semval = newsemval;
semakptr->u.sem_base[semnum].sempid = p->p_pid;
/* XXX scottl Should there be a MAC call here? */
semundo_clear(semid, semnum);
}
int
-semget(__unused struct proc *p, struct semget_args *uap, register_t *retval)
+semget(__unused struct proc *p, struct semget_args *uap, int32_t *retval)
{
int semid, eval;
int key = uap->key;
sema[semid].u.sem_perm._key = key;
sema[semid].u.sem_perm.cuid = kauth_cred_getuid(cred);
sema[semid].u.sem_perm.uid = kauth_cred_getuid(cred);
- sema[semid].u.sem_perm.cgid = cred->cr_gid;
- sema[semid].u.sem_perm.gid = cred->cr_gid;
+ sema[semid].u.sem_perm.cgid = kauth_cred_getgid(cred);
+ sema[semid].u.sem_perm.gid = kauth_cred_getgid(cred);
sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
sema[semid].u.sem_perm._seq =
(sema[semid].u.sem_perm._seq + 1) & 0x7fff;
}
int
-semop(struct proc *p, struct semop_args *uap, register_t *retval)
+semop(struct proc *p, struct semop_args *uap, int32_t *retval)
{
int semid = uap->semid;
int nsops = uap->nsops;
- struct sembuf sops[MAX_SOPS];
+ struct sembuf sops[seminfo.semopm];
register struct semid_kernel *semakptr;
register struct sembuf *sopptr = NULL; /* protected by 'semptr' */
register struct sem *semptr = NULL; /* protected by 'if' */
goto semopout;
}
- if (nsops < 0 || nsops > MAX_SOPS) {
+ if (nsops < 0 || nsops > seminfo.semopm) {
#ifdef SEM_DEBUG
- printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
+ printf("too many sops (max=%d, nsops=%d)\n",
+ seminfo.semopm, nsops);
#endif
eval = E2BIG;
goto semopout;
}
+
+ /* OK for LP64, since sizeof(struct sembuf) is currently invariant */
+ if ((eval = copyin(uap->sops, &sops, nsops * sizeof(struct sembuf))) != 0) {
+#ifdef SEM_DEBUG
+ printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval,
+ uap->sops, &sops, nsops * sizeof(struct sembuf));
+#endif
+ goto semopout;
+ }
#if CONFIG_MACF
/*
goto semopout;
#endif
- /* OK for LP64, since sizeof(struct sembuf) is currently invariant */
- if ((eval = copyin(uap->sops, &sops, nsops * sizeof(struct sembuf))) != 0) {
-#ifdef SEM_DEBUG
- printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval,
- uap->sops, &sops, nsops * sizeof(struct sembuf));
-#endif
- goto semopout;
- }
-
/*
* Loop trying to satisfy the vector of requests.
* If we reach a point where we must wait, any requests already
/* Maybe we should build a list of semakptr's to wake
* up, finish all access to data structures, release the
* subsystem lock, and wake all the processes. Something
- * to think about. It wouldn't buy us anything unless
- * wakeup had the potential to block, or the syscall
- * funnel state was changed to allow multiple threads
- * in the BSD code at once.
+ * to think about.
*/
#ifdef SEM_WAKEUP
sem_wakeup((caddr_t)semakptr);
/* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */
extern struct sysctl_oid_list sysctl__kern_sysv_children;
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
&limitseminfo.semmni, 0, &sysctl_seminfo ,"I","semmni");
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
&limitseminfo.semmns, 0, &sysctl_seminfo ,"I","semmns");
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
&limitseminfo.semmnu, 0, &sysctl_seminfo ,"I","semmnu");
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
&limitseminfo.semmsl, 0, &sysctl_seminfo ,"I","semmsl");
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
&limitseminfo.semume, 0, &sysctl_seminfo ,"I","semume");
int error;
int cursor;
union {
- struct IPCS_command u32;
+ struct user32_IPCS_command u32;
struct user_IPCS_command u64;
} ipcs;
- struct semid_ds semid_ds32; /* post conversion, 32 bit version */
+ struct user32_semid_ds semid_ds32; /* post conversion, 32 bit version */
+ struct user64_semid_ds semid_ds64; /* post conversion, 64 bit version */
void *semid_dsp;
- size_t ipcs_sz = sizeof(struct user_IPCS_command);
- size_t semid_ds_sz = sizeof(struct user_semid_ds);
+ size_t ipcs_sz;
+ size_t semid_ds_sz;
struct proc *p = current_proc();
- if (!IS_64BIT_PROCESS(p)) {
- ipcs_sz = sizeof(struct IPCS_command);
- semid_ds_sz = sizeof(struct semid_ds);
+ if (IS_64BIT_PROCESS(p)) {
+ ipcs_sz = sizeof(struct user_IPCS_command);
+ semid_ds_sz = sizeof(struct user64_semid_ds);
+ } else {
+ ipcs_sz = sizeof(struct user32_IPCS_command);
+ semid_ds_sz = sizeof(struct user32_semid_ds);
}
/* Copy in the command structure */
* descriptor to a 32 bit user one.
*/
if (!IS_64BIT_PROCESS(p)) {
- semid_ds_64to32(semid_dsp, &semid_ds32);
+ bzero(&semid_ds32, sizeof(semid_ds32));
+ semid_ds_kernelto32(semid_dsp, &semid_ds32);
semid_dsp = &semid_ds32;
+ } else {
+ bzero(&semid_ds64, sizeof(semid_ds64));
+ semid_ds_kernelto64(semid_dsp, &semid_ds64);
+ semid_dsp = &semid_ds64;
}
+
error = copyout(semid_dsp, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
if (!error) {
/* update cursor */
ipcs.u64.ipcs_cursor = cursor + 1;
+
+ if (!IS_64BIT_PROCESS(p)) /* convert in place */
+ ipcs.u32.ipcs_data = CAST_DOWN_EXPLICIT(user32_addr_t,ipcs.u64.ipcs_data);
+
error = SYSCTL_OUT(req, &ipcs, ipcs_sz);
}
break;
}
SYSCTL_DECL(_kern_sysv_ipcs);
-SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, sem, CTLFLAG_RW|CTLFLAG_ANYBODY,
+SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, sem, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
0, 0, IPCS_sem_sysctl,
"S,IPCS_sem_command",
"ipcs sem command interface");