[RFC PATCH V2 06/38] riscv: u64ilp32: Add signal support for compat

From: guoren
Date: Sun Nov 12 2023 - 01:16:26 EST


From: Guo Ren <guoren@xxxxxxxxxxxxxxxxx>

The u64ilp32 reuses compat mode on the 64-bit Linux kernel, but the
signal context is the same as the native 64-bit, not u32ilp32. So use
the native signal procedure for u64ilp32 applications.

Signed-off-by: Guo Ren <guoren@xxxxxxxxxxxxxxxxx>
Signed-off-by: Guo Ren <guoren@xxxxxxxxxx>
---
arch/riscv/include/asm/signal32.h | 9 ++++++
arch/riscv/kernel/compat_signal.c | 21 ++++--------
arch/riscv/kernel/signal.c | 53 ++++++++++++++++++++++---------
3 files changed, 54 insertions(+), 29 deletions(-)

diff --git a/arch/riscv/include/asm/signal32.h b/arch/riscv/include/asm/signal32.h
index 96dc56932e76..cda62d7eb0a5 100644
--- a/arch/riscv/include/asm/signal32.h
+++ b/arch/riscv/include/asm/signal32.h
@@ -6,6 +6,7 @@
#if IS_ENABLED(CONFIG_COMPAT)
int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs);
+long __riscv_compat_rt_sigreturn(void);
#else
static inline
int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set,
@@ -13,6 +14,14 @@ int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set,
{
return -1;
}
+
+static inline
+long __riscv_compat_rt_sigreturn(void)
+{
+ return -1;
+}
#endif

+void __riscv_rt_sigreturn_badframe(void);
+
#endif
diff --git a/arch/riscv/kernel/compat_signal.c b/arch/riscv/kernel/compat_signal.c
index 8dea2012836e..955a638da2a4 100644
--- a/arch/riscv/kernel/compat_signal.c
+++ b/arch/riscv/kernel/compat_signal.c
@@ -116,18 +116,16 @@ static long compat_restore_sigcontext(struct pt_regs *regs,
return err;
}

-COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
+long __riscv_compat_rt_sigreturn(void)
{
- struct pt_regs *regs = current_pt_regs();
- struct compat_rt_sigframe __user *frame;
- struct task_struct *task;
sigset_t set;
+ struct pt_regs *regs = current_pt_regs();
+ struct compat_rt_sigframe __user *frame =
+ (struct compat_rt_sigframe __user *)kernel_stack_pointer(regs);

/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;

- frame = (struct compat_rt_sigframe __user *)regs->sp;
-
if (!access_ok(frame, sizeof(*frame)))
goto badframe;

@@ -142,17 +140,12 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
if (compat_restore_altstack(&frame->uc.uc_stack))
goto badframe;

+ regs->cause = -1UL;
+
return regs->a0;

badframe:
- task = current;
- if (show_unhandled_signals) {
- pr_info_ratelimited(
- "%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
- task->comm, task_pid_nr(task), __func__,
- frame, (void *)regs->epc, (void *)regs->sp);
- }
- force_sig(SIGSEGV);
+ __riscv_rt_sigreturn_badframe();
return 0;
}

diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index 95c4a8d8a3f5..1c51a6783c98 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -224,19 +224,34 @@ static size_t get_rt_frame_size(bool cal_all)
return frame_size;
}

-SYSCALL_DEFINE0(rt_sigreturn)
+void __riscv_rt_sigreturn_badframe(void)
+{
+ struct task_struct *task = current;
+ struct pt_regs *regs = task_pt_regs(task);
+
+ if (show_unhandled_signals) {
+ pr_info_ratelimited(
+ "%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
+ task->comm, task_pid_nr(task), __func__,
+ (void *)kernel_stack_pointer(regs),
+ (void *)instruction_pointer(regs),
+ (void *)kernel_stack_pointer(regs));
+ }
+
+ force_sig(SIGSEGV);
+}
+
+static long __riscv_rt_sigreturn(void)
{
- struct pt_regs *regs = current_pt_regs();
- struct rt_sigframe __user *frame;
- struct task_struct *task;
sigset_t set;
size_t frame_size = get_rt_frame_size(false);
+ struct pt_regs *regs = current_pt_regs();
+ struct rt_sigframe __user *frame =
+ (struct rt_sigframe __user *)kernel_stack_pointer(regs);

/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;

- frame = (struct rt_sigframe __user *)regs->sp;
-
if (!access_ok(frame, frame_size))
goto badframe;

@@ -256,17 +271,25 @@ SYSCALL_DEFINE0(rt_sigreturn)
return regs->a0;

badframe:
- task = current;
- if (show_unhandled_signals) {
- pr_info_ratelimited(
- "%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
- task->comm, task_pid_nr(task), __func__,
- frame, (void *)regs->epc, (void *)regs->sp);
- }
- force_sig(SIGSEGV);
+ __riscv_rt_sigreturn_badframe();
return 0;
}

+SYSCALL_DEFINE0(rt_sigreturn)
+{
+ return __riscv_rt_sigreturn();
+}
+
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
+{
+ if (test_thread_flag(TIF_32BIT) && !test_thread_flag(TIF_64ILP32))
+ return __riscv_compat_rt_sigreturn();
+ else
+ return __riscv_rt_sigreturn();
+}
+#endif
+
static long setup_sigcontext(struct rt_sigframe __user *frame,
struct pt_regs *regs)
{
@@ -433,7 +456,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
rseq_signal_deliver(ksig, regs);

/* Set up the stack frame */
- if (is_compat_task())
+ if (test_thread_flag(TIF_32BIT) && !test_thread_flag(TIF_64ILP32))
ret = compat_setup_rt_frame(ksig, oldset, regs);
else
ret = setup_rt_frame(ksig, oldset, regs);
--
2.36.1