Commit 58661489 authored by Martin Schwidefsky's avatar Martin Schwidefsky

Merge branch 'compat' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux into features

Pull tip branch with Arnds compat system call wrapper rework.
parents c6ac8754 fb8bfca0
......@@ -75,6 +75,7 @@ config S390
select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX
select ARCH_HAS_STRICT_MODULE_RWX
select ARCH_HAS_SYSCALL_WRAPPER
select ARCH_HAS_UBSAN_SANITIZE_ALL
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select ARCH_INLINE_READ_LOCK
......@@ -379,6 +380,7 @@ config COMPAT
select COMPAT_BINFMT_ELF if BINFMT_ELF
select ARCH_WANT_OLD_COMPAT_IPC
select COMPAT_OLD_SIGACTION
select HAVE_UID16
depends on MULTIUSER
help
Select this option if you want to enable your system kernel to
......
......@@ -81,5 +81,30 @@ static inline void ftrace_generate_call_insn(struct ftrace_insn *insn,
#endif
}
/*
* Even though the system call numbers are identical for s390/s390x a
* different system call table is used for compat tasks. This may lead
* to e.g. incorrect or missing trace event sysfs files.
* Therefore simply do not trace compat system calls at all.
* See kernel/trace/trace_syscalls.c.
*/
#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
{
return is_compat_task();
}
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
static inline bool arch_syscall_match_sym_name(const char *sym,
const char *name)
{
/*
* Skip __s390_ and __s390x_ prefix - due to compat wrappers
* and aliasing some symbols of 64 bit system call functions
* may get the __s390_ prefix instead of the __s390x_ prefix.
*/
return !strcmp(sym + 7, name) || !strcmp(sym + 8, name);
}
#endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_FTRACE_H */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* syscall_wrapper.h - s390 specific wrappers to syscall definitions
*
*/
#ifndef _ASM_S390_SYSCALL_WRAPPER_H
#define _ASM_S390_SYSCALL_WRAPPER_H
#ifdef CONFIG_COMPAT
#define __SC_COMPAT_TYPE(t, a) \
__typeof(__builtin_choose_expr(sizeof(t) > 4, 0L, (t)0)) a
#define __SC_COMPAT_CAST(t, a) \
({ \
long __ReS = a; \
\
BUILD_BUG_ON((sizeof(t) > 4) && !__TYPE_IS_L(t) && \
!__TYPE_IS_UL(t) && !__TYPE_IS_PTR(t) && \
!__TYPE_IS_LL(t)); \
if (__TYPE_IS_L(t)) \
__ReS = (s32)a; \
if (__TYPE_IS_UL(t)) \
__ReS = (u32)a; \
if (__TYPE_IS_PTR(t)) \
__ReS = a & 0x7fffffff; \
if (__TYPE_IS_LL(t)) \
return -ENOSYS; \
(t)__ReS; \
})
#define __S390_SYS_STUBx(x, name, ...) \
asmlinkage long __s390_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))\
ALLOW_ERROR_INJECTION(__s390_sys##name, ERRNO); \
asmlinkage long __s390_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))\
{ \
long ret = __s390x_sys##name(__MAP(x,__SC_COMPAT_CAST,__VA_ARGS__));\
__MAP(x,__SC_TEST,__VA_ARGS__); \
return ret; \
}
/*
* To keep the naming coherent, re-define SYSCALL_DEFINE0 to create an alias
* named __s390x_sys_*()
*/
#define COMPAT_SYSCALL_DEFINE0(sname) \
SYSCALL_METADATA(_##sname, 0); \
asmlinkage long __s390_compat_sys_##sname(void); \
ALLOW_ERROR_INJECTION(__s390_compat__sys_##sname, ERRNO); \
asmlinkage long __s390_compat_sys_##sname(void)
#define SYSCALL_DEFINE0(sname) \
SYSCALL_METADATA(_##sname, 0); \
asmlinkage long __s390x_sys_##sname(void); \
ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO); \
asmlinkage long __s390_sys_##sname(void) \
__attribute__((alias(__stringify(__s390x_sys_##sname)))); \
asmlinkage long __s390x_sys_##sname(void)
#define COND_SYSCALL(name) \
cond_syscall(__s390x_sys_##name); \
cond_syscall(__s390_sys_##name)
#define SYS_NI(name) \
SYSCALL_ALIAS(__s390x_sys_##name, sys_ni_posix_timers); \
SYSCALL_ALIAS(__s390_sys_##name, sys_ni_posix_timers)
#define COMPAT_SYSCALL_DEFINEx(x, name, ...) \
__diag_push(); \
__diag_ignore(GCC, 8, "-Wattribute-alias", \
"Type aliasing is used to sanitize syscall arguments");\
asmlinkage long __s390_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
asmlinkage long __s390_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \
__attribute__((alias(__stringify(__se_compat_sys##name)))); \
ALLOW_ERROR_INJECTION(compat_sys##name, ERRNO); \
static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
asmlinkage long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
asmlinkage long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
{ \
long ret = __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));\
__MAP(x,__SC_TEST,__VA_ARGS__); \
return ret; \
} \
__diag_pop(); \
static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
/*
* As some compat syscalls may not be implemented, we need to expand
* COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in
* kernel/time/posix-stubs.c to cover this case as well.
*/
#define COND_SYSCALL_COMPAT(name) \
cond_syscall(__s390_compat_sys_##name)
#define COMPAT_SYS_NI(name) \
SYSCALL_ALIAS(__s390_compat_sys_##name, sys_ni_posix_timers)
#else /* CONFIG_COMPAT */
#define __S390_SYS_STUBx(x, fullname, name, ...)
#define SYSCALL_DEFINE0(sname) \
SYSCALL_METADATA(_##sname, 0); \
asmlinkage long __s390x_sys_##sname(void); \
ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO); \
asmlinkage long __s390x_sys_##sname(void)
#define COND_SYSCALL(name) \
cond_syscall(__s390x_sys_##name)
#define SYS_NI(name) \
SYSCALL_ALIAS(__s390x_sys_##name, sys_ni_posix_timers);
#endif /* CONFIG_COMPAT */
#define __SYSCALL_DEFINEx(x, name, ...) \
__diag_push(); \
__diag_ignore(GCC, 8, "-Wattribute-alias", \
"Type aliasing is used to sanitize syscall arguments");\
asmlinkage long __s390x_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \
__attribute__((alias(__stringify(__se_sys##name)))); \
ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO); \
static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
__S390_SYS_STUBx(x, name, __VA_ARGS__) \
asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
{ \
long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \
__MAP(x,__SC_TEST,__VA_ARGS__); \
return ret; \
} \
__diag_pop(); \
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
#endif /* _ASM_X86_SYSCALL_WRAPPER_H */
......@@ -20,6 +20,12 @@ typedef long __kernel_ssize_t;
typedef unsigned short __kernel_old_dev_t;
#define __kernel_old_dev_t __kernel_old_dev_t
#ifdef __KERNEL__
typedef unsigned short __kernel_old_uid_t;
typedef unsigned short __kernel_old_gid_t;
#define __kernel_old_uid_t __kernel_old_uid_t
#endif
#ifndef __s390x__
typedef unsigned long __kernel_ino_t;
......
......@@ -65,7 +65,7 @@ obj-$(CONFIG_HIBERNATION) += suspend.o swsusp.o
obj-$(CONFIG_AUDIT) += audit.o
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o
obj-$(CONFIG_COMPAT) += compat_wrapper.o $(compat-obj-y)
obj-$(CONFIG_COMPAT) += $(compat-obj-y)
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_KPROBES) += kprobes.o
......
......@@ -34,7 +34,6 @@
#include <linux/stat.h>
#include <linux/filter.h>
#include <linux/highmem.h>
#include <linux/highuid.h>
#include <linux/mman.h>
#include <linux/ipv6.h>
#include <linux/in.h>
......@@ -58,245 +57,13 @@
#include "compat_linux.h"
/* For this source file, we want overflow handling. */
#undef high2lowuid
#undef high2lowgid
#undef low2highuid
#undef low2highgid
#undef SET_UID16
#undef SET_GID16
#undef NEW_TO_OLD_UID
#undef NEW_TO_OLD_GID
#undef SET_OLDSTAT_UID
#undef SET_OLDSTAT_GID
#undef SET_STAT_UID
#undef SET_STAT_GID
#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
#define SET_UID16(var, uid) var = high2lowuid(uid)
#define SET_GID16(var, gid) var = high2lowgid(gid)
#define NEW_TO_OLD_UID(uid) high2lowuid(uid)
#define NEW_TO_OLD_GID(gid) high2lowgid(gid)
#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
COMPAT_SYSCALL_DEFINE3(s390_chown16, const char __user *, filename,
u16, user, u16, group)
{
return ksys_chown(filename, low2highuid(user), low2highgid(group));
}
COMPAT_SYSCALL_DEFINE3(s390_lchown16, const char __user *,
filename, u16, user, u16, group)
{
return ksys_lchown(filename, low2highuid(user), low2highgid(group));
}
COMPAT_SYSCALL_DEFINE3(s390_fchown16, unsigned int, fd, u16, user, u16, group)
{
return ksys_fchown(fd, low2highuid(user), low2highgid(group));
}
COMPAT_SYSCALL_DEFINE2(s390_setregid16, u16, rgid, u16, egid)
{
return sys_setregid(low2highgid(rgid), low2highgid(egid));
}
COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid)
{
return sys_setgid(low2highgid(gid));
}
COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
{
return sys_setreuid(low2highuid(ruid), low2highuid(euid));
}
COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid)
{
return sys_setuid(low2highuid(uid));
}
COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid)
{
return sys_setresuid(low2highuid(ruid), low2highuid(euid),
low2highuid(suid));
}
COMPAT_SYSCALL_DEFINE3(s390_getresuid16, u16 __user *, ruidp,
u16 __user *, euidp, u16 __user *, suidp)
{
const struct cred *cred = current_cred();
int retval;
u16 ruid, euid, suid;
ruid = high2lowuid(from_kuid_munged(cred->user_ns, cred->uid));
euid = high2lowuid(from_kuid_munged(cred->user_ns, cred->euid));
suid = high2lowuid(from_kuid_munged(cred->user_ns, cred->suid));
if (!(retval = put_user(ruid, ruidp)) &&
!(retval = put_user(euid, euidp)))
retval = put_user(suid, suidp);
return retval;
}
COMPAT_SYSCALL_DEFINE3(s390_setresgid16, u16, rgid, u16, egid, u16, sgid)
{
return sys_setresgid(low2highgid(rgid), low2highgid(egid),
low2highgid(sgid));
}
COMPAT_SYSCALL_DEFINE3(s390_getresgid16, u16 __user *, rgidp,
u16 __user *, egidp, u16 __user *, sgidp)
{
const struct cred *cred = current_cred();
int retval;
u16 rgid, egid, sgid;
rgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->gid));
egid = high2lowgid(from_kgid_munged(cred->user_ns, cred->egid));
sgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->sgid));
if (!(retval = put_user(rgid, rgidp)) &&
!(retval = put_user(egid, egidp)))
retval = put_user(sgid, sgidp);
return retval;
}
COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid)
{
return sys_setfsuid(low2highuid(uid));
}
COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid)
{
return sys_setfsgid(low2highgid(gid));
}
static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
{
struct user_namespace *user_ns = current_user_ns();
int i;
u16 group;
kgid_t kgid;
for (i = 0; i < group_info->ngroups; i++) {
kgid = group_info->gid[i];
group = (u16)from_kgid_munged(user_ns, kgid);
if (put_user(group, grouplist+i))
return -EFAULT;
}
return 0;
}
static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
{
struct user_namespace *user_ns = current_user_ns();
int i;
u16 group;
kgid_t kgid;
for (i = 0; i < group_info->ngroups; i++) {
if (get_user(group, grouplist+i))
return -EFAULT;
kgid = make_kgid(user_ns, (gid_t)group);
if (!gid_valid(kgid))
return -EINVAL;
group_info->gid[i] = kgid;
}
return 0;
}
COMPAT_SYSCALL_DEFINE2(s390_getgroups16, int, gidsetsize, u16 __user *, grouplist)
{
const struct cred *cred = current_cred();
int i;
if (gidsetsize < 0)
return -EINVAL;
get_group_info(cred->group_info);
i = cred->group_info->ngroups;
if (gidsetsize) {
if (i > gidsetsize) {
i = -EINVAL;
goto out;
}
if (groups16_to_user(grouplist, cred->group_info)) {
i = -EFAULT;
goto out;
}
}
out:
put_group_info(cred->group_info);
return i;
}
COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplist)
{
struct group_info *group_info;
int retval;
if (!may_setgroups())
return -EPERM;
if ((unsigned)gidsetsize > NGROUPS_MAX)
return -EINVAL;
group_info = groups_alloc(gidsetsize);
if (!group_info)
return -ENOMEM;
retval = groups16_from_user(group_info, grouplist);
if (retval) {
put_group_info(group_info);
return retval;
}
groups_sort(group_info);
retval = set_current_groups(group_info);
put_group_info(group_info);
return retval;
}
COMPAT_SYSCALL_DEFINE0(s390_getuid16)
{
return high2lowuid(from_kuid_munged(current_user_ns(), current_uid()));
}
COMPAT_SYSCALL_DEFINE0(s390_geteuid16)
{
return high2lowuid(from_kuid_munged(current_user_ns(), current_euid()));
}
COMPAT_SYSCALL_DEFINE0(s390_getgid16)
{
return high2lowgid(from_kgid_munged(current_user_ns(), current_gid()));
}
COMPAT_SYSCALL_DEFINE0(s390_getegid16)
{
return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
}
#ifdef CONFIG_SYSVIPC
COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second,
compat_ulong_t, third, compat_uptr_t, ptr)
{
if (call >> 16) /* hack for backward compatibility */
return -EINVAL;
return compat_sys_ipc(call, first, second, third, ptr, third);
return compat_ksys_ipc(call, first, second, third, ptr, third);
}
#endif
......
This diff is collapsed.
......@@ -1512,7 +1512,7 @@ cleanup_critical:
.quad .Lsie_skip - .Lsie_entry
#endif
.section .rodata, "a"
#define SYSCALL(esame,emu) .long esame
#define SYSCALL(esame,emu) .long __s390x_ ## esame
.globl sys_call_table
sys_call_table:
#include "asm/syscall_table.h"
......@@ -1520,7 +1520,7 @@ sys_call_table:
#ifdef CONFIG_COMPAT
#define SYSCALL(esame,emu) .long emu
#define SYSCALL(esame,emu) .long __s390_ ## emu
.globl sys_call_table_emu
sys_call_table_emu:
#include "asm/syscall_table.h"
......
......@@ -58,6 +58,7 @@ SYSCALL_DEFINE1(mmap2, struct s390_mmap_arg_struct __user *, arg)
return error;
}
#ifdef CONFIG_SYSVIPC
/*
* sys_ipc() is the de-multiplexer for the SysV IPC calls.
*/
......@@ -74,19 +75,28 @@ SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second,
* Therefore we can call the generic variant by simply passing the
* third parameter also as fifth parameter.
*/
return sys_ipc(call, first, second, third, ptr, third);
return ksys_ipc(call, first, second, third, ptr, third);
}
#endif /* CONFIG_SYSVIPC */
SYSCALL_DEFINE1(s390_personality, unsigned int, personality)
{
unsigned int ret;
unsigned int ret = current->personality;
if (personality(current->personality) == PER_LINUX32 &&
personality(personality) == PER_LINUX)
personality |= PER_LINUX32;
ret = sys_personality(personality);
if (personality != 0xffffffff)
set_personality(personality);
if (personality(ret) == PER_LINUX32)
ret &= ~PER_LINUX32;
return ret;
}
SYSCALL_DEFINE0(ni_syscall)
{
return -ENOSYS;
}
This diff is collapsed.
......@@ -1185,6 +1185,10 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff);
ssize_t ksys_readahead(int fd, loff_t offset, size_t count);
int ksys_ipc(unsigned int call, int first, unsigned long second,
unsigned long third, void __user * ptr, long fifth);
int compat_ksys_ipc(u32 call, int first, int second,
u32 third, u32 ptr, u32 fifth);
/*
* The following kernel syscall equivalents are just wrappers to fs-internal
......
......@@ -17,8 +17,8 @@
#include <linux/shm.h>
#include <linux/uaccess.h>
SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
unsigned long, third, void __user *, ptr, long, fifth)
int ksys_ipc(unsigned int call, int first, unsigned long second,
unsigned long third, void __user * ptr, long fifth)
{
int version, ret;
......@@ -106,6 +106,12 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
return -ENOSYS;
}
}
SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
unsigned long, third, void __user *, ptr, long, fifth)
{
return ksys_ipc(call, first, second, third, ptr, fifth);
}
#endif
#ifdef CONFIG_COMPAT
......@@ -121,8 +127,8 @@ struct compat_ipc_kludge {
};
#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
u32, third, compat_uptr_t, ptr, u32, fifth)
int compat_ksys_ipc(u32 call, int first, int second,
u32 third, compat_uptr_t ptr, u32 fifth)
{
int version;
u32 pad;
......@@ -195,5 +201,11 @@ COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
return -ENOSYS;
}
COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
u32, third, compat_uptr_t, ptr, u32, fifth)
{
return compat_ksys_ipc(call, first, second, third, ptr, fifth);
}
#endif
#endif
......@@ -366,6 +366,7 @@ COND_SYSCALL(kexec_file_load);
/* s390 */
COND_SYSCALL(s390_pci_mmio_read);
COND_SYSCALL(s390_pci_mmio_write);
COND_SYSCALL(s390_ipc);
COND_SYSCALL_COMPAT(s390_ipc);
/* powerpc */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment