ARM: 9107/1: syscall: always store thread_info->abi_syscall
authorArnd Bergmann <arnd@arndb.de>
Wed, 11 Aug 2021 07:30:21 +0000 (08:30 +0100)
committerRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Fri, 20 Aug 2021 10:39:26 +0000 (11:39 +0100)
The system call number is used in a a couple of places, in particular
ptrace, seccomp and /proc/<pid>/syscall.

The last one apparently never worked reliably on ARM for tasks that are
not currently getting traced.

Storing the syscall number in the normal entry path makes it work,
as well as allowing us to see if the current system call is for OABI
compat mode, which is the next thing I want to hook into.

Since the thread_info->syscall field is not just the number any more, it
is now renamed to abi_syscall. In kernels that enable both OABI and EABI,
the upper bits of this field encode 0x900000 (__NR_OABI_SYSCALL_BASE)
for OABI tasks, while normal EABI tasks do not set the upper bits. This
makes it possible to implement the in_oabi_syscall() helper later.

All other users of thread_info->syscall go through the syscall_get_nr()
helper, which in turn filters out the ABI bits.

Note that the ABI information is lost with PTRACE_SET_SYSCALL, so one
cannot set the internal number to a particular version, but this was
already the case. We could change it to let gdb encode the ABI type along
with the syscall in a CONFIG_OABI_COMPAT-enabled kernel, but that itself
would be a (backwards-compatible) ABI change, so I don't do it here.

Acked-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
arch/arm/include/asm/syscall.h
arch/arm/include/asm/thread_info.h
arch/arm/include/uapi/asm/unistd.h
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/entry-common.S
arch/arm/kernel/ptrace.c

