1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1994-1995 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_compat.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/capsicum.h> 37 #include <sys/conf.h> 38 #include <sys/dirent.h> 39 #include <sys/fcntl.h> 40 #include <sys/file.h> 41 #include <sys/filedesc.h> 42 #include <sys/lock.h> 43 #include <sys/malloc.h> 44 #include <sys/mman.h> 45 #include <sys/mount.h> 46 #include <sys/mutex.h> 47 #include <sys/namei.h> 48 #include <sys/proc.h> 49 #include <sys/stat.h> 50 #include <sys/sx.h> 51 #include <sys/syscallsubr.h> 52 #include <sys/sysproto.h> 53 #include <sys/tty.h> 54 #include <sys/unistd.h> 55 #include <sys/vnode.h> 56 57 #ifdef COMPAT_LINUX32 58 #include <compat/freebsd32/freebsd32_misc.h> 59 #include <machine/../linux32/linux.h> 60 #include <machine/../linux32/linux32_proto.h> 61 #else 62 #include <machine/../linux/linux.h> 63 #include <machine/../linux/linux_proto.h> 64 #endif 65 #include <compat/linux/linux_misc.h> 66 #include <compat/linux/linux_util.h> 67 #include <compat/linux/linux_file.h> 68 69 static int linux_common_open(struct thread *, int, const char *, int, int, 70 enum uio_seg); 71 static int linux_getdents_error(struct thread *, int, int); 72 73 static struct bsd_to_linux_bitmap seal_bitmap[] = { 74 BITMAP_1t1_LINUX(F_SEAL_SEAL), 75 BITMAP_1t1_LINUX(F_SEAL_SHRINK), 76 BITMAP_1t1_LINUX(F_SEAL_GROW), 77 BITMAP_1t1_LINUX(F_SEAL_WRITE), 78 }; 79 80 #define MFD_HUGETLB_ENTRY(_size) \ 81 { \ 82 .bsd_value = MFD_HUGE_##_size, \ 83 .linux_value = LINUX_HUGETLB_FLAG_ENCODE_##_size \ 84 } 85 static struct bsd_to_linux_bitmap mfd_bitmap[] = { 86 BITMAP_1t1_LINUX(MFD_CLOEXEC), 87 BITMAP_1t1_LINUX(MFD_ALLOW_SEALING), 88 BITMAP_1t1_LINUX(MFD_HUGETLB), 89 MFD_HUGETLB_ENTRY(64KB), 90 MFD_HUGETLB_ENTRY(512KB), 91 MFD_HUGETLB_ENTRY(1MB), 92 MFD_HUGETLB_ENTRY(2MB), 93 MFD_HUGETLB_ENTRY(8MB), 94 MFD_HUGETLB_ENTRY(16MB), 95 MFD_HUGETLB_ENTRY(32MB), 96 MFD_HUGETLB_ENTRY(256MB), 97 MFD_HUGETLB_ENTRY(512MB), 98 MFD_HUGETLB_ENTRY(1GB), 99 MFD_HUGETLB_ENTRY(2GB), 100 MFD_HUGETLB_ENTRY(16GB), 101 }; 102 #undef MFD_HUGETLB_ENTRY 103 104 #ifdef LINUX_LEGACY_SYSCALLS 105 int 106 linux_creat(struct thread *td, struct linux_creat_args *args) 107 { 108 char *path; 109 int error; 110 111 if (!LUSECONVPATH(td)) { 112 return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE, 113 O_WRONLY | O_CREAT | O_TRUNC, args->mode)); 114 } 115 LCONVPATHEXIST(td, args->path, &path); 116 error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE, 117 O_WRONLY | O_CREAT | O_TRUNC, args->mode); 118 LFREEPATH(path); 119 return (error); 120 } 121 #endif 122 123 static int 124 linux_common_openflags(int l_flags) 125 { 126 int bsd_flags; 127 128 bsd_flags = 0; 129 switch (l_flags & LINUX_O_ACCMODE) { 130 case LINUX_O_WRONLY: 131 bsd_flags |= O_WRONLY; 132 break; 133 case LINUX_O_RDWR: 134 bsd_flags |= O_RDWR; 135 break; 136 default: 137 bsd_flags |= O_RDONLY; 138 } 139 if (l_flags & LINUX_O_NDELAY) 140 bsd_flags |= O_NONBLOCK; 141 if (l_flags & LINUX_O_APPEND) 142 bsd_flags |= O_APPEND; 143 if (l_flags & LINUX_O_SYNC) 144 bsd_flags |= O_FSYNC; 145 if (l_flags & LINUX_O_CLOEXEC) 146 bsd_flags |= O_CLOEXEC; 147 if (l_flags & LINUX_O_NONBLOCK) 148 bsd_flags |= O_NONBLOCK; 149 if (l_flags & LINUX_O_ASYNC) 150 bsd_flags |= O_ASYNC; 151 if (l_flags & LINUX_O_CREAT) 152 bsd_flags |= O_CREAT; 153 if (l_flags & LINUX_O_TRUNC) 154 bsd_flags |= O_TRUNC; 155 if (l_flags & LINUX_O_EXCL) 156 bsd_flags |= O_EXCL; 157 if (l_flags & LINUX_O_NOCTTY) 158 bsd_flags |= O_NOCTTY; 159 if (l_flags & LINUX_O_DIRECT) 160 bsd_flags |= O_DIRECT; 161 if (l_flags & LINUX_O_NOFOLLOW) 162 bsd_flags |= O_NOFOLLOW; 163 if (l_flags & LINUX_O_DIRECTORY) 164 bsd_flags |= O_DIRECTORY; 165 if (l_flags & LINUX_O_PATH) 166 bsd_flags |= O_PATH; 167 /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 168 return (bsd_flags); 169 } 170 171 static int 172 linux_common_open(struct thread *td, int dirfd, const char *path, int l_flags, 173 int mode, enum uio_seg seg) 174 { 175 struct proc *p = td->td_proc; 176 struct file *fp; 177 int fd; 178 int bsd_flags, error; 179 180 bsd_flags = linux_common_openflags(l_flags); 181 error = kern_openat(td, dirfd, path, seg, bsd_flags, mode); 182 if (error != 0) { 183 if (error == EMLINK) 184 error = ELOOP; 185 goto done; 186 } 187 if (p->p_flag & P_CONTROLT) 188 goto done; 189 if (bsd_flags & O_NOCTTY) 190 goto done; 191 192 /* 193 * XXX In between kern_openat() and fget(), another process 194 * having the same filedesc could use that fd without 195 * checking below. 196 */ 197 fd = td->td_retval[0]; 198 if (fget(td, fd, &cap_ioctl_rights, &fp) == 0) { 199 if (fp->f_type != DTYPE_VNODE) { 200 fdrop(fp, td); 201 goto done; 202 } 203 sx_slock(&proctree_lock); 204 PROC_LOCK(p); 205 if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 206 PROC_UNLOCK(p); 207 sx_sunlock(&proctree_lock); 208 /* XXXPJD: Verify if TIOCSCTTY is allowed. */ 209 (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 210 td->td_ucred, td); 211 } else { 212 PROC_UNLOCK(p); 213 sx_sunlock(&proctree_lock); 214 } 215 fdrop(fp, td); 216 } 217 218 done: 219 return (error); 220 } 221 222 int 223 linux_openat(struct thread *td, struct linux_openat_args *args) 224 { 225 char *path; 226 int dfd, error; 227 228 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 229 if (!LUSECONVPATH(td)) { 230 return (linux_common_open(td, dfd, args->filename, args->flags, 231 args->mode, UIO_USERSPACE)); 232 } 233 if (args->flags & LINUX_O_CREAT) 234 LCONVPATH_AT(td, args->filename, &path, 1, dfd); 235 else 236 LCONVPATH_AT(td, args->filename, &path, 0, dfd); 237 238 error = linux_common_open(td, dfd, path, args->flags, args->mode, 239 UIO_SYSSPACE); 240 LFREEPATH(path); 241 return (error); 242 } 243 244 #ifdef LINUX_LEGACY_SYSCALLS 245 int 246 linux_open(struct thread *td, struct linux_open_args *args) 247 { 248 char *path; 249 int error; 250 251 if (!LUSECONVPATH(td)) { 252 return (linux_common_open(td, AT_FDCWD, args->path, args->flags, 253 args->mode, UIO_USERSPACE)); 254 } 255 if (args->flags & LINUX_O_CREAT) 256 LCONVPATHCREAT(td, args->path, &path); 257 else 258 LCONVPATHEXIST(td, args->path, &path); 259 260 error = linux_common_open(td, AT_FDCWD, path, args->flags, args->mode, 261 UIO_SYSSPACE); 262 LFREEPATH(path); 263 return (error); 264 } 265 #endif 266 267 int 268 linux_name_to_handle_at(struct thread *td, 269 struct linux_name_to_handle_at_args *args) 270 { 271 static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW | 272 LINUX_AT_EMPTY_PATH); 273 static const l_uint fh_size = sizeof(fhandle_t); 274 275 fhandle_t fh; 276 l_uint fh_bytes; 277 l_int mount_id; 278 int error, fd, bsd_flags; 279 280 if (args->flags & ~valid_flags) 281 return (EINVAL); 282 if (args->flags & LINUX_AT_EMPTY_PATH) 283 /* XXX: not supported yet */ 284 return (EOPNOTSUPP); 285 286 fd = args->dirfd; 287 if (fd == LINUX_AT_FDCWD) 288 fd = AT_FDCWD; 289 290 bsd_flags = 0; 291 if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW)) 292 bsd_flags |= AT_SYMLINK_NOFOLLOW; 293 294 if (!LUSECONVPATH(td)) { 295 error = kern_getfhat(td, bsd_flags, fd, args->name, 296 UIO_USERSPACE, &fh, UIO_SYSSPACE); 297 } else { 298 char *path; 299 300 LCONVPATH_AT(td, args->name, &path, 0, fd); 301 error = kern_getfhat(td, bsd_flags, fd, path, UIO_SYSSPACE, 302 &fh, UIO_SYSSPACE); 303 LFREEPATH(path); 304 } 305 if (error != 0) 306 return (error); 307 308 /* Emit mount_id -- required before EOVERFLOW case. */ 309 mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]); 310 error = copyout(&mount_id, args->mnt_id, sizeof(mount_id)); 311 if (error != 0) 312 return (error); 313 314 /* Check if there is room for handle. */ 315 error = copyin(&args->handle->handle_bytes, &fh_bytes, 316 sizeof(fh_bytes)); 317 if (error != 0) 318 return (error); 319 320 if (fh_bytes < fh_size) { 321 error = copyout(&fh_size, &args->handle->handle_bytes, 322 sizeof(fh_size)); 323 if (error == 0) 324 error = EOVERFLOW; 325 return (error); 326 } 327 328 /* Emit handle. */ 329 mount_id = 0; 330 /* 331 * We don't use handle_type for anything yet, but initialize a known 332 * value. 333 */ 334 error = copyout(&mount_id, &args->handle->handle_type, 335 sizeof(mount_id)); 336 if (error != 0) 337 return (error); 338 339 error = copyout(&fh, &args->handle->f_handle, 340 sizeof(fh)); 341 return (error); 342 } 343 344 int 345 linux_open_by_handle_at(struct thread *td, 346 struct linux_open_by_handle_at_args *args) 347 { 348 l_uint fh_bytes; 349 int bsd_flags, error; 350 351 error = copyin(&args->handle->handle_bytes, &fh_bytes, 352 sizeof(fh_bytes)); 353 if (error != 0) 354 return (error); 355 356 if (fh_bytes < sizeof(fhandle_t)) 357 return (EINVAL); 358 359 bsd_flags = linux_common_openflags(args->flags); 360 return (kern_fhopen(td, (void *)&args->handle->f_handle, bsd_flags)); 361 } 362 363 int 364 linux_lseek(struct thread *td, struct linux_lseek_args *args) 365 { 366 367 return (kern_lseek(td, args->fdes, args->off, args->whence)); 368 } 369 370 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 371 int 372 linux_llseek(struct thread *td, struct linux_llseek_args *args) 373 { 374 int error; 375 off_t off; 376 377 off = (args->olow) | (((off_t) args->ohigh) << 32); 378 379 error = kern_lseek(td, args->fd, off, args->whence); 380 if (error != 0) 381 return (error); 382 383 error = copyout(td->td_retval, args->res, sizeof(off_t)); 384 if (error != 0) 385 return (error); 386 387 td->td_retval[0] = 0; 388 return (0); 389 } 390 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 391 392 /* 393 * Note that linux_getdents(2) and linux_getdents64(2) have the same 394 * arguments. They only differ in the definition of struct dirent they 395 * operate on. 396 * Note that linux_readdir(2) is a special case of linux_getdents(2) 397 * where count is always equals 1, meaning that the buffer is one 398 * dirent-structure in size and that the code can't handle more anyway. 399 * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2) 400 * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will 401 * trash user stack. 402 */ 403 404 static int 405 linux_getdents_error(struct thread *td, int fd, int err) 406 { 407 struct vnode *vp; 408 struct file *fp; 409 int error; 410 411 /* Linux return ENOTDIR in case when fd is not a directory. */ 412 error = getvnode(td, fd, &cap_read_rights, &fp); 413 if (error != 0) 414 return (error); 415 vp = fp->f_vnode; 416 if (vp->v_type != VDIR) { 417 fdrop(fp, td); 418 return (ENOTDIR); 419 } 420 fdrop(fp, td); 421 return (err); 422 } 423 424 struct l_dirent { 425 l_ulong d_ino; 426 l_off_t d_off; 427 l_ushort d_reclen; 428 char d_name[LINUX_NAME_MAX + 1]; 429 }; 430 431 struct l_dirent64 { 432 uint64_t d_ino; 433 int64_t d_off; 434 l_ushort d_reclen; 435 u_char d_type; 436 char d_name[LINUX_NAME_MAX + 1]; 437 }; 438 439 /* 440 * Linux uses the last byte in the dirent buffer to store d_type, 441 * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes. 442 */ 443 #define LINUX_RECLEN(namlen) \ 444 roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong)) 445 446 #define LINUX_RECLEN64(namlen) \ 447 roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \ 448 sizeof(uint64_t)) 449 450 #ifdef LINUX_LEGACY_SYSCALLS 451 int 452 linux_getdents(struct thread *td, struct linux_getdents_args *args) 453 { 454 struct dirent *bdp; 455 caddr_t inp, buf; /* BSD-format */ 456 int len, reclen; /* BSD-format */ 457 caddr_t outp; /* Linux-format */ 458 int resid, linuxreclen; /* Linux-format */ 459 caddr_t lbuf; /* Linux-format */ 460 off_t base; 461 struct l_dirent *linux_dirent; 462 int buflen, error; 463 size_t retval; 464 465 buflen = min(args->count, MAXBSIZE); 466 buf = malloc(buflen, M_TEMP, M_WAITOK); 467 468 error = kern_getdirentries(td, args->fd, buf, buflen, 469 &base, NULL, UIO_SYSSPACE); 470 if (error != 0) { 471 error = linux_getdents_error(td, args->fd, error); 472 goto out1; 473 } 474 475 lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 476 477 len = td->td_retval[0]; 478 inp = buf; 479 outp = (caddr_t)args->dent; 480 resid = args->count; 481 retval = 0; 482 483 while (len > 0) { 484 bdp = (struct dirent *) inp; 485 reclen = bdp->d_reclen; 486 linuxreclen = LINUX_RECLEN(bdp->d_namlen); 487 /* 488 * No more space in the user supplied dirent buffer. 489 * Return EINVAL. 490 */ 491 if (resid < linuxreclen) { 492 error = EINVAL; 493 goto out; 494 } 495 496 linux_dirent = (struct l_dirent*)lbuf; 497 linux_dirent->d_ino = bdp->d_fileno; 498 linux_dirent->d_off = base + reclen; 499 linux_dirent->d_reclen = linuxreclen; 500 /* 501 * Copy d_type to last byte of l_dirent buffer 502 */ 503 lbuf[linuxreclen - 1] = bdp->d_type; 504 strlcpy(linux_dirent->d_name, bdp->d_name, 505 linuxreclen - offsetof(struct l_dirent, d_name)-1); 506 error = copyout(linux_dirent, outp, linuxreclen); 507 if (error != 0) 508 goto out; 509 510 inp += reclen; 511 base += reclen; 512 len -= reclen; 513 514 retval += linuxreclen; 515 outp += linuxreclen; 516 resid -= linuxreclen; 517 } 518 td->td_retval[0] = retval; 519 520 out: 521 free(lbuf, M_TEMP); 522 out1: 523 free(buf, M_TEMP); 524 return (error); 525 } 526 #endif 527 528 int 529 linux_getdents64(struct thread *td, struct linux_getdents64_args *args) 530 { 531 struct dirent *bdp; 532 caddr_t inp, buf; /* BSD-format */ 533 int len, reclen; /* BSD-format */ 534 caddr_t outp; /* Linux-format */ 535 int resid, linuxreclen; /* Linux-format */ 536 caddr_t lbuf; /* Linux-format */ 537 off_t base; 538 struct l_dirent64 *linux_dirent64; 539 int buflen, error; 540 size_t retval; 541 542 buflen = min(args->count, MAXBSIZE); 543 buf = malloc(buflen, M_TEMP, M_WAITOK); 544 545 error = kern_getdirentries(td, args->fd, buf, buflen, 546 &base, NULL, UIO_SYSSPACE); 547 if (error != 0) { 548 error = linux_getdents_error(td, args->fd, error); 549 goto out1; 550 } 551 552 lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 553 554 len = td->td_retval[0]; 555 inp = buf; 556 outp = (caddr_t)args->dirent; 557 resid = args->count; 558 retval = 0; 559 560 while (len > 0) { 561 bdp = (struct dirent *) inp; 562 reclen = bdp->d_reclen; 563 linuxreclen = LINUX_RECLEN64(bdp->d_namlen); 564 /* 565 * No more space in the user supplied dirent buffer. 566 * Return EINVAL. 567 */ 568 if (resid < linuxreclen) { 569 error = EINVAL; 570 goto out; 571 } 572 573 linux_dirent64 = (struct l_dirent64*)lbuf; 574 linux_dirent64->d_ino = bdp->d_fileno; 575 linux_dirent64->d_off = base + reclen; 576 linux_dirent64->d_reclen = linuxreclen; 577 linux_dirent64->d_type = bdp->d_type; 578 strlcpy(linux_dirent64->d_name, bdp->d_name, 579 linuxreclen - offsetof(struct l_dirent64, d_name)); 580 error = copyout(linux_dirent64, outp, linuxreclen); 581 if (error != 0) 582 goto out; 583 584 inp += reclen; 585 base += reclen; 586 len -= reclen; 587 588 retval += linuxreclen; 589 outp += linuxreclen; 590 resid -= linuxreclen; 591 } 592 td->td_retval[0] = retval; 593 594 out: 595 free(lbuf, M_TEMP); 596 out1: 597 free(buf, M_TEMP); 598 return (error); 599 } 600 601 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 602 int 603 linux_readdir(struct thread *td, struct linux_readdir_args *args) 604 { 605 struct dirent *bdp; 606 caddr_t buf; /* BSD-format */ 607 int linuxreclen; /* Linux-format */ 608 caddr_t lbuf; /* Linux-format */ 609 off_t base; 610 struct l_dirent *linux_dirent; 611 int buflen, error; 612 613 buflen = LINUX_RECLEN(LINUX_NAME_MAX); 614 buf = malloc(buflen, M_TEMP, M_WAITOK); 615 616 error = kern_getdirentries(td, args->fd, buf, buflen, 617 &base, NULL, UIO_SYSSPACE); 618 if (error != 0) { 619 error = linux_getdents_error(td, args->fd, error); 620 goto out; 621 } 622 if (td->td_retval[0] == 0) 623 goto out; 624 625 lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 626 627 bdp = (struct dirent *) buf; 628 linuxreclen = LINUX_RECLEN(bdp->d_namlen); 629 630 linux_dirent = (struct l_dirent*)lbuf; 631 linux_dirent->d_ino = bdp->d_fileno; 632 linux_dirent->d_off = linuxreclen; 633 linux_dirent->d_reclen = bdp->d_namlen; 634 strlcpy(linux_dirent->d_name, bdp->d_name, 635 linuxreclen - offsetof(struct l_dirent, d_name)); 636 error = copyout(linux_dirent, args->dent, linuxreclen); 637 if (error == 0) 638 td->td_retval[0] = linuxreclen; 639 640 free(lbuf, M_TEMP); 641 out: 642 free(buf, M_TEMP); 643 return (error); 644 } 645 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 646 647 /* 648 * These exist mainly for hooks for doing /compat/linux translation. 649 */ 650 651 #ifdef LINUX_LEGACY_SYSCALLS 652 int 653 linux_access(struct thread *td, struct linux_access_args *args) 654 { 655 char *path; 656 int error; 657 658 /* Linux convention. */ 659 if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 660 return (EINVAL); 661 662 if (!LUSECONVPATH(td)) { 663 error = kern_accessat(td, AT_FDCWD, args->path, UIO_USERSPACE, 0, 664 args->amode); 665 } else { 666 LCONVPATHEXIST(td, args->path, &path); 667 error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, 668 args->amode); 669 LFREEPATH(path); 670 } 671 672 return (error); 673 } 674 #endif 675 676 int 677 linux_faccessat(struct thread *td, struct linux_faccessat_args *args) 678 { 679 char *path; 680 int error, dfd; 681 682 /* Linux convention. */ 683 if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 684 return (EINVAL); 685 686 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 687 if (!LUSECONVPATH(td)) { 688 error = kern_accessat(td, dfd, args->filename, UIO_USERSPACE, 0, args->amode); 689 } else { 690 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 691 error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode); 692 LFREEPATH(path); 693 } 694 695 return (error); 696 } 697 698 #ifdef LINUX_LEGACY_SYSCALLS 699 int 700 linux_unlink(struct thread *td, struct linux_unlink_args *args) 701 { 702 char *path; 703 int error; 704 struct stat st; 705 706 if (!LUSECONVPATH(td)) { 707 error = kern_funlinkat(td, AT_FDCWD, args->path, FD_NONE, 708 UIO_USERSPACE, 0, 0); 709 if (error == EPERM) { 710 /* Introduce POSIX noncompliant behaviour of Linux */ 711 if (kern_statat(td, 0, AT_FDCWD, args->path, 712 UIO_SYSSPACE, &st, NULL) == 0) { 713 if (S_ISDIR(st.st_mode)) 714 error = EISDIR; 715 } 716 } 717 } else { 718 LCONVPATHEXIST(td, args->path, &path); 719 error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0); 720 if (error == EPERM) { 721 /* Introduce POSIX noncompliant behaviour of Linux */ 722 if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st, 723 NULL) == 0) { 724 if (S_ISDIR(st.st_mode)) 725 error = EISDIR; 726 } 727 } 728 LFREEPATH(path); 729 } 730 731 return (error); 732 } 733 #endif 734 735 static int 736 linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path, 737 int dfd, struct linux_unlinkat_args *args) 738 { 739 struct stat st; 740 int error; 741 742 if (args->flag & LINUX_AT_REMOVEDIR) 743 error = kern_frmdirat(td, dfd, path, FD_NONE, pathseg, 0); 744 else 745 error = kern_funlinkat(td, dfd, path, FD_NONE, pathseg, 0, 0); 746 if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { 747 /* Introduce POSIX noncompliant behaviour of Linux */ 748 if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, 749 UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode)) 750 error = EISDIR; 751 } 752 return (error); 753 } 754 755 int 756 linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) 757 { 758 char *path; 759 int error, dfd; 760 761 if (args->flag & ~LINUX_AT_REMOVEDIR) 762 return (EINVAL); 763 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 764 if (!LUSECONVPATH(td)) { 765 return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname, 766 dfd, args)); 767 } 768 LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 769 error = linux_unlinkat_impl(td, UIO_SYSSPACE, path, dfd, args); 770 LFREEPATH(path); 771 return (error); 772 } 773 int 774 linux_chdir(struct thread *td, struct linux_chdir_args *args) 775 { 776 char *path; 777 int error; 778 779 if (!LUSECONVPATH(td)) { 780 return (kern_chdir(td, args->path, UIO_USERSPACE)); 781 } 782 LCONVPATHEXIST(td, args->path, &path); 783 error = kern_chdir(td, path, UIO_SYSSPACE); 784 LFREEPATH(path); 785 return (error); 786 } 787 788 #ifdef LINUX_LEGACY_SYSCALLS 789 int 790 linux_chmod(struct thread *td, struct linux_chmod_args *args) 791 { 792 char *path; 793 int error; 794 795 if (!LUSECONVPATH(td)) { 796 return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE, 797 args->mode, 0)); 798 } 799 LCONVPATHEXIST(td, args->path, &path); 800 error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, 0); 801 LFREEPATH(path); 802 return (error); 803 } 804 #endif 805 806 int 807 linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) 808 { 809 char *path; 810 int error, dfd; 811 812 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 813 if (!LUSECONVPATH(td)) { 814 return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE, 815 args->mode, 0)); 816 } 817 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 818 error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); 819 LFREEPATH(path); 820 return (error); 821 } 822 823 #ifdef LINUX_LEGACY_SYSCALLS 824 int 825 linux_mkdir(struct thread *td, struct linux_mkdir_args *args) 826 { 827 char *path; 828 int error; 829 830 if (!LUSECONVPATH(td)) { 831 return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode)); 832 } 833 LCONVPATHCREAT(td, args->path, &path); 834 error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode); 835 LFREEPATH(path); 836 return (error); 837 } 838 #endif 839 840 int 841 linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) 842 { 843 char *path; 844 int error, dfd; 845 846 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 847 if (!LUSECONVPATH(td)) { 848 return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode)); 849 } 850 LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); 851 error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); 852 LFREEPATH(path); 853 return (error); 854 } 855 856 #ifdef LINUX_LEGACY_SYSCALLS 857 int 858 linux_rmdir(struct thread *td, struct linux_rmdir_args *args) 859 { 860 char *path; 861 int error; 862 863 if (!LUSECONVPATH(td)) { 864 return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE, 865 UIO_USERSPACE, 0)); 866 } 867 LCONVPATHEXIST(td, args->path, &path); 868 error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0); 869 LFREEPATH(path); 870 return (error); 871 } 872 873 int 874 linux_rename(struct thread *td, struct linux_rename_args *args) 875 { 876 char *from, *to; 877 int error; 878 879 if (!LUSECONVPATH(td)) { 880 return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD, 881 args->to, UIO_USERSPACE)); 882 } 883 LCONVPATHEXIST(td, args->from, &from); 884 /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 885 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 886 if (to == NULL) { 887 LFREEPATH(from); 888 return (error); 889 } 890 error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE); 891 LFREEPATH(from); 892 LFREEPATH(to); 893 return (error); 894 } 895 #endif 896 897 int 898 linux_renameat(struct thread *td, struct linux_renameat_args *args) 899 { 900 struct linux_renameat2_args renameat2_args = { 901 .olddfd = args->olddfd, 902 .oldname = args->oldname, 903 .newdfd = args->newdfd, 904 .newname = args->newname, 905 .flags = 0 906 }; 907 908 return (linux_renameat2(td, &renameat2_args)); 909 } 910 911 int 912 linux_renameat2(struct thread *td, struct linux_renameat2_args *args) 913 { 914 char *from, *to; 915 int error, olddfd, newdfd; 916 917 if (args->flags != 0) { 918 if (args->flags & ~(LINUX_RENAME_EXCHANGE | 919 LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT)) 920 return (EINVAL); 921 if (args->flags & LINUX_RENAME_EXCHANGE && 922 args->flags & (LINUX_RENAME_NOREPLACE | 923 LINUX_RENAME_WHITEOUT)) 924 return (EINVAL); 925 #if 0 926 /* 927 * This spams the console on Ubuntu Focal. 928 * 929 * What's needed here is a general mechanism to let users know 930 * about missing features without hogging the system. 931 */ 932 linux_msg(td, "renameat2 unsupported flags 0x%x", 933 args->flags); 934 #endif 935 return (EINVAL); 936 } 937 938 olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 939 newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 940 if (!LUSECONVPATH(td)) { 941 return (kern_renameat(td, olddfd, args->oldname, newdfd, 942 args->newname, UIO_USERSPACE)); 943 } 944 LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd); 945 /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 946 error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 947 if (to == NULL) { 948 LFREEPATH(from); 949 return (error); 950 } 951 error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); 952 LFREEPATH(from); 953 LFREEPATH(to); 954 return (error); 955 } 956 957 #ifdef LINUX_LEGACY_SYSCALLS 958 int 959 linux_symlink(struct thread *td, struct linux_symlink_args *args) 960 { 961 char *path, *to; 962 int error; 963 964 if (!LUSECONVPATH(td)) { 965 return (kern_symlinkat(td, args->path, AT_FDCWD, args->to, 966 UIO_USERSPACE)); 967 } 968 LCONVPATHEXIST(td, args->path, &path); 969 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 970 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 971 if (to == NULL) { 972 LFREEPATH(path); 973 return (error); 974 } 975 error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE); 976 LFREEPATH(path); 977 LFREEPATH(to); 978 return (error); 979 } 980 #endif 981 982 int 983 linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) 984 { 985 char *path, *to; 986 int error, dfd; 987 988 dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 989 if (!LUSECONVPATH(td)) { 990 return (kern_symlinkat(td, args->oldname, dfd, args->newname, 991 UIO_USERSPACE)); 992 } 993 LCONVPATHEXIST(td, args->oldname, &path); 994 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 995 error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); 996 if (to == NULL) { 997 LFREEPATH(path); 998 return (error); 999 } 1000 error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); 1001 LFREEPATH(path); 1002 LFREEPATH(to); 1003 return (error); 1004 } 1005 1006 #ifdef LINUX_LEGACY_SYSCALLS 1007 int 1008 linux_readlink(struct thread *td, struct linux_readlink_args *args) 1009 { 1010 char *name; 1011 int error; 1012 1013 if (!LUSECONVPATH(td)) { 1014 return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE, 1015 args->buf, UIO_USERSPACE, args->count)); 1016 } 1017 LCONVPATHEXIST(td, args->name, &name); 1018 error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE, 1019 args->buf, UIO_USERSPACE, args->count); 1020 LFREEPATH(name); 1021 return (error); 1022 } 1023 #endif 1024 1025 int 1026 linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) 1027 { 1028 char *name; 1029 int error, dfd; 1030 1031 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 1032 if (!LUSECONVPATH(td)) { 1033 return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE, 1034 args->buf, UIO_USERSPACE, args->bufsiz)); 1035 } 1036 LCONVPATHEXIST_AT(td, args->path, &name, dfd); 1037 error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, 1038 UIO_USERSPACE, args->bufsiz); 1039 LFREEPATH(name); 1040 return (error); 1041 } 1042 1043 int 1044 linux_truncate(struct thread *td, struct linux_truncate_args *args) 1045 { 1046 char *path; 1047 int error; 1048 1049 if (!LUSECONVPATH(td)) { 1050 return (kern_truncate(td, args->path, UIO_USERSPACE, args->length)); 1051 } 1052 LCONVPATHEXIST(td, args->path, &path); 1053 error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 1054 LFREEPATH(path); 1055 return (error); 1056 } 1057 1058 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1059 int 1060 linux_truncate64(struct thread *td, struct linux_truncate64_args *args) 1061 { 1062 char *path; 1063 off_t length; 1064 int error; 1065 1066 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1067 length = PAIR32TO64(off_t, args->length); 1068 #else 1069 length = args->length; 1070 #endif 1071 1072 if (!LUSECONVPATH(td)) { 1073 return (kern_truncate(td, args->path, UIO_USERSPACE, length)); 1074 } 1075 LCONVPATHEXIST(td, args->path, &path); 1076 error = kern_truncate(td, path, UIO_SYSSPACE, length); 1077 LFREEPATH(path); 1078 return (error); 1079 } 1080 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1081 1082 int 1083 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 1084 { 1085 1086 return (kern_ftruncate(td, args->fd, args->length)); 1087 } 1088 1089 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1090 int 1091 linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args) 1092 { 1093 off_t length; 1094 1095 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1096 length = PAIR32TO64(off_t, args->length); 1097 #else 1098 length = args->length; 1099 #endif 1100 1101 return (kern_ftruncate(td, args->fd, length)); 1102 } 1103 #endif 1104 1105 #ifdef LINUX_LEGACY_SYSCALLS 1106 int 1107 linux_link(struct thread *td, struct linux_link_args *args) 1108 { 1109 char *path, *to; 1110 int error; 1111 1112 if (!LUSECONVPATH(td)) { 1113 return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to, 1114 UIO_USERSPACE, AT_SYMLINK_FOLLOW)); 1115 } 1116 LCONVPATHEXIST(td, args->path, &path); 1117 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 1118 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 1119 if (to == NULL) { 1120 LFREEPATH(path); 1121 return (error); 1122 } 1123 error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE, 1124 AT_SYMLINK_FOLLOW); 1125 LFREEPATH(path); 1126 LFREEPATH(to); 1127 return (error); 1128 } 1129 #endif 1130 1131 int 1132 linux_linkat(struct thread *td, struct linux_linkat_args *args) 1133 { 1134 char *path, *to; 1135 int error, olddfd, newdfd, flag; 1136 1137 if (args->flag & ~(LINUX_AT_SYMLINK_FOLLOW | LINUX_AT_EMPTY_PATH)) 1138 return (EINVAL); 1139 1140 flag = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? AT_SYMLINK_FOLLOW : 1141 0; 1142 flag |= (args->flag & LINUX_AT_EMPTY_PATH) == 0 ? AT_EMPTY_PATH : 0; 1143 1144 olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 1145 newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 1146 if (!LUSECONVPATH(td)) { 1147 return (kern_linkat(td, olddfd, newdfd, args->oldname, 1148 args->newname, UIO_USERSPACE, flag)); 1149 } 1150 LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); 1151 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 1152 error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 1153 if (to == NULL) { 1154 LFREEPATH(path); 1155 return (error); 1156 } 1157 error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, flag); 1158 LFREEPATH(path); 1159 LFREEPATH(to); 1160 return (error); 1161 } 1162 1163 int 1164 linux_fdatasync(struct thread *td, struct linux_fdatasync_args *uap) 1165 { 1166 1167 return (kern_fsync(td, uap->fd, false)); 1168 } 1169 1170 int 1171 linux_sync_file_range(struct thread *td, struct linux_sync_file_range_args *uap) 1172 { 1173 off_t nbytes, offset; 1174 1175 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1176 nbytes = PAIR32TO64(off_t, uap->nbytes); 1177 offset = PAIR32TO64(off_t, uap->offset); 1178 #else 1179 nbytes = uap->nbytes; 1180 offset = uap->offset; 1181 #endif 1182 1183 if (offset < 0 || nbytes < 0 || 1184 (uap->flags & ~(LINUX_SYNC_FILE_RANGE_WAIT_BEFORE | 1185 LINUX_SYNC_FILE_RANGE_WRITE | 1186 LINUX_SYNC_FILE_RANGE_WAIT_AFTER)) != 0) { 1187 return (EINVAL); 1188 } 1189 1190 return (kern_fsync(td, uap->fd, false)); 1191 } 1192 1193 int 1194 linux_pread(struct thread *td, struct linux_pread_args *uap) 1195 { 1196 struct vnode *vp; 1197 off_t offset; 1198 int error; 1199 1200 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1201 offset = PAIR32TO64(off_t, uap->offset); 1202 #else 1203 offset = uap->offset; 1204 #endif 1205 1206 error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, offset); 1207 if (error == 0) { 1208 /* This seems to violate POSIX but Linux does it. */ 1209 error = fgetvp(td, uap->fd, &cap_pread_rights, &vp); 1210 if (error != 0) 1211 return (error); 1212 if (vp->v_type == VDIR) 1213 error = EISDIR; 1214 vrele(vp); 1215 } 1216 return (error); 1217 } 1218 1219 int 1220 linux_pwrite(struct thread *td, struct linux_pwrite_args *uap) 1221 { 1222 off_t offset; 1223 1224 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1225 offset = PAIR32TO64(off_t, uap->offset); 1226 #else 1227 offset = uap->offset; 1228 #endif 1229 1230 return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset)); 1231 } 1232 1233 int 1234 linux_preadv(struct thread *td, struct linux_preadv_args *uap) 1235 { 1236 struct uio *auio; 1237 int error; 1238 off_t offset; 1239 1240 /* 1241 * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES 1242 * pos_l and pos_h, respectively, contain the 1243 * low order and high order 32 bits of offset. 1244 */ 1245 offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << 1246 (sizeof(offset) * 4)) | uap->pos_l; 1247 if (offset < 0) 1248 return (EINVAL); 1249 #ifdef COMPAT_LINUX32 1250 error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); 1251 #else 1252 error = copyinuio(uap->vec, uap->vlen, &auio); 1253 #endif 1254 if (error != 0) 1255 return (error); 1256 error = kern_preadv(td, uap->fd, auio, offset); 1257 free(auio, M_IOV); 1258 return (error); 1259 } 1260 1261 int 1262 linux_pwritev(struct thread *td, struct linux_pwritev_args *uap) 1263 { 1264 struct uio *auio; 1265 int error; 1266 off_t offset; 1267 1268 /* 1269 * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES 1270 * pos_l and pos_h, respectively, contain the 1271 * low order and high order 32 bits of offset. 1272 */ 1273 offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << 1274 (sizeof(offset) * 4)) | uap->pos_l; 1275 if (offset < 0) 1276 return (EINVAL); 1277 #ifdef COMPAT_LINUX32 1278 error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); 1279 #else 1280 error = copyinuio(uap->vec, uap->vlen, &auio); 1281 #endif 1282 if (error != 0) 1283 return (error); 1284 error = kern_pwritev(td, uap->fd, auio, offset); 1285 free(auio, M_IOV); 1286 return (error); 1287 } 1288 1289 int 1290 linux_mount(struct thread *td, struct linux_mount_args *args) 1291 { 1292 struct mntarg *ma = NULL; 1293 char *fstypename, *mntonname, *mntfromname, *data; 1294 int error, fsflags; 1295 1296 fstypename = malloc(MNAMELEN, M_TEMP, M_WAITOK); 1297 mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK); 1298 mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK); 1299 data = NULL; 1300 error = copyinstr(args->filesystemtype, fstypename, MNAMELEN - 1, 1301 NULL); 1302 if (error != 0) 1303 goto out; 1304 if (args->specialfile != NULL) { 1305 error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 1306 if (error != 0) 1307 goto out; 1308 } else { 1309 mntfromname[0] = '\0'; 1310 } 1311 error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 1312 if (error != 0) 1313 goto out; 1314 1315 if (strcmp(fstypename, "ext2") == 0) { 1316 strcpy(fstypename, "ext2fs"); 1317 } else if (strcmp(fstypename, "proc") == 0) { 1318 strcpy(fstypename, "linprocfs"); 1319 } else if (strcmp(fstypename, "vfat") == 0) { 1320 strcpy(fstypename, "msdosfs"); 1321 } else if (strcmp(fstypename, "fuse") == 0) { 1322 char *fuse_options, *fuse_option, *fuse_name; 1323 1324 if (strcmp(mntfromname, "fuse") == 0) 1325 strcpy(mntfromname, "/dev/fuse"); 1326 1327 strcpy(fstypename, "fusefs"); 1328 data = malloc(MNAMELEN, M_TEMP, M_WAITOK); 1329 error = copyinstr(args->data, data, MNAMELEN - 1, NULL); 1330 if (error != 0) 1331 goto out; 1332 1333 fuse_options = data; 1334 while ((fuse_option = strsep(&fuse_options, ",")) != NULL) { 1335 fuse_name = strsep(&fuse_option, "="); 1336 if (fuse_name == NULL || fuse_option == NULL) 1337 goto out; 1338 ma = mount_arg(ma, fuse_name, fuse_option, -1); 1339 } 1340 1341 /* 1342 * The FUSE server uses Linux errno values instead of FreeBSD 1343 * ones; add a flag to tell fuse(4) to do errno translation. 1344 */ 1345 ma = mount_arg(ma, "linux_errnos", "1", -1); 1346 } 1347 1348 fsflags = 0; 1349 1350 /* 1351 * Linux SYNC flag is not included; the closest equivalent 1352 * FreeBSD has is !ASYNC, which is our default. 1353 */ 1354 if (args->rwflag & LINUX_MS_RDONLY) 1355 fsflags |= MNT_RDONLY; 1356 if (args->rwflag & LINUX_MS_NOSUID) 1357 fsflags |= MNT_NOSUID; 1358 if (args->rwflag & LINUX_MS_NOEXEC) 1359 fsflags |= MNT_NOEXEC; 1360 if (args->rwflag & LINUX_MS_REMOUNT) 1361 fsflags |= MNT_UPDATE; 1362 1363 ma = mount_arg(ma, "fstype", fstypename, -1); 1364 ma = mount_arg(ma, "fspath", mntonname, -1); 1365 ma = mount_arg(ma, "from", mntfromname, -1); 1366 error = kernel_mount(ma, fsflags); 1367 out: 1368 free(fstypename, M_TEMP); 1369 free(mntonname, M_TEMP); 1370 free(mntfromname, M_TEMP); 1371 free(data, M_TEMP); 1372 return (error); 1373 } 1374 1375 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1376 int 1377 linux_oldumount(struct thread *td, struct linux_oldumount_args *args) 1378 { 1379 1380 return (kern_unmount(td, args->path, 0)); 1381 } 1382 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1383 1384 #ifdef LINUX_LEGACY_SYSCALLS 1385 int 1386 linux_umount(struct thread *td, struct linux_umount_args *args) 1387 { 1388 int flags; 1389 1390 flags = 0; 1391 if ((args->flags & LINUX_MNT_FORCE) != 0) { 1392 args->flags &= ~LINUX_MNT_FORCE; 1393 flags |= MNT_FORCE; 1394 } 1395 if (args->flags != 0) { 1396 linux_msg(td, "unsupported umount2 flags %#x", args->flags); 1397 return (EINVAL); 1398 } 1399 1400 return (kern_unmount(td, args->path, flags)); 1401 } 1402 #endif 1403 1404 /* 1405 * fcntl family of syscalls 1406 */ 1407 1408 struct l_flock { 1409 l_short l_type; 1410 l_short l_whence; 1411 l_off_t l_start; 1412 l_off_t l_len; 1413 l_pid_t l_pid; 1414 } 1415 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1416 __packed 1417 #endif 1418 ; 1419 1420 static void 1421 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 1422 { 1423 switch (linux_flock->l_type) { 1424 case LINUX_F_RDLCK: 1425 bsd_flock->l_type = F_RDLCK; 1426 break; 1427 case LINUX_F_WRLCK: 1428 bsd_flock->l_type = F_WRLCK; 1429 break; 1430 case LINUX_F_UNLCK: 1431 bsd_flock->l_type = F_UNLCK; 1432 break; 1433 default: 1434 bsd_flock->l_type = -1; 1435 break; 1436 } 1437 bsd_flock->l_whence = linux_flock->l_whence; 1438 bsd_flock->l_start = (off_t)linux_flock->l_start; 1439 bsd_flock->l_len = (off_t)linux_flock->l_len; 1440 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1441 bsd_flock->l_sysid = 0; 1442 } 1443 1444 static void 1445 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 1446 { 1447 switch (bsd_flock->l_type) { 1448 case F_RDLCK: 1449 linux_flock->l_type = LINUX_F_RDLCK; 1450 break; 1451 case F_WRLCK: 1452 linux_flock->l_type = LINUX_F_WRLCK; 1453 break; 1454 case F_UNLCK: 1455 linux_flock->l_type = LINUX_F_UNLCK; 1456 break; 1457 } 1458 linux_flock->l_whence = bsd_flock->l_whence; 1459 linux_flock->l_start = (l_off_t)bsd_flock->l_start; 1460 linux_flock->l_len = (l_off_t)bsd_flock->l_len; 1461 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 1462 } 1463 1464 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1465 struct l_flock64 { 1466 l_short l_type; 1467 l_short l_whence; 1468 l_loff_t l_start; 1469 l_loff_t l_len; 1470 l_pid_t l_pid; 1471 } 1472 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1473 __packed 1474 #endif 1475 ; 1476 1477 static void 1478 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 1479 { 1480 switch (linux_flock->l_type) { 1481 case LINUX_F_RDLCK: 1482 bsd_flock->l_type = F_RDLCK; 1483 break; 1484 case LINUX_F_WRLCK: 1485 bsd_flock->l_type = F_WRLCK; 1486 break; 1487 case LINUX_F_UNLCK: 1488 bsd_flock->l_type = F_UNLCK; 1489 break; 1490 default: 1491 bsd_flock->l_type = -1; 1492 break; 1493 } 1494 bsd_flock->l_whence = linux_flock->l_whence; 1495 bsd_flock->l_start = (off_t)linux_flock->l_start; 1496 bsd_flock->l_len = (off_t)linux_flock->l_len; 1497 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1498 bsd_flock->l_sysid = 0; 1499 } 1500 1501 static void 1502 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 1503 { 1504 switch (bsd_flock->l_type) { 1505 case F_RDLCK: 1506 linux_flock->l_type = LINUX_F_RDLCK; 1507 break; 1508 case F_WRLCK: 1509 linux_flock->l_type = LINUX_F_WRLCK; 1510 break; 1511 case F_UNLCK: 1512 linux_flock->l_type = LINUX_F_UNLCK; 1513 break; 1514 } 1515 linux_flock->l_whence = bsd_flock->l_whence; 1516 linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 1517 linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 1518 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 1519 } 1520 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1521 1522 static int 1523 fcntl_common(struct thread *td, struct linux_fcntl_args *args) 1524 { 1525 struct l_flock linux_flock; 1526 struct flock bsd_flock; 1527 struct file *fp; 1528 long arg; 1529 int error, result; 1530 1531 switch (args->cmd) { 1532 case LINUX_F_DUPFD: 1533 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 1534 1535 case LINUX_F_GETFD: 1536 return (kern_fcntl(td, args->fd, F_GETFD, 0)); 1537 1538 case LINUX_F_SETFD: 1539 return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 1540 1541 case LINUX_F_GETFL: 1542 error = kern_fcntl(td, args->fd, F_GETFL, 0); 1543 result = td->td_retval[0]; 1544 td->td_retval[0] = 0; 1545 if (result & O_RDONLY) 1546 td->td_retval[0] |= LINUX_O_RDONLY; 1547 if (result & O_WRONLY) 1548 td->td_retval[0] |= LINUX_O_WRONLY; 1549 if (result & O_RDWR) 1550 td->td_retval[0] |= LINUX_O_RDWR; 1551 if (result & O_NDELAY) 1552 td->td_retval[0] |= LINUX_O_NONBLOCK; 1553 if (result & O_APPEND) 1554 td->td_retval[0] |= LINUX_O_APPEND; 1555 if (result & O_FSYNC) 1556 td->td_retval[0] |= LINUX_O_SYNC; 1557 if (result & O_ASYNC) 1558 td->td_retval[0] |= LINUX_O_ASYNC; 1559 #ifdef LINUX_O_NOFOLLOW 1560 if (result & O_NOFOLLOW) 1561 td->td_retval[0] |= LINUX_O_NOFOLLOW; 1562 #endif 1563 #ifdef LINUX_O_DIRECT 1564 if (result & O_DIRECT) 1565 td->td_retval[0] |= LINUX_O_DIRECT; 1566 #endif 1567 return (error); 1568 1569 case LINUX_F_SETFL: 1570 arg = 0; 1571 if (args->arg & LINUX_O_NDELAY) 1572 arg |= O_NONBLOCK; 1573 if (args->arg & LINUX_O_APPEND) 1574 arg |= O_APPEND; 1575 if (args->arg & LINUX_O_SYNC) 1576 arg |= O_FSYNC; 1577 if (args->arg & LINUX_O_ASYNC) 1578 arg |= O_ASYNC; 1579 #ifdef LINUX_O_NOFOLLOW 1580 if (args->arg & LINUX_O_NOFOLLOW) 1581 arg |= O_NOFOLLOW; 1582 #endif 1583 #ifdef LINUX_O_DIRECT 1584 if (args->arg & LINUX_O_DIRECT) 1585 arg |= O_DIRECT; 1586 #endif 1587 return (kern_fcntl(td, args->fd, F_SETFL, arg)); 1588 1589 case LINUX_F_GETLK: 1590 error = copyin((void *)args->arg, &linux_flock, 1591 sizeof(linux_flock)); 1592 if (error) 1593 return (error); 1594 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1595 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1596 if (error) 1597 return (error); 1598 bsd_to_linux_flock(&bsd_flock, &linux_flock); 1599 return (copyout(&linux_flock, (void *)args->arg, 1600 sizeof(linux_flock))); 1601 1602 case LINUX_F_SETLK: 1603 error = copyin((void *)args->arg, &linux_flock, 1604 sizeof(linux_flock)); 1605 if (error) 1606 return (error); 1607 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1608 return (kern_fcntl(td, args->fd, F_SETLK, 1609 (intptr_t)&bsd_flock)); 1610 1611 case LINUX_F_SETLKW: 1612 error = copyin((void *)args->arg, &linux_flock, 1613 sizeof(linux_flock)); 1614 if (error) 1615 return (error); 1616 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1617 return (kern_fcntl(td, args->fd, F_SETLKW, 1618 (intptr_t)&bsd_flock)); 1619 1620 case LINUX_F_GETOWN: 1621 return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 1622 1623 case LINUX_F_SETOWN: 1624 /* 1625 * XXX some Linux applications depend on F_SETOWN having no 1626 * significant effect for pipes (SIGIO is not delivered for 1627 * pipes under Linux-2.2.35 at least). 1628 */ 1629 error = fget(td, args->fd, 1630 &cap_fcntl_rights, &fp); 1631 if (error) 1632 return (error); 1633 if (fp->f_type == DTYPE_PIPE) { 1634 fdrop(fp, td); 1635 return (EINVAL); 1636 } 1637 fdrop(fp, td); 1638 1639 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 1640 1641 case LINUX_F_DUPFD_CLOEXEC: 1642 return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg)); 1643 /* 1644 * Our F_SEAL_* values match Linux one for maximum compatibility. So we 1645 * only needed to account for different values for fcntl(2) commands. 1646 */ 1647 case LINUX_F_GET_SEALS: 1648 error = kern_fcntl(td, args->fd, F_GET_SEALS, 0); 1649 if (error != 0) 1650 return (error); 1651 td->td_retval[0] = bsd_to_linux_bits(td->td_retval[0], 1652 seal_bitmap, 0); 1653 return (0); 1654 1655 case LINUX_F_ADD_SEALS: 1656 return (kern_fcntl(td, args->fd, F_ADD_SEALS, 1657 linux_to_bsd_bits(args->arg, seal_bitmap, 0))); 1658 default: 1659 linux_msg(td, "unsupported fcntl cmd %d", args->cmd); 1660 return (EINVAL); 1661 } 1662 } 1663 1664 int 1665 linux_fcntl(struct thread *td, struct linux_fcntl_args *args) 1666 { 1667 1668 return (fcntl_common(td, args)); 1669 } 1670 1671 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1672 int 1673 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 1674 { 1675 struct l_flock64 linux_flock; 1676 struct flock bsd_flock; 1677 struct linux_fcntl_args fcntl_args; 1678 int error; 1679 1680 switch (args->cmd) { 1681 case LINUX_F_GETLK64: 1682 error = copyin((void *)args->arg, &linux_flock, 1683 sizeof(linux_flock)); 1684 if (error) 1685 return (error); 1686 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1687 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1688 if (error) 1689 return (error); 1690 bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1691 return (copyout(&linux_flock, (void *)args->arg, 1692 sizeof(linux_flock))); 1693 1694 case LINUX_F_SETLK64: 1695 error = copyin((void *)args->arg, &linux_flock, 1696 sizeof(linux_flock)); 1697 if (error) 1698 return (error); 1699 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1700 return (kern_fcntl(td, args->fd, F_SETLK, 1701 (intptr_t)&bsd_flock)); 1702 1703 case LINUX_F_SETLKW64: 1704 error = copyin((void *)args->arg, &linux_flock, 1705 sizeof(linux_flock)); 1706 if (error) 1707 return (error); 1708 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1709 return (kern_fcntl(td, args->fd, F_SETLKW, 1710 (intptr_t)&bsd_flock)); 1711 } 1712 1713 fcntl_args.fd = args->fd; 1714 fcntl_args.cmd = args->cmd; 1715 fcntl_args.arg = args->arg; 1716 return (fcntl_common(td, &fcntl_args)); 1717 } 1718 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1719 1720 #ifdef LINUX_LEGACY_SYSCALLS 1721 int 1722 linux_chown(struct thread *td, struct linux_chown_args *args) 1723 { 1724 char *path; 1725 int error; 1726 1727 if (!LUSECONVPATH(td)) { 1728 return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, 1729 args->uid, args->gid, 0)); 1730 } 1731 LCONVPATHEXIST(td, args->path, &path); 1732 error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, 1733 args->gid, 0); 1734 LFREEPATH(path); 1735 return (error); 1736 } 1737 #endif 1738 1739 int 1740 linux_fchownat(struct thread *td, struct linux_fchownat_args *args) 1741 { 1742 char *path; 1743 int error, dfd, flag; 1744 1745 if (args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH)) { 1746 linux_msg(td, "fchownat unsupported flag 0x%x", args->flag); 1747 return (EINVAL); 1748 } 1749 1750 flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : 1751 AT_SYMLINK_NOFOLLOW; 1752 flag |= (args->flag & LINUX_AT_EMPTY_PATH) == 0 ? 0 : 1753 AT_EMPTY_PATH; 1754 1755 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 1756 if (!LUSECONVPATH(td)) { 1757 return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE, 1758 args->uid, args->gid, flag)); 1759 } 1760 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 1761 error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, 1762 flag); 1763 LFREEPATH(path); 1764 return (error); 1765 } 1766 1767 #ifdef LINUX_LEGACY_SYSCALLS 1768 int 1769 linux_lchown(struct thread *td, struct linux_lchown_args *args) 1770 { 1771 char *path; 1772 int error; 1773 1774 if (!LUSECONVPATH(td)) { 1775 return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid, 1776 args->gid, AT_SYMLINK_NOFOLLOW)); 1777 } 1778 LCONVPATHEXIST(td, args->path, &path); 1779 error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid, 1780 AT_SYMLINK_NOFOLLOW); 1781 LFREEPATH(path); 1782 return (error); 1783 } 1784 #endif 1785 1786 static int 1787 convert_fadvice(int advice) 1788 { 1789 switch (advice) { 1790 case LINUX_POSIX_FADV_NORMAL: 1791 return (POSIX_FADV_NORMAL); 1792 case LINUX_POSIX_FADV_RANDOM: 1793 return (POSIX_FADV_RANDOM); 1794 case LINUX_POSIX_FADV_SEQUENTIAL: 1795 return (POSIX_FADV_SEQUENTIAL); 1796 case LINUX_POSIX_FADV_WILLNEED: 1797 return (POSIX_FADV_WILLNEED); 1798 case LINUX_POSIX_FADV_DONTNEED: 1799 return (POSIX_FADV_DONTNEED); 1800 case LINUX_POSIX_FADV_NOREUSE: 1801 return (POSIX_FADV_NOREUSE); 1802 default: 1803 return (-1); 1804 } 1805 } 1806 1807 int 1808 linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args) 1809 { 1810 off_t offset; 1811 int advice; 1812 1813 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1814 offset = PAIR32TO64(off_t, args->offset); 1815 #else 1816 offset = args->offset; 1817 #endif 1818 1819 advice = convert_fadvice(args->advice); 1820 if (advice == -1) 1821 return (EINVAL); 1822 return (kern_posix_fadvise(td, args->fd, offset, args->len, advice)); 1823 } 1824 1825 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1826 int 1827 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args) 1828 { 1829 off_t len, offset; 1830 int advice; 1831 1832 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1833 len = PAIR32TO64(off_t, args->len); 1834 offset = PAIR32TO64(off_t, args->offset); 1835 #else 1836 len = args->len; 1837 offset = args->offset; 1838 #endif 1839 1840 advice = convert_fadvice(args->advice); 1841 if (advice == -1) 1842 return (EINVAL); 1843 return (kern_posix_fadvise(td, args->fd, offset, len, advice)); 1844 } 1845 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1846 1847 #ifdef LINUX_LEGACY_SYSCALLS 1848 int 1849 linux_pipe(struct thread *td, struct linux_pipe_args *args) 1850 { 1851 int fildes[2]; 1852 int error; 1853 1854 error = kern_pipe(td, fildes, 0, NULL, NULL); 1855 if (error != 0) 1856 return (error); 1857 1858 error = copyout(fildes, args->pipefds, sizeof(fildes)); 1859 if (error != 0) { 1860 (void)kern_close(td, fildes[0]); 1861 (void)kern_close(td, fildes[1]); 1862 } 1863 1864 return (error); 1865 } 1866 #endif 1867 1868 int 1869 linux_pipe2(struct thread *td, struct linux_pipe2_args *args) 1870 { 1871 int fildes[2]; 1872 int error, flags; 1873 1874 if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0) 1875 return (EINVAL); 1876 1877 flags = 0; 1878 if ((args->flags & LINUX_O_NONBLOCK) != 0) 1879 flags |= O_NONBLOCK; 1880 if ((args->flags & LINUX_O_CLOEXEC) != 0) 1881 flags |= O_CLOEXEC; 1882 error = kern_pipe(td, fildes, flags, NULL, NULL); 1883 if (error != 0) 1884 return (error); 1885 1886 error = copyout(fildes, args->pipefds, sizeof(fildes)); 1887 if (error != 0) { 1888 (void)kern_close(td, fildes[0]); 1889 (void)kern_close(td, fildes[1]); 1890 } 1891 1892 return (error); 1893 } 1894 1895 int 1896 linux_dup3(struct thread *td, struct linux_dup3_args *args) 1897 { 1898 int cmd; 1899 intptr_t newfd; 1900 1901 if (args->oldfd == args->newfd) 1902 return (EINVAL); 1903 if ((args->flags & ~LINUX_O_CLOEXEC) != 0) 1904 return (EINVAL); 1905 if (args->flags & LINUX_O_CLOEXEC) 1906 cmd = F_DUP2FD_CLOEXEC; 1907 else 1908 cmd = F_DUP2FD; 1909 1910 newfd = args->newfd; 1911 return (kern_fcntl(td, args->oldfd, cmd, newfd)); 1912 } 1913 1914 int 1915 linux_fallocate(struct thread *td, struct linux_fallocate_args *args) 1916 { 1917 off_t len, offset; 1918 1919 /* 1920 * We emulate only posix_fallocate system call for which 1921 * mode should be 0. 1922 */ 1923 if (args->mode != 0) 1924 return (EOPNOTSUPP); 1925 1926 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1927 len = PAIR32TO64(off_t, args->len); 1928 offset = PAIR32TO64(off_t, args->offset); 1929 #else 1930 len = args->len; 1931 offset = args->offset; 1932 #endif 1933 1934 return (kern_posix_fallocate(td, args->fd, offset, len)); 1935 } 1936 1937 int 1938 linux_copy_file_range(struct thread *td, struct linux_copy_file_range_args 1939 *args) 1940 { 1941 l_loff_t inoff, outoff, *inoffp, *outoffp; 1942 int error, flags; 1943 1944 /* 1945 * copy_file_range(2) on Linux doesn't define any flags (yet), so is 1946 * the native implementation. Enforce it. 1947 */ 1948 if (args->flags != 0) { 1949 linux_msg(td, "copy_file_range unsupported flags 0x%x", 1950 args->flags); 1951 return (EINVAL); 1952 } 1953 flags = 0; 1954 inoffp = outoffp = NULL; 1955 if (args->off_in != NULL) { 1956 error = copyin(args->off_in, &inoff, sizeof(l_loff_t)); 1957 if (error != 0) 1958 return (error); 1959 inoffp = &inoff; 1960 } 1961 if (args->off_out != NULL) { 1962 error = copyin(args->off_out, &outoff, sizeof(l_loff_t)); 1963 if (error != 0) 1964 return (error); 1965 outoffp = &outoff; 1966 } 1967 1968 error = kern_copy_file_range(td, args->fd_in, inoffp, args->fd_out, 1969 outoffp, args->len, flags); 1970 if (error == 0 && args->off_in != NULL) 1971 error = copyout(inoffp, args->off_in, sizeof(l_loff_t)); 1972 if (error == 0 && args->off_out != NULL) 1973 error = copyout(outoffp, args->off_out, sizeof(l_loff_t)); 1974 return (error); 1975 } 1976 1977 #define LINUX_MEMFD_PREFIX "memfd:" 1978 1979 int 1980 linux_memfd_create(struct thread *td, struct linux_memfd_create_args *args) 1981 { 1982 char memfd_name[LINUX_NAME_MAX + 1]; 1983 int error, flags, shmflags, oflags; 1984 1985 /* 1986 * This is our clever trick to avoid the heap allocation to copy in the 1987 * uname. We don't really need to go this far out of our way, but it 1988 * does keep the rest of this function fairly clean as they don't have 1989 * to worry about cleanup on the way out. 1990 */ 1991 error = copyinstr(args->uname_ptr, 1992 memfd_name + sizeof(LINUX_MEMFD_PREFIX) - 1, 1993 LINUX_NAME_MAX - sizeof(LINUX_MEMFD_PREFIX) - 1, NULL); 1994 if (error != 0) { 1995 if (error == ENAMETOOLONG) 1996 error = EINVAL; 1997 return (error); 1998 } 1999 2000 memcpy(memfd_name, LINUX_MEMFD_PREFIX, sizeof(LINUX_MEMFD_PREFIX) - 1); 2001 flags = linux_to_bsd_bits(args->flags, mfd_bitmap, 0); 2002 if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | 2003 MFD_HUGE_MASK)) != 0) 2004 return (EINVAL); 2005 /* Size specified but no HUGETLB. */ 2006 if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0) 2007 return (EINVAL); 2008 /* We don't actually support HUGETLB. */ 2009 if ((flags & MFD_HUGETLB) != 0) 2010 return (ENOSYS); 2011 oflags = O_RDWR; 2012 shmflags = SHM_GROW_ON_WRITE; 2013 if ((flags & MFD_CLOEXEC) != 0) 2014 oflags |= O_CLOEXEC; 2015 if ((flags & MFD_ALLOW_SEALING) != 0) 2016 shmflags |= SHM_ALLOW_SEALING; 2017 return (kern_shm_open2(td, SHM_ANON, oflags, 0, shmflags, NULL, 2018 memfd_name)); 2019 } 2020 2021 int 2022 linux_splice(struct thread *td, struct linux_splice_args *args) 2023 { 2024 2025 linux_msg(td, "syscall splice not really implemented"); 2026 2027 /* 2028 * splice(2) is documented to return EINVAL in various circumstances; 2029 * returning it instead of ENOSYS should hint the caller to use fallback 2030 * instead. 2031 */ 2032 return (EINVAL); 2033 } 2034