ipc: rename old-style shmctl/semctl/msgctl syscalls

The behavior of these system calls is slightly different between
architectures, as determined by the CONFIG_ARCH_WANT_IPC_PARSE_VERSION
symbol. Most architectures that implement the split IPC syscalls don't set
that symbol and only get the modern version, but alpha, arm, microblaze,
mips-n32, mips-n64 and xtensa expect the caller to pass the IPC_64 flag.

For the architectures that so far only implement sys_ipc(), i.e. m68k,
mips-o32, powerpc, s390, sh, sparc, and x86-32, we want the new behavior
when adding the split syscalls, so we need to distinguish between the
two groups of architectures.

The method I picked for this distinction is to have a separate system call
entry point: sys_old_*ctl() now uses ipc_parse_version, while sys_*ctl()
does not. The system call tables of the five architectures are changed
accordingly.

As an additional benefit, we no longer need the configuration specific
definition for ipc_parse_version(), it always does the same thing now,
but simply won't get called on architectures with the modern interface.

A small downside is that on architectures that do set
ARCH_WANT_IPC_PARSE_VERSION, we now have an extra set of entry points
that are never called. They only add a few bytes of bloat, so it seems
better to keep them compared to adding yet another Kconfig symbol.
I considered adding new syscall numbers for the IPC_64 variants for
consistency, but decided against that for now.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann
2018-12-31 22:22:40 +01:00
parent 73a66023c9
commit 275f22148e
14 changed files with 137 additions and 62 deletions

View File

@@ -567,9 +567,8 @@ out_unlock:
return err;
}
long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
static long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf, int version)
{
int version;
struct ipc_namespace *ns;
struct msqid64_ds msqid64;
int err;
@@ -577,7 +576,6 @@ long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
if (msqid < 0 || cmd < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
switch (cmd) {
@@ -613,9 +611,23 @@ long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
{
return ksys_msgctl(msqid, cmd, buf);
return ksys_msgctl(msqid, cmd, buf, IPC_64);
}
#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
{
int version = ipc_parse_version(&cmd);
return ksys_msgctl(msqid, cmd, buf, version);
}
SYSCALL_DEFINE3(old_msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
{
return ksys_old_msgctl(msqid, cmd, buf);
}
#endif
#ifdef CONFIG_COMPAT
struct compat_msqid_ds {
@@ -689,12 +701,11 @@ static int copy_compat_msqid_to_user(void __user *buf, struct msqid64_ds *in,
}
}
long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr)
static long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr, int version)
{
struct ipc_namespace *ns;
int err;
struct msqid64_ds msqid64;
int version = compat_ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
@@ -734,8 +745,22 @@ long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr)
COMPAT_SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, void __user *, uptr)
{
return compat_ksys_msgctl(msqid, cmd, uptr);
return compat_ksys_msgctl(msqid, cmd, uptr, IPC_64);
}
#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
long compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr)
{
int version = compat_ipc_parse_version(&cmd);
return compat_ksys_msgctl(msqid, cmd, uptr, version);
}
COMPAT_SYSCALL_DEFINE3(old_msgctl, int, msqid, int, cmd, void __user *, uptr)
{
return compat_ksys_old_msgctl(msqid, cmd, uptr);
}
#endif
#endif
static int testmsg(struct msg_msg *msg, long type, int mode)

View File

