]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/entry/ia32: Ensure s32 is sign extended to s64
authorRichard Palethorpe <rpalethorpe@suse.com>
Wed, 10 Jan 2024 13:01:22 +0000 (15:01 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Feb 2024 07:54:36 +0000 (08:54 +0100)
commit 56062d60f117dccfb5281869e0ab61e090baf864 upstream.

Presently ia32 registers stored in ptregs are unconditionally cast to
unsigned int by the ia32 stub. They are then cast to long when passed to
__se_sys*, but will not be sign extended.

This takes the sign of the syscall argument into account in the ia32
stub. It still casts to unsigned int to avoid implementation specific
behavior. However then casts to int or unsigned int as necessary. So that
the following cast to long sign extends the value.

This fixes the io_pgetevents02 LTP test when compiled with -m32. Presently
the systemcall io_pgetevents_time64() unexpectedly accepts -1 for the
maximum number of events.

It doesn't appear other systemcalls with signed arguments are effected
because they all have compat variants defined and wired up.

Fixes: ebeb8c82ffaf ("syscalls/x86: Use 'struct pt_regs' based syscall calling for IA32_EMULATION and x32")
Suggested-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
Signed-off-by: Nikolay Borisov <nik.borisov@suse.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20240110130122.3836513-1-nik.borisov@suse.com
Link: https://lore.kernel.org/ltp/20210921130127.24131-1-rpalethorpe@suse.com/
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/include/asm/syscall_wrapper.h
include/linux/syscalls.h

index e8ab7c1f1080a38f2ec2fcad0588141a2369a6a9..4163d02728cf8d0cdb6639252d9d8c0683e99f60 100644 (file)
@@ -58,12 +58,29 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
                ,,regs->di,,regs->si,,regs->dx                          \
                ,,regs->r10,,regs->r8,,regs->r9)                        \
 
+
+/* SYSCALL_PT_ARGS is Adapted from s390x */
+#define SYSCALL_PT_ARG6(m, t1, t2, t3, t4, t5, t6)                     \
+       SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5), m(t6, (regs->bp))
+#define SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5)                         \
+       SYSCALL_PT_ARG4(m, t1, t2, t3, t4),  m(t5, (regs->di))
+#define SYSCALL_PT_ARG4(m, t1, t2, t3, t4)                             \
+       SYSCALL_PT_ARG3(m, t1, t2, t3),  m(t4, (regs->si))
+#define SYSCALL_PT_ARG3(m, t1, t2, t3)                                 \
+       SYSCALL_PT_ARG2(m, t1, t2), m(t3, (regs->dx))
+#define SYSCALL_PT_ARG2(m, t1, t2)                                     \
+       SYSCALL_PT_ARG1(m, t1), m(t2, (regs->cx))
+#define SYSCALL_PT_ARG1(m, t1) m(t1, (regs->bx))
+#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__)
+
+#define __SC_COMPAT_CAST(t, a)                                         \
+       (__typeof(__builtin_choose_expr(__TYPE_IS_L(t), 0, 0U)))        \
+       (unsigned int)a
+
 /* Mapping of registers to parameters for syscalls on i386 */
 #define SC_IA32_REGS_TO_ARGS(x, ...)                                   \
-       __MAP(x,__SC_ARGS                                               \
-             ,,(unsigned int)regs->bx,,(unsigned int)regs->cx          \
-             ,,(unsigned int)regs->dx,,(unsigned int)regs->si          \
-             ,,(unsigned int)regs->di,,(unsigned int)regs->bp)
+       SYSCALL_PT_ARGS(x, __SC_COMPAT_CAST,                            \
+                       __MAP(x, __SC_TYPE, __VA_ARGS__))               \
 
 #define __SYS_STUB0(abi, name)                                         \
        long __##abi##_##name(const struct pt_regs *regs);              \
index 252243c7783db92c623634358b7937dc3fc38231..7a1446a7e336b348b8bc421b628f0598bf7c7ccf 100644 (file)
@@ -122,6 +122,7 @@ enum landlock_rule_type;
 #define __TYPE_IS_LL(t) (__TYPE_AS(t, 0LL) || __TYPE_AS(t, 0ULL))
 #define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a
 #define __SC_CAST(t, a)        (__force t) a
+#define __SC_TYPE(t, a)        t
 #define __SC_ARGS(t, a)        a
 #define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))