1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | |
3 | #include <linux/compat.h> |
4 | #include <linux/signal.h> |
5 | #include <linux/uaccess.h> |
6 | #include <linux/syscalls.h> |
7 | #include <linux/linkage.h> |
8 | |
9 | #include <asm/csr.h> |
10 | #include <asm/signal32.h> |
11 | #include <asm/switch_to.h> |
12 | #include <asm/ucontext.h> |
13 | #include <asm/vdso.h> |
14 | |
15 | #define COMPAT_DEBUG_SIG 0 |
16 | |
17 | struct compat_sigcontext { |
18 | struct compat_user_regs_struct sc_regs; |
19 | union __riscv_fp_state sc_fpregs; |
20 | }; |
21 | |
22 | struct compat_ucontext { |
23 | compat_ulong_t uc_flags; |
24 | struct compat_ucontext *uc_link; |
25 | compat_stack_t uc_stack; |
26 | sigset_t uc_sigmask; |
27 | /* There's some padding here to allow sigset_t to be expanded in the |
28 | * future. Though this is unlikely, other architectures put uc_sigmask |
29 | * at the end of this structure and explicitly state it can be |
30 | * expanded, so we didn't want to box ourselves in here. */ |
31 | __u8 __unused[1024 / 8 - sizeof(sigset_t)]; |
32 | /* We can't put uc_sigmask at the end of this structure because we need |
33 | * to be able to expand sigcontext in the future. For example, the |
34 | * vector ISA extension will almost certainly add ISA state. We want |
35 | * to ensure all user-visible ISA state can be saved and restored via a |
36 | * ucontext, so we're putting this at the end in order to allow for |
37 | * infinite extensibility. Since we know this will be extended and we |
38 | * assume sigset_t won't be extended an extreme amount, we're |
39 | * prioritizing this. */ |
40 | struct compat_sigcontext uc_mcontext; |
41 | }; |
42 | |
43 | struct compat_rt_sigframe { |
44 | struct compat_siginfo info; |
45 | struct compat_ucontext uc; |
46 | }; |
47 | |
48 | #ifdef CONFIG_FPU |
49 | static long compat_restore_fp_state(struct pt_regs *regs, |
50 | union __riscv_fp_state __user *sc_fpregs) |
51 | { |
52 | long err; |
53 | struct __riscv_d_ext_state __user *state = &sc_fpregs->d; |
54 | size_t i; |
55 | |
56 | err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state)); |
57 | if (unlikely(err)) |
58 | return err; |
59 | |
60 | fstate_restore(current, regs); |
61 | |
62 | /* We support no other extension state at this time. */ |
63 | for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { |
64 | u32 value; |
65 | |
66 | err = __get_user(value, &sc_fpregs->q.reserved[i]); |
67 | if (unlikely(err)) |
68 | break; |
69 | if (value != 0) |
70 | return -EINVAL; |
71 | } |
72 | |
73 | return err; |
74 | } |
75 | |
76 | static long compat_save_fp_state(struct pt_regs *regs, |
77 | union __riscv_fp_state __user *sc_fpregs) |
78 | { |
79 | long err; |
80 | struct __riscv_d_ext_state __user *state = &sc_fpregs->d; |
81 | size_t i; |
82 | |
83 | fstate_save(current, regs); |
84 | err = __copy_to_user(state, ¤t->thread.fstate, sizeof(*state)); |
85 | if (unlikely(err)) |
86 | return err; |
87 | |
88 | /* We support no other extension state at this time. */ |
89 | for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) { |
90 | err = __put_user(0, &sc_fpregs->q.reserved[i]); |
91 | if (unlikely(err)) |
92 | break; |
93 | } |
94 | |
95 | return err; |
96 | } |
97 | #else |
98 | #define compat_save_fp_state(task, regs) (0) |
99 | #define compat_restore_fp_state(task, regs) (0) |
100 | #endif |
101 | |
102 | static long compat_restore_sigcontext(struct pt_regs *regs, |
103 | struct compat_sigcontext __user *sc) |
104 | { |
105 | long err; |
106 | struct compat_user_regs_struct cregs; |
107 | |
108 | /* sc_regs is structured the same as the start of pt_regs */ |
109 | err = __copy_from_user(to: &cregs, from: &sc->sc_regs, n: sizeof(sc->sc_regs)); |
110 | |
111 | cregs_to_regs(&cregs, regs); |
112 | |
113 | /* Restore the floating-point state. */ |
114 | if (has_fpu()) |
115 | err |= compat_restore_fp_state(regs, &sc->sc_fpregs); |
116 | return err; |
117 | } |
118 | |
119 | COMPAT_SYSCALL_DEFINE0(rt_sigreturn) |
120 | { |
121 | struct pt_regs *regs = current_pt_regs(); |
122 | struct compat_rt_sigframe __user *frame; |
123 | struct task_struct *task; |
124 | sigset_t set; |
125 | |
126 | /* Always make any pending restarted system calls return -EINTR */ |
127 | current->restart_block.fn = do_no_restart_syscall; |
128 | |
129 | frame = (struct compat_rt_sigframe __user *)regs->sp; |
130 | |
131 | if (!access_ok(frame, sizeof(*frame))) |
132 | goto badframe; |
133 | |
134 | if (__copy_from_user(to: &set, from: &frame->uc.uc_sigmask, n: sizeof(set))) |
135 | goto badframe; |
136 | |
137 | set_current_blocked(&set); |
138 | |
139 | if (compat_restore_sigcontext(regs, sc: &frame->uc.uc_mcontext)) |
140 | goto badframe; |
141 | |
142 | if (compat_restore_altstack(uss: &frame->uc.uc_stack)) |
143 | goto badframe; |
144 | |
145 | return regs->a0; |
146 | |
147 | badframe: |
148 | task = current; |
149 | if (show_unhandled_signals) { |
150 | pr_info_ratelimited( |
151 | "%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n" , |
152 | task->comm, task_pid_nr(task), __func__, |
153 | frame, (void *)regs->epc, (void *)regs->sp); |
154 | } |
155 | force_sig(SIGSEGV); |
156 | return 0; |
157 | } |
158 | |
159 | static long compat_setup_sigcontext(struct compat_rt_sigframe __user *frame, |
160 | struct pt_regs *regs) |
161 | { |
162 | struct compat_sigcontext __user *sc = &frame->uc.uc_mcontext; |
163 | struct compat_user_regs_struct cregs; |
164 | long err; |
165 | |
166 | regs_to_cregs(&cregs, regs); |
167 | |
168 | /* sc_regs is structured the same as the start of pt_regs */ |
169 | err = __copy_to_user(to: &sc->sc_regs, from: &cregs, n: sizeof(sc->sc_regs)); |
170 | /* Save the floating-point state. */ |
171 | if (has_fpu()) |
172 | err |= compat_save_fp_state(regs, &sc->sc_fpregs); |
173 | return err; |
174 | } |
175 | |
176 | static inline void __user *compat_get_sigframe(struct ksignal *ksig, |
177 | struct pt_regs *regs, size_t framesize) |
178 | { |
179 | unsigned long sp; |
180 | /* Default to using normal stack */ |
181 | sp = regs->sp; |
182 | |
183 | /* |
184 | * If we are on the alternate signal stack and would overflow it, don't. |
185 | * Return an always-bogus address instead so we will die with SIGSEGV. |
186 | */ |
187 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) |
188 | return (void __user __force *)(-1UL); |
189 | |
190 | /* This is the X/Open sanctioned signal stack switching. */ |
191 | sp = sigsp(sp, ksig) - framesize; |
192 | |
193 | /* Align the stack frame. */ |
194 | sp &= ~0xfUL; |
195 | |
196 | return (void __user *)sp; |
197 | } |
198 | |
199 | int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set, |
200 | struct pt_regs *regs) |
201 | { |
202 | struct compat_rt_sigframe __user *frame; |
203 | long err = 0; |
204 | |
205 | frame = compat_get_sigframe(ksig, regs, framesize: sizeof(*frame)); |
206 | if (!access_ok(frame, sizeof(*frame))) |
207 | return -EFAULT; |
208 | |
209 | err |= copy_siginfo_to_user32(to: &frame->info, from: &ksig->info); |
210 | |
211 | /* Create the ucontext. */ |
212 | err |= __put_user(0, &frame->uc.uc_flags); |
213 | err |= __put_user(NULL, &frame->uc.uc_link); |
214 | err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp); |
215 | err |= compat_setup_sigcontext(frame, regs); |
216 | err |= __copy_to_user(to: &frame->uc.uc_sigmask, from: set, n: sizeof(*set)); |
217 | if (err) |
218 | return -EFAULT; |
219 | |
220 | regs->ra = (unsigned long)COMPAT_VDSO_SYMBOL( |
221 | current->mm->context.vdso, rt_sigreturn); |
222 | |
223 | /* |
224 | * Set up registers for signal handler. |
225 | * Registers that we don't modify keep the value they had from |
226 | * user-space at the time we took the signal. |
227 | * We always pass siginfo and mcontext, regardless of SA_SIGINFO, |
228 | * since some things rely on this (e.g. glibc's debug/segfault.c). |
229 | */ |
230 | regs->epc = (unsigned long)ksig->ka.sa.sa_handler; |
231 | regs->sp = (unsigned long)frame; |
232 | regs->a0 = ksig->sig; /* a0: signal number */ |
233 | regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */ |
234 | regs->a2 = (unsigned long)(&frame->uc); /* a2: ucontext pointer */ |
235 | |
236 | #if COMPAT_DEBUG_SIG |
237 | pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n" , |
238 | current->comm, task_pid_nr(current), ksig->sig, |
239 | (void *)regs->epc, (void *)regs->ra, frame); |
240 | #endif |
241 | |
242 | return 0; |
243 | } |
244 | |