@@ -1634,9 +1634,8 @@ out_up:
return err;
}
long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg)
static long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg, int version)
{
int version;
struct ipc_namespace *ns;
void __user *p = (void __user *)arg;
struct semid64_ds semid64;
@@ -1645,7 +1644,6 @@ long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg)
if (semid < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
switch (cmd) {
@@ -1691,9 +1689,23 @@ long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg)
SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
{
return ksys_semctl(semid, semnum, cmd, arg);
return ksys_semctl(semid, semnum, cmd, arg, IPC_64);
}
#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg)
{
int version = ipc_parse_version(&cmd);
return ksys_semctl(semid, semnum, cmd, arg, version);
}
SYSCALL_DEFINE4(old_semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
{
return ksys_old_semctl(semid, semnum, cmd, arg);
}
#endif
#ifdef CONFIG_COMPAT
struct compat_semid_ds {
@@ -1744,12 +1756,11 @@ static int copy_compat_semid_to_user(void __user *buf, struct semid64_ds *in,
}
}
long compat_ksys_semctl(int semid, int semnum, int cmd, int arg)
static long compat_ksys_semctl(int semid, int semnum, int cmd, int arg, int version)
{
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;
@@ -1792,8 +1803,22 @@ long compat_ksys_semctl(int semid, int semnum, int cmd, int arg)
COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
{
return compat_ksys_semctl(semid, semnum, cmd, arg);
return compat_ksys_semctl(semid, semnum, cmd, arg, IPC_64);
}
#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
long compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg)
{
int version = compat_ipc_parse_version(&cmd);
return compat_ksys_semctl(semid, semnum, cmd, arg, version);
}
COMPAT_SYSCALL_DEFINE4(old_semctl, int, semid, int, semnum, int, cmd, int, arg)
{
return compat_ksys_old_semctl(semid, semnum, cmd, arg);
}
#endif
#endif
/* If the task doesn't already have a undo_list, then allocate one

View File

@@ -1137,16 +1137,15 @@ out_unlock1:
return err;
}
long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
static long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf, int version)
{
int err, version;
int err;
struct ipc_namespace *ns;
struct shmid64_ds sem64;
if (cmd < 0 || shmid < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
switch (cmd) {
@@ -1194,9 +1193,23 @@ long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
{
return ksys_shmctl(shmid, cmd, buf);
return ksys_shmctl(shmid, cmd, buf, IPC_64);
}
#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
{
int version = ipc_parse_version(&cmd);
return ksys_shmctl(shmid, cmd, buf, version);
}
SYSCALL_DEFINE3(old_shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
{
return ksys_old_shmctl(shmid, cmd, buf);
}
#endif
#ifdef CONFIG_COMPAT
struct compat_shmid_ds {
@@ -1319,11 +1332,10 @@ static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf,
}
}
long compat_ksys_shmctl(int shmid, int cmd, void __user *uptr)
long compat_ksys_shmctl(int shmid, int cmd, void __user *uptr, int version)
{
struct ipc_namespace *ns;
struct shmid64_ds sem64;
int version = compat_ipc_parse_version(&cmd);
int err;
ns = current->nsproxy->ipc_ns;
@@ -1378,8 +1390,22 @@ long compat_ksys_shmctl(int shmid, int cmd, void __user *uptr)
COMPAT_SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, void __user *, uptr)
{
return compat_ksys_shmctl(shmid, cmd, uptr);
return compat_ksys_shmctl(shmid, cmd, uptr, IPC_64);
}
#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
long compat_ksys_old_shmctl(int shmid, int cmd, void __user *uptr)
{
int version = compat_ipc_parse_version(&cmd);
return compat_ksys_shmctl(shmid, cmd, uptr, version);
}
COMPAT_SYSCALL_DEFINE3(old_shmctl, int, shmid, int, cmd, void __user *, uptr)
{
return compat_ksys_old_shmctl(shmid, cmd, uptr);
}
#endif
#endif
/*

View File

@@ -47,7 +47,7 @@ int ksys_ipc(unsigned int call, int first, unsigned long second,
return -EINVAL;
if (get_user(arg, (unsigned long __user *) ptr))
return -EFAULT;
return ksys_semctl(first, second, third, arg);
return ksys_old_semctl(first, second, third, arg);
}
case MSGSND:
@@ -75,7 +75,7 @@ int ksys_ipc(unsigned int call, int first, unsigned long second,
case MSGGET:
return ksys_msgget((key_t) first, second);
case MSGCTL:
return ksys_msgctl(first, second,
return ksys_old_msgctl(first, second,
(struct msqid_ds __user *)ptr);
case SHMAT:
@@ -100,7 +100,7 @@ int ksys_ipc(unsigned int call, int first, unsigned long second,
case SHMGET:
return ksys_shmget(first, second, third);
case SHMCTL:
return ksys_shmctl(first, second,
return ksys_old_shmctl(first, second,
(struct shmid_ds __user *) ptr);
default:
return -ENOSYS;
@@ -152,7 +152,7 @@ int compat_ksys_ipc(u32 call, int first, int second,
return -EINVAL;
if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
return -EFAULT;
return compat_ksys_semctl(first, second, third, pad);
return compat_ksys_old_semctl(first, second, third, pad);
case MSGSND:
return compat_ksys_msgsnd(first, ptr, second, third);
@@ -177,7 +177,7 @@ int compat_ksys_ipc(u32 call, int first, int second,
case MSGGET:
return ksys_msgget(first, second);
case MSGCTL:
return compat_ksys_msgctl(first, second, compat_ptr(ptr));
return compat_ksys_old_msgctl(first, second, compat_ptr(ptr));
case SHMAT: {
int err;
@@ -196,7 +196,7 @@ int compat_ksys_ipc(u32 call, int first, int second,
case SHMGET:
return ksys_shmget(first, (unsigned int)second, third);
case SHMCTL:
return compat_ksys_shmctl(first, second, compat_ptr(ptr));
return compat_ksys_old_shmctl(first, second, compat_ptr(ptr));
}
return -ENOSYS;

View File

@@ -160,10 +160,7 @@ static inline void ipc_update_pid(struct pid **pos, struct pid *pid)
}
}
#ifndef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
/* On IA-64, we always use the "64-bit version" of the IPC structures. */
# define ipc_parse_version(cmd) IPC_64
#else
#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
int ipc_parse_version(int *cmd);
#endif
@@ -246,13 +243,9 @@ int get_compat_ipc64_perm(struct ipc64_perm *,
static inline int compat_ipc_parse_version(int *cmd)
{
#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
int version = *cmd & IPC_64;
*cmd &= ~IPC_64;
return version;
#else
return IPC_64;
#endif
}
#endif
@@ -261,29 +254,29 @@ long ksys_semtimedop(int semid, struct sembuf __user *tsops,
unsigned int nsops,
const struct __kernel_timespec __user *timeout);
long ksys_semget(key_t key, int nsems, int semflg);
long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg);
long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg);
long ksys_msgget(key_t key, int msgflg);
long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
long msgtyp, int msgflg);
long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz,
int msgflg);
long ksys_shmget(key_t key, size_t size, int shmflg);
long ksys_shmdt(char __user *shmaddr);
long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
/* for CONFIG_ARCH_WANT_OLD_COMPAT_IPC */
long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems,
unsigned int nsops,
const struct old_timespec32 __user *timeout);
#ifdef CONFIG_COMPAT
long compat_ksys_semctl(int semid, int semnum, int cmd, int arg);
long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr);
long compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg);
long compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr);
long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz,
compat_long_t msgtyp, int msgflg);
long compat_ksys_msgsnd(int msqid, compat_uptr_t msgp,
compat_ssize_t msgsz, int msgflg);
long compat_ksys_shmctl(int shmid, int cmd, void __user *uptr);
long compat_ksys_old_shmctl(int shmid, int cmd, void __user *uptr);
#endif /* CONFIG_COMPAT */
#endif