1 /* $NetBSD: linux32_unistd.c,v 1.34 2009/11/11 09:48:51 rmind 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.34 2009/11/11 09:48:51 rmind 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 51 #include <machine/types.h> 52 53 #include <sys/syscallargs.h> 54 55 #include <compat/netbsd32/netbsd32.h> 56 #include <compat/netbsd32/netbsd32_conv.h> 57 58 #include <compat/linux/common/linux_types.h> 59 #include <compat/linux/common/linux_signal.h> 60 #include <compat/linux/common/linux_machdep.h> 61 #include <compat/linux/common/linux_misc.h> 62 #include <compat/linux/common/linux_oldolduname.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 #include <compat/linux32/common/linux32_types.h> 68 #include <compat/linux32/common/linux32_signal.h> 69 #include <compat/linux32/common/linux32_machdep.h> 70 #include <compat/linux32/common/linux32_sysctl.h> 71 #include <compat/linux32/common/linux32_socketcall.h> 72 #include <compat/linux32/linux32_syscallargs.h> 73 74 static int linux32_select1(struct lwp *, register_t *, 75 int, fd_set *, fd_set *, fd_set *, struct timeval *); 76 77 int 78 linux32_sys_brk(struct lwp *l, const struct linux32_sys_brk_args *uap, register_t *retval) 79 { 80 /* { 81 syscallarg(netbsd32_charp) nsize; 82 } */ 83 struct linux_sys_brk_args ua; 84 85 NETBSD32TOP_UAP(nsize, char); 86 return linux_sys_brk(l, &ua, retval); 87 } 88 89 int 90 linux32_sys_llseek(struct lwp *l, const struct linux32_sys_llseek_args *uap, register_t *retval) 91 { 92 /* { 93 syscallarg(int) fd; 94 syscallarg(u_int32_t) ohigh; 95 syscallarg(u_int32_t) olow; 96 syscallarg(netbsd32_voidp) res; 97 syscallarg(int) whence; 98 } */ 99 struct linux_sys_llseek_args ua; 100 101 NETBSD32TO64_UAP(fd); 102 NETBSD32TO64_UAP(ohigh); 103 NETBSD32TO64_UAP(olow); 104 NETBSD32TOP_UAP(res, void); 105 NETBSD32TO64_UAP(whence); 106 107 return linux_sys_llseek(l, &ua, retval); 108 } 109 110 int 111 linux32_sys_select(struct lwp *l, const struct linux32_sys_select_args *uap, register_t *retval) 112 { 113 /* { 114 syscallarg(int) nfds; 115 syscallarg(netbsd32_fd_setp_t) readfds; 116 syscallarg(netbsd32_fd_setp_t) writefds; 117 syscallarg(netbsd32_fd_setp_t) exceptfds; 118 syscallarg(netbsd32_timeval50p_t) timeout; 119 } */ 120 121 return linux32_select1(l, retval, SCARG(uap, nfds), 122 SCARG_P32(uap, readfds), 123 SCARG_P32(uap, writefds), 124 SCARG_P32(uap, exceptfds), 125 SCARG_P32(uap, timeout)); 126 } 127 128 int 129 linux32_sys_oldselect(struct lwp *l, const struct linux32_sys_oldselect_args *uap, register_t *retval) 130 { 131 /* { 132 syscallarg(linux32_oldselectp_t) lsp; 133 } */ 134 struct linux32_oldselect lsp32; 135 int error; 136 137 if ((error = copyin(SCARG_P32(uap, lsp), &lsp32, sizeof(lsp32))) != 0) 138 return error; 139 140 return linux32_select1(l, retval, lsp32.nfds, 141 NETBSD32PTR64(lsp32.readfds), NETBSD32PTR64(lsp32.writefds), 142 NETBSD32PTR64(lsp32.exceptfds), NETBSD32PTR64(lsp32.timeout)); 143 } 144 145 static int 146 linux32_select1(struct lwp *l, register_t *retval, int nfds, 147 fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 148 struct timeval *timeout) 149 { 150 struct timespec ts0, ts1, uts, *ts = NULL; 151 struct netbsd32_timeval50 utv32; 152 int error; 153 154 155 /* 156 * Store current time for computation of the amount of 157 * time left. 158 */ 159 if (timeout) { 160 if ((error = copyin(timeout, &utv32, sizeof(utv32)))) 161 return error; 162 163 uts.tv_sec = utv32.tv_sec; 164 uts.tv_nsec = utv32.tv_usec * 1000; 165 166 if (itimespecfix(&uts)) { 167 /* 168 * The timeval was invalid. Convert it to something 169 * valid that will act as it does under Linux. 170 */ 171 uts.tv_sec += uts.tv_nsec / 1000000000; 172 uts.tv_nsec %= 1000000000; 173 if (uts.tv_nsec < 0) { 174 uts.tv_sec -= 1; 175 uts.tv_nsec += 1000000000; 176 } 177 if (uts.tv_sec < 0) 178 timespecclear(&uts); 179 } 180 nanotime(&ts0); 181 ts = &uts; 182 } else 183 timespecclear(&uts); /* XXX GCC4 */ 184 185 error = selcommon(retval, nfds, readfds, writefds, exceptfds, ts, NULL); 186 187 if (error) { 188 /* 189 * See fs/select.c in the Linux kernel. Without this, 190 * Maelstrom doesn't work. 191 */ 192 if (error == ERESTART) 193 error = EINTR; 194 return error; 195 } 196 197 if (timeout) { 198 if (*retval) { 199 /* 200 * Compute how much time was left of the timeout, 201 * by subtracting the current time and the time 202 * before we started the call, and subtracting 203 * that result from the user-supplied value. 204 */ 205 nanotime(&ts1); 206 timespecsub(&ts1, &ts0, &ts1); 207 timespecsub(&uts, &ts1, &uts); 208 if (uts.tv_sec < 0) 209 timespecclear(&uts); 210 } else { 211 timespecclear(&uts); 212 } 213 214 utv32.tv_sec = uts.tv_sec; 215 utv32.tv_usec = uts.tv_nsec / 1000; 216 217 if ((error = copyout(&utv32, timeout, sizeof(utv32)))) 218 return error; 219 } 220 221 return 0; 222 } 223 224 int 225 linux32_sys_pipe(struct lwp *l, const struct linux32_sys_pipe_args *uap, register_t *retval) 226 { 227 /* { 228 syscallarg(netbsd32_intp) fd; 229 } */ 230 int error; 231 int pfds[2]; 232 233 if ((error = sys_pipe(l, 0, retval))) 234 return error; 235 236 pfds[0] = (int)retval[0]; 237 pfds[1] = (int)retval[1]; 238 239 if ((error = copyout(pfds, SCARG_P32(uap, fd), 2 * sizeof (int))) != 0) 240 return error; 241 242 retval[0] = 0; 243 retval[1] = 0; 244 245 return 0; 246 } 247 248 249 int 250 linux32_sys_unlink(struct lwp *l, const struct linux32_sys_unlink_args *uap, register_t *retval) 251 { 252 /* { 253 syscallarg(const netbsd32_charp) path; 254 } */ 255 struct linux_sys_unlink_args ua; 256 257 NETBSD32TOP_UAP(path, const char); 258 259 return linux_sys_unlink(l, &ua, retval); 260 } 261 262 int 263 linux32_sys_creat(struct lwp *l, const struct linux32_sys_creat_args *uap, register_t *retval) 264 { 265 /* { 266 syscallarg(const netbsd32_charp) path; 267 syscallarg(int) mode; 268 } */ 269 struct sys_open_args ua; 270 271 NETBSD32TOP_UAP(path, const char); 272 SCARG(&ua, flags) = O_CREAT | O_TRUNC | O_WRONLY; 273 NETBSD32TO64_UAP(mode); 274 275 return sys_open(l, &ua, retval); 276 } 277 278 int 279 linux32_sys_mknod(struct lwp *l, const struct linux32_sys_mknod_args *uap, register_t *retval) 280 { 281 /* { 282 syscallarg(const netbsd32_charp) path; 283 syscallarg(int) mode; 284 syscallarg(int) dev; 285 } */ 286 struct linux_sys_mknod_args ua; 287 288 NETBSD32TOP_UAP(path, const char); 289 NETBSD32TO64_UAP(mode); 290 NETBSD32TO64_UAP(dev); 291 292 return linux_sys_mknod(l, &ua, retval); 293 } 294 295 int 296 linux32_sys_break(struct lwp *l, const struct linux32_sys_break_args *uap, register_t *retval) 297 { 298 #if 0 299 /* { 300 syscallarg(const netbsd32_charp) nsize; 301 } */ 302 #endif 303 304 return ENOSYS; 305 } 306 307 int 308 linux32_sys_swapon(struct lwp *l, const struct linux32_sys_swapon_args *uap, register_t *retval) 309 { 310 /* { 311 syscallarg(const netbsd32_charp) name; 312 } */ 313 struct sys_swapctl_args ua; 314 315 SCARG(&ua, cmd) = SWAP_ON; 316 SCARG(&ua, arg) = SCARG_P32(uap, name); 317 SCARG(&ua, misc) = 0; /* priority */ 318 return (sys_swapctl(l, &ua, retval)); 319 } 320 321 int 322 linux32_sys_swapoff(struct lwp *l, const struct linux32_sys_swapoff_args *uap, register_t *retval) 323 { 324 /* { 325 syscallarg(const netbsd32_charp) path; 326 } */ 327 struct sys_swapctl_args ua; 328 329 SCARG(&ua, cmd) = SWAP_OFF; 330 SCARG(&ua, arg) = SCARG_P32(uap, path); 331 SCARG(&ua, misc) = 0; /* priority */ 332 return (sys_swapctl(l, &ua, retval)); 333 } 334 335 336 int 337 linux32_sys_reboot(struct lwp *l, const struct linux32_sys_reboot_args *uap, register_t *retval) 338 { 339 /* { 340 syscallarg(int) magic1; 341 syscallarg(int) magic2; 342 syscallarg(int) cmd; 343 syscallarg(netbsd32_voidp) arg; 344 } */ 345 struct linux_sys_reboot_args ua; 346 347 NETBSD32TO64_UAP(magic1); 348 NETBSD32TO64_UAP(magic2); 349 NETBSD32TO64_UAP(cmd); 350 NETBSD32TOP_UAP(arg, void); 351 352 return linux_sys_reboot(l, &ua, retval); 353 } 354 355 int 356 linux32_sys_setresuid(struct lwp *l, const struct linux32_sys_setresuid_args *uap, register_t *retval) 357 { 358 /* { 359 syscallarg(uid_t) ruid; 360 syscallarg(uid_t) euid; 361 syscallarg(uid_t) suid; 362 } */ 363 struct linux_sys_setresuid_args ua; 364 365 NETBSD32TO64_UAP(ruid); 366 NETBSD32TO64_UAP(euid); 367 NETBSD32TO64_UAP(suid); 368 369 return linux_sys_setresuid(l, &ua, retval); 370 } 371 372 int 373 linux32_sys_getresuid(struct lwp *l, const struct linux32_sys_getresuid_args *uap, register_t *retval) 374 { 375 /* { 376 syscallarg(linux32_uidp_t) ruid; 377 syscallarg(linux32_uidp_t) euid; 378 syscallarg(linux32_uidp_t) suid; 379 } */ 380 kauth_cred_t pc = l->l_cred; 381 int error; 382 uid_t uid; 383 384 uid = kauth_cred_getuid(pc); 385 if ((error = copyout(&uid, SCARG_P32(uap, ruid), sizeof(uid_t))) != 0) 386 return error; 387 388 uid = kauth_cred_geteuid(pc); 389 if ((error = copyout(&uid, SCARG_P32(uap, euid), sizeof(uid_t))) != 0) 390 return error; 391 392 uid = kauth_cred_getsvuid(pc); 393 return copyout(&uid, SCARG_P32(uap, suid), sizeof(uid_t)); 394 } 395 396 int 397 linux32_sys_setresgid(struct lwp *l, const struct linux32_sys_setresgid_args *uap, register_t *retval) 398 { 399 /* { 400 syscallarg(gid_t) rgid; 401 syscallarg(gid_t) egid; 402 syscallarg(gid_t) sgid; 403 } */ 404 struct linux_sys_setresgid_args ua; 405 406 NETBSD32TO64_UAP(rgid); 407 NETBSD32TO64_UAP(egid); 408 NETBSD32TO64_UAP(sgid); 409 410 return linux_sys_setresgid(l, &ua, retval); 411 } 412 413 int 414 linux32_sys_getresgid(struct lwp *l, const struct linux32_sys_getresgid_args *uap, register_t *retval) 415 { 416 /* { 417 syscallarg(linux32_gidp_t) rgid; 418 syscallarg(linux32_gidp_t) egid; 419 syscallarg(linux32_gidp_t) sgid; 420 } */ 421 kauth_cred_t pc = l->l_cred; 422 int error; 423 gid_t gid; 424 425 gid = kauth_cred_getgid(pc); 426 if ((error = copyout(&gid, SCARG_P32(uap, rgid), sizeof(gid_t))) != 0) 427 return error; 428 429 gid = kauth_cred_getegid(pc); 430 if ((error = copyout(&gid, SCARG_P32(uap, egid), sizeof(gid_t))) != 0) 431 return error; 432 433 gid = kauth_cred_getsvgid(pc); 434 return copyout(&gid, SCARG_P32(uap, sgid), sizeof(gid_t)); 435 } 436 437 int 438 linux32_sys_nice(struct lwp *l, const struct linux32_sys_nice_args *uap, register_t *retval) 439 { 440 /* { 441 syscallarg(int) incr; 442 } */ 443 struct proc *p = l->l_proc; 444 struct sys_setpriority_args bsa; 445 int error; 446 447 SCARG(&bsa, which) = PRIO_PROCESS; 448 SCARG(&bsa, who) = 0; 449 SCARG(&bsa, prio) = p->p_nice - NZERO + SCARG(uap, incr); 450 451 error = sys_setpriority(l, &bsa, retval); 452 return (error) ? EPERM : 0; 453 } 454 455 int 456 linux32_sys_alarm(struct lwp *l, const struct linux32_sys_alarm_args *uap, register_t *retval) 457 { 458 /* { 459 syscallarg(unsigned int) secs; 460 } */ 461 struct linux_sys_alarm_args ua; 462 463 NETBSD32TO64_UAP(secs); 464 465 return linux_sys_alarm(l, &ua, retval); 466 } 467 468 int 469 linux32_sys_fdatasync(struct lwp *l, const struct linux32_sys_fdatasync_args *uap, register_t *retval) 470 { 471 /* { 472 syscallarg(int) fd; 473 } */ 474 struct linux_sys_fdatasync_args ua; 475 476 NETBSD32TO64_UAP(fd); 477 478 return linux_sys_fdatasync(l, &ua, retval); 479 } 480 481 int 482 linux32_sys_setfsuid(struct lwp *l, const struct linux32_sys_setfsuid_args *uap, register_t *retval) 483 { 484 /* { 485 syscallarg(uid_t) uid; 486 } */ 487 struct linux_sys_setfsuid_args ua; 488 489 NETBSD32TO64_UAP(uid); 490 491 return linux_sys_setfsuid(l, &ua, retval); 492 } 493 494 int 495 linux32_sys_setfsgid(struct lwp *l, const struct linux32_sys_setfsgid_args *uap, register_t *retval) 496 { 497 /* { 498 syscallarg(gid_t) gid; 499 } */ 500 struct linux_sys_setfsgid_args ua; 501 502 NETBSD32TO64_UAP(gid); 503 504 return linux_sys_setfsgid(l, &ua, retval); 505 } 506 507 /* 508 * pread(2). 509 */ 510 int 511 linux32_sys_pread(struct lwp *l, 512 const struct linux32_sys_pread_args *uap, register_t *retval) 513 { 514 /* { 515 syscallarg(int) fd; 516 syscallarg(netbsd32_voidp) buf; 517 syscallarg(netbsd32_size_t) nbyte; 518 syscallarg(linux32_off_t) offset; 519 } */ 520 struct sys_pread_args pra; 521 522 SCARG(&pra, fd) = SCARG(uap, fd); 523 SCARG(&pra, buf) = SCARG_P32(uap, buf); 524 SCARG(&pra, nbyte) = SCARG(uap, nbyte); 525 SCARG(&pra, offset) = SCARG(uap, offset); 526 527 return sys_pread(l, &pra, retval); 528 } 529 530 /* 531 * pwrite(2). 532 */ 533 int 534 linux32_sys_pwrite(struct lwp *l, 535 const struct linux32_sys_pwrite_args *uap, register_t *retval) 536 { 537 /* { 538 syscallarg(int) fd; 539 syscallarg(const netbsd32_voidp) buf; 540 syscallarg(netbsd32_size_t) nbyte; 541 syscallarg(linux32_off_t) offset; 542 } */ 543 struct sys_pwrite_args pra; 544 545 SCARG(&pra, fd) = SCARG(uap, fd); 546 SCARG(&pra, buf) = SCARG_P32(uap, buf); 547 SCARG(&pra, nbyte) = SCARG(uap, nbyte); 548 SCARG(&pra, offset) = SCARG(uap, offset); 549 550 return sys_pwrite(l, &pra, retval); 551 } 552 553