semctl(): move compat to native
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
94
ipc/sem.c
94
ipc/sem.c
@@ -1617,6 +1617,100 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
struct compat_semid_ds {
|
||||
struct compat_ipc_perm sem_perm;
|
||||
compat_time_t sem_otime;
|
||||
compat_time_t sem_ctime;
|
||||
compat_uptr_t sem_base;
|
||||
compat_uptr_t sem_pending;
|
||||
compat_uptr_t sem_pending_last;
|
||||
compat_uptr_t undo;
|
||||
unsigned short sem_nsems;
|
||||
};
|
||||
|
||||
static int copy_compat_semid_from_user(struct semid64_ds *out, void __user *buf,
|
||||
int version)
|
||||
{
|
||||
memset(out, 0, sizeof(*out));
|
||||
if (version == IPC_64) {
|
||||
struct compat_semid64_ds *p = buf;
|
||||
return get_compat_ipc64_perm(&out->sem_perm, &p->sem_perm);
|
||||
} else {
|
||||
struct compat_semid_ds *p = buf;
|
||||
return get_compat_ipc_perm(&out->sem_perm, &p->sem_perm);
|
||||
}
|
||||
}
|
||||
|
||||
static int copy_compat_semid_to_user(void __user *buf, struct semid64_ds *in,
|
||||
int version)
|
||||
{
|
||||
if (version == IPC_64) {
|
||||
struct compat_semid64_ds v;
|
||||
memset(&v, 0, sizeof(v));
|
||||
to_compat_ipc64_perm(&v.sem_perm, &in->sem_perm);
|
||||
v.sem_otime = in->sem_otime;
|
||||
v.sem_ctime = in->sem_ctime;
|
||||
v.sem_nsems = in->sem_nsems;
|
||||
return copy_to_user(buf, &v, sizeof(v));
|
||||
} else {
|
||||
struct compat_semid_ds v;
|
||||
memset(&v, 0, sizeof(v));
|
||||
to_compat_ipc_perm(&v.sem_perm, &in->sem_perm);
|
||||
v.sem_otime = in->sem_otime;
|
||||
v.sem_ctime = in->sem_ctime;
|
||||
v.sem_nsems = in->sem_nsems;
|
||||
return copy_to_user(buf, &v, sizeof(v));
|
||||
}
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
|
||||
{
|
||||
void __user *p = compat_ptr(arg);
|
||||
struct ipc_namespace *ns;
|
||||
struct semid64_ds semid64;
|
||||
int version = compat_ipc_parse_version(&cmd);
|
||||
int err;
|
||||
|
||||
ns = current->nsproxy->ipc_ns;
|
||||
|
||||
if (semid < 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd & (~IPC_64)) {
|
||||
case IPC_INFO:
|
||||
case SEM_INFO:
|
||||
return semctl_info(ns, semid, cmd, p);
|
||||
case IPC_STAT:
|
||||
case SEM_STAT:
|
||||
err = semctl_stat(ns, semid, cmd, &semid64);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (copy_compat_semid_to_user(p, &semid64, version))
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
case GETVAL:
|
||||
case GETPID:
|
||||
case GETNCNT:
|
||||
case GETZCNT:
|
||||
case GETALL:
|
||||
case SETALL:
|
||||
return semctl_main(ns, semid, semnum, cmd, p);
|
||||
case SETVAL:
|
||||
return semctl_setval(ns, semid, semnum, arg);
|
||||
case IPC_SET:
|
||||
if (copy_compat_semid_from_user(&semid64, p, version))
|
||||
return -EFAULT;
|
||||
/* fallthru */
|
||||
case IPC_RMID:
|
||||
return semctl_down(ns, semid, cmd, &semid64);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the task doesn't already have a undo_list, then allocate one
|
||||
* here. We guarantee there is only one thread using this undo list,
|
||||
* and current is THE ONE
|
||||
|
Reference in New Issue
Block a user