linux32_misc.c revision 1.30.2.3 1 /* $NetBSD: linux32_misc.c,v 1.30.2.3 2021/01/03 16:12:44 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe
9 * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center;
10 * by Edgar Fu\ss, Mathematisches Institut der Uni Bonn.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.30.2.3 2021/01/03 16:12:44 thorpej Exp $");
36
37 #include <sys/param.h>
38 #include <sys/proc.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/fstypes.h>
42 #include <sys/vfs_syscalls.h>
43 #include <sys/ptrace.h>
44 #include <sys/syscall.h>
45 #include <sys/poll.h>
46 #include <sys/futex.h>
47
48 #include <compat/netbsd32/netbsd32.h>
49 #include <compat/netbsd32/netbsd32_syscallargs.h>
50
51 #include <compat/linux/common/linux_types.h>
52
53 #include <compat/linux32/common/linux32_types.h>
54 #include <compat/linux32/common/linux32_signal.h>
55 #include <compat/linux32/common/linux32_sched.h>
56 #include <compat/linux32/linux32_syscallargs.h>
57
58 #include <compat/linux/common/linux_ptrace.h>
59 #include <compat/linux/common/linux_emuldata.h>
60 #include <compat/linux/common/linux_signal.h>
61 #include <compat/linux/common/linux_misc.h>
62 #include <compat/linux/common/linux_statfs.h>
63 #include <compat/linux/common/linux_ipc.h>
64 #include <compat/linux/common/linux_sem.h>
65 #include <compat/linux/linux_syscallargs.h>
66
67 extern const struct linux_mnttypes linux_fstypes[];
68 extern const int linux_fstypes_cnt;
69
70 /*
71 * Implement the fs stat functions. Straightforward.
72 */
73 int
74 linux32_sys_statfs(struct lwp *l, const struct linux32_sys_statfs_args *uap, register_t *retval)
75 {
76 /* {
77 syscallarg(const netbsd32_charp char) path;
78 syscallarg(linux32_statfsp) sp;
79 } */
80 struct statvfs *sb;
81 struct linux_statfs ltmp;
82 int error;
83
84 sb = STATVFSBUF_GET();
85 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb);
86 if (error == 0) {
87 bsd_to_linux_statfs(sb, <mp);
88 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp);
89 }
90
91 STATVFSBUF_PUT(sb);
92 return error;
93 }
94
95 int
96 linux32_sys_fstatfs(struct lwp *l, const struct linux32_sys_fstatfs_args *uap, register_t *retval)
97 {
98 /* {
99 syscallarg(int) fd;
100 syscallarg(linux32_statfsp) sp;
101 } */
102 struct statvfs *sb;
103 struct linux_statfs ltmp;
104 int error;
105
106 sb = STATVFSBUF_GET();
107 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb);
108 if (error == 0) {
109 bsd_to_linux_statfs(sb, <mp);
110 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp);
111 }
112 STATVFSBUF_PUT(sb);
113
114 return error;
115 }
116
117 int
118 linux32_sys_statfs64(struct lwp *l, const struct linux32_sys_statfs64_args *uap, register_t *retval)
119 {
120 /* {
121 syscallarg(const netbsd32_charp char) path;
122 syscallarg(linux32_statfs64p) sp;
123 } */
124 struct statvfs *sb;
125 struct linux_statfs64 ltmp;
126 int error;
127
128 sb = STATVFSBUF_GET();
129 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb);
130 if (error == 0) {
131 bsd_to_linux_statfs64(sb, <mp);
132 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp);
133 }
134
135 STATVFSBUF_PUT(sb);
136 return error;
137 }
138
139 int
140 linux32_sys_fstatfs64(struct lwp *l, const struct linux32_sys_fstatfs64_args *uap, register_t *retval)
141 {
142 /* {
143 syscallarg(int) fd;
144 syscallarg(linux32_statfs64p) sp;
145 } */
146 struct statvfs *sb;
147 struct linux_statfs64 ltmp;
148 int error;
149
150 sb = STATVFSBUF_GET();
151 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb);
152 if (error == 0) {
153 bsd_to_linux_statfs64(sb, <mp);
154 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp);
155 }
156 STATVFSBUF_PUT(sb);
157
158 return error;
159 }
160
161 extern const int linux_ptrace_request_map[];
162
163 int
164 linux32_sys_ptrace(struct lwp *l, const struct linux32_sys_ptrace_args *uap, register_t *retval)
165 {
166 /* {
167 i386, m68k, powerpc: T=int
168 alpha, amd64: T=long
169 syscallarg(T) request;
170 syscallarg(T) pid;
171 syscallarg(T) addr;
172 syscallarg(T) data;
173 } */
174 const int *ptr;
175 int request;
176 int error;
177
178 ptr = linux_ptrace_request_map;
179 request = SCARG(uap, request);
180 while (*ptr != -1)
181 if (*ptr++ == request) {
182 struct sys_ptrace_args pta;
183
184 SCARG(&pta, req) = *ptr;
185 SCARG(&pta, pid) = SCARG(uap, pid);
186 SCARG(&pta, addr) = NETBSD32IPTR64(SCARG(uap, addr));
187 SCARG(&pta, data) = SCARG(uap, data);
188
189 /*
190 * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually
191 * to continue where the process left off previously.
192 * The same thing is achieved by addr == (void *) 1
193 * on NetBSD, so rewrite 'addr' appropriately.
194 */
195 if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0)
196 SCARG(&pta, addr) = (void *) 1;
197
198 error = sysent[SYS_ptrace].sy_call(l, &pta, retval);
199 if (error)
200 return error;
201 switch (request) {
202 case LINUX_PTRACE_PEEKTEXT:
203 case LINUX_PTRACE_PEEKDATA:
204 error = copyout (retval,
205 NETBSD32IPTR64(SCARG(uap, data)),
206 sizeof *retval);
207 *retval = SCARG(uap, data);
208 break;
209 default:
210 break;
211 }
212 return error;
213 }
214 else
215 ptr++;
216
217 return EIO;
218 }
219
220 int
221 linux32_sys_personality(struct lwp *l, const struct linux32_sys_personality_args *uap, register_t *retval)
222 {
223 /* {
224 syscallarg(netbsd32_u_long) per;
225 } */
226 struct linux_sys_personality_args ua;
227
228 NETBSD32TOX_UAP(per, long);
229 return linux_sys_personality(l, &ua, retval);
230 }
231
232 int
233 linux32_sys_futex(struct lwp *l,
234 const struct linux32_sys_futex_args *uap, register_t *retval)
235 {
236 /* {
237 syscallarg(linux32_intp_t) uaddr;
238 syscallarg(int) op;
239 syscallarg(int) val;
240 syscallarg(linux32_timespecp_t) timeout;
241 syscallarg(linux32_intp_t) uaddr2;
242 syscallarg(int) val3;
243 } */
244 struct linux32_timespec lts;
245 struct timespec ts, *tsp = NULL;
246 int val2 = 0;
247 int error;
248
249 /*
250 * Linux overlays the "timeout" field and the "val2" field.
251 * "timeout" is only valid for FUTEX_WAIT and FUTEX_WAIT_BITSET
252 * on Linux.
253 */
254 const int op = (SCARG(uap, op) & FUTEX_CMD_MASK);
255 if ((op == FUTEX_WAIT || op == FUTEX_WAIT_BITSET) &&
256 SCARG_P32(uap, timeout) != NULL) {
257 if ((error = copyin(SCARG_P32(uap, timeout),
258 <s, sizeof(lts))) != 0) {
259 return error;
260 }
261 linux32_to_native_timespec(&ts, <s);
262 tsp = &ts;
263 } else {
264 val2 = (int)(uintptr_t)SCARG_P32(uap, timeout);
265 }
266
267 return linux_do_futex(SCARG_P32(uap, uaddr), SCARG(uap, op),
268 SCARG(uap, val), tsp, SCARG_P32(uap, uaddr2), val2,
269 SCARG(uap, val3), retval);
270 }
271
272 int
273 linux32_sys_truncate64(struct lwp *l, const struct linux32_sys_truncate64_args *uap, register_t *retval)
274 {
275 /* {
276 syscallarg(netbsd32_charp) path;
277 syscallarg(off_t) length;
278 } */
279 struct sys_truncate_args ua;
280
281 /* Linux doesn't have the 'pad' pseudo-parameter */
282 NETBSD32TOP_UAP(path, const char *);
283 SCARG(&ua, PAD) = 0;
284 SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo);
285 return sys_truncate(l, &ua, retval);
286 }
287
288 int
289 linux32_sys_ftruncate64(struct lwp *l, const struct linux32_sys_ftruncate64_args *uap, register_t *retval)
290 {
291 /* {
292 syscallarg(unsigned int) fd;
293 syscallarg(off_t) length;
294 } */
295 struct sys_ftruncate_args ua;
296
297 /* Linux doesn't have the 'pad' pseudo-parameter */
298 NETBSD32TO64_UAP(fd);
299 SCARG(&ua, PAD) = 0;
300 SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo);
301 return sys_ftruncate(l, &ua, retval);
302 }
303
304 int
305 linux32_sys_setdomainname(struct lwp *l, const struct linux32_sys_setdomainname_args *uap, register_t *retval)
306 {
307 /* {
308 syscallarg(netbsd32_charp) domainname;
309 syscallarg(int) len;
310 } */
311 struct linux_sys_setdomainname_args ua;
312
313 NETBSD32TOP_UAP(domainname, char);
314 NETBSD32TO64_UAP(len);
315 return linux_sys_setdomainname(l, &ua, retval);
316 }
317
318 int
319 linux32_sys_ppoll(struct lwp *l, const struct linux32_sys_ppoll_args *uap,
320 register_t *retval)
321 {
322 /* {
323 syscallarg(netbsd32_pollfdp_t) fds;
324 syscallarg(u_int) nfds;
325 syscallarg(linux32_timespecp_t) timeout;
326 syscallarg(linux32_sigsetp_t) sigset;
327 } */
328 struct linux32_timespec lts0, *lts;
329 struct timespec ts0, *ts = NULL;
330 linux32_sigset_t lsigmask0, *lsigmask;
331 sigset_t sigmask0, *sigmask = NULL;
332 int error;
333
334 lts = SCARG_P32(uap, timeout);
335 if (lts) {
336 if ((error = copyin(lts, <s0, sizeof(lts0))) != 0)
337 return error;
338 linux32_to_native_timespec(&ts0, <s0);
339 ts = &ts0;
340 }
341
342 lsigmask = SCARG_P32(uap, sigset);
343 if (lsigmask) {
344 if ((error = copyin(lsigmask, &lsigmask0, sizeof(lsigmask0))))
345 return error;
346 linux32_to_native_sigset(&sigmask0, &lsigmask0);
347 sigmask = &sigmask0;
348 }
349
350 return pollcommon(retval, SCARG_P32(uap, fds), SCARG(uap, nfds),
351 ts, sigmask);
352 }
353
354 int
355 linux32_sys_eventfd(struct lwp *l, const struct linux32_sys_eventfd_args *uap,
356 register_t *retval)
357 {
358 /* {
359 syscallarg(unsigned int) initval;
360 } */
361 struct linux_sys_eventfd_args ua;
362
363 NETBSD32TO64_UAP(initval);
364
365 return linux_sys_eventfd(l, &ua, retval);
366 }
367
368 int
369 linux32_sys_eventfd2(struct lwp *l, const struct linux32_sys_eventfd2_args *uap,
370 register_t *retval)
371 {
372 /* {
373 syscallarg(unsigned int) initval;
374 syscallarg(int) flags;
375 } */
376 struct linux_sys_eventfd2_args ua;
377
378 NETBSD32TO64_UAP(initval);
379 NETBSD32TO64_UAP(flags);
380
381 return linux_sys_eventfd2(l, &ua, retval);
382 }
383
384 static inline off_t
385 linux32_hilo_to_off_t(unsigned long hi, unsigned long lo)
386 {
387 return (((off_t)hi) << 32) | lo;
388 }
389
390 int
391 linux32_sys_preadv(struct lwp *l, const struct linux32_sys_preadv_args *uap,
392 register_t *retval)
393 {
394 /* {
395 syscallarg(int) fd;
396 syscallarg(const netbsd32_iovecp_t) iovp;
397 syscallarg(int) iovcnt;
398 syscallarg(netbsd32_u_long) off_lo;
399 syscallarg(netbsd32_u_long) off_hi;
400 } */
401 struct netbsd32_preadv_args ua;
402
403 SCARG(&ua, fd) = SCARG(uap, fd);
404 SCARG(&ua, iovp) = SCARG(uap, iovp);
405 SCARG(&ua, iovcnt) = SCARG(uap, iovcnt);
406 SCARG(&ua, PAD) = 0;
407 SCARG(&ua, offset) = linux32_hilo_to_off_t(SCARG(uap, off_hi),
408 SCARG(uap, off_lo));
409 return netbsd32_preadv(l, &ua, retval);
410 }
411
412 int
413 linux32_sys_pwritev(struct lwp *l, const struct linux32_sys_pwritev_args *uap,
414 register_t *retval)
415 {
416 /* {
417 syscallarg(int) fd;
418 syscallarg(const netbsd32_iovecp_t) iovp;
419 syscallarg(int) iovcnt;
420 syscallarg(netbsd32_u_long) off_lo;
421 syscallarg(netbsd32_u_long) off_hi;
422 } */
423 struct netbsd32_pwritev_args ua;
424
425 SCARG(&ua, fd) = SCARG(uap, fd);
426 SCARG(&ua, iovp) = SCARG(uap, iovp);
427 SCARG(&ua, iovcnt) = SCARG(uap, iovcnt);
428 SCARG(&ua, PAD) = 0;
429 SCARG(&ua, offset) = linux32_hilo_to_off_t(SCARG(uap, off_hi),
430 SCARG(uap, off_lo));
431 return netbsd32_pwritev(l, &ua, retval);
432 }
433