xref: /netbsd-src/sys/compat/linux32/common/linux32_misc.c (revision 122b5006ee1bd67145794b4cde92f4fe4781a5ec)
1 /*	$NetBSD: linux32_misc.c,v 1.33 2021/09/20 02:20:03 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.33 2021/09/20 02:20:03 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, &ltmp);
88 		error = copyout(&ltmp, 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, &ltmp);
110 		error = copyout(&ltmp, 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, &ltmp);
132 		error = copyout(&ltmp, 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, &ltmp);
154 		error = copyout(&ltmp, 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 		    &lts, sizeof(lts))) != 0) {
259 			return error;
260 		}
261 		linux32_to_native_timespec(&ts, &lts);
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, &lts0, sizeof(lts0))) != 0)
337 			return error;
338 		linux32_to_native_timespec(&ts0, &lts0);
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