diff options
| author | Mark Brown <broonie@kernel.org> | 2026-10-27 13:26:19 +0000 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-10-27 13:26:19 +0000 |
| commit | d4be97694d2ff9a4c8db7658eb08da191a64f16d (patch) | |
| tree | ee1c5ea904e1dd2a6d43568f3e90a9c9f04876af | |
| parent | 565024bc4970d6ac541bf10bff413870c5aba160 (diff) | |
| parent | 17c6912e81b271ba31a747f0f5493100bbaab7e0 (diff) | |
| download | linux-next-d4be97694d2ff9a4c8db7658eb08da191a64f16d.tar.gz linux-next-d4be97694d2ff9a4c8db7658eb08da191a64f16d.zip | |
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git
| -rw-r--r-- | arch/s390/Kconfig | 1 | ||||
| -rw-r--r-- | arch/s390/appldata/appldata_base.c | 12 | ||||
| -rw-r--r-- | arch/s390/include/asm/futex_robust.h | 25 | ||||
| -rw-r--r-- | arch/s390/include/asm/ptrace.h | 4 | ||||
| -rw-r--r-- | arch/s390/include/asm/syscall.h | 1 | ||||
| -rw-r--r-- | arch/s390/kernel/ptrace.c | 28 | ||||
| -rw-r--r-- | arch/s390/kernel/syscall.c | 20 | ||||
| -rw-r--r-- | arch/s390/kernel/vdso.c | 19 | ||||
| -rw-r--r-- | arch/s390/kernel/vdso/Makefile | 7 | ||||
| -rwxr-xr-x | arch/s390/kernel/vdso/gen_vdso_offsets.sh | 3 | ||||
| -rw-r--r-- | arch/s390/kernel/vdso/vdso.lds.S | 3 | ||||
| -rw-r--r-- | arch/s390/kernel/vdso/vfutex.S | 22 |
12 files changed, 118 insertions, 27 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 7138d923d86f..840d81f7a750 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -213,6 +213,7 @@ config S390 select HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_EBPF_JIT if HAVE_MARCH_Z196_FEATURES select HAVE_EFFICIENT_UNALIGNED_ACCESS + select HAVE_FUTEX_ROBUST_UNLOCK select HAVE_GENERIC_TIF_BITS select HAVE_GUP_FAST select HAVE_FENTRY diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 836c51da18f4..f10b2f040cc2 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -360,21 +360,25 @@ appldata_generic_handler(const struct ctl_table *ctl, int write, pr_err("Starting the data collection for %s " "failed with rc=%d\n", ops->name, rc); module_put(ops->owner); + rc = -EIO; } else ops->active = 1; } else if (!active && (ops->active == 1)) { - ops->active = 0; rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, (unsigned long) ops->data, ops->size, ops->mod_lvl); - if (rc != 0) + if (rc != 0) { pr_err("Stopping the data collection for %s " "failed with rc=%d\n", ops->name, rc); - module_put(ops->owner); + rc = -EIO; + } else { + ops->active = 0; + module_put(ops->owner); + } } mutex_unlock(&appldata_ops_mutex); module_put(ops->owner); - return 0; + return rc; } /*************************** /proc stuff <END> *******************************/ diff --git a/arch/s390/include/asm/futex_robust.h b/arch/s390/include/asm/futex_robust.h new file mode 100644 index 000000000000..6a5fb2506192 --- /dev/null +++ b/arch/s390/include/asm/futex_robust.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_FUTEX_ROBUST_H +#define _ASM_S390_FUTEX_ROBUST_H + +#include <asm/ptrace.h> + +#define VDSO_FUTEX_ROBUST_POP_GPR 4 + +static __always_inline void __user *s390_futex_robust_unlock_get_pop(struct pt_regs *regs) +{ + /* + * Within critical section of + * __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop) + * + * If condition code is 0, cmpxchg succeeded, and the pending + * op pointer in gpr4 needs to be returned for clearing. + */ + if (psw_bits(regs->psw).cc != 0) + return NULL; + return (void __user *)regs->gprs[VDSO_FUTEX_ROBUST_POP_GPR]; +} + +#define arch_futex_robust_unlock_get_pop(regs) s390_futex_robust_unlock_get_pop(regs) + +#endif /* _ASM_S390_FUTEX_ROBUST_H */ diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 3e56ef8c268b..d8f3a2dbe689 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -15,14 +15,14 @@ #define PIF_SYSCALL 0 /* inside a system call */ #define PIF_PSW_ADDR_ADJUSTED 1 /* psw address has been adjusted */ -#define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */ +#define PIF_SYSCALL_ENTRY 2 /* ptrace gpr2 access redirected to syscall nr */ #define PIF_FTRACE_FULL_REGS 3 /* all register contents valid (ftrace) */ #define PIF_WARN_TRAP_SKIPPED 4 /* __WARN_trap() was skipped */ #define PIF_PGM_CHECK 5 /* inside a program check */ #define _PIF_SYSCALL BIT(PIF_SYSCALL) #define _PIF_ADDR_PSW_ADJUSTED BIT(PIF_PSW_ADDR_ADJUSTED) -#define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET) +#define _PIF_SYSCALL_ENTRY BIT(PIF_SYSCALL_ENTRY) #define _PIF_FTRACE_FULL_REGS BIT(PIF_FTRACE_FULL_REGS) #define _PIF_WARN_TRAP_SKIPPED BIT(PIF_WARN_TRAP_SKIPPED) #define _PIF_PGM_CHECK BIT(PIF_PGM_CHECK) diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index 5f310caad1fc..47f66202977f 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h @@ -59,7 +59,6 @@ static inline void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, int error, long val) { - set_pt_regs_flag(regs, PIF_SYSCALL_RET_SET); regs->gprs[2] = error ? error : val; } diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 5202f9a2d939..577fb2c3d5a8 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -204,15 +204,24 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) addr_t offset, tmp; if (addr < offsetof(struct user, regs.acrs)) { - /* - * psw and gprs are stored on the stack - */ - tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); + struct pt_regs *regs = task_pt_regs(child); + + /* psw and gprs are on the stack. */ + tmp = *(addr_t *)((addr_t)®s->psw + addr); if (addr == offsetof(struct user, regs.psw.mask)) { /* Return a clean psw mask. */ tmp &= PSW_MASK_USER | PSW_MASK_RI; tmp |= PSW_USER_BITS; } + /* + * During system call entry gpr2 contains the return + * value. Redirect reads of gpr2 to int_code so that + * readers see the system call number. + */ + if (addr == offsetof(struct user, regs.gprs[2])) { + if (test_pt_regs_flag(regs, PIF_SYSCALL_ENTRY)) + tmp = syscall_get_nr(child, regs); + } } else if (addr < offsetof(struct user, regs.orig_gpr2)) { /* @@ -347,8 +356,17 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) } if (addr == offsetof(struct user, regs.gprs[2])) { - if (test_pt_regs_flag(regs, PIF_SYSCALL)) + if (test_pt_regs_flag(regs, PIF_SYSCALL_ENTRY)) { + /* + * System call entry path: only change system + * call number in int_code, but leave gpr2 + * alone, which contains the return value. + */ syscall_set_nr(child, regs, data); + return 0; + } else if (test_pt_regs_flag(regs, PIF_SYSCALL)) { + syscall_set_nr(child, regs, data); + } } *(addr_t *)((addr_t) ®s->psw + addr) = data; } else if (addr < offsetof(struct user, regs.orig_gpr2)) { diff --git a/arch/s390/kernel/syscall.c b/arch/s390/kernel/syscall.c index bcc0b76bd868..a94bfcef2e8c 100644 --- a/arch/s390/kernel/syscall.c +++ b/arch/s390/kernel/syscall.c @@ -117,24 +117,22 @@ void noinstr __do_syscall(struct pt_regs *regs, unsigned long flags) regs->int_code &= ~0xffffUL; regs->int_code |= nr; } - regs->gprs[2] = nr; if (nr == __NR_restart_syscall && !(current->restart_block.arch_data & 1)) { regs->psw.addr = current->restart_block.arch_data; current->restart_block.arch_data = 1; } - - permit = syscall_enter_from_user_mode_work(regs, &nr); - /* - * In the s390 ptrace ABI, both the syscall number and the return value - * use gpr2. However, userspace puts the syscall number either in the - * svc instruction itself, or uses gpr1. To make at least skipping syscalls - * work, the ptrace code sets PIF_SYSCALL_RET_SET, which is checked here - * and if set, the syscall will be skipped. + * gpr2 is the return value register. Set it to -ENOSYS so that a + * skipped system call gets a defined default return value. + * Set PIF_SYSCALL_ENTRY so that ptrace reads and writes to gpr2 + * are redirected to the system call number in int_code. */ - if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET) || !permit)) + syscall_set_return_value(current, regs, -ENOSYS, 0); + set_pt_regs_flag(regs, PIF_SYSCALL_ENTRY); + permit = syscall_enter_from_user_mode_work(regs, &nr); + clear_pt_regs_flag(regs, PIF_SYSCALL_ENTRY); + if (unlikely(!permit)) goto out; - regs->gprs[2] = -ENOSYS; if (likely(nr < NR_syscalls)) { nr = array_index_nospec(nr, NR_syscalls); regs->gprs[2] = sys_call_table[nr](regs); diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index a905f989f910..efe492364a93 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/futex.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/smp.h> @@ -19,14 +20,31 @@ #include <linux/vdso_datastore.h> #include <vdso/datapage.h> #include <asm/alternative.h> +#include <asm/vdso/vsyscall.h> +#include <asm/vdso-symbols.h> #include <asm/vdso.h> extern char vdso_start[], vdso_end[]; +static inline void vdso_futex_robust_unlock_update_ips(void) +{ +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK + unsigned long vdso = current->mm->context.vdso_base; + struct futex_mm_data *fd = ¤t->mm->futex; + + futex_reset_cs_ranges(fd); + futex_set_vdso_cs_range(fd, 0, + vdso + vdso_offset___futex_list64_try_unlock_cs_start, + vdso + vdso_offset___futex_list64_try_unlock_cs_end, + false); +#endif +} + static int vdso_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *vma) { current->mm->context.vdso_base = vma->vm_start; + vdso_futex_robust_unlock_update_ips(); return 0; } @@ -73,6 +91,7 @@ static int map_vdso(unsigned long addr, unsigned long vdso_mapping_len) rc = PTR_ERR(vma); } else { current->mm->context.vdso_base = vdso_text_start; + vdso_futex_robust_unlock_update_ips(); rc = 0; } out: diff --git a/arch/s390/kernel/vdso/Makefile b/arch/s390/kernel/vdso/Makefile index 54bcf2984ca1..35e4e3dd23c7 100644 --- a/arch/s390/kernel/vdso/Makefile +++ b/arch/s390/kernel/vdso/Makefile @@ -3,7 +3,8 @@ # Include the generic Makefile to check the built vdso. include $(srctree)/lib/vdso/Makefile.include -obj-vdso = vdso_user_wrapper.o note.o vgetrandom-chacha.o +obj-vdso-y = vdso_user_wrapper.o note.o vgetrandom-chacha.o +obj-vdso-$(CONFIG_FUTEX_ROBUST_UNLOCK) += vfutex.o obj-cvdso = vdso_generic.o getcpu.o vgetrandom.o VDSO_CFLAGS_REMOVE := -pg $(CC_FLAGS_FTRACE) $(CC_FLAGS_EXPOLINE) CFLAGS_REMOVE_getcpu.o = $(VDSO_CFLAGS_REMOVE) @@ -16,8 +17,8 @@ endif # Build rules -targets := $(obj-vdso) $(obj-cvdso) vdso.so vdso.so.dbg -obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) +targets := $(obj-vdso-y) $(obj-cvdso) vdso.so vdso.so.dbg +obj-vdso := $(addprefix $(obj)/, $(obj-vdso-y)) obj-cvdso := $(addprefix $(obj)/, $(obj-cvdso)) KBUILD_AFLAGS_VDSO := $(KBUILD_AFLAGS) -DBUILD_VDSO diff --git a/arch/s390/kernel/vdso/gen_vdso_offsets.sh b/arch/s390/kernel/vdso/gen_vdso_offsets.sh index 359982fb002d..4039e6cfca51 100755 --- a/arch/s390/kernel/vdso/gen_vdso_offsets.sh +++ b/arch/s390/kernel/vdso/gen_vdso_offsets.sh @@ -12,4 +12,5 @@ # LC_ALL=C -sed -n 's/\([0-9a-f]*\) . __kernel_\(.*\)/\#define vdso_offset_\2\t0x\1/p' +sed -n -e 's/\([0-9a-f]*\) . __kernel_\(.*\)/\#define vdso_offset_\2\t0x\1/p' \ + -e 's/\([0-9a-f]*\) . \(__futex_.*\)/\#define vdso_offset_\2\t0x\1/p' diff --git a/arch/s390/kernel/vdso/vdso.lds.S b/arch/s390/kernel/vdso/vdso.lds.S index 6bcdb64315f2..1172f05f609d 100644 --- a/arch/s390/kernel/vdso/vdso.lds.S +++ b/arch/s390/kernel/vdso/vdso.lds.S @@ -110,6 +110,9 @@ VERSION __kernel_rt_sigreturn; __kernel_sigreturn; __kernel_getrandom; +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK + __vdso_futex_robust_list64_try_unlock; +#endif local: *; }; } diff --git a/arch/s390/kernel/vdso/vfutex.S b/arch/s390/kernel/vdso/vfutex.S new file mode 100644 index 000000000000..8a25bd4ecea4 --- /dev/null +++ b/arch/s390/kernel/vdso/vfutex.S @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <linux/linkage.h> +#include <asm/dwarf.h> + +/* + * __u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop) + * + * Returns tid on success, or lock value on failure. + */ +SYM_FUNC_START(__vdso_futex_robust_list64_try_unlock) + CFI_STARTPROC + lghi %r1,0 + cs %r3,%r1,0(%r2) +__futex_list64_try_unlock_cs_start: + jnz __futex_list64_try_unlock_cs_end +__futex_list64_try_unlock_cs_success: + mvghi 0(%r4),0 +__futex_list64_try_unlock_cs_end: + llgfr %r2,%r3 + br %r14 + CFI_ENDPROC +SYM_FUNC_END(__vdso_futex_robust_list64_try_unlock) |