index fd02761ba06cf5f1a2e780ee4ece115f7861c262..f055e846a5ccf8a46bda1426e20b388d93d34e94 100644 (file)
@@ -22,7 +22,10 @@ extern const unsigned long sys_call_table[];
 static inline int syscall_get_nr(struct task_struct *task,
                                 struct pt_regs *regs)
 {
-       return task_thread_info(task)->syscall;
+       if (IS_ENABLED(CONFIG_AEABI) && !IS_ENABLED(CONFIG_OABI_COMPAT))
+               return task_thread_info(task)->abi_syscall;
+
+       return task_thread_info(task)->abi_syscall & __NR_SYSCALL_MASK;
 }
 
 static inline void syscall_rollback(struct task_struct *task,
index 70d4cbc49ae122b35f676133cab34062e2ec0bed..17c56051747b38056568b7d0ac3f0200c246179c 100644 (file)
@@ -62,7 +62,7 @@ struct thread_info {
        unsigned long           stack_canary;
 #endif
        struct cpu_context_save cpu_context;    /* cpu context */
-       __u32                   syscall;        /* syscall number */
+       __u32                   abi_syscall;    /* ABI type and syscall nr */
        __u8                    used_cp[16];    /* thread used copro */
        unsigned long           tp_value[2];    /* TLS registers */
 #ifdef CONFIG_CRUNCH
index ae7749e15726747164c220f6a2bfbce3f93c1b16..a1149911464c3b5005714e19b2d743961005c5fb 100644 (file)
@@ -15,6 +15,7 @@
 #define _UAPI__ASM_ARM_UNISTD_H
 
 #define __NR_OABI_SYSCALL_BASE 0x900000
+#define __NR_SYSCALL_MASK      0x0fffff
 
 #if defined(__thumb__) || defined(__ARM_EABI__)
 #define __NR_SYSCALL_BASE      0
index 70993af22d80cf9a2afc305cbe76d47bce2e8c9e..a0945b898ca31acf9ee8bd39ba66b67bbdec1d32 100644 (file)
@@ -48,6 +48,7 @@ int main(void)
   DEFINE(TI_CPU,               offsetof(struct thread_info, cpu));
   DEFINE(TI_CPU_DOMAIN,                offsetof(struct thread_info, cpu_domain));
   DEFINE(TI_CPU_SAVE,          offsetof(struct thread_info, cpu_context));
+  DEFINE(TI_ABI_SYSCALL,       offsetof(struct thread_info, abi_syscall));
   DEFINE(TI_USED_CP,           offsetof(struct thread_info, used_cp));
   DEFINE(TI_TP_VALUE,          offsetof(struct thread_info, tp_value));
   DEFINE(TI_FPSTATE,           offsetof(struct thread_info, fpstate));
index 7f0b7aba1498839a015c2f2ae6474e49cbeb0380..e837af90cd4407f874ea20793bb9aa632e4c976f 100644 (file)
@@ -226,6 +226,7 @@ ENTRY(vector_swi)
        /* saved_psr and saved_pc are now dead */
 
        uaccess_disable tbl
+       get_thread_info tsk
 
        adr     tbl, sys_call_table             @ load syscall table pointer
 
@@ -237,13 +238,17 @@ ENTRY(vector_swi)
         * get the old ABI syscall table address.
         */
        bics    r10, r10, #0xff000000
+       strne   r10, [tsk, #TI_ABI_SYSCALL]
+       streq   scno, [tsk, #TI_ABI_SYSCALL]
        eorne   scno, r10, #__NR_OABI_SYSCALL_BASE
        ldrne   tbl, =sys_oabi_call_table
 #elif !defined(CONFIG_AEABI)
        bic     scno, scno, #0xff000000         @ mask off SWI op-code
+       str     scno, [tsk, #TI_ABI_SYSCALL]
        eor     scno, scno, #__NR_SYSCALL_BASE  @ check OS number
+#else
+       str     scno, [tsk, #TI_ABI_SYSCALL]
 #endif
-       get_thread_info tsk
        /*
         * Reload the registers that may have been corrupted on entry to
         * the syscall assembly (by tracing or context tracking.)
@@ -288,7 +293,6 @@ ENDPROC(vector_swi)
         * context switches, and waiting for our parent to respond.
         */
 __sys_trace:
-       mov     r1, scno
        add     r0, sp, #S_OFF
        bl      syscall_trace_enter
        mov     scno, r0
index 2771e682220b454073e77853f3e0ea0cce7e82cf..d886ea8910cb4f6fe22d8379a6d85979191f18af 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/tracehook.h>
 #include <linux/unistd.h>
 
+#include <asm/syscall.h>
 #include <asm/traps.h>
 
 #define CREATE_TRACE_POINTS
@@ -811,7 +812,8 @@ long arch_ptrace(struct task_struct *child, long request,
                        break;
 
                case PTRACE_SET_SYSCALL:
-                       task_thread_info(child)->syscall = data;
+                       task_thread_info(child)->abi_syscall = data &
+                                                       __NR_SYSCALL_MASK;
                        ret = 0;
                        break;
 
@@ -880,14 +882,14 @@ static void tracehook_report_syscall(struct pt_regs *regs,
        if (dir == PTRACE_SYSCALL_EXIT)
                tracehook_report_syscall_exit(regs, 0);
        else if (tracehook_report_syscall_entry(regs))
-               current_thread_info()->syscall = -1;
+               current_thread_info()->abi_syscall = -1;
 
        regs->ARM_ip = ip;
 }
 
-asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 {
-       current_thread_info()->syscall = scno;
+       int scno;
 
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
@@ -898,11 +900,11 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
                return -1;
 #else
        /* XXX: remove this once OABI gets fixed */
-       secure_computing_strict(current_thread_info()->syscall);
+       secure_computing_strict(syscall_get_nr(current, regs));
 #endif
 
        /* Tracer or seccomp may have changed syscall. */
-       scno = current_thread_info()->syscall;
+       scno = syscall_get_nr(current, regs);
 
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
                trace_sys_enter(regs, scno);