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