Index: head/sys/amd64/linux/linux_dummy.c =================================================================== --- head/sys/amd64/linux/linux_dummy.c (revision 362768) +++ head/sys/amd64/linux/linux_dummy.c (revision 362769) @@ -1,190 +1,189 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 Dmitry Chagin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include /* DTrace init */ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); UNIMPLEMENTED(afs_syscall); UNIMPLEMENTED(create_module); /* Added in Linux 1.0 removed in 2.6. */ UNIMPLEMENTED(epoll_ctl_old); UNIMPLEMENTED(epoll_wait_old); UNIMPLEMENTED(get_kernel_syms); /* Added in Linux 1.0 removed in 2.6. */ UNIMPLEMENTED(get_thread_area); UNIMPLEMENTED(getpmsg); UNIMPLEMENTED(nfsservctl); /* Added in Linux 2.2 removed in 3.1. */ UNIMPLEMENTED(putpmsg); UNIMPLEMENTED(query_module); /* Added in Linux 2.2 removed in 2.6. */ UNIMPLEMENTED(tuxcall); UNIMPLEMENTED(security); UNIMPLEMENTED(set_thread_area); UNIMPLEMENTED(uselib); UNIMPLEMENTED(vserver); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(sysfs); DUMMY(vhangup); DUMMY(modify_ldt); DUMMY(pivot_root); DUMMY(adjtimex); DUMMY(swapoff); DUMMY(init_module); DUMMY(ioperm); DUMMY(delete_module); DUMMY(quotactl); DUMMY(readahead); DUMMY(io_setup); DUMMY(io_destroy); DUMMY(io_getevents); DUMMY(io_submit); DUMMY(io_cancel); DUMMY(lookup_dcookie); DUMMY(remap_file_pages); DUMMY(restart_syscall); DUMMY(semtimedop); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(mq_open); DUMMY(mq_unlink); DUMMY(mq_timedsend); DUMMY(mq_timedreceive); DUMMY(mq_notify); DUMMY(mq_getsetattr); DUMMY(kexec_load); /* Linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); /* Linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_init); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); /* Linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(unshare); /* Linux 2.6.17: */ DUMMY(splice); DUMMY(tee); DUMMY(vmsplice); /* Linux 2.6.18: */ DUMMY(move_pages); /* Linux 2.6.22: */ DUMMY(signalfd); /* Linux 2.6.27: */ DUMMY(signalfd4); DUMMY(inotify_init1); /* Linux 2.6.31: */ DUMMY(perf_event_open); /* Linux 2.6.36: */ DUMMY(fanotify_init); DUMMY(fanotify_mark); /* Linux 2.6.39: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); /* Linux 3.0: */ DUMMY(setns); /* Linux 3.2: */ DUMMY(process_vm_readv); DUMMY(process_vm_writev); /* Linux 3.5: */ DUMMY(kcmp); /* Linux 3.8: */ DUMMY(finit_module); DUMMY(sched_setattr); DUMMY(sched_getattr); /* Linux 3.15: */ DUMMY(kexec_file_load); /* Linux 3.17: */ -DUMMY(memfd_create); DUMMY(seccomp); /* Linux 3.18: */ DUMMY(bpf); /* Linux 3.19: */ DUMMY(execveat); /* Linux 4.2: */ DUMMY(userfaultfd); /* Linux 4.3: */ DUMMY(membarrier); /* Linux 4.4: */ DUMMY(mlock2); /* Linux 4.6: */ DUMMY(preadv2); DUMMY(pwritev2); /* Linux 4.8: */ DUMMY(pkey_mprotect); DUMMY(pkey_alloc); DUMMY(pkey_free); /* Linux 4.11: */ DUMMY(statx); /* Linux 4.18: */ DUMMY(io_pgetevents); DUMMY(rseq); /* Linux 5.0: */ DUMMY(pidfd_send_signal); DUMMY(io_uring_setup); DUMMY(io_uring_enter); DUMMY(io_uring_register); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (EOPNOTSUPP); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove); Index: head/sys/amd64/linux32/linux32_dummy.c =================================================================== --- head/sys/amd64/linux32/linux32_dummy.c (revision 362768) +++ head/sys/amd64/linux32/linux32_dummy.c (revision 362769) @@ -1,206 +1,205 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include /* DTrace init */ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); UNIMPLEMENTED(afs_syscall); UNIMPLEMENTED(break); UNIMPLEMENTED(create_module); /* Added in Linux 1.0 removed in 2.6. */ UNIMPLEMENTED(ftime); UNIMPLEMENTED(get_kernel_syms); /* Added in Linux 1.0 removed in 2.6. */ UNIMPLEMENTED(getpmsg); UNIMPLEMENTED(gtty); UNIMPLEMENTED(stty); UNIMPLEMENTED(lock); UNIMPLEMENTED(mpx); UNIMPLEMENTED(nfsservctl); /* Added in Linux 2.2 removed in 3.1. */ UNIMPLEMENTED(prof); UNIMPLEMENTED(profil); UNIMPLEMENTED(putpmsg); UNIMPLEMENTED(query_module); /* Added in Linux 2.2 removed in 2.6. */ UNIMPLEMENTED(ulimit); UNIMPLEMENTED(vserver); DUMMY(stime); DUMMY(olduname); DUMMY(uname); DUMMY(vhangup); DUMMY(swapoff); DUMMY(adjtimex); DUMMY(init_module); DUMMY(delete_module); DUMMY(quotactl); DUMMY(bdflush); DUMMY(sysfs); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); DUMMY(ptrace); DUMMY(lookup_dcookie); DUMMY(remap_file_pages); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(mq_open); DUMMY(mq_unlink); DUMMY(mq_timedsend); DUMMY(mq_timedreceive); DUMMY(mq_notify); DUMMY(mq_getsetattr); DUMMY(kexec_load); /* Linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); /* Linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_init); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); /* Linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(unshare); /* Linux 2.6.17: */ DUMMY(splice); DUMMY(tee); DUMMY(vmsplice); /* Linux 2.6.18: */ DUMMY(move_pages); /* Linux 2.6.22: */ DUMMY(signalfd); /* Linux 2.6.27: */ DUMMY(signalfd4); DUMMY(inotify_init1); /* Linux 2.6.31: */ DUMMY(perf_event_open); /* Linux 2.6.36: */ DUMMY(fanotify_init); DUMMY(fanotify_mark); /* Linux 2.6.39: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); /* Linux 3.0: */ DUMMY(setns); /* Linux 3.2: */ DUMMY(process_vm_readv); DUMMY(process_vm_writev); /* Linux 3.5: */ DUMMY(kcmp); /* Linux 3.8: */ DUMMY(finit_module); DUMMY(sched_setattr); DUMMY(sched_getattr); /* Linux 3.17: */ -DUMMY(memfd_create); DUMMY(seccomp); /* Linux 3.18: */ DUMMY(bpf); /* Linux 3.19: */ DUMMY(execveat); /* Linux 4.2: */ DUMMY(userfaultfd); /* Linux 4.3: */ DUMMY(membarrier); /* Linux 4.4: */ DUMMY(mlock2); /* Linux 4.6: */ DUMMY(preadv2); DUMMY(pwritev2); /* Linux 4.8: */ DUMMY(pkey_mprotect); DUMMY(pkey_alloc); DUMMY(pkey_free); /* Linux 4.11: */ DUMMY(statx); DUMMY(arch_prctl); /* Linux 4.18: */ DUMMY(io_pgetevents); DUMMY(rseq); /* Linux 5.0: */ DUMMY(clock_gettime64); DUMMY(clock_settime64); DUMMY(clock_adjtime64); DUMMY(clock_getres_time64); DUMMY(clock_nanosleep_time64); DUMMY(timer_gettime64); DUMMY(timer_settime64); DUMMY(timerfd_gettime64); DUMMY(timerfd_settime64); DUMMY(utimensat_time64); DUMMY(pselect6_time64); DUMMY(ppoll_time64); DUMMY(io_pgetevents_time64); DUMMY(recvmmsg_time64); DUMMY(mq_timedsend_time64); DUMMY(mq_timedreceive_time64); DUMMY(semtimedop_time64); DUMMY(rt_sigtimedwait_time64); DUMMY(futex_time64); DUMMY(sched_rr_get_interval_time64); DUMMY(pidfd_send_signal); DUMMY(io_uring_setup); DUMMY(io_uring_enter); DUMMY(io_uring_register); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (EOPNOTSUPP); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove); Index: head/sys/arm64/linux/linux_dummy.c =================================================================== --- head/sys/arm64/linux/linux_dummy.c (revision 362768) +++ head/sys/arm64/linux/linux_dummy.c (revision 362769) @@ -1,169 +1,168 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 Dmitry Chagin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include // LINUXTODO: deduplicate arm64 dummy against other archs? // LINUXTODO: review/update/add unimplemented syscalls /* DTrace init */ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); UNIMPLEMENTED(afs_syscall); UNIMPLEMENTED(create_module); /* Added in Linux 1.0 removed in 2.6. */ UNIMPLEMENTED(epoll_ctl_old); UNIMPLEMENTED(epoll_wait_old); UNIMPLEMENTED(get_kernel_syms); /* Added in Linux 1.0 removed in 2.6. */ UNIMPLEMENTED(get_thread_area); UNIMPLEMENTED(getpmsg); UNIMPLEMENTED(nfsservctl); /* Added in Linux 2.2 removed in 3.1. */ UNIMPLEMENTED(putpmsg); UNIMPLEMENTED(query_module); /* Added in Linux 2.2 removed in 2.6. */ UNIMPLEMENTED(security); UNIMPLEMENTED(set_thread_area); UNIMPLEMENTED(tuxcall); UNIMPLEMENTED(uselib); UNIMPLEMENTED(vserver); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(vhangup); DUMMY(pivot_root); DUMMY(adjtimex); DUMMY(swapoff); DUMMY(init_module); DUMMY(delete_module); DUMMY(lookup_dcookie); DUMMY(remap_file_pages); DUMMY(semtimedop); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(mq_open); DUMMY(mq_unlink); DUMMY(mq_timedsend); DUMMY(mq_timedreceive); DUMMY(mq_notify); DUMMY(mq_getsetattr); DUMMY(kexec_load); /* Linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); /* Linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); /* Linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(unshare); /* Linux 2.6.17: */ DUMMY(splice); DUMMY(tee); DUMMY(vmsplice); /* Linux 2.6.18: */ DUMMY(move_pages); /* Linux 2.6.27: */ DUMMY(signalfd4); DUMMY(inotify_init1); /* Linux 2.6.31: */ DUMMY(perf_event_open); /* Linux 2.6.36: */ DUMMY(fanotify_init); DUMMY(fanotify_mark); /* Linux 2.6.39: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); /* Linux 3.0: */ DUMMY(setns); /* Linux 3.2: */ DUMMY(process_vm_readv); DUMMY(process_vm_writev); /* Linux 3.5: */ DUMMY(kcmp); /* Linux 3.8: */ DUMMY(finit_module); DUMMY(sched_setattr); DUMMY(sched_getattr); /* Linux 3.17: */ -DUMMY(memfd_create); DUMMY(seccomp); /* Linux 3.18: */ DUMMY(bpf); /* Linux 3.19: */ DUMMY(execveat); /* Linux 4.2: */ DUMMY(userfaultfd); /* Linux 4.3: */ DUMMY(membarrier); /* Linux 4.4: */ DUMMY(mlock2); /* Linux 4.6: */ DUMMY(preadv2); DUMMY(pwritev2); /* Linux 4.8: */ DUMMY(pkey_mprotect); DUMMY(pkey_alloc); DUMMY(pkey_free); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (EOPNOTSUPP); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove); Index: head/sys/compat/linux/linux.c =================================================================== --- head/sys/compat/linux/linux.c (revision 362768) +++ head/sys/compat/linux/linux.c (revision 362769) @@ -1,553 +1,629 @@ /*- * Copyright (c) 2015 Dmitry Chagin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct futex_list futex_list; struct mtx futex_mtx; /* protects the futex list */ CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ); static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = { LINUX_SIGHUP, /* SIGHUP */ LINUX_SIGINT, /* SIGINT */ LINUX_SIGQUIT, /* SIGQUIT */ LINUX_SIGILL, /* SIGILL */ LINUX_SIGTRAP, /* SIGTRAP */ LINUX_SIGABRT, /* SIGABRT */ 0, /* SIGEMT */ LINUX_SIGFPE, /* SIGFPE */ LINUX_SIGKILL, /* SIGKILL */ LINUX_SIGBUS, /* SIGBUS */ LINUX_SIGSEGV, /* SIGSEGV */ LINUX_SIGSYS, /* SIGSYS */ LINUX_SIGPIPE, /* SIGPIPE */ LINUX_SIGALRM, /* SIGALRM */ LINUX_SIGTERM, /* SIGTERM */ LINUX_SIGURG, /* SIGURG */ LINUX_SIGSTOP, /* SIGSTOP */ LINUX_SIGTSTP, /* SIGTSTP */ LINUX_SIGCONT, /* SIGCONT */ LINUX_SIGCHLD, /* SIGCHLD */ LINUX_SIGTTIN, /* SIGTTIN */ LINUX_SIGTTOU, /* SIGTTOU */ LINUX_SIGIO, /* SIGIO */ LINUX_SIGXCPU, /* SIGXCPU */ LINUX_SIGXFSZ, /* SIGXFSZ */ LINUX_SIGVTALRM,/* SIGVTALRM */ LINUX_SIGPROF, /* SIGPROF */ LINUX_SIGWINCH, /* SIGWINCH */ 0, /* SIGINFO */ LINUX_SIGUSR1, /* SIGUSR1 */ LINUX_SIGUSR2 /* SIGUSR2 */ }; static int linux_to_bsd_sigtbl[LINUX_SIGTBLSZ] = { SIGHUP, /* LINUX_SIGHUP */ SIGINT, /* LINUX_SIGINT */ SIGQUIT, /* LINUX_SIGQUIT */ SIGILL, /* LINUX_SIGILL */ SIGTRAP, /* LINUX_SIGTRAP */ SIGABRT, /* LINUX_SIGABRT */ SIGBUS, /* LINUX_SIGBUS */ SIGFPE, /* LINUX_SIGFPE */ SIGKILL, /* LINUX_SIGKILL */ SIGUSR1, /* LINUX_SIGUSR1 */ SIGSEGV, /* LINUX_SIGSEGV */ SIGUSR2, /* LINUX_SIGUSR2 */ SIGPIPE, /* LINUX_SIGPIPE */ SIGALRM, /* LINUX_SIGALRM */ SIGTERM, /* LINUX_SIGTERM */ SIGBUS, /* LINUX_SIGSTKFLT */ SIGCHLD, /* LINUX_SIGCHLD */ SIGCONT, /* LINUX_SIGCONT */ SIGSTOP, /* LINUX_SIGSTOP */ SIGTSTP, /* LINUX_SIGTSTP */ SIGTTIN, /* LINUX_SIGTTIN */ SIGTTOU, /* LINUX_SIGTTOU */ SIGURG, /* LINUX_SIGURG */ SIGXCPU, /* LINUX_SIGXCPU */ SIGXFSZ, /* LINUX_SIGXFSZ */ SIGVTALRM, /* LINUX_SIGVTALARM */ SIGPROF, /* LINUX_SIGPROF */ SIGWINCH, /* LINUX_SIGWINCH */ SIGIO, /* LINUX_SIGIO */ /* * FreeBSD does not have SIGPWR signal, map Linux SIGPWR signal * to the first unused FreeBSD signal number. Since Linux supports * signals from 1 to 64 we are ok here as our SIGRTMIN = 65. */ SIGRTMIN, /* LINUX_SIGPWR */ SIGSYS /* LINUX_SIGSYS */ }; static struct cdev *dev_shm_cdev; static struct cdevsw dev_shm_cdevsw = { .d_version = D_VERSION, .d_name = "dev_shm", }; /* * Map Linux RT signals to the FreeBSD RT signals. */ static inline int linux_to_bsd_rt_signal(int sig) { return (SIGRTMIN + 1 + sig - LINUX_SIGRTMIN); } static inline int bsd_to_linux_rt_signal(int sig) { return (sig - SIGRTMIN - 1 + LINUX_SIGRTMIN); } int linux_to_bsd_signal(int sig) { KASSERT(sig > 0 && sig <= LINUX_SIGRTMAX, ("invalid Linux signal %d\n", sig)); if (sig < LINUX_SIGRTMIN) return (linux_to_bsd_sigtbl[_SIG_IDX(sig)]); return (linux_to_bsd_rt_signal(sig)); } int bsd_to_linux_signal(int sig) { if (sig <= LINUX_SIGTBLSZ) return (bsd_to_linux_sigtbl[_SIG_IDX(sig)]); if (sig == SIGRTMIN) return (LINUX_SIGPWR); return (bsd_to_linux_rt_signal(sig)); } int linux_to_bsd_sigaltstack(int lsa) { int bsa = 0; if (lsa & LINUX_SS_DISABLE) bsa |= SS_DISABLE; /* * Linux ignores SS_ONSTACK flag for ss * parameter while FreeBSD prohibits it. */ return (bsa); } int bsd_to_linux_sigaltstack(int bsa) { int lsa = 0; if (bsa & SS_DISABLE) lsa |= LINUX_SS_DISABLE; if (bsa & SS_ONSTACK) lsa |= LINUX_SS_ONSTACK; return (lsa); } void linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss) { int b, l; SIGEMPTYSET(*bss); for (l = 1; l <= LINUX_SIGRTMAX; l++) { if (LINUX_SIGISMEMBER(*lss, l)) { b = linux_to_bsd_signal(l); if (b) SIGADDSET(*bss, b); } } } void bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss) { int b, l; LINUX_SIGEMPTYSET(*lss); for (b = 1; b <= SIGRTMAX; b++) { if (SIGISMEMBER(*bss, b)) { l = bsd_to_linux_signal(b); if (l) LINUX_SIGADDSET(*lss, l); } } } /* * Translate a Linux interface name to a FreeBSD interface name, * and return the associated ifnet structure * bsdname and lxname need to be least IFNAMSIZ bytes long, but * can point to the same buffer. */ struct ifnet * ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) { struct ifnet *ifp; int len, unit; char *ep; int index; bool is_eth, is_lo; for (len = 0; len < LINUX_IFNAMSIZ; ++len) if (!isalpha(lxname[len]) || lxname[len] == '\0') break; if (len == 0 || len == LINUX_IFNAMSIZ) return (NULL); /* Linux loopback interface name is lo (not lo0) */ is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0); unit = (int)strtoul(lxname + len, &ep, 10); if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) && is_lo == 0) return (NULL); index = 0; is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0); CURVNET_SET(TD_TO_VNET(td)); IFNET_RLOCK(); CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { /* * Allow Linux programs to use FreeBSD names. Don't presume * we never have an interface named "eth", so don't make * the test optional based on is_eth. */ if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0) break; if (is_eth && IFP_IS_ETH(ifp) && unit == index++) break; if (is_lo && IFP_IS_LOOP(ifp)) break; } IFNET_RUNLOCK(); CURVNET_RESTORE(); if (ifp != NULL && bsdname != NULL) strlcpy(bsdname, ifp->if_xname, IFNAMSIZ); return (ifp); } void linux_ifflags(struct ifnet *ifp, short *flags) { unsigned short fl; fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff; *flags = 0; if (fl & IFF_UP) *flags |= LINUX_IFF_UP; if (fl & IFF_BROADCAST) *flags |= LINUX_IFF_BROADCAST; if (fl & IFF_DEBUG) *flags |= LINUX_IFF_DEBUG; if (fl & IFF_LOOPBACK) *flags |= LINUX_IFF_LOOPBACK; if (fl & IFF_POINTOPOINT) *flags |= LINUX_IFF_POINTOPOINT; if (fl & IFF_DRV_RUNNING) *flags |= LINUX_IFF_RUNNING; if (fl & IFF_NOARP) *flags |= LINUX_IFF_NOARP; if (fl & IFF_PROMISC) *flags |= LINUX_IFF_PROMISC; if (fl & IFF_ALLMULTI) *flags |= LINUX_IFF_ALLMULTI; if (fl & IFF_MULTICAST) *flags |= LINUX_IFF_MULTICAST; } int linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa) { struct ifaddr *ifa; struct sockaddr_dl *sdl; if (IFP_IS_LOOP(ifp)) { bzero(lsa, sizeof(*lsa)); lsa->sa_family = LINUX_ARPHRD_LOOPBACK; return (0); } if (!IFP_IS_ETH(ifp)) return (ENOENT); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { sdl = (struct sockaddr_dl*)ifa->ifa_addr; if (sdl != NULL && (sdl->sdl_family == AF_LINK) && (sdl->sdl_type == IFT_ETHER)) { bzero(lsa, sizeof(*lsa)); lsa->sa_family = LINUX_ARPHRD_ETHER; bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN); return (0); } } return (ENOENT); } int linux_to_bsd_domain(int domain) { switch (domain) { case LINUX_AF_UNSPEC: return (AF_UNSPEC); case LINUX_AF_UNIX: return (AF_LOCAL); case LINUX_AF_INET: return (AF_INET); case LINUX_AF_INET6: return (AF_INET6); case LINUX_AF_AX25: return (AF_CCITT); case LINUX_AF_IPX: return (AF_IPX); case LINUX_AF_APPLETALK: return (AF_APPLETALK); } return (-1); } int bsd_to_linux_domain(int domain) { switch (domain) { case AF_UNSPEC: return (LINUX_AF_UNSPEC); case AF_LOCAL: return (LINUX_AF_UNIX); case AF_INET: return (LINUX_AF_INET); case AF_INET6: return (LINUX_AF_INET6); case AF_CCITT: return (LINUX_AF_AX25); case AF_IPX: return (LINUX_AF_IPX); case AF_APPLETALK: return (LINUX_AF_APPLETALK); } return (-1); } /* * Based on the fact that: * 1. Native and Linux storage of struct sockaddr * and struct sockaddr_in6 are equal. * 2. On Linux sa_family is the first member of all struct sockaddr. */ int bsd_to_linux_sockaddr(const struct sockaddr *sa, struct l_sockaddr **lsa, socklen_t len) { struct l_sockaddr *kosa; int error, bdom; *lsa = NULL; if (len < 2 || len > UCHAR_MAX) return (EINVAL); kosa = malloc(len, M_SONAME, M_WAITOK); bcopy(sa, kosa, len); bdom = bsd_to_linux_domain(sa->sa_family); if (bdom == -1) { error = EAFNOSUPPORT; goto out; } kosa->sa_family = bdom; *lsa = kosa; return (0); out: free(kosa, M_SONAME); return (error); } int linux_to_bsd_sockaddr(const struct l_sockaddr *osa, struct sockaddr **sap, socklen_t *len) { struct sockaddr *sa; struct l_sockaddr *kosa; #ifdef INET6 struct sockaddr_in6 *sin6; bool oldv6size; #endif char *name; int salen, bdom, error, hdrlen, namelen; if (*len < 2 || *len > UCHAR_MAX) return (EINVAL); salen = *len; #ifdef INET6 oldv6size = false; /* * Check for old (pre-RFC2553) sockaddr_in6. We may accept it * if it's a v4-mapped address, so reserve the proper space * for it. */ if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) { salen += sizeof(uint32_t); oldv6size = true; } #endif kosa = malloc(salen, M_SONAME, M_WAITOK); if ((error = copyin(osa, kosa, *len))) goto out; bdom = linux_to_bsd_domain(kosa->sa_family); if (bdom == -1) { error = EAFNOSUPPORT; goto out; } #ifdef INET6 /* * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, * which lacks the scope id compared with RFC2553 one. If we detect * the situation, reject the address and write a message to system log. * * Still accept addresses for which the scope id is not used. */ if (oldv6size) { if (bdom == AF_INET6) { sin6 = (struct sockaddr_in6 *)kosa; if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) && !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { sin6->sin6_scope_id = 0; } else { linux_msg(curthread, "obsolete pre-RFC2553 sockaddr_in6 rejected"); error = EINVAL; goto out; } } else salen -= sizeof(uint32_t); } #endif if (bdom == AF_INET) { if (salen < sizeof(struct sockaddr_in)) { error = EINVAL; goto out; } salen = sizeof(struct sockaddr_in); } if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) { hdrlen = offsetof(struct sockaddr_un, sun_path); name = ((struct sockaddr_un *)kosa)->sun_path; if (*name == '\0') { /* * Linux abstract namespace starts with a NULL byte. * XXX We do not support abstract namespace yet. */ namelen = strnlen(name + 1, salen - hdrlen - 1) + 1; } else namelen = strnlen(name, salen - hdrlen); salen = hdrlen + namelen; if (salen > sizeof(struct sockaddr_un)) { error = ENAMETOOLONG; goto out; } } sa = (struct sockaddr *)kosa; sa->sa_family = bdom; sa->sa_len = salen; *sap = sa; *len = salen; return (0); out: free(kosa, M_SONAME); return (error); } void linux_dev_shm_create(void) { int error; error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev_shm_cdev, &dev_shm_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0, "shm/.mountpoint"); if (error != 0) { printf("%s: failed to create device node, error %d\n", __func__, error); } } void linux_dev_shm_destroy(void) { destroy_dev(dev_shm_cdev); } + +int +bsd_to_linux_bits_(int value, struct bsd_to_linux_bitmap *bitmap, + size_t mapcnt, int no_value) +{ + int bsd_mask, bsd_value, linux_mask, linux_value; + int linux_ret; + size_t i; + bool applied; + + applied = false; + linux_ret = 0; + for (i = 0; i < mapcnt; ++i) { + bsd_mask = bitmap[i].bsd_mask; + bsd_value = bitmap[i].bsd_value; + if (bsd_mask == 0) + bsd_mask = bsd_value; + + linux_mask = bitmap[i].linux_mask; + linux_value = bitmap[i].linux_value; + if (linux_mask == 0) + linux_mask = linux_value; + + /* + * If a mask larger than just the value is set, we explicitly + * want to make sure that only this bit we mapped within that + * mask is set. + */ + if ((value & bsd_mask) == bsd_value) { + linux_ret = (linux_ret & ~linux_mask) | linux_value; + applied = true; + } + } + + if (!applied) + return (no_value); + return (linux_ret); +} + +int +linux_to_bsd_bits_(int value, struct bsd_to_linux_bitmap *bitmap, + size_t mapcnt, int no_value) +{ + int bsd_mask, bsd_value, linux_mask, linux_value; + int bsd_ret; + size_t i; + bool applied; + + applied = false; + bsd_ret = 0; + for (i = 0; i < mapcnt; ++i) { + bsd_mask = bitmap[i].bsd_mask; + bsd_value = bitmap[i].bsd_value; + if (bsd_mask == 0) + bsd_mask = bsd_value; + + linux_mask = bitmap[i].linux_mask; + linux_value = bitmap[i].linux_value; + if (linux_mask == 0) + linux_mask = linux_value; + + /* + * If a mask larger than just the value is set, we explicitly + * want to make sure that only this bit we mapped within that + * mask is set. + */ + if ((value & linux_mask) == linux_value) { + bsd_ret = (bsd_ret & ~bsd_mask) | bsd_value; + applied = true; + } + } + + if (!applied) + return (no_value); + return (bsd_ret); +} Index: head/sys/compat/linux/linux.h =================================================================== --- head/sys/compat/linux/linux.h (revision 362768) +++ head/sys/compat/linux/linux.h (revision 362769) @@ -1,151 +1,196 @@ /*- * Copyright (c) 2015 Dmitry Chagin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _LINUX_MI_H_ #define _LINUX_MI_H_ #include #define LINUX_IFHWADDRLEN 6 #define LINUX_IFNAMSIZ 16 /* * Criteria for interface name translation */ #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER) #define IFP_IS_LOOP(ifp) (ifp->if_type == IFT_LOOP) struct l_sockaddr { unsigned short sa_family; char sa_data[14]; }; #define LINUX_ARPHRD_ETHER 1 #define LINUX_ARPHRD_LOOPBACK 772 /* * Supported address families */ #define LINUX_AF_UNSPEC 0 #define LINUX_AF_UNIX 1 #define LINUX_AF_INET 2 #define LINUX_AF_AX25 3 #define LINUX_AF_IPX 4 #define LINUX_AF_APPLETALK 5 #define LINUX_AF_INET6 10 /* * net device flags */ #define LINUX_IFF_UP 0x0001 #define LINUX_IFF_BROADCAST 0x0002 #define LINUX_IFF_DEBUG 0x0004 #define LINUX_IFF_LOOPBACK 0x0008 #define LINUX_IFF_POINTOPOINT 0x0010 #define LINUX_IFF_NOTRAILERS 0x0020 #define LINUX_IFF_RUNNING 0x0040 #define LINUX_IFF_NOARP 0x0080 #define LINUX_IFF_PROMISC 0x0100 #define LINUX_IFF_ALLMULTI 0x0200 #define LINUX_IFF_MASTER 0x0400 #define LINUX_IFF_SLAVE 0x0800 #define LINUX_IFF_MULTICAST 0x1000 #define LINUX_IFF_PORTSEL 0x2000 #define LINUX_IFF_AUTOMEDIA 0x4000 #define LINUX_IFF_DYNAMIC 0x8000 /* sigaltstack */ #define LINUX_SS_ONSTACK 1 #define LINUX_SS_DISABLE 2 int linux_to_bsd_sigaltstack(int lsa); int bsd_to_linux_sigaltstack(int bsa); /* sigset */ typedef struct { uint64_t __mask; } l_sigset_t; /* primitives to manipulate sigset_t */ #define LINUX_SIGEMPTYSET(set) (set).__mask = 0 #define LINUX_SIGISMEMBER(set, sig) (1UL & ((set).__mask >> _SIG_IDX(sig))) #define LINUX_SIGADDSET(set, sig) (set).__mask |= 1UL << _SIG_IDX(sig) void linux_to_bsd_sigset(l_sigset_t *, sigset_t *); void bsd_to_linux_sigset(sigset_t *, l_sigset_t *); /* signaling */ #define LINUX_SIGHUP 1 #define LINUX_SIGINT 2 #define LINUX_SIGQUIT 3 #define LINUX_SIGILL 4 #define LINUX_SIGTRAP 5 #define LINUX_SIGABRT 6 #define LINUX_SIGIOT LINUX_SIGABRT #define LINUX_SIGBUS 7 #define LINUX_SIGFPE 8 #define LINUX_SIGKILL 9 #define LINUX_SIGUSR1 10 #define LINUX_SIGSEGV 11 #define LINUX_SIGUSR2 12 #define LINUX_SIGPIPE 13 #define LINUX_SIGALRM 14 #define LINUX_SIGTERM 15 #define LINUX_SIGSTKFLT 16 #define LINUX_SIGCHLD 17 #define LINUX_SIGCONT 18 #define LINUX_SIGSTOP 19 #define LINUX_SIGTSTP 20 #define LINUX_SIGTTIN 21 #define LINUX_SIGTTOU 22 #define LINUX_SIGURG 23 #define LINUX_SIGXCPU 24 #define LINUX_SIGXFSZ 25 #define LINUX_SIGVTALRM 26 #define LINUX_SIGPROF 27 #define LINUX_SIGWINCH 28 #define LINUX_SIGIO 29 #define LINUX_SIGPOLL LINUX_SIGIO #define LINUX_SIGPWR 30 #define LINUX_SIGSYS 31 #define LINUX_SIGTBLSZ 31 #define LINUX_SIGRTMIN 32 #define LINUX_SIGRTMAX 64 #define LINUX_SIG_VALID(sig) ((sig) <= LINUX_SIGRTMAX && (sig) > 0) int linux_to_bsd_signal(int sig); int bsd_to_linux_signal(int sig); extern LIST_HEAD(futex_list, futex) futex_list; extern struct mtx futex_mtx; void linux_dev_shm_create(void); void linux_dev_shm_destroy(void); +/* + * mask=0 is not sensible for this application, so it will be taken to mean + * a mask equivalent to the value. Otherwise, (word & mask) == value maps to + * (word & ~mask) | value in a bitfield for the platform we're converting to. + */ +struct bsd_to_linux_bitmap { + int bsd_mask; + int bsd_value; + int linux_mask; + int linux_value; +}; + +int bsd_to_linux_bits_(int value, struct bsd_to_linux_bitmap *bitmap, + size_t mapcnt, int no_value); +int linux_to_bsd_bits_(int value, struct bsd_to_linux_bitmap *bitmap, + size_t mapcnt, int no_value); + +#define bsd_to_linux_bits(_val, _bmap, _noval) \ + bsd_to_linux_bits_((_val), (_bmap), nitems((_bmap)), (_noval)) + +/* + * These functions are used for simplification of BSD <-> Linux bit conversions. + * Given `value`, a bit field, these functions will walk the given bitmap table + * and set the appropriate bits for the target platform. If any bits were + * successfully converted, then the return value is the equivalent of value + * represented with the bit values appropriate for the target platform. + * Otherwise, the value supplied as `no_value` is returned. + */ +#define linux_to_bsd_bits(_val, _bmap, _noval) \ + linux_to_bsd_bits_((_val), (_bmap), nitems((_bmap)), (_noval)) + +/* + * Easy mapping helpers. BITMAP_EASY_LINUX represents a single bit to be + * translated, and the FreeBSD and Linux values are supplied. BITMAP_1t1_LINUX + * is the extreme version of this, where not only is it a single bit, but the + * name of the macro used to represent the Linux version of a bit literally has + * LINUX_ prepended to the normal name. + */ +#define BITMAP_EASY_LINUX(_name, _linux_name) \ + { \ + .bsd_value = (_name), \ + .linux_value = (_linux_name), \ + } +#define BITMAP_1t1_LINUX(_name) BITMAP_EASY_LINUX(_name, LINUX_##_name) + #endif /* _LINUX_MI_H_ */ Index: head/sys/compat/linux/linux_file.c =================================================================== --- head/sys/compat/linux/linux_file.c (revision 362768) +++ head/sys/compat/linux/linux_file.c (revision 362769) @@ -1,1678 +1,1768 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #ifdef COMPAT_LINUX32 #include #include #include #else #include #include #endif #include #include #include static int linux_common_open(struct thread *, int, char *, int, int); static int linux_getdents_error(struct thread *, int, int); +static struct bsd_to_linux_bitmap seal_bitmap[] = { + BITMAP_1t1_LINUX(F_SEAL_SEAL), + BITMAP_1t1_LINUX(F_SEAL_SHRINK), + BITMAP_1t1_LINUX(F_SEAL_GROW), + BITMAP_1t1_LINUX(F_SEAL_WRITE), +}; + +#define MFD_HUGETLB_ENTRY(_size) \ + { \ + .bsd_value = MFD_HUGE_##_size, \ + .linux_value = LINUX_HUGETLB_FLAG_ENCODE_##_size \ + } +static struct bsd_to_linux_bitmap mfd_bitmap[] = { + BITMAP_1t1_LINUX(MFD_CLOEXEC), + BITMAP_1t1_LINUX(MFD_ALLOW_SEALING), + BITMAP_1t1_LINUX(MFD_HUGETLB), + MFD_HUGETLB_ENTRY(64KB), + MFD_HUGETLB_ENTRY(512KB), + MFD_HUGETLB_ENTRY(1MB), + MFD_HUGETLB_ENTRY(2MB), + MFD_HUGETLB_ENTRY(8MB), + MFD_HUGETLB_ENTRY(16MB), + MFD_HUGETLB_ENTRY(32MB), + MFD_HUGETLB_ENTRY(256MB), + MFD_HUGETLB_ENTRY(512MB), + MFD_HUGETLB_ENTRY(1GB), + MFD_HUGETLB_ENTRY(2GB), + MFD_HUGETLB_ENTRY(16GB), +}; +#undef MFD_HUGETLB_ENTRY + #ifdef LINUX_LEGACY_SYSCALLS int linux_creat(struct thread *td, struct linux_creat_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, args->mode); LFREEPATH(path); return (error); } #endif static int linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) { struct proc *p = td->td_proc; struct file *fp; int fd; int bsd_flags, error; bsd_flags = 0; switch (l_flags & LINUX_O_ACCMODE) { case LINUX_O_WRONLY: bsd_flags |= O_WRONLY; break; case LINUX_O_RDWR: bsd_flags |= O_RDWR; break; default: bsd_flags |= O_RDONLY; } if (l_flags & LINUX_O_NDELAY) bsd_flags |= O_NONBLOCK; if (l_flags & LINUX_O_APPEND) bsd_flags |= O_APPEND; if (l_flags & LINUX_O_SYNC) bsd_flags |= O_FSYNC; if (l_flags & LINUX_O_CLOEXEC) bsd_flags |= O_CLOEXEC; if (l_flags & LINUX_O_NONBLOCK) bsd_flags |= O_NONBLOCK; if (l_flags & LINUX_O_ASYNC) bsd_flags |= O_ASYNC; if (l_flags & LINUX_O_CREAT) bsd_flags |= O_CREAT; if (l_flags & LINUX_O_TRUNC) bsd_flags |= O_TRUNC; if (l_flags & LINUX_O_EXCL) bsd_flags |= O_EXCL; if (l_flags & LINUX_O_NOCTTY) bsd_flags |= O_NOCTTY; if (l_flags & LINUX_O_DIRECT) bsd_flags |= O_DIRECT; if (l_flags & LINUX_O_NOFOLLOW) bsd_flags |= O_NOFOLLOW; if (l_flags & LINUX_O_DIRECTORY) bsd_flags |= O_DIRECTORY; /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); if (error != 0) { if (error == EMLINK) error = ELOOP; goto done; } if (p->p_flag & P_CONTROLT) goto done; if (bsd_flags & O_NOCTTY) goto done; /* * XXX In between kern_openat() and fget(), another process * having the same filedesc could use that fd without * checking below. */ fd = td->td_retval[0]; if (fget(td, fd, &cap_ioctl_rights, &fp) == 0) { if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); goto done; } sx_slock(&proctree_lock); PROC_LOCK(p); if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { PROC_UNLOCK(p); sx_sunlock(&proctree_lock); /* XXXPJD: Verify if TIOCSCTTY is allowed. */ (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, td); } else { PROC_UNLOCK(p); sx_sunlock(&proctree_lock); } fdrop(fp, td); } done: LFREEPATH(path); return (error); } int linux_openat(struct thread *td, struct linux_openat_args *args) { char *path; int dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; if (args->flags & LINUX_O_CREAT) LCONVPATH_AT(td, args->filename, &path, 1, dfd); else LCONVPATH_AT(td, args->filename, &path, 0, dfd); return (linux_common_open(td, dfd, path, args->flags, args->mode)); } #ifdef LINUX_LEGACY_SYSCALLS int linux_open(struct thread *td, struct linux_open_args *args) { char *path; if (args->flags & LINUX_O_CREAT) LCONVPATHCREAT(td, args->path, &path); else LCONVPATHEXIST(td, args->path, &path); return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); } #endif int linux_lseek(struct thread *td, struct linux_lseek_args *args) { return (kern_lseek(td, args->fdes, args->off, args->whence)); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_llseek(struct thread *td, struct linux_llseek_args *args) { int error; off_t off; off = (args->olow) | (((off_t) args->ohigh) << 32); error = kern_lseek(td, args->fd, off, args->whence); if (error != 0) return (error); error = copyout(td->td_retval, args->res, sizeof(off_t)); if (error != 0) return (error); td->td_retval[0] = 0; return (0); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ /* * Note that linux_getdents(2) and linux_getdents64(2) have the same * arguments. They only differ in the definition of struct dirent they * operate on. * Note that linux_readdir(2) is a special case of linux_getdents(2) * where count is always equals 1, meaning that the buffer is one * dirent-structure in size and that the code can't handle more anyway. * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2) * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will * trash user stack. */ static int linux_getdents_error(struct thread *td, int fd, int err) { struct vnode *vp; struct file *fp; int error; /* Linux return ENOTDIR in case when fd is not a directory. */ error = getvnode(td, fd, &cap_read_rights, &fp); if (error != 0) return (error); vp = fp->f_vnode; if (vp->v_type != VDIR) { fdrop(fp, td); return (ENOTDIR); } fdrop(fp, td); return (err); } struct l_dirent { l_ulong d_ino; l_off_t d_off; l_ushort d_reclen; char d_name[LINUX_NAME_MAX + 1]; }; struct l_dirent64 { uint64_t d_ino; int64_t d_off; l_ushort d_reclen; u_char d_type; char d_name[LINUX_NAME_MAX + 1]; }; /* * Linux uses the last byte in the dirent buffer to store d_type, * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes. */ #define LINUX_RECLEN(namlen) \ roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong)) #define LINUX_RECLEN64(namlen) \ roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \ sizeof(uint64_t)) #ifdef LINUX_LEGACY_SYSCALLS int linux_getdents(struct thread *td, struct linux_getdents_args *args) { struct dirent *bdp; caddr_t inp, buf; /* BSD-format */ int len, reclen; /* BSD-format */ caddr_t outp; /* Linux-format */ int resid, linuxreclen; /* Linux-format */ caddr_t lbuf; /* Linux-format */ off_t base; struct l_dirent *linux_dirent; int buflen, error; size_t retval; buflen = min(args->count, MAXBSIZE); buf = malloc(buflen, M_TEMP, M_WAITOK); error = kern_getdirentries(td, args->fd, buf, buflen, &base, NULL, UIO_SYSSPACE); if (error != 0) { error = linux_getdents_error(td, args->fd, error); goto out1; } lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); len = td->td_retval[0]; inp = buf; outp = (caddr_t)args->dent; resid = args->count; retval = 0; while (len > 0) { bdp = (struct dirent *) inp; reclen = bdp->d_reclen; linuxreclen = LINUX_RECLEN(bdp->d_namlen); /* * No more space in the user supplied dirent buffer. * Return EINVAL. */ if (resid < linuxreclen) { error = EINVAL; goto out; } linux_dirent = (struct l_dirent*)lbuf; linux_dirent->d_ino = bdp->d_fileno; linux_dirent->d_off = base + reclen; linux_dirent->d_reclen = linuxreclen; /* * Copy d_type to last byte of l_dirent buffer */ lbuf[linuxreclen - 1] = bdp->d_type; strlcpy(linux_dirent->d_name, bdp->d_name, linuxreclen - offsetof(struct l_dirent, d_name)-1); error = copyout(linux_dirent, outp, linuxreclen); if (error != 0) goto out; inp += reclen; base += reclen; len -= reclen; retval += linuxreclen; outp += linuxreclen; resid -= linuxreclen; } td->td_retval[0] = retval; out: free(lbuf, M_TEMP); out1: free(buf, M_TEMP); return (error); } #endif int linux_getdents64(struct thread *td, struct linux_getdents64_args *args) { struct dirent *bdp; caddr_t inp, buf; /* BSD-format */ int len, reclen; /* BSD-format */ caddr_t outp; /* Linux-format */ int resid, linuxreclen; /* Linux-format */ caddr_t lbuf; /* Linux-format */ off_t base; struct l_dirent64 *linux_dirent64; int buflen, error; size_t retval; buflen = min(args->count, MAXBSIZE); buf = malloc(buflen, M_TEMP, M_WAITOK); error = kern_getdirentries(td, args->fd, buf, buflen, &base, NULL, UIO_SYSSPACE); if (error != 0) { error = linux_getdents_error(td, args->fd, error); goto out1; } lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); len = td->td_retval[0]; inp = buf; outp = (caddr_t)args->dirent; resid = args->count; retval = 0; while (len > 0) { bdp = (struct dirent *) inp; reclen = bdp->d_reclen; linuxreclen = LINUX_RECLEN64(bdp->d_namlen); /* * No more space in the user supplied dirent buffer. * Return EINVAL. */ if (resid < linuxreclen) { error = EINVAL; goto out; } linux_dirent64 = (struct l_dirent64*)lbuf; linux_dirent64->d_ino = bdp->d_fileno; linux_dirent64->d_off = base + reclen; linux_dirent64->d_reclen = linuxreclen; linux_dirent64->d_type = bdp->d_type; strlcpy(linux_dirent64->d_name, bdp->d_name, linuxreclen - offsetof(struct l_dirent64, d_name)); error = copyout(linux_dirent64, outp, linuxreclen); if (error != 0) goto out; inp += reclen; base += reclen; len -= reclen; retval += linuxreclen; outp += linuxreclen; resid -= linuxreclen; } td->td_retval[0] = retval; out: free(lbuf, M_TEMP); out1: free(buf, M_TEMP); return (error); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_readdir(struct thread *td, struct linux_readdir_args *args) { struct dirent *bdp; caddr_t buf; /* BSD-format */ int linuxreclen; /* Linux-format */ caddr_t lbuf; /* Linux-format */ off_t base; struct l_dirent *linux_dirent; int buflen, error; buflen = LINUX_RECLEN(LINUX_NAME_MAX); buf = malloc(buflen, M_TEMP, M_WAITOK); error = kern_getdirentries(td, args->fd, buf, buflen, &base, NULL, UIO_SYSSPACE); if (error != 0) { error = linux_getdents_error(td, args->fd, error); goto out; } if (td->td_retval[0] == 0) goto out; lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); bdp = (struct dirent *) buf; linuxreclen = LINUX_RECLEN(bdp->d_namlen); linux_dirent = (struct l_dirent*)lbuf; linux_dirent->d_ino = bdp->d_fileno; linux_dirent->d_off = linuxreclen; linux_dirent->d_reclen = bdp->d_namlen; strlcpy(linux_dirent->d_name, bdp->d_name, linuxreclen - offsetof(struct l_dirent, d_name)); error = copyout(linux_dirent, args->dent, linuxreclen); if (error == 0) td->td_retval[0] = linuxreclen; free(lbuf, M_TEMP); out: free(buf, M_TEMP); return (error); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ /* * These exist mainly for hooks for doing /compat/linux translation. */ #ifdef LINUX_LEGACY_SYSCALLS int linux_access(struct thread *td, struct linux_access_args *args) { char *path; int error; /* Linux convention. */ if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) return (EINVAL); LCONVPATHEXIST(td, args->path, &path); error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, args->amode); LFREEPATH(path); return (error); } #endif int linux_faccessat(struct thread *td, struct linux_faccessat_args *args) { char *path; int error, dfd; /* Linux convention. */ if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) return (EINVAL); dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->filename, &path, dfd); error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode); LFREEPATH(path); return (error); } #ifdef LINUX_LEGACY_SYSCALLS int linux_unlink(struct thread *td, struct linux_unlink_args *args) { char *path; int error; struct stat st; LCONVPATHEXIST(td, args->path, &path); error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0); if (error == EPERM) { /* Introduce POSIX noncompliant behaviour of Linux */ if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st, NULL) == 0) { if (S_ISDIR(st.st_mode)) error = EISDIR; } } LFREEPATH(path); return (error); } #endif int linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) { char *path; int error, dfd; struct stat st; if (args->flag & ~LINUX_AT_REMOVEDIR) return (EINVAL); dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); if (args->flag & LINUX_AT_REMOVEDIR) error = kern_frmdirat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0); else error = kern_funlinkat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0, 0); if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { /* Introduce POSIX noncompliant behaviour of Linux */ if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode)) error = EISDIR; } LFREEPATH(path); return (error); } int linux_chdir(struct thread *td, struct linux_chdir_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); error = kern_chdir(td, path, UIO_SYSSPACE); LFREEPATH(path); return (error); } #ifdef LINUX_LEGACY_SYSCALLS int linux_chmod(struct thread *td, struct linux_chmod_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, 0); LFREEPATH(path); return (error); } #endif int linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) { char *path; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->filename, &path, dfd); error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); LFREEPATH(path); return (error); } #ifdef LINUX_LEGACY_SYSCALLS int linux_mkdir(struct thread *td, struct linux_mkdir_args *args) { char *path; int error; LCONVPATHCREAT(td, args->path, &path); error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode); LFREEPATH(path); return (error); } #endif int linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) { char *path; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); LFREEPATH(path); return (error); } #ifdef LINUX_LEGACY_SYSCALLS int linux_rmdir(struct thread *td, struct linux_rmdir_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0); LFREEPATH(path); return (error); } int linux_rename(struct thread *td, struct linux_rename_args *args) { char *from, *to; int error; LCONVPATHEXIST(td, args->from, &from); /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); if (to == NULL) { LFREEPATH(from); return (error); } error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE); LFREEPATH(from); LFREEPATH(to); return (error); } #endif int linux_renameat(struct thread *td, struct linux_renameat_args *args) { struct linux_renameat2_args renameat2_args = { .olddfd = args->olddfd, .oldname = args->oldname, .newdfd = args->newdfd, .newname = args->newname, .flags = 0 }; return (linux_renameat2(td, &renameat2_args)); } int linux_renameat2(struct thread *td, struct linux_renameat2_args *args) { char *from, *to; int error, olddfd, newdfd; if (args->flags != 0) { if (args->flags & ~(LINUX_RENAME_EXCHANGE | LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT)) return (EINVAL); if (args->flags & LINUX_RENAME_EXCHANGE && args->flags & (LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT)) return (EINVAL); linux_msg(td, "renameat2 unsupported flags 0x%x", args->flags); return (EINVAL); } olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd); /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); if (to == NULL) { LFREEPATH(from); return (error); } error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); LFREEPATH(from); LFREEPATH(to); return (error); } #ifdef LINUX_LEGACY_SYSCALLS int linux_symlink(struct thread *td, struct linux_symlink_args *args) { char *path, *to; int error; LCONVPATHEXIST(td, args->path, &path); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); if (to == NULL) { LFREEPATH(path); return (error); } error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE); LFREEPATH(path); LFREEPATH(to); return (error); } #endif int linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) { char *path, *to; int error, dfd; dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; LCONVPATHEXIST(td, args->oldname, &path); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); if (to == NULL) { LFREEPATH(path); return (error); } error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); LFREEPATH(path); LFREEPATH(to); return (error); } #ifdef LINUX_LEGACY_SYSCALLS int linux_readlink(struct thread *td, struct linux_readlink_args *args) { char *name; int error; LCONVPATHEXIST(td, args->name, &name); error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, args->count); LFREEPATH(name); return (error); } #endif int linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) { char *name; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->path, &name, dfd); error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, args->bufsiz); LFREEPATH(name); return (error); } int linux_truncate(struct thread *td, struct linux_truncate_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); error = kern_truncate(td, path, UIO_SYSSPACE, args->length); LFREEPATH(path); return (error); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_truncate64(struct thread *td, struct linux_truncate64_args *args) { char *path; off_t length; int error; #if defined(__amd64__) && defined(COMPAT_LINUX32) length = PAIR32TO64(off_t, args->length); #else length = args->length; #endif LCONVPATHEXIST(td, args->path, &path); error = kern_truncate(td, path, UIO_SYSSPACE, length); LFREEPATH(path); return (error); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) { return (kern_ftruncate(td, args->fd, args->length)); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args) { off_t length; #if defined(__amd64__) && defined(COMPAT_LINUX32) length = PAIR32TO64(off_t, args->length); #else length = args->length; #endif return (kern_ftruncate(td, args->fd, length)); } #endif #ifdef LINUX_LEGACY_SYSCALLS int linux_link(struct thread *td, struct linux_link_args *args) { char *path, *to; int error; LCONVPATHEXIST(td, args->path, &path); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); if (to == NULL) { LFREEPATH(path); return (error); } error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE, FOLLOW); LFREEPATH(path); LFREEPATH(to); return (error); } #endif int linux_linkat(struct thread *td, struct linux_linkat_args *args) { char *path, *to; int error, olddfd, newdfd, follow; if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW) return (EINVAL); olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); if (to == NULL) { LFREEPATH(path); return (error); } follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW : FOLLOW; error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow); LFREEPATH(path); LFREEPATH(to); return (error); } int linux_fdatasync(struct thread *td, struct linux_fdatasync_args *uap) { return (kern_fsync(td, uap->fd, false)); } int linux_sync_file_range(struct thread *td, struct linux_sync_file_range_args *uap) { off_t nbytes, offset; #if defined(__amd64__) && defined(COMPAT_LINUX32) nbytes = PAIR32TO64(off_t, uap->nbytes); offset = PAIR32TO64(off_t, uap->offset); #else nbytes = uap->nbytes; offset = uap->offset; #endif if (offset < 0 || nbytes < 0 || (uap->flags & ~(LINUX_SYNC_FILE_RANGE_WAIT_BEFORE | LINUX_SYNC_FILE_RANGE_WRITE | LINUX_SYNC_FILE_RANGE_WAIT_AFTER)) != 0) { return (EINVAL); } return (kern_fsync(td, uap->fd, false)); } int linux_pread(struct thread *td, struct linux_pread_args *uap) { struct vnode *vp; off_t offset; int error; #if defined(__amd64__) && defined(COMPAT_LINUX32) offset = PAIR32TO64(off_t, uap->offset); #else offset = uap->offset; #endif error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, offset); if (error == 0) { /* This seems to violate POSIX but Linux does it. */ error = fgetvp(td, uap->fd, &cap_pread_rights, &vp); if (error != 0) return (error); if (vp->v_type == VDIR) error = EISDIR; vrele(vp); } return (error); } int linux_pwrite(struct thread *td, struct linux_pwrite_args *uap) { off_t offset; #if defined(__amd64__) && defined(COMPAT_LINUX32) offset = PAIR32TO64(off_t, uap->offset); #else offset = uap->offset; #endif return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset)); } int linux_preadv(struct thread *td, struct linux_preadv_args *uap) { struct uio *auio; int error; off_t offset; /* * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES * pos_l and pos_h, respectively, contain the * low order and high order 32 bits of offset. */ offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << (sizeof(offset) * 4)) | uap->pos_l; if (offset < 0) return (EINVAL); #ifdef COMPAT_LINUX32 error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); #else error = copyinuio(uap->vec, uap->vlen, &auio); #endif if (error != 0) return (error); error = kern_preadv(td, uap->fd, auio, offset); free(auio, M_IOV); return (error); } int linux_pwritev(struct thread *td, struct linux_pwritev_args *uap) { struct uio *auio; int error; off_t offset; /* * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES * pos_l and pos_h, respectively, contain the * low order and high order 32 bits of offset. */ offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << (sizeof(offset) * 4)) | uap->pos_l; if (offset < 0) return (EINVAL); #ifdef COMPAT_LINUX32 error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); #else error = copyinuio(uap->vec, uap->vlen, &auio); #endif if (error != 0) return (error); error = kern_pwritev(td, uap->fd, auio, offset); free(auio, M_IOV); return (error); } int linux_mount(struct thread *td, struct linux_mount_args *args) { char fstypename[MFSNAMELEN]; char *mntonname, *mntfromname; int error, fsflags; mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK); mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK); error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, NULL); if (error != 0) goto out; if (args->specialfile != NULL) { error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); if (error != 0) goto out; } else { mntfromname[0] = '\0'; } error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); if (error != 0) goto out; if (strcmp(fstypename, "ext2") == 0) { strcpy(fstypename, "ext2fs"); } else if (strcmp(fstypename, "proc") == 0) { strcpy(fstypename, "linprocfs"); } else if (strcmp(fstypename, "vfat") == 0) { strcpy(fstypename, "msdosfs"); } fsflags = 0; /* * Linux SYNC flag is not included; the closest equivalent * FreeBSD has is !ASYNC, which is our default. */ if (args->rwflag & LINUX_MS_RDONLY) fsflags |= MNT_RDONLY; if (args->rwflag & LINUX_MS_NOSUID) fsflags |= MNT_NOSUID; if (args->rwflag & LINUX_MS_NOEXEC) fsflags |= MNT_NOEXEC; if (args->rwflag & LINUX_MS_REMOUNT) fsflags |= MNT_UPDATE; error = kernel_vmount(fsflags, "fstype", fstypename, "fspath", mntonname, "from", mntfromname, NULL); out: free(mntonname, M_TEMP); free(mntfromname, M_TEMP); return (error); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_oldumount(struct thread *td, struct linux_oldumount_args *args) { return (kern_unmount(td, args->path, 0)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ #ifdef LINUX_LEGACY_SYSCALLS int linux_umount(struct thread *td, struct linux_umount_args *args) { int flags; flags = 0; if ((args->flags & LINUX_MNT_FORCE) != 0) { args->flags &= ~LINUX_MNT_FORCE; flags |= MNT_FORCE; } if (args->flags != 0) { linux_msg(td, "unsupported umount2 flags %#x", args->flags); return (EINVAL); } return (kern_unmount(td, args->path, flags)); } #endif /* * fcntl family of syscalls */ struct l_flock { l_short l_type; l_short l_whence; l_off_t l_start; l_off_t l_len; l_pid_t l_pid; } #if defined(__amd64__) && defined(COMPAT_LINUX32) __packed #endif ; static void linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) { switch (linux_flock->l_type) { case LINUX_F_RDLCK: bsd_flock->l_type = F_RDLCK; break; case LINUX_F_WRLCK: bsd_flock->l_type = F_WRLCK; break; case LINUX_F_UNLCK: bsd_flock->l_type = F_UNLCK; break; default: bsd_flock->l_type = -1; break; } bsd_flock->l_whence = linux_flock->l_whence; bsd_flock->l_start = (off_t)linux_flock->l_start; bsd_flock->l_len = (off_t)linux_flock->l_len; bsd_flock->l_pid = (pid_t)linux_flock->l_pid; bsd_flock->l_sysid = 0; } static void bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) { switch (bsd_flock->l_type) { case F_RDLCK: linux_flock->l_type = LINUX_F_RDLCK; break; case F_WRLCK: linux_flock->l_type = LINUX_F_WRLCK; break; case F_UNLCK: linux_flock->l_type = LINUX_F_UNLCK; break; } linux_flock->l_whence = bsd_flock->l_whence; linux_flock->l_start = (l_off_t)bsd_flock->l_start; linux_flock->l_len = (l_off_t)bsd_flock->l_len; linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) struct l_flock64 { l_short l_type; l_short l_whence; l_loff_t l_start; l_loff_t l_len; l_pid_t l_pid; } #if defined(__amd64__) && defined(COMPAT_LINUX32) __packed #endif ; static void linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) { switch (linux_flock->l_type) { case LINUX_F_RDLCK: bsd_flock->l_type = F_RDLCK; break; case LINUX_F_WRLCK: bsd_flock->l_type = F_WRLCK; break; case LINUX_F_UNLCK: bsd_flock->l_type = F_UNLCK; break; default: bsd_flock->l_type = -1; break; } bsd_flock->l_whence = linux_flock->l_whence; bsd_flock->l_start = (off_t)linux_flock->l_start; bsd_flock->l_len = (off_t)linux_flock->l_len; bsd_flock->l_pid = (pid_t)linux_flock->l_pid; bsd_flock->l_sysid = 0; } static void bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) { switch (bsd_flock->l_type) { case F_RDLCK: linux_flock->l_type = LINUX_F_RDLCK; break; case F_WRLCK: linux_flock->l_type = LINUX_F_WRLCK; break; case F_UNLCK: linux_flock->l_type = LINUX_F_UNLCK; break; } linux_flock->l_whence = bsd_flock->l_whence; linux_flock->l_start = (l_loff_t)bsd_flock->l_start; linux_flock->l_len = (l_loff_t)bsd_flock->l_len; linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ static int fcntl_common(struct thread *td, struct linux_fcntl_args *args) { struct l_flock linux_flock; struct flock bsd_flock; struct file *fp; long arg; int error, result; switch (args->cmd) { case LINUX_F_DUPFD: return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); case LINUX_F_GETFD: return (kern_fcntl(td, args->fd, F_GETFD, 0)); case LINUX_F_SETFD: return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); case LINUX_F_GETFL: error = kern_fcntl(td, args->fd, F_GETFL, 0); result = td->td_retval[0]; td->td_retval[0] = 0; if (result & O_RDONLY) td->td_retval[0] |= LINUX_O_RDONLY; if (result & O_WRONLY) td->td_retval[0] |= LINUX_O_WRONLY; if (result & O_RDWR) td->td_retval[0] |= LINUX_O_RDWR; if (result & O_NDELAY) td->td_retval[0] |= LINUX_O_NONBLOCK; if (result & O_APPEND) td->td_retval[0] |= LINUX_O_APPEND; if (result & O_FSYNC) td->td_retval[0] |= LINUX_O_SYNC; if (result & O_ASYNC) td->td_retval[0] |= LINUX_O_ASYNC; #ifdef LINUX_O_NOFOLLOW if (result & O_NOFOLLOW) td->td_retval[0] |= LINUX_O_NOFOLLOW; #endif #ifdef LINUX_O_DIRECT if (result & O_DIRECT) td->td_retval[0] |= LINUX_O_DIRECT; #endif return (error); case LINUX_F_SETFL: arg = 0; if (args->arg & LINUX_O_NDELAY) arg |= O_NONBLOCK; if (args->arg & LINUX_O_APPEND) arg |= O_APPEND; if (args->arg & LINUX_O_SYNC) arg |= O_FSYNC; if (args->arg & LINUX_O_ASYNC) arg |= O_ASYNC; #ifdef LINUX_O_NOFOLLOW if (args->arg & LINUX_O_NOFOLLOW) arg |= O_NOFOLLOW; #endif #ifdef LINUX_O_DIRECT if (args->arg & LINUX_O_DIRECT) arg |= O_DIRECT; #endif return (kern_fcntl(td, args->fd, F_SETFL, arg)); case LINUX_F_GETLK: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock(&linux_flock, &bsd_flock); error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); if (error) return (error); bsd_to_linux_flock(&bsd_flock, &linux_flock); return (copyout(&linux_flock, (void *)args->arg, sizeof(linux_flock))); case LINUX_F_SETLK: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock(&linux_flock, &bsd_flock); return (kern_fcntl(td, args->fd, F_SETLK, (intptr_t)&bsd_flock)); case LINUX_F_SETLKW: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock(&linux_flock, &bsd_flock); return (kern_fcntl(td, args->fd, F_SETLKW, (intptr_t)&bsd_flock)); case LINUX_F_GETOWN: return (kern_fcntl(td, args->fd, F_GETOWN, 0)); case LINUX_F_SETOWN: /* * XXX some Linux applications depend on F_SETOWN having no * significant effect for pipes (SIGIO is not delivered for * pipes under Linux-2.2.35 at least). */ error = fget(td, args->fd, &cap_fcntl_rights, &fp); if (error) return (error); if (fp->f_type == DTYPE_PIPE) { fdrop(fp, td); return (EINVAL); } fdrop(fp, td); return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); case LINUX_F_DUPFD_CLOEXEC: return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg)); + /* + * Our F_SEAL_* values match Linux one for maximum compatibility. So we + * only needed to account for different values for fcntl(2) commands. + */ + case LINUX_F_GET_SEALS: + error = kern_fcntl(td, args->fd, F_GET_SEALS, 0); + if (error != 0) + return (error); + td->td_retval[0] = bsd_to_linux_bits(td->td_retval[0], + seal_bitmap, 0); + return (0); + + case LINUX_F_ADD_SEALS: + return (kern_fcntl(td, args->fd, F_ADD_SEALS, + linux_to_bsd_bits(args->arg, seal_bitmap, 0))); default: linux_msg(td, "unsupported fcntl cmd %d\n", args->cmd); return (EINVAL); } } int linux_fcntl(struct thread *td, struct linux_fcntl_args *args) { return (fcntl_common(td, args)); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) { struct l_flock64 linux_flock; struct flock bsd_flock; struct linux_fcntl_args fcntl_args; int error; switch (args->cmd) { case LINUX_F_GETLK64: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock64(&linux_flock, &bsd_flock); error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); if (error) return (error); bsd_to_linux_flock64(&bsd_flock, &linux_flock); return (copyout(&linux_flock, (void *)args->arg, sizeof(linux_flock))); case LINUX_F_SETLK64: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock64(&linux_flock, &bsd_flock); return (kern_fcntl(td, args->fd, F_SETLK, (intptr_t)&bsd_flock)); case LINUX_F_SETLKW64: error = copyin((void *)args->arg, &linux_flock, sizeof(linux_flock)); if (error) return (error); linux_to_bsd_flock64(&linux_flock, &bsd_flock); return (kern_fcntl(td, args->fd, F_SETLKW, (intptr_t)&bsd_flock)); } fcntl_args.fd = args->fd; fcntl_args.cmd = args->cmd; fcntl_args.arg = args->arg; return (fcntl_common(td, &fcntl_args)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ #ifdef LINUX_LEGACY_SYSCALLS int linux_chown(struct thread *td, struct linux_chown_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid, 0); LFREEPATH(path); return (error); } #endif int linux_fchownat(struct thread *td, struct linux_fchownat_args *args) { char *path; int error, dfd, flag; if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) return (EINVAL); dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->filename, &path, dfd); flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : AT_SYMLINK_NOFOLLOW; error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, flag); LFREEPATH(path); return (error); } #ifdef LINUX_LEGACY_SYSCALLS int linux_lchown(struct thread *td, struct linux_lchown_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid, AT_SYMLINK_NOFOLLOW); LFREEPATH(path); return (error); } #endif static int convert_fadvice(int advice) { switch (advice) { case LINUX_POSIX_FADV_NORMAL: return (POSIX_FADV_NORMAL); case LINUX_POSIX_FADV_RANDOM: return (POSIX_FADV_RANDOM); case LINUX_POSIX_FADV_SEQUENTIAL: return (POSIX_FADV_SEQUENTIAL); case LINUX_POSIX_FADV_WILLNEED: return (POSIX_FADV_WILLNEED); case LINUX_POSIX_FADV_DONTNEED: return (POSIX_FADV_DONTNEED); case LINUX_POSIX_FADV_NOREUSE: return (POSIX_FADV_NOREUSE); default: return (-1); } } int linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args) { off_t offset; int advice; #if defined(__amd64__) && defined(COMPAT_LINUX32) offset = PAIR32TO64(off_t, args->offset); #else offset = args->offset; #endif advice = convert_fadvice(args->advice); if (advice == -1) return (EINVAL); return (kern_posix_fadvise(td, args->fd, offset, args->len, advice)); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args) { off_t len, offset; int advice; #if defined(__amd64__) && defined(COMPAT_LINUX32) len = PAIR32TO64(off_t, args->len); offset = PAIR32TO64(off_t, args->offset); #else len = args->len; offset = args->offset; #endif advice = convert_fadvice(args->advice); if (advice == -1) return (EINVAL); return (kern_posix_fadvise(td, args->fd, offset, len, advice)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ #ifdef LINUX_LEGACY_SYSCALLS int linux_pipe(struct thread *td, struct linux_pipe_args *args) { int fildes[2]; int error; error = kern_pipe(td, fildes, 0, NULL, NULL); if (error != 0) return (error); error = copyout(fildes, args->pipefds, sizeof(fildes)); if (error != 0) { (void)kern_close(td, fildes[0]); (void)kern_close(td, fildes[1]); } return (error); } #endif int linux_pipe2(struct thread *td, struct linux_pipe2_args *args) { int fildes[2]; int error, flags; if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0) return (EINVAL); flags = 0; if ((args->flags & LINUX_O_NONBLOCK) != 0) flags |= O_NONBLOCK; if ((args->flags & LINUX_O_CLOEXEC) != 0) flags |= O_CLOEXEC; error = kern_pipe(td, fildes, flags, NULL, NULL); if (error != 0) return (error); error = copyout(fildes, args->pipefds, sizeof(fildes)); if (error != 0) { (void)kern_close(td, fildes[0]); (void)kern_close(td, fildes[1]); } return (error); } int linux_dup3(struct thread *td, struct linux_dup3_args *args) { int cmd; intptr_t newfd; if (args->oldfd == args->newfd) return (EINVAL); if ((args->flags & ~LINUX_O_CLOEXEC) != 0) return (EINVAL); if (args->flags & LINUX_O_CLOEXEC) cmd = F_DUP2FD_CLOEXEC; else cmd = F_DUP2FD; newfd = args->newfd; return (kern_fcntl(td, args->oldfd, cmd, newfd)); } int linux_fallocate(struct thread *td, struct linux_fallocate_args *args) { off_t len, offset; /* * We emulate only posix_fallocate system call for which * mode should be 0. */ if (args->mode != 0) return (ENOSYS); #if defined(__amd64__) && defined(COMPAT_LINUX32) len = PAIR32TO64(off_t, args->len); offset = PAIR32TO64(off_t, args->offset); #else len = args->len; offset = args->offset; #endif return (kern_posix_fallocate(td, args->fd, offset, len)); } int linux_copy_file_range(struct thread *td, struct linux_copy_file_range_args *args) { l_loff_t inoff, outoff, *inoffp, *outoffp; int error, flags; /* * copy_file_range(2) on Linux doesn't define any flags (yet), so is * the native implementation. Enforce it. */ if (args->flags != 0) { linux_msg(td, "copy_file_range unsupported flags 0x%x", args->flags); return (EINVAL); } flags = 0; inoffp = outoffp = NULL; if (args->off_in != NULL) { error = copyin(args->off_in, &inoff, sizeof(l_loff_t)); if (error != 0) return (error); inoffp = &inoff; } if (args->off_out != NULL) { error = copyin(args->off_out, &outoff, sizeof(l_loff_t)); if (error != 0) return (error); outoffp = &outoff; } error = kern_copy_file_range(td, args->fd_in, inoffp, args->fd_out, outoffp, args->len, flags); if (error == 0 && args->off_in != NULL) error = copyout(inoffp, args->off_in, sizeof(l_loff_t)); if (error == 0 && args->off_out != NULL) error = copyout(outoffp, args->off_out, sizeof(l_loff_t)); return (error); } +#define LINUX_MEMFD_PREFIX "memfd:" + +int +linux_memfd_create(struct thread *td, struct linux_memfd_create_args *args) +{ + char memfd_name[LINUX_NAME_MAX + 1]; + int error, flags, shmflags, oflags; + + /* + * This is our clever trick to avoid the heap allocation to copy in the + * uname. We don't really need to go this far out of our way, but it + * does keep the rest of this function fairly clean as they don't have + * to worry about cleanup on the way out. + */ + error = copyinstr(args->uname_ptr, + memfd_name + sizeof(LINUX_MEMFD_PREFIX) - 1, + LINUX_NAME_MAX - sizeof(LINUX_MEMFD_PREFIX) - 1, NULL); + if (error != 0) { + if (error == ENAMETOOLONG) + error = EINVAL; + return (error); + } + + memcpy(memfd_name, LINUX_MEMFD_PREFIX, sizeof(LINUX_MEMFD_PREFIX) - 1); + flags = linux_to_bsd_bits(args->flags, mfd_bitmap, 0); + if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | + MFD_HUGE_MASK)) != 0) + return (EINVAL); + /* Size specified but no HUGETLB. */ + if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0) + return (EINVAL); + /* We don't actually support HUGETLB. */ + if ((flags & MFD_HUGETLB) != 0) + return (ENOSYS); + oflags = O_RDWR; + shmflags = 0; + if ((flags & MFD_CLOEXEC) != 0) + oflags |= O_CLOEXEC; + if ((flags & MFD_ALLOW_SEALING) != 0) + shmflags |= SHM_ALLOW_SEALING; + return (kern_shm_open2(td, SHM_ANON, oflags, 0, shmflags, NULL, + memfd_name)); +} Index: head/sys/compat/linux/linux_file.h =================================================================== --- head/sys/compat/linux/linux_file.h (revision 362768) +++ head/sys/compat/linux/linux_file.h (revision 362769) @@ -1,149 +1,177 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2007 Roman Divacky * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _LINUX_FILE_H_ #define _LINUX_FILE_H_ #define LINUX_AT_FDCWD -100 #define LINUX_AT_SYMLINK_NOFOLLOW 0x100 #define LINUX_AT_EACCESS 0x200 #define LINUX_AT_REMOVEDIR 0x200 #define LINUX_AT_SYMLINK_FOLLOW 0x400 /* * posix_fadvise advice */ #define LINUX_POSIX_FADV_NORMAL 0 #define LINUX_POSIX_FADV_RANDOM 1 #define LINUX_POSIX_FADV_SEQUENTIAL 2 #define LINUX_POSIX_FADV_WILLNEED 3 #define LINUX_POSIX_FADV_DONTNEED 4 #define LINUX_POSIX_FADV_NOREUSE 5 /* * mount flags */ #define LINUX_MS_RDONLY 0x0001 #define LINUX_MS_NOSUID 0x0002 #define LINUX_MS_NODEV 0x0004 #define LINUX_MS_NOEXEC 0x0008 #define LINUX_MS_REMOUNT 0x0020 /* * umount2 flags */ #define LINUX_MNT_FORCE 0x0001 /* * common open/fcntl flags */ #define LINUX_O_RDONLY 00000000 #define LINUX_O_WRONLY 00000001 #define LINUX_O_RDWR 00000002 #define LINUX_O_ACCMODE 00000003 #define LINUX_O_CREAT 00000100 #define LINUX_O_EXCL 00000200 #define LINUX_O_NOCTTY 00000400 #define LINUX_O_TRUNC 00001000 #define LINUX_O_APPEND 00002000 #define LINUX_O_NONBLOCK 00004000 #define LINUX_O_NDELAY LINUX_O_NONBLOCK #define LINUX_O_SYNC 00010000 #define LINUX_O_ASYNC 00020000 #define LINUX_O_DIRECT 00040000 /* Direct disk access hint */ #define LINUX_O_LARGEFILE 00100000 #define LINUX_O_DIRECTORY 00200000 /* Must be a directory */ #define LINUX_O_NOFOLLOW 00400000 /* Do not follow links */ #define LINUX_O_NOATIME 01000000 #define LINUX_O_CLOEXEC 02000000 #define LINUX_F_DUPFD 0 #define LINUX_F_GETFD 1 #define LINUX_F_SETFD 2 #define LINUX_F_GETFL 3 #define LINUX_F_SETFL 4 #ifndef LINUX_F_GETLK #define LINUX_F_GETLK 5 #define LINUX_F_SETLK 6 #define LINUX_F_SETLKW 7 #endif #ifndef LINUX_F_SETOWN #define LINUX_F_SETOWN 8 #define LINUX_F_GETOWN 9 #endif #ifndef LINUX_F_SETSIG #define LINUX_F_SETSIG 10 #define LINUX_F_GETSIG 11 #endif #ifndef LINUX_F_SETOWN_EX #define LINUX_F_SETOWN_EX 15 #define LINUX_F_GETOWN_EX 16 #define LINUX_F_GETOWNER_UIDS 17 #endif #define LINUX_F_SPECIFIC_BASE 1024 #define LINUX_F_SETLEASE (LINUX_F_SPECIFIC_BASE + 0) #define LINUX_F_GETLEASE (LINUX_F_SPECIFIC_BASE + 1) #define LINUX_F_CANCELLK (LINUX_F_SPECIFIC_BASE + 5) #define LINUX_F_DUPFD_CLOEXEC (LINUX_F_SPECIFIC_BASE + 6) #define LINUX_F_NOTIFY (LINUX_F_SPECIFIC_BASE + 2) #define LINUX_F_SETPIPE_SZ (LINUX_F_SPECIFIC_BASE + 7) #define LINUX_F_GETPIPE_SZ (LINUX_F_SPECIFIC_BASE + 8) +#define LINUX_F_ADD_SEALS (LINUX_F_SPECIFIC_BASE + 9) +#define LINUX_F_GET_SEALS (LINUX_F_SPECIFIC_BASE + 10) + #define LINUX_F_GETLKP 36 #define LINUX_F_SETLKP 37 #define LINUX_F_SETLKPW 38 #define LINUX_F_OWNER_TID 0 #define LINUX_F_OWNER_PID 1 #define LINUX_F_OWNER_PGRP 2 #ifndef LINUX_F_RDLCK #define LINUX_F_RDLCK 0 #define LINUX_F_WRLCK 1 #define LINUX_F_UNLCK 2 #endif /* * renameat2 flags */ #define LINUX_RENAME_NOREPLACE 0x00000001 #define LINUX_RENAME_EXCHANGE 0x00000002 #define LINUX_RENAME_WHITEOUT 0x00000004 /* * sync_file_range flags */ #define LINUX_SYNC_FILE_RANGE_WAIT_BEFORE 1 #define LINUX_SYNC_FILE_RANGE_WRITE 2 #define LINUX_SYNC_FILE_RANGE_WAIT_AFTER 4 + +#define LINUX_F_SEAL_SEAL 0x0001 +#define LINUX_F_SEAL_SHRINK 0x0002 +#define LINUX_F_SEAL_GROW 0x0004 +#define LINUX_F_SEAL_WRITE 0x0008 + +#define LINUX_MFD_CLOEXEC 0x0001 +#define LINUX_MFD_ALLOW_SEALING 0x0002 +#define LINUX_MFD_HUGETLB 0x0004 + +#define LINUX_HUGETLB_FLAG_ENCODE_SHIFT 26 +#define LINUX_HUGETLB_FLAG_ENCODE_MASK 0x3f + +#define LINUX_HUGETLB_FLAG_ENCODE_64KB (16 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_512KB (19 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_1MB (20 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_2MB (21 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_8MB (23 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_16MB (24 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_32MB (25 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_256MB (28 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_512MB (29 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_1GB (30 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_2GB (31 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) +#define LINUX_HUGETLB_FLAG_ENCODE_16GB (34U << LINUX_HUGETLB_FLAG_ENCODE_SHIFT) #endif /* !_LINUX_FILE_H_ */ Index: head/sys/i386/linux/linux_dummy.c =================================================================== --- head/sys/i386/linux/linux_dummy.c (revision 362768) +++ head/sys/i386/linux/linux_dummy.c (revision 362769) @@ -1,202 +1,201 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include /* DTrace init */ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); UNIMPLEMENTED(afs_syscall); UNIMPLEMENTED(break); UNIMPLEMENTED(create_module); /* Added in Linux 1.0 removed in 2.6. */ UNIMPLEMENTED(ftime); UNIMPLEMENTED(get_kernel_syms); /* Added in Linux 1.0 removed in 2.6. */ UNIMPLEMENTED(getpmsg); UNIMPLEMENTED(gtty); UNIMPLEMENTED(stty); UNIMPLEMENTED(lock); UNIMPLEMENTED(mpx); UNIMPLEMENTED(nfsservctl); /* Added in Linux 2.2 removed in 3.1. */ UNIMPLEMENTED(prof); UNIMPLEMENTED(profil); UNIMPLEMENTED(putpmsg); UNIMPLEMENTED(query_module); /* Added in Linux 2.2 removed in 2.6. */ UNIMPLEMENTED(ulimit); UNIMPLEMENTED(vserver); DUMMY(stime); DUMMY(fstat); DUMMY(olduname); DUMMY(uname); DUMMY(vhangup); DUMMY(vm86old); DUMMY(swapoff); DUMMY(adjtimex); DUMMY(init_module); DUMMY(delete_module); DUMMY(quotactl); DUMMY(bdflush); DUMMY(sysfs); DUMMY(vm86); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); DUMMY(lookup_dcookie); DUMMY(remap_file_pages); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(kexec_load); /* Linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); /* Linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_init); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); /* Linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(unshare); /* Linux 2.6.17: */ DUMMY(splice); DUMMY(tee); DUMMY(vmsplice); /* Linux 2.6.18: */ DUMMY(move_pages); /* Linux 2.6.22: */ DUMMY(signalfd); /* Linux 2.6.27: */ DUMMY(signalfd4); DUMMY(inotify_init1); /* Linux 2.6.31: */ DUMMY(perf_event_open); /* Linux 2.6.36: */ DUMMY(fanotify_init); DUMMY(fanotify_mark); /* Linux 2.6.39: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); /* Linux 3.0: */ DUMMY(setns); /* Linux 3.2: */ DUMMY(process_vm_readv); DUMMY(process_vm_writev); /* Linux 3.5: */ DUMMY(kcmp); /* Linux 3.8: */ DUMMY(finit_module); DUMMY(sched_setattr); DUMMY(sched_getattr); /* Linux 3.17: */ -DUMMY(memfd_create); DUMMY(seccomp); /* Linux 3.18: */ DUMMY(bpf); /* Linux 3.19: */ DUMMY(execveat); /* Linux 4.2: */ DUMMY(userfaultfd); /* Linux 4.3: */ DUMMY(membarrier); /* Linux 4.4: */ DUMMY(mlock2); /* Linux 4.6: */ DUMMY(preadv2); DUMMY(pwritev2); /* Linux 4.8: */ DUMMY(pkey_mprotect); DUMMY(pkey_alloc); DUMMY(pkey_free); /* Linux 4.11: */ DUMMY(statx); DUMMY(arch_prctl); /* Linux 4.18: */ DUMMY(io_pgetevents); DUMMY(rseq); /* Linux 5.0: */ DUMMY(clock_gettime64); DUMMY(clock_settime64); DUMMY(clock_adjtime64); DUMMY(clock_getres_time64); DUMMY(clock_nanosleep_time64); DUMMY(timer_gettime64); DUMMY(timer_settime64); DUMMY(timerfd_gettime64); DUMMY(timerfd_settime64); DUMMY(utimensat_time64); DUMMY(pselect6_time64); DUMMY(ppoll_time64); DUMMY(io_pgetevents_time64); DUMMY(recvmmsg_time64); DUMMY(mq_timedsend_time64); DUMMY(mq_timedreceive_time64); DUMMY(semtimedop_time64); DUMMY(rt_sigtimedwait_time64); DUMMY(futex_time64); DUMMY(sched_rr_get_interval_time64); DUMMY(pidfd_send_signal); DUMMY(io_uring_setup); DUMMY(io_uring_enter); DUMMY(io_uring_register); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (EOPNOTSUPP); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove);