1 /*	$NetBSD: linux32_misc.c,v 1.21 2010/11/02 18:18:07 chs 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.21 2010/11/02 18:18:07 chs 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/malloc.h>
42 #include <sys/fstypes.h>
43 #include <sys/vfs_syscalls.h>
44 #include <sys/ptrace.h>
45 #include <sys/syscall.h>
46 
47 #include <compat/netbsd32/netbsd32.h>
48 #include <compat/netbsd32/netbsd32_syscallargs.h>
49 
50 #include <compat/linux32/common/linux32_types.h>
51 #include <compat/linux32/common/linux32_signal.h>
52 #include <compat/linux32/linux32_syscallargs.h>
53 
54 #include <compat/linux/common/linux_ptrace.h>
55 #include <compat/linux/common/linux_types.h>
56 #include <compat/linux/common/linux_emuldata.h>
57 #include <compat/linux/common/linux_signal.h>
58 #include <compat/linux/common/linux_misc.h>
59 #include <compat/linux/common/linux_statfs.h>
60 #include <compat/linux/common/linux_ipc.h>
61 #include <compat/linux/common/linux_sem.h>
62 #include <compat/linux/common/linux_futex.h>
63 #include <compat/linux/linux_syscallargs.h>
64 
65 extern const struct linux_mnttypes linux_fstypes[];
66 extern const int linux_fstypes_cnt;
67 
68 void linux32_to_native_timespec(struct timespec *, struct linux32_timespec *);
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 linux_sys_futex_args ua;
245 	struct linux32_timespec lts;
246 	struct timespec ts = { 0, 0 };
247 	int error;
248 
249 	NETBSD32TOP_UAP(uaddr, int);
250 	NETBSD32TO64_UAP(op);
251 	NETBSD32TO64_UAP(val);
252 	NETBSD32TOP_UAP(timeout, struct linux_timespec);
253 	NETBSD32TOP_UAP(uaddr2, int);
254 	NETBSD32TO64_UAP(val3);
255 	if ((SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) == LINUX_FUTEX_WAIT &&
256 	    SCARG_P32(uap, timeout) != NULL) {
257 		if ((error = copyin((void *)SCARG_P32(uap, timeout),
258 		    &lts, sizeof(lts))) != 0) {
259 			return error;
260 		}
261 		linux32_to_native_timespec(&ts, &lts);
262 	}
263 	return linux_do_futex(l, &ua, retval, &ts);
264 }
265 
266 int
267 linux32_sys_set_robust_list(struct lwp *l,
268     const struct linux32_sys_set_robust_list_args *uap, register_t *retval)
269 {
270 	/* {
271 		syscallarg(linux32_robust_list_headp_t) head;
272 		syscallarg(linux32_size_t) len;
273 	} */
274 	struct linux_sys_set_robust_list_args ua;
275 	struct linux_emuldata *led;
276 
277 	if (SCARG(uap, len) != 12)
278 		return EINVAL;
279 
280 	NETBSD32TOP_UAP(head, struct robust_list_head);
281 	NETBSD32TOX64_UAP(len, size_t);
282 
283 	led = l->l_emuldata;
284 	led->led_robust_head = SCARG(&ua, head);
285 	*retval = 0;
286 	return 0;
287 }
288 
289 int
290 linux32_sys_get_robust_list(struct lwp *l,
291     const struct linux32_sys_get_robust_list_args *uap, register_t *retval)
292 {
293 	/* {
294 		syscallarg(linux32_robust_list_headpp_t) head;
295 		syscallarg(linux32_sizep_t) len;
296 	} */
297 	struct linux_sys_get_robust_list_args ua;
298 
299 	NETBSD32TOP_UAP(head, struct robust_list_head *);
300 	NETBSD32TOP_UAP(len, size_t *);
301 	return linux_sys_get_robust_list(l, &ua, retval);
302 }
303 
304 int
305 linux32_sys_truncate64(struct lwp *l, const struct linux32_sys_truncate64_args *uap, register_t *retval)
306 {
307 	/* {
308 		syscallarg(netbsd32_charp) path;
309 		syscallarg(off_t) length;
310 	} */
311 	struct sys_truncate_args ua;
312 
313 	/* Linux doesn't have the 'pad' pseudo-parameter */
314 	NETBSD32TOP_UAP(path, const char *);
315 	SCARG(&ua, PAD) = 0;
316 	SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo);
317 	return sys_truncate(l, &ua, retval);
318 }
319 
320 int
321 linux32_sys_ftruncate64(struct lwp *l, const struct linux32_sys_ftruncate64_args *uap, register_t *retval)
322 {
323 	/* {
324 		syscallarg(unsigned int) fd;
325 		syscallarg(off_t) length;
326 	} */
327 	struct sys_ftruncate_args ua;
328 
329 	/* Linux doesn't have the 'pad' pseudo-parameter */
330 	NETBSD32TO64_UAP(fd);
331 	SCARG(&ua, PAD) = 0;
332 	SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo);
333 	return sys_ftruncate(l, &ua, retval);
334 }
335 
336 int
337 linux32_sys_setdomainname(struct lwp *l, const struct linux32_sys_setdomainname_args *uap, register_t *retval)
338 {
339 	/* {
340 		syscallarg(netbsd32_charp) domainname;
341 		syscallarg(int) len;
342 	} */
343 	struct linux_sys_setdomainname_args ua;
344 
345 	NETBSD32TOP_UAP(domainname, char);
346 	NETBSD32TO64_UAP(len);
347 	return linux_sys_setdomainname(l, &ua, retval);
348 }
349