1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/sched.h>
16#include <linux/mm.h>
17#include <linux/smp.h>
18#include <linux/kernel.h>
19#include <linux/signal.h>
20#include <linux/errno.h>
21#include <linux/wait.h>
22#include <linux/unistd.h>
23#include <linux/stddef.h>
24#include <linux/personality.h>
25#include <linux/suspend.h>
26#include <linux/ptrace.h>
27#include <linux/elf.h>
28#include <linux/compat.h>
29#include <linux/syscalls.h>
30#include <linux/uaccess.h>
31#include <asm/processor.h>
32#include <asm/ucontext.h>
33#include <asm/sigframe.h>
34#include <asm/syscalls.h>
35#include <asm/vdso.h>
36#include <arch/interrupts.h>
37
38struct compat_ucontext {
39 compat_ulong_t uc_flags;
40 compat_uptr_t uc_link;
41 struct compat_sigaltstack uc_stack;
42 struct sigcontext uc_mcontext;
43 sigset_t uc_sigmask;
44};
45
46struct compat_rt_sigframe {
47 unsigned char save_area[C_ABI_SAVE_AREA_SIZE];
48 struct compat_siginfo info;
49 struct compat_ucontext uc;
50};
51
52int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from)
53{
54 int err;
55
56 if (!access_ok(VERIFY_WRITE, to, sizeof(struct compat_siginfo)))
57 return -EFAULT;
58
59
60
61
62
63
64 err = __put_user(from->si_signo, &to->si_signo);
65 err |= __put_user(from->si_errno, &to->si_errno);
66 err |= __put_user((short)from->si_code, &to->si_code);
67
68 if (from->si_code < 0) {
69 err |= __put_user(from->si_pid, &to->si_pid);
70 err |= __put_user(from->si_uid, &to->si_uid);
71 err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
72 } else {
73
74
75
76
77 err |= __put_user(from->_sifields._pad[0],
78 &to->_sifields._pad[0]);
79 switch (from->si_code >> 16) {
80 case __SI_FAULT >> 16:
81 break;
82 case __SI_CHLD >> 16:
83 err |= __put_user(from->si_utime, &to->si_utime);
84 err |= __put_user(from->si_stime, &to->si_stime);
85 err |= __put_user(from->si_status, &to->si_status);
86
87 default:
88 case __SI_KILL >> 16:
89 err |= __put_user(from->si_uid, &to->si_uid);
90 break;
91 case __SI_POLL >> 16:
92 err |= __put_user(from->si_fd, &to->si_fd);
93 break;
94 case __SI_TIMER >> 16:
95 err |= __put_user(from->si_overrun, &to->si_overrun);
96 err |= __put_user(ptr_to_compat(from->si_ptr),
97 &to->si_ptr);
98 break;
99
100 case __SI_RT >> 16:
101 case __SI_MESGQ >> 16:
102 err |= __put_user(from->si_uid, &to->si_uid);
103 err |= __put_user(from->si_int, &to->si_int);
104 break;
105 }
106 }
107 return err;
108}
109
110int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
111{
112 int err;
113 u32 ptr32;
114
115 if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
116 return -EFAULT;
117
118 err = __get_user(to->si_signo, &from->si_signo);
119 err |= __get_user(to->si_errno, &from->si_errno);
120 err |= __get_user(to->si_code, &from->si_code);
121
122 err |= __get_user(to->si_pid, &from->si_pid);
123 err |= __get_user(to->si_uid, &from->si_uid);
124 err |= __get_user(ptr32, &from->si_ptr);
125 to->si_ptr = compat_ptr(ptr32);
126
127 return err;
128}
129
130
131long compat_sys_rt_sigreturn(void)
132{
133 struct pt_regs *regs = current_pt_regs();
134 struct compat_rt_sigframe __user *frame =
135 (struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
136 sigset_t set;
137
138 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
139 goto badframe;
140 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
141 goto badframe;
142
143 set_current_blocked(&set);
144
145 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
146 goto badframe;
147
148 if (compat_restore_altstack(&frame->uc.uc_stack))
149 goto badframe;
150
151 return 0;
152
153badframe:
154 signal_fault("bad sigreturn frame", regs, frame, 0);
155 return 0;
156}
157
158
159
160
161static inline void __user *compat_get_sigframe(struct k_sigaction *ka,
162 struct pt_regs *regs,
163 size_t frame_size)
164{
165 unsigned long sp;
166
167
168 sp = (unsigned long)compat_ptr(regs->sp);
169
170
171
172
173
174
175 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
176 return (void __user __force *)-1UL;
177
178
179 if (ka->sa.sa_flags & SA_ONSTACK) {
180 if (sas_ss_flags(sp) == 0)
181 sp = current->sas_ss_sp + current->sas_ss_size;
182 }
183
184 sp -= frame_size;
185
186
187
188
189 sp &= -16UL;
190 return (void __user *) sp;
191}
192
193int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
194 sigset_t *set, struct pt_regs *regs)
195{
196 unsigned long restorer;
197 struct compat_rt_sigframe __user *frame;
198 int err = 0;
199 int usig;
200
201 frame = compat_get_sigframe(ka, regs, sizeof(*frame));
202
203 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
204 goto give_sigsegv;
205
206 usig = current_thread_info()->exec_domain
207 && current_thread_info()->exec_domain->signal_invmap
208 && sig < 32
209 ? current_thread_info()->exec_domain->signal_invmap[sig]
210 : sig;
211
212
213 if (ka->sa.sa_flags & SA_SIGINFO) {
214
215 err |= copy_siginfo_to_user32(&frame->info, info);
216 regs->flags |= PT_FLAGS_RESTORE_REGS;
217 } else {
218 err |= __put_user(info->si_signo, &frame->info.si_signo);
219 }
220
221
222 err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
223 err |= __put_user(0, &frame->uc.uc_flags);
224 err |= __put_user(0, &frame->uc.uc_link);
225 err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
226 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
227 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
228 if (err)
229 goto give_sigsegv;
230
231 restorer = VDSO_SYM(&__vdso_rt_sigreturn);
232 if (ka->sa.sa_flags & SA_RESTORER)
233 restorer = ptr_to_compat_reg(ka->sa.sa_restorer);
234
235
236
237
238
239
240
241
242 regs->pc = ptr_to_compat_reg(ka->sa.sa_handler);
243 regs->ex1 = PL_ICS_EX1(USER_PL, 1);
244 regs->sp = ptr_to_compat_reg(frame);
245 regs->lr = restorer;
246 regs->regs[0] = (unsigned long) usig;
247 regs->regs[1] = ptr_to_compat_reg(&frame->info);
248 regs->regs[2] = ptr_to_compat_reg(&frame->uc);
249 regs->flags |= PT_FLAGS_CALLER_SAVES;
250 return 0;
251
252give_sigsegv:
253 signal_fault("bad setup frame", regs, frame, sig);
254 return -EFAULT;
255}
256