s390/syscalls: get rid of system call alias functions
authorHeiko Carstens <hca@linux.ibm.com>
Mon, 23 Jan 2023 13:30:46 +0000 (14:30 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Wed, 25 Jan 2023 19:51:11 +0000 (20:51 +0100)
bpftrace and friends only consider functions present in
/sys/kernel/tracing/available_filter_functions.

For system calls there is the s390 specific problem that the system call
function itself is present via __se_sys##name() while the system call
itself is wired up via an __s390x_sys##name() alias. The required DWARF
debug information however is only available for the original function, not
the alias, but within available_filter_functions only the functions with
__s390x_ prefix are available. Which means the required DWARF debug
information cannot be found.
While this could be solved via tooling, it is easier to change the s390
specific system call wrapper handling.

Therefore get rid of this alias handling and implement system call wrappers
like most other architectures are doing. In result the implementation
generates the following functions:

long __s390x_sys##name(struct pt_regs *regs)
static inline long __se_sys##name(...)
static inline long __do_sys##name(...)

__s390x_sys##name() is the visible system call function which is also wired
up in the system call table. Its only parameter is a pt_regs variable.

This function calls the corresponding __se_sys##name() function, which has
as many parameters like the system call definition. This function in turn
performs all zero and sign extensions of all system call parameters, taken
from the pt_regs structure, and finally calls __do_sys##name().

__do_sys##name() is the actual inlined system call function implementation.

For all 64 bit system calls there is a 31/32 bit system call function
__s390_sys##name() generated, which handles all system call parameters
correctly as required by compat handling. This function may be wired
up within the compat system call table, unless there exists an
explicit compat system call function, which is then used instead.

Reported-by: Ilya Leoshkevich <iii@linux.ibm.com>
Tested-by: Ilya Leoshkevich <iii@linux.ibm.com>
Reviewed-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/syscall_wrapper.h

index 8007d9e..9286430 100644 (file)
@@ -7,32 +7,11 @@
 #ifndef _ASM_S390_SYSCALL_WRAPPER_H
 #define _ASM_S390_SYSCALL_WRAPPER_H
 
-#define __SC_TYPE(t, a) t
-
-#define SYSCALL_PT_ARG6(regs, m, t1, t2, t3, t4, t5, t6)\
-       SYSCALL_PT_ARG5(regs, m, t1, t2, t3, t4, t5),   \
-               m(t6, (regs->gprs[7]))
-
-#define SYSCALL_PT_ARG5(regs, m, t1, t2, t3, t4, t5)   \
-       SYSCALL_PT_ARG4(regs, m, t1, t2, t3, t4),       \
-               m(t5, (regs->gprs[6]))
-
-#define SYSCALL_PT_ARG4(regs, m, t1, t2, t3, t4)       \
-       SYSCALL_PT_ARG3(regs, m, t1, t2, t3),           \
-               m(t4, (regs->gprs[5]))
-
-#define SYSCALL_PT_ARG3(regs, m, t1, t2, t3)           \
-       SYSCALL_PT_ARG2(regs, m, t1, t2),               \
-               m(t3, (regs->gprs[4]))
-
-#define SYSCALL_PT_ARG2(regs, m, t1, t2)               \
-       SYSCALL_PT_ARG1(regs, m, t1),                   \
-               m(t2, (regs->gprs[3]))
-
-#define SYSCALL_PT_ARG1(regs, m, t1)                   \
-               m(t1, (regs->orig_gpr2))
-
-#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__)
+/* Mapping of registers to parameters for syscalls */
+#define SC_S390_REGS_TO_ARGS(x, ...)                                   \
+       __MAP(x, __SC_ARGS                                              \
+             ,, regs->orig_gpr2,, regs->gprs[3],, regs->gprs[4]        \
+             ,, regs->gprs[5],, regs->gprs[6],, regs->gprs[7])
 
 #ifdef CONFIG_COMPAT
 
 
 #define SYSCALL_DEFINE0(sname)                                         \
        SYSCALL_METADATA(_##sname, 0);                                  \
+       long __s390_sys_##sname(void);                                  \
+       ALLOW_ERROR_INJECTION(__s390_sys_##sname, ERRNO);               \
        long __s390x_sys_##sname(void);                                 \
        ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO);              \
+       static inline long __do_sys_##sname(void);                      \
        long __s390_sys_##sname(void)                                   \
-               __attribute__((alias(__stringify(__s390x_sys_##sname)))); \
-       long __s390x_sys_##sname(void)
+       {                                                               \
+               return __do_sys_##sname();                              \
+       }                                                               \
+       long __s390x_sys_##sname(void)                                  \
+       {                                                               \
+               return __do_sys_##sname();                              \
+       }                                                               \
+       static inline long __do_sys_##sname(void)
 
 #define COND_SYSCALL(name)                                             \
        cond_syscall(__s390x_sys_##name);                               \
        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");           \
        long __s390_compat_sys##name(struct pt_regs *regs);                             \
-       long __s390_compat_sys##name(struct pt_regs *regs)                              \
-               __attribute__((alias(__stringify(__se_compat_sys##name))));             \
        ALLOW_ERROR_INJECTION(__s390_compat_sys##name, ERRNO);                          \
-       static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));       \
-       long __se_compat_sys##name(struct pt_regs *regs);                               \
-       long __se_compat_sys##name(struct pt_regs *regs)                                \
+       static inline long __se_compat_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__));     \
+       static inline long __do_compat_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__));     \
+       long __s390_compat_sys##name(struct pt_regs *regs)                              \
+       {                                                                               \
+               return __se_compat_sys##name(SC_S390_REGS_TO_ARGS(x, __VA_ARGS__));     \
+       }                                                                               \
+       static inline long __se_compat_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__))      \
        {                                                                               \
-               long ret = __do_compat_sys##name(SYSCALL_PT_ARGS(x, regs, __SC_DELOUSE, \
-                                                __MAP(x, __SC_TYPE, __VA_ARGS__)));    \
-               __MAP(x,__SC_TEST,__VA_ARGS__);                                         \
-               return ret;                                                             \
+               __MAP(x, __SC_TEST, __VA_ARGS__);                                       \
+               return __do_compat_sys##name(__MAP(x, __SC_DELOUSE, __VA_ARGS__));      \
        }                                                                               \
-       __diag_pop();                                                                   \
-       static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
+       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
 #define __S390_SYS_STUBx(x, name, ...)                                         \
        long __s390_sys##name(struct pt_regs *regs);                            \
        ALLOW_ERROR_INJECTION(__s390_sys##name, ERRNO);                         \
+       static inline long ___se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__));   \
        long __s390_sys##name(struct pt_regs *regs)                             \
        {                                                                       \
-               long ret = __do_sys##name(SYSCALL_PT_ARGS(x, regs,              \
-                       __SC_COMPAT_CAST, __MAP(x, __SC_TYPE, __VA_ARGS__)));   \
-               __MAP(x,__SC_TEST,__VA_ARGS__);                                 \
-               return ret;                                                     \
+               return ___se_sys##name(SC_S390_REGS_TO_ARGS(x, __VA_ARGS__));   \
+       }                                                                       \
+       static inline long ___se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__))    \
+       {                                                                       \
+               __MAP(x, __SC_TEST, __VA_ARGS__);                               \
+               return __do_sys##name(__MAP(x, __SC_COMPAT_CAST, __VA_ARGS__)); \
        }
 
 #else /* CONFIG_COMPAT */
        SYSCALL_METADATA(_##sname, 0);                                  \
        long __s390x_sys_##sname(void);                                 \
        ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO);              \
-       long __s390x_sys_##sname(void)
+       static inline long __do_sys_##sname(void);                      \
+       long __s390x_sys_##sname(void)                                  \
+       {                                                               \
+               return __do_sys_##sname();                              \
+       }                                                               \
+       static inline long __do_sys_##sname(void)
 
 #define COND_SYSCALL(name)                                             \
        cond_syscall(__s390x_sys_##name)
 
 #endif /* CONFIG_COMPAT */
 
-#define __SYSCALL_DEFINEx(x, name, ...)                                                        \
-       __diag_push();                                                                  \
-       __diag_ignore(GCC, 8, "-Wattribute-alias",                                      \
-                     "Type aliasing is used to sanitize syscall arguments");           \
-       long __s390x_sys##name(struct pt_regs *regs)                                    \
-               __attribute__((alias(__stringify(__se_sys##name))));                    \
-       ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO);                                \
-       static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));              \
-       long __se_sys##name(struct pt_regs *regs);                                      \
-       __S390_SYS_STUBx(x, name, __VA_ARGS__)                                          \
-       long __se_sys##name(struct pt_regs *regs)                                       \
-       {                                                                               \
-               long ret = __do_sys##name(SYSCALL_PT_ARGS(x, regs,                      \
-                                   __SC_CAST, __MAP(x, __SC_TYPE, __VA_ARGS__)));      \
-               __MAP(x,__SC_TEST,__VA_ARGS__);                                         \
-               return ret;                                                             \
-       }                                                                               \
-       __diag_pop();                                                                   \
-       static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
+#define __SYSCALL_DEFINEx(x, name, ...)                                                \
+       long __s390x_sys##name(struct pt_regs *regs);                           \
+       ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO);                        \
+       static inline 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__);                                 \
+       long __s390x_sys##name(struct pt_regs *regs)                            \
+       {                                                                       \
+               return __se_sys##name(SC_S390_REGS_TO_ARGS(x, __VA_ARGS__));    \
+       }                                                                       \
+       static inline long __se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__))     \
+       {                                                                       \
+               __MAP(x, __SC_TEST, __VA_ARGS__);                               \
+               return __do_sys##name(__MAP(x, __SC_CAST, __VA_ARGS__));        \
+       }                                                                       \
+       static inline long __do_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__))
 
 #endif /* _ASM_S390_SYSCALL_WRAPPER_H */