1#include <linux/compat.h>
2#include <linux/uaccess.h>
3#include <linux/ptrace.h>
4
5
6
7
8
9
10
11
12
13
14
15
16
17static inline void signal_compat_build_tests(void)
18{
19 int _sifields_offset = offsetof(compat_siginfo_t, _sifields);
20
21
22
23
24
25
26
27 BUILD_BUG_ON(NSIGILL != 8);
28 BUILD_BUG_ON(NSIGFPE != 8);
29 BUILD_BUG_ON(NSIGSEGV != 4);
30 BUILD_BUG_ON(NSIGBUS != 5);
31 BUILD_BUG_ON(NSIGTRAP != 4);
32 BUILD_BUG_ON(NSIGCHLD != 6);
33 BUILD_BUG_ON(NSIGSYS != 1);
34
35
36 BUILD_BUG_ON(sizeof(compat_siginfo_t) != 128);
37
38
39
40
41
42 BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int));
43#define CHECK_CSI_OFFSET(name) BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name))
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58#define CHECK_CSI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((compat_siginfo_t *)0)->_sifields.name))
59#define CHECK_SI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((siginfo_t *)0)->_sifields.name))
60
61 CHECK_CSI_OFFSET(_kill);
62 CHECK_CSI_SIZE (_kill, 2*sizeof(int));
63 CHECK_SI_SIZE (_kill, 2*sizeof(int));
64
65 CHECK_CSI_OFFSET(_timer);
66 CHECK_CSI_SIZE (_timer, 5*sizeof(int));
67 CHECK_SI_SIZE (_timer, 6*sizeof(int));
68
69 CHECK_CSI_OFFSET(_rt);
70 CHECK_CSI_SIZE (_rt, 3*sizeof(int));
71 CHECK_SI_SIZE (_rt, 4*sizeof(int));
72
73 CHECK_CSI_OFFSET(_sigchld);
74 CHECK_CSI_SIZE (_sigchld, 5*sizeof(int));
75 CHECK_SI_SIZE (_sigchld, 8*sizeof(int));
76
77 CHECK_CSI_OFFSET(_sigchld_x32);
78 CHECK_CSI_SIZE (_sigchld_x32, 7*sizeof(int));
79
80
81 CHECK_CSI_OFFSET(_sigfault);
82 CHECK_CSI_SIZE (_sigfault, 4*sizeof(int));
83 CHECK_SI_SIZE (_sigfault, 8*sizeof(int));
84
85 CHECK_CSI_OFFSET(_sigpoll);
86 CHECK_CSI_SIZE (_sigpoll, 2*sizeof(int));
87 CHECK_SI_SIZE (_sigpoll, 4*sizeof(int));
88
89 CHECK_CSI_OFFSET(_sigsys);
90 CHECK_CSI_SIZE (_sigsys, 3*sizeof(int));
91 CHECK_SI_SIZE (_sigsys, 4*sizeof(int));
92
93
94}
95
96void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
97{
98
99 if (oact)
100 oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
101
102 if (!act)
103 return;
104
105
106 act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
107
108 if (in_ia32_syscall())
109 act->sa.sa_flags |= SA_IA32_ABI;
110 if (in_x32_syscall())
111 act->sa.sa_flags |= SA_X32_ABI;
112}
113
114int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
115 bool x32_ABI)
116{
117 int err = 0;
118
119 signal_compat_build_tests();
120
121 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
122 return -EFAULT;
123
124 put_user_try {
125
126
127
128
129
130 put_user_ex(from->si_signo, &to->si_signo);
131 put_user_ex(from->si_errno, &to->si_errno);
132 put_user_ex((short)from->si_code, &to->si_code);
133
134 if (from->si_code < 0) {
135 put_user_ex(from->si_pid, &to->si_pid);
136 put_user_ex(from->si_uid, &to->si_uid);
137 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
138 } else {
139
140
141
142
143 put_user_ex(from->_sifields._pad[0],
144 &to->_sifields._pad[0]);
145 switch (from->si_code >> 16) {
146 case __SI_FAULT >> 16:
147 if (from->si_signo == SIGBUS &&
148 (from->si_code == BUS_MCEERR_AR ||
149 from->si_code == BUS_MCEERR_AO))
150 put_user_ex(from->si_addr_lsb, &to->si_addr_lsb);
151
152 if (from->si_signo == SIGSEGV) {
153 if (from->si_code == SEGV_BNDERR) {
154 compat_uptr_t lower = (unsigned long)&to->si_lower;
155 compat_uptr_t upper = (unsigned long)&to->si_upper;
156 put_user_ex(lower, &to->si_lower);
157 put_user_ex(upper, &to->si_upper);
158 }
159 if (from->si_code == SEGV_PKUERR)
160 put_user_ex(from->si_pkey, &to->si_pkey);
161 }
162 break;
163 case __SI_SYS >> 16:
164 put_user_ex(from->si_syscall, &to->si_syscall);
165 put_user_ex(from->si_arch, &to->si_arch);
166 break;
167 case __SI_CHLD >> 16:
168 if (!x32_ABI) {
169 put_user_ex(from->si_utime, &to->si_utime);
170 put_user_ex(from->si_stime, &to->si_stime);
171 } else {
172 put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
173 put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
174 }
175 put_user_ex(from->si_status, &to->si_status);
176
177 default:
178 case __SI_KILL >> 16:
179 put_user_ex(from->si_uid, &to->si_uid);
180 break;
181 case __SI_POLL >> 16:
182 put_user_ex(from->si_fd, &to->si_fd);
183 break;
184 case __SI_TIMER >> 16:
185 put_user_ex(from->si_overrun, &to->si_overrun);
186 put_user_ex(ptr_to_compat(from->si_ptr),
187 &to->si_ptr);
188 break;
189
190 case __SI_RT >> 16:
191 case __SI_MESGQ >> 16:
192 put_user_ex(from->si_uid, &to->si_uid);
193 put_user_ex(from->si_int, &to->si_int);
194 break;
195 }
196 }
197 } put_user_catch(err);
198
199 return err;
200}
201
202
203int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
204{
205 return __copy_siginfo_to_user32(to, from, in_x32_syscall());
206}
207
208int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
209{
210 int err = 0;
211 u32 ptr32;
212
213 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
214 return -EFAULT;
215
216 get_user_try {
217 get_user_ex(to->si_signo, &from->si_signo);
218 get_user_ex(to->si_errno, &from->si_errno);
219 get_user_ex(to->si_code, &from->si_code);
220
221 get_user_ex(to->si_pid, &from->si_pid);
222 get_user_ex(to->si_uid, &from->si_uid);
223 get_user_ex(ptr32, &from->si_ptr);
224 to->si_ptr = compat_ptr(ptr32);
225 } get_user_catch(err);
226
227 return err;
228}
229