xref: /netbsd-src/sys/compat/linux32/common/linux32_unistd.c (revision a536ee5124e62c9a0051a252f7833dc8f50f44c9)
1 /*	$NetBSD: linux32_unistd.c,v 1.35 2011/04/10 15:48:23 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Emmanuel Dreyfus
17  * 4. The name of the author may not be used to endorse or promote
18  *    products derived from this software without specific prior written
19  *    permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR 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 
36 __KERNEL_RCSID(0, "$NetBSD: linux32_unistd.c,v 1.35 2011/04/10 15:48:23 christos Exp $");
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/fstypes.h>
41 #include <sys/signal.h>
42 #include <sys/dirent.h>
43 #include <sys/kernel.h>
44 #include <sys/fcntl.h>
45 #include <sys/select.h>
46 #include <sys/proc.h>
47 #include <sys/ucred.h>
48 #include <sys/swap.h>
49 #include <sys/kauth.h>
50 #include <sys/filedesc.h>
51 
52 #include <machine/types.h>
53 
54 #include <sys/syscallargs.h>
55 
56 #include <compat/netbsd32/netbsd32.h>
57 #include <compat/netbsd32/netbsd32_conv.h>
58 
59 #include <compat/linux/common/linux_types.h>
60 #include <compat/linux/common/linux_signal.h>
61 #include <compat/linux/common/linux_machdep.h>
62 #include <compat/linux/common/linux_misc.h>
63 #include <compat/linux/common/linux_oldolduname.h>
64 #include <compat/linux/common/linux_ipc.h>
65 #include <compat/linux/common/linux_sem.h>
66 #include <compat/linux/common/linux_fcntl.h>
67 #include <compat/linux/linux_syscallargs.h>
68 
69 #include <compat/linux32/common/linux32_types.h>
70 #include <compat/linux32/common/linux32_signal.h>
71 #include <compat/linux32/common/linux32_machdep.h>
72 #include <compat/linux32/common/linux32_sysctl.h>
73 #include <compat/linux32/common/linux32_socketcall.h>
74 #include <compat/linux32/linux32_syscallargs.h>
75 
76 static int linux32_select1(struct lwp *, register_t *,
77     int, fd_set *, fd_set *, fd_set *, struct timeval *);
78 
79 int
80 linux32_sys_brk(struct lwp *l, const struct linux32_sys_brk_args *uap, register_t *retval)
81 {
82 	/* {
83 		syscallarg(netbsd32_charp) nsize;
84 	} */
85 	struct linux_sys_brk_args ua;
86 
87 	NETBSD32TOP_UAP(nsize, char);
88 	return linux_sys_brk(l, &ua, retval);
89 }
90 
91 int
92 linux32_sys_llseek(struct lwp *l, const struct linux32_sys_llseek_args *uap, register_t *retval)
93 {
94 	/* {
95 		syscallarg(int) fd;
96                 syscallarg(u_int32_t) ohigh;
97                 syscallarg(u_int32_t) olow;
98 		syscallarg(netbsd32_voidp) res;
99 		syscallarg(int) whence;
100 	} */
101 	struct linux_sys_llseek_args ua;
102 
103 	NETBSD32TO64_UAP(fd);
104 	NETBSD32TO64_UAP(ohigh);
105 	NETBSD32TO64_UAP(olow);
106 	NETBSD32TOP_UAP(res, void);
107 	NETBSD32TO64_UAP(whence);
108 
109 	return linux_sys_llseek(l, &ua, retval);
110 }
111 
112 int
113 linux32_sys_select(struct lwp *l, const struct linux32_sys_select_args *uap, register_t *retval)
114 {
115 	/* {
116 		syscallarg(int) nfds;
117 		syscallarg(netbsd32_fd_setp_t) readfds;
118 		syscallarg(netbsd32_fd_setp_t) writefds;
119 		syscallarg(netbsd32_fd_setp_t) exceptfds;
120 		syscallarg(netbsd32_timeval50p_t) timeout;
121 	} */
122 
123 	return linux32_select1(l, retval, SCARG(uap, nfds),
124 	    SCARG_P32(uap, readfds),
125 	    SCARG_P32(uap, writefds),
126 	    SCARG_P32(uap, exceptfds),
127 	    SCARG_P32(uap, timeout));
128 }
129 
130 int
131 linux32_sys_oldselect(struct lwp *l, const struct linux32_sys_oldselect_args *uap, register_t *retval)
132 {
133 	/* {
134 		syscallarg(linux32_oldselectp_t) lsp;
135 	} */
136 	struct linux32_oldselect lsp32;
137 	int error;
138 
139 	if ((error = copyin(SCARG_P32(uap, lsp), &lsp32, sizeof(lsp32))) != 0)
140 		return error;
141 
142 	return linux32_select1(l, retval, lsp32.nfds,
143 	     NETBSD32PTR64(lsp32.readfds), NETBSD32PTR64(lsp32.writefds),
144 	     NETBSD32PTR64(lsp32.exceptfds), NETBSD32PTR64(lsp32.timeout));
145 }
146 
147 static int
148 linux32_select1(struct lwp *l, register_t *retval, int nfds,
149 		fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
150 		struct timeval *timeout)
151 {
152 	struct timespec ts0, ts1, uts, *ts = NULL;
153 	struct netbsd32_timeval50 utv32;
154 	int error;
155 
156 
157 	/*
158 	 * Store current time for computation of the amount of
159 	 * time left.
160 	 */
161 	if (timeout) {
162 		if ((error = copyin(timeout, &utv32, sizeof(utv32))))
163 			return error;
164 
165 		uts.tv_sec = utv32.tv_sec;
166 		uts.tv_nsec = utv32.tv_usec * 1000;
167 
168 		if (itimespecfix(&uts)) {
169 			/*
170 			 * The timeval was invalid.  Convert it to something
171 			 * valid that will act as it does under Linux.
172 			 */
173 			uts.tv_sec += uts.tv_nsec / 1000000000;
174 			uts.tv_nsec %= 1000000000;
175 			if (uts.tv_nsec < 0) {
176 				uts.tv_sec -= 1;
177 				uts.tv_nsec += 1000000000;
178 			}
179 			if (uts.tv_sec < 0)
180 				timespecclear(&uts);
181 		}
182 		nanotime(&ts0);
183 		ts = &uts;
184 	} else
185 		timespecclear(&uts); /* XXX GCC4 */
186 
187 	error = selcommon(retval, nfds, readfds, writefds, exceptfds, ts, NULL);
188 
189 	if (error) {
190 		/*
191 		 * See fs/select.c in the Linux kernel.  Without this,
192 		 * Maelstrom doesn't work.
193 		 */
194 		if (error == ERESTART)
195 			error = EINTR;
196 		return error;
197 	}
198 
199 	if (timeout) {
200 		if (*retval) {
201 			/*
202 			 * Compute how much time was left of the timeout,
203 			 * by subtracting the current time and the time
204 			 * before we started the call, and subtracting
205 			 * that result from the user-supplied value.
206 			 */
207 			nanotime(&ts1);
208 			timespecsub(&ts1, &ts0, &ts1);
209 			timespecsub(&uts, &ts1, &uts);
210 			if (uts.tv_sec < 0)
211 				timespecclear(&uts);
212 		} else {
213 			timespecclear(&uts);
214 		}
215 
216 		utv32.tv_sec = uts.tv_sec;
217 		utv32.tv_usec = uts.tv_nsec / 1000;
218 
219 		if ((error = copyout(&utv32, timeout, sizeof(utv32))))
220 			return error;
221 	}
222 
223 	return 0;
224 }
225 
226 static int
227 linux32_pipe(struct lwp *l, int *fd, register_t *retval, int flags)
228 {
229 	/* {
230 		syscallarg(netbsd32_intp) fd;
231 	} */
232 	int error;
233 	int pfds[2];
234 
235 	pfds[0] = (int)retval[0];
236 	pfds[1] = (int)retval[1];
237 
238 	if ((error = copyout(pfds, fd, 2 * sizeof(*fd))) != 0)
239 		return error;
240 
241 	if (flags & LINUX_O_CLOEXEC) {
242 		fd_set_exclose(l, retval[0], true);
243 		fd_set_exclose(l, retval[1], true);
244 	}
245 	retval[0] = 0;
246 	retval[1] = 0;
247 
248 	return 0;
249 }
250 
251 int
252 linux32_sys_pipe(struct lwp *l, const struct linux32_sys_pipe_args *uap,
253     register_t *retval)
254 {
255 	int error;
256 	if ((error = pipe1(l, retval, 0)))
257 		return error;
258 	return linux32_pipe(l, SCARG_P32(uap, fd), retval, 0);
259 }
260 
261 int
262 linux32_sys_pipe2(struct lwp *l, const struct linux32_sys_pipe2_args *uap,
263     register_t *retval)
264 {
265 	int flag = 0;
266 	int error;
267 
268 	switch (SCARG(uap, flags)) {
269 	case LINUX_O_CLOEXEC:
270 		break;
271 	case LINUX_O_NONBLOCK:
272 	case LINUX_O_NONBLOCK|LINUX_O_CLOEXEC:
273 		flag = O_NONBLOCK;
274 		break;
275 	default:
276 		return EINVAL;
277 	}
278 
279 	if ((error = pipe1(l, retval, flag)))
280 		return error;
281 
282 	return linux32_pipe(l, SCARG_P32(uap, fd), retval, SCARG(uap, flags));
283 }
284 
285 int
286 linux32_sys_dup3(struct lwp *l, const struct linux32_sys_dup3_args *uap,
287     register_t *retval)
288 {
289 	/* {
290 		syscallarg(int) from;
291 		syscallarg(int) to;
292 		syscallarg(int) flags;
293 	} */
294 	struct sys_dup2_args ua;
295 	int error;
296 
297 	NETBSD32TO64_UAP(from);
298 	NETBSD32TO64_UAP(to);
299 
300 	if ((error = sys_dup2(l, &ua, retval)))
301 		return error;
302 
303 	if (SCARG(uap, flags) & LINUX_O_CLOEXEC)
304 		fd_set_exclose(l, SCARG(uap, to), true);
305 
306 	return 0;
307 }
308 
309 int
310 linux32_sys_unlink(struct lwp *l, const struct linux32_sys_unlink_args *uap, register_t *retval)
311 {
312 	/* {
313 		syscallarg(const netbsd32_charp) path;
314 	} */
315 	struct linux_sys_unlink_args ua;
316 
317 	NETBSD32TOP_UAP(path, const char);
318 
319 	return linux_sys_unlink(l, &ua, retval);
320 }
321 
322 int
323 linux32_sys_creat(struct lwp *l, const struct linux32_sys_creat_args *uap, register_t *retval)
324 {
325 	/* {
326 		syscallarg(const netbsd32_charp) path;
327 		syscallarg(int) mode;
328 	} */
329 	struct sys_open_args ua;
330 
331 	NETBSD32TOP_UAP(path, const char);
332 	SCARG(&ua, flags) = O_CREAT | O_TRUNC | O_WRONLY;
333 	NETBSD32TO64_UAP(mode);
334 
335 	return sys_open(l, &ua, retval);
336 }
337 
338 int
339 linux32_sys_mknod(struct lwp *l, const struct linux32_sys_mknod_args *uap, register_t *retval)
340 {
341 	/* {
342 		syscallarg(const netbsd32_charp) path;
343 		syscallarg(int) mode;
344 		syscallarg(int) dev;
345 	} */
346 	struct linux_sys_mknod_args ua;
347 
348 	NETBSD32TOP_UAP(path, const char);
349 	NETBSD32TO64_UAP(mode);
350 	NETBSD32TO64_UAP(dev);
351 
352 	return linux_sys_mknod(l, &ua, retval);
353 }
354 
355 int
356 linux32_sys_break(struct lwp *l, const struct linux32_sys_break_args *uap, register_t *retval)
357 {
358 #if 0
359 	/* {
360 		syscallarg(const netbsd32_charp) nsize;
361 	} */
362 #endif
363 
364 	return ENOSYS;
365 }
366 
367 int
368 linux32_sys_swapon(struct lwp *l, const struct linux32_sys_swapon_args *uap, register_t *retval)
369 {
370 	/* {
371 		syscallarg(const netbsd32_charp) name;
372 	} */
373 	struct sys_swapctl_args ua;
374 
375         SCARG(&ua, cmd) = SWAP_ON;
376         SCARG(&ua, arg) = SCARG_P32(uap, name);
377         SCARG(&ua, misc) = 0;   /* priority */
378         return (sys_swapctl(l, &ua, retval));
379 }
380 
381 int
382 linux32_sys_swapoff(struct lwp *l, const struct linux32_sys_swapoff_args *uap, register_t *retval)
383 {
384 	/* {
385 		syscallarg(const netbsd32_charp) path;
386 	} */
387 	struct sys_swapctl_args ua;
388 
389         SCARG(&ua, cmd) = SWAP_OFF;
390         SCARG(&ua, arg) = SCARG_P32(uap, path);
391         SCARG(&ua, misc) = 0;   /* priority */
392         return (sys_swapctl(l, &ua, retval));
393 }
394 
395 
396 int
397 linux32_sys_reboot(struct lwp *l, const struct linux32_sys_reboot_args *uap, register_t *retval)
398 {
399 	/* {
400 		syscallarg(int) magic1;
401 		syscallarg(int) magic2;
402 		syscallarg(int) cmd;
403 		syscallarg(netbsd32_voidp) arg;
404 	} */
405 	struct linux_sys_reboot_args ua;
406 
407 	NETBSD32TO64_UAP(magic1);
408 	NETBSD32TO64_UAP(magic2);
409 	NETBSD32TO64_UAP(cmd);
410 	NETBSD32TOP_UAP(arg, void);
411 
412 	return linux_sys_reboot(l, &ua, retval);
413 }
414 
415 int
416 linux32_sys_setresuid(struct lwp *l, const struct linux32_sys_setresuid_args *uap, register_t *retval)
417 {
418 	/* {
419 		syscallarg(uid_t) ruid;
420 		syscallarg(uid_t) euid;
421 		syscallarg(uid_t) suid;
422 	} */
423 	struct linux_sys_setresuid_args ua;
424 
425 	NETBSD32TO64_UAP(ruid);
426 	NETBSD32TO64_UAP(euid);
427 	NETBSD32TO64_UAP(suid);
428 
429 	return linux_sys_setresuid(l, &ua, retval);
430 }
431 
432 int
433 linux32_sys_getresuid(struct lwp *l, const struct linux32_sys_getresuid_args *uap, register_t *retval)
434 {
435 	/* {
436 		syscallarg(linux32_uidp_t) ruid;
437 		syscallarg(linux32_uidp_t) euid;
438 		syscallarg(linux32_uidp_t) suid;
439 	} */
440 	kauth_cred_t pc = l->l_cred;
441 	int error;
442 	uid_t uid;
443 
444 	uid = kauth_cred_getuid(pc);
445 	if ((error = copyout(&uid, SCARG_P32(uap, ruid), sizeof(uid_t))) != 0)
446 		return error;
447 
448 	uid = kauth_cred_geteuid(pc);
449 	if ((error = copyout(&uid, SCARG_P32(uap, euid), sizeof(uid_t))) != 0)
450 		return error;
451 
452 	uid = kauth_cred_getsvuid(pc);
453 	return copyout(&uid, SCARG_P32(uap, suid), sizeof(uid_t));
454 }
455 
456 int
457 linux32_sys_setresgid(struct lwp *l, const struct linux32_sys_setresgid_args *uap, register_t *retval)
458 {
459 	/* {
460 		syscallarg(gid_t) rgid;
461 		syscallarg(gid_t) egid;
462 		syscallarg(gid_t) sgid;
463 	} */
464 	struct linux_sys_setresgid_args ua;
465 
466 	NETBSD32TO64_UAP(rgid);
467 	NETBSD32TO64_UAP(egid);
468 	NETBSD32TO64_UAP(sgid);
469 
470 	return linux_sys_setresgid(l, &ua, retval);
471 }
472 
473 int
474 linux32_sys_getresgid(struct lwp *l, const struct linux32_sys_getresgid_args *uap, register_t *retval)
475 {
476 	/* {
477 		syscallarg(linux32_gidp_t) rgid;
478 		syscallarg(linux32_gidp_t) egid;
479 		syscallarg(linux32_gidp_t) sgid;
480 	} */
481 	kauth_cred_t pc = l->l_cred;
482 	int error;
483 	gid_t gid;
484 
485 	gid = kauth_cred_getgid(pc);
486 	if ((error = copyout(&gid, SCARG_P32(uap, rgid), sizeof(gid_t))) != 0)
487 		return error;
488 
489 	gid = kauth_cred_getegid(pc);
490 	if ((error = copyout(&gid, SCARG_P32(uap, egid), sizeof(gid_t))) != 0)
491 		return error;
492 
493 	gid = kauth_cred_getsvgid(pc);
494 	return copyout(&gid, SCARG_P32(uap, sgid), sizeof(gid_t));
495 }
496 
497 int
498 linux32_sys_nice(struct lwp *l, const struct linux32_sys_nice_args *uap, register_t *retval)
499 {
500 	/* {
501 		syscallarg(int) incr;
502 	} */
503 	struct proc *p = l->l_proc;
504 	struct sys_setpriority_args bsa;
505 	int error;
506 
507 	SCARG(&bsa, which) = PRIO_PROCESS;
508 	SCARG(&bsa, who) = 0;
509 	SCARG(&bsa, prio) = p->p_nice - NZERO + SCARG(uap, incr);
510 
511 	error = sys_setpriority(l, &bsa, retval);
512 	return (error) ? EPERM : 0;
513 }
514 
515 int
516 linux32_sys_alarm(struct lwp *l, const struct linux32_sys_alarm_args *uap, register_t *retval)
517 {
518 	/* {
519 		syscallarg(unsigned int) secs;
520 	} */
521 	struct linux_sys_alarm_args ua;
522 
523 	NETBSD32TO64_UAP(secs);
524 
525 	return linux_sys_alarm(l, &ua, retval);
526 }
527 
528 int
529 linux32_sys_fdatasync(struct lwp *l, const struct linux32_sys_fdatasync_args *uap, register_t *retval)
530 {
531 	/* {
532 		syscallarg(int) fd;
533 	} */
534 	struct linux_sys_fdatasync_args ua;
535 
536 	NETBSD32TO64_UAP(fd);
537 
538 	return linux_sys_fdatasync(l, &ua, retval);
539 }
540 
541 int
542 linux32_sys_setfsuid(struct lwp *l, const struct linux32_sys_setfsuid_args *uap, register_t *retval)
543 {
544 	/* {
545 		syscallarg(uid_t) uid;
546 	} */
547 	struct linux_sys_setfsuid_args ua;
548 
549 	NETBSD32TO64_UAP(uid);
550 
551 	return linux_sys_setfsuid(l, &ua, retval);
552 }
553 
554 int
555 linux32_sys_setfsgid(struct lwp *l, const struct linux32_sys_setfsgid_args *uap, register_t *retval)
556 {
557 	/* {
558 		syscallarg(gid_t) gid;
559 	} */
560 	struct linux_sys_setfsgid_args ua;
561 
562 	NETBSD32TO64_UAP(gid);
563 
564 	return linux_sys_setfsgid(l, &ua, retval);
565 }
566 
567 /*
568  * pread(2).
569  */
570 int
571 linux32_sys_pread(struct lwp *l,
572     const struct linux32_sys_pread_args *uap, register_t *retval)
573 {
574 	/* {
575 		syscallarg(int) fd;
576 		syscallarg(netbsd32_voidp) buf;
577 		syscallarg(netbsd32_size_t) nbyte;
578 		syscallarg(linux32_off_t) offset;
579 	} */
580 	struct sys_pread_args pra;
581 
582 	SCARG(&pra, fd) = SCARG(uap, fd);
583 	SCARG(&pra, buf) = SCARG_P32(uap, buf);
584 	SCARG(&pra, nbyte) = SCARG(uap, nbyte);
585 	SCARG(&pra, offset) = SCARG(uap, offset);
586 
587 	return sys_pread(l, &pra, retval);
588 }
589 
590 /*
591  * pwrite(2).
592  */
593 int
594 linux32_sys_pwrite(struct lwp *l,
595     const struct linux32_sys_pwrite_args *uap, register_t *retval)
596 {
597 	/* {
598 		syscallarg(int) fd;
599 		syscallarg(const netbsd32_voidp) buf;
600 		syscallarg(netbsd32_size_t) nbyte;
601 		syscallarg(linux32_off_t) offset;
602 	} */
603 	struct sys_pwrite_args pra;
604 
605 	SCARG(&pra, fd) = SCARG(uap, fd);
606 	SCARG(&pra, buf) = SCARG_P32(uap, buf);
607 	SCARG(&pra, nbyte) = SCARG(uap, nbyte);
608 	SCARG(&pra, offset) = SCARG(uap, offset);
609 
610 	return sys_pwrite(l, &pra, retval);
611 }
612 
613