diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..986518aa81ac --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,49 @@ +{ + "files.associations": { + "array": "c", + "bitset": "c", + "deque": "c", + "format": "c", + "initializer_list": "c", + "list": "c", + "queue": "c", + "random": "c", + "ranges": "c", + "regex": "c", + "span": "c", + "stack": "c", + "utility": "c", + "valarray": "c", + "vector": "c", + "xhash": "c", + "xstring": "c", + "xtree": "c", + "xutility": "c", + "__hash_table": "c", + "__split_buffer": "c", + "__tree": "c", + "hash_map": "c", + "hash_set": "c", + "map": "c", + "set": "c", + "string": "c", + "string_view": "c", + "unordered_map": "c", + "unordered_set": "c", + "simd": "c", + "chrono": "c", + "future": "c", + "system_error": "c", + "typeindex": "c", + "xlocale": "c", + "typeinfo": "c", + "*.inc": "c", + "thread": "c", + "__threading_support": "c", + "linux_emul.h": "c", + "linux.h": "c", + "linux32_proto.h": "c", + "__config": "cpp", + "__locale": "c" + } +} \ No newline at end of file diff --git a/lib/libgeom/geom_stats.c b/lib/libgeom/geom_stats.c index 7ae5c947b7b1..ad4f5d799e1f 100644 --- a/lib/libgeom/geom_stats.c +++ b/lib/libgeom/geom_stats.c @@ -29,6 +29,7 @@ * SUCH DAMAGE. */ +#include #include #include #include @@ -74,7 +75,7 @@ geom_stats_resync(void) err(1, "DIOCGMEDIASIZE(" _PATH_DEV DEVSTAT_DEVICE_NAME ")"); munmap(statp, npages * pagesize); - p = mmap(statp, mediasize, PROT_READ, MAP_SHARED, statsfd, 0); + p = mmap((void *)(uintptr_t)(uint64_t)(uintptr_t)statp, mediasize, PROT_READ, MAP_SHARED, statsfd, 0); if (p == MAP_FAILED) err(1, "mmap(/dev/devstat):"); else { diff --git a/lib/libsysdecode/errno.c b/lib/libsysdecode/errno.c index 7bd01d2b5ba4..edcc7e347809 100644 --- a/lib/libsysdecode/errno.c +++ b/lib/libsysdecode/errno.c @@ -48,7 +48,8 @@ sysdecode_abi_to_freebsd_errno(enum sysdecode_abi abi, int error) return (error); #if defined(__aarch64__) || defined(__amd64__) || defined(__i386__) case SYSDECODE_ABI_LINUX: - case SYSDECODE_ABI_LINUX32: { + case SYSDECODE_ABI_LINUX32: + case SYSDECODE_ABI_LINUX64: { unsigned int i; /* @@ -80,6 +81,7 @@ sysdecode_freebsd_to_abi_errno(enum sysdecode_abi abi, int error) #if defined(__aarch64__) || defined(__amd64__) || defined(__i386__) case SYSDECODE_ABI_LINUX: case SYSDECODE_ABI_LINUX32: + case SYSDECODE_ABI_LINUX64: if (error >= 0 && error <= ELAST) return (linux_errtbl[error]); break; diff --git a/lib/libsysdecode/syscallnames.c b/lib/libsysdecode/syscallnames.c index 12cf268d796d..f1dd5100ae34 100644 --- a/lib/libsysdecode/syscallnames.c +++ b/lib/libsysdecode/syscallnames.c @@ -55,6 +55,10 @@ static static #ifdef __aarch64__ #include +#if __has_feature(capabilities) +static +#include +#endif #elif __amd64__ #include #else @@ -93,6 +97,12 @@ sysdecode_syscallname(enum sysdecode_abi abi, unsigned int code) if (code < nitems(linux_syscallnames)) return (linux_syscallnames[code]); break; +#if __has_feature(capabilities) + case SYSDECODE_ABI_LINUX64: + if (code < nitems(linux64_syscallnames)) + return (linux64_syscallnames[code]); + break; +#endif #endif #ifdef __amd64__ case SYSDECODE_ABI_LINUX32: diff --git a/lib/libsysdecode/sysdecode.h b/lib/libsysdecode/sysdecode.h index 8ab7f5de892f..abe2978e9cd0 100644 --- a/lib/libsysdecode/sysdecode.h +++ b/lib/libsysdecode/sysdecode.h @@ -42,6 +42,7 @@ enum sysdecode_abi { * value when merged upstream. */ SYSDECODE_ABI_FREEBSD64 = 100, + SYSDECODE_ABI_LINUX64 = 101, }; int sysdecode_abi_to_freebsd_errno(enum sysdecode_abi _abi, int _error); diff --git a/sys/arm64/arm64/elf_machdep.c b/sys/arm64/arm64/elf_machdep.c index b1982541b75f..60ad85230b61 100644 --- a/sys/arm64/arm64/elf_machdep.c +++ b/sys/arm64/arm64/elf_machdep.c @@ -268,6 +268,9 @@ elf64c_header_supported(const struct image_params *imgp, { uint32_t note_value; + const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header; + if (hdr->e_ident[EI_OSABI] == ELFOSABI_LINUX) return false; + if (get_benchmark_abi_note(imgp, ¬e_value)) return (note_value == 0); @@ -280,6 +283,9 @@ elf64cb_header_supported(const struct image_params *imgp, { uint32_t note_value; + const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header; + if (hdr->e_ident[EI_OSABI] == ELFOSABI_LINUX) return false; + if (get_benchmark_abi_note(imgp, ¬e_value)) return (note_value == 1); diff --git a/sys/arm64/linux/linux.h b/sys/arm64/linux/linux.h index d612ba8e5d9e..f6813ec49fd5 100644 --- a/sys/arm64/linux/linux.h +++ b/sys/arm64/linux/linux.h @@ -31,7 +31,12 @@ #include #include + +#ifdef COMPAT_LINUX64 +#include +#else #include +#endif #define LINUX_DTRACE linuxulator @@ -43,7 +48,12 @@ typedef uint32_t l_uint; typedef uint64_t l_ulong; typedef uint16_t l_ushort; +#if defined(COMPAT_LINUX64) || defined(COMPAT_LINUX32) typedef l_ulong l_uintptr_t; +#else +typedef uintcap_t l_uintptr_t; +#endif +typedef uintcap_t l_uintcap_t; typedef l_long l_clock_t; typedef l_int l_daddr_t; typedef l_uint l_gid_t; @@ -77,7 +87,7 @@ typedef struct { #define l_fd_set fd_set /* Miscellaneous */ -#define LINUX_AT_COUNT 21 /* Count of used aux entry types. +#define LINUX_AT_COUNT 41 /* Count of used aux entry types. * Keep this synchronized with * linux_copyout_auxargs() code. */ @@ -157,7 +167,7 @@ struct l_newstat { #define LINUX_SA_NOMASK 0x40000000 /* SA_NODEFER */ #define LINUX_SA_ONESHOT 0x80000000 /* SA_RESETHAND */ -typedef void (*l_handler_t)(l_int); +typedef l_uintptr_t l_handler_t; typedef struct { l_handler_t lsa_handler; @@ -189,10 +199,10 @@ struct linux_pt_regset { l_ulong cpsr; }; + #ifdef _KERNEL struct reg; struct syscall_info; - void bsd_to_linux_regset(const struct reg *b_reg, struct linux_pt_regset *l_regset); void linux_to_bsd_regset(struct reg *b_reg, @@ -202,9 +212,9 @@ void linux_ptrace_get_syscall_info_machdep(const struct reg *reg, int linux_ptrace_getregs_machdep(struct thread *td, pid_t pid, struct linux_pt_regset *l_regset); int linux_ptrace_peekuser(struct thread *td, pid_t pid, - void *addr, void *data); + void * __capability addr, void * __capability data); int linux_ptrace_pokeuser(struct thread *td, pid_t pid, - void *addr, void *data); + void * __capability addr, void * __capability data); #endif /* _KERNEL */ #endif /* _ARM64_LINUX_H_ */ diff --git a/sys/arm64/linux/linux_dummy_machdep.c b/sys/arm64/linux/linux_dummy_machdep.c index 5ff6bfafe2d6..9253ed6c39f4 100644 --- a/sys/arm64/linux/linux_dummy_machdep.c +++ b/sys/arm64/linux/linux_dummy_machdep.c @@ -30,8 +30,13 @@ #include #include +#ifdef COMPAT_LINUX64 +#include +#include +#else #include #include +#endif #include #include diff --git a/sys/arm64/linux/linux_locore.asm b/sys/arm64/linux/linux_locore.asm index c330546702f1..2f38a0309466 100644 --- a/sys/arm64/linux/linux_locore.asm +++ b/sys/arm64/linux/linux_locore.asm @@ -33,14 +33,17 @@ #include +#ifdef COMPAT_LINUX64 +#include +#else #include +#endif .data .globl linux_platform linux_platform: .asciz "aarch64" - .text EENTRY(__kernel_rt_sigreturn) @@ -48,6 +51,10 @@ EENTRY(__kernel_rt_sigreturn) .globl __user_rt_sigreturn __user_rt_sigreturn: +#ifdef COMPAT_LINUX64 + mov x8, #LINUX64_SYS_linux_rt_sigreturn +#else mov x8, #LINUX_SYS_linux_rt_sigreturn +#endif svc #0 EEND(__kernel_rt_sigreturn) diff --git a/sys/arm64/linux/linux_machdep.c b/sys/arm64/linux/linux_machdep.c index 3bc2923b9d4d..729c9b5af30e 100644 --- a/sys/arm64/linux/linux_machdep.c +++ b/sys/arm64/linux/linux_machdep.c @@ -33,8 +33,13 @@ #include +#ifdef COMPAT_LINUX64 +#include +#include +#else #include #include +#endif #include #include #include @@ -43,11 +48,11 @@ int -linux_set_upcall(struct thread *td, register_t stack) +linux_set_upcall(struct thread *td, void * __capability stack) { if (stack) - td->td_frame->tf_sp = stack; + td->td_frame->tf_sp = (uintcap_t)stack; /* * The newly created Linux thread returns @@ -58,10 +63,10 @@ linux_set_upcall(struct thread *td, register_t stack) } int -linux_set_cloned_tls(struct thread *td, void *desc) +linux_set_cloned_tls(struct thread *td, void * __capability desc) { - if ((uint64_t)desc >= VM_MAXUSER_ADDRESS) + if ((uint64_t)(uintcap_t)desc >= VM_MAXUSER_ADDRESS) return (EPERM); return (cpu_set_user_tls(td, desc)); @@ -113,19 +118,20 @@ linux_ptrace_getregs_machdep(struct thread *td __unused, pid_t pid __unused, } int -linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data) +linux_ptrace_peekuser(struct thread *td, pid_t pid, void * __capability addr, void * __capability data) { LINUX_RATELIMIT_MSG_OPT1("PTRACE_PEEKUSER offset %ld not implemented; " - "returning EINVAL", (uintptr_t)addr); + "returning EINVAL", (__cheri_addr long)addr); + return (EINVAL); } int -linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data) +linux_ptrace_pokeuser(struct thread *td, pid_t pid, void * __capability addr, void * __capability data) { LINUX_RATELIMIT_MSG_OPT1("PTRACE_POKEUSER offset %ld " - "not implemented; returning EINVAL", (uintptr_t)addr); + "not implemented; returning EINVAL", (__cheri_addr long)addr); return (EINVAL); } diff --git a/sys/arm64/linux/linux_proto.h b/sys/arm64/linux/linux_proto.h index ae3d8569df58..63b7ca4f6ae1 100644 --- a/sys/arm64/linux/linux_proto.h +++ b/sys/arm64/linux/linux_proto.h @@ -34,73 +34,73 @@ struct thread; #endif struct linux_setxattr_args { - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; - char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; + char value_l_[PADL_(void * __capability)]; void * __capability value; char value_r_[PADR_(void * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_lsetxattr_args { - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; - char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; + char value_l_[PADL_(void * __capability)]; void * __capability value; char value_r_[PADR_(void * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_fsetxattr_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; - char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; + char value_l_[PADL_(void * __capability)]; void * __capability value; char value_r_[PADR_(void * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_getxattr_args { - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; - char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; + char value_l_[PADL_(void * __capability)]; void * __capability value; char value_r_[PADR_(void * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; }; struct linux_lgetxattr_args { - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; - char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; + char value_l_[PADL_(void * __capability)]; void * __capability value; char value_r_[PADR_(void * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; }; struct linux_fgetxattr_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; - char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; + char value_l_[PADL_(void * __capability)]; void * __capability value; char value_r_[PADR_(void * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; }; struct linux_listxattr_args { - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char list_l_[PADL_(char *)]; char * list; char list_r_[PADR_(char *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char list_l_[PADL_(char * __capability)]; char * __capability list; char list_r_[PADR_(char * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; }; struct linux_llistxattr_args { - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char list_l_[PADL_(char *)]; char * list; char list_r_[PADR_(char *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char list_l_[PADL_(char * __capability)]; char * __capability list; char list_r_[PADR_(char * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; }; struct linux_flistxattr_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; - char list_l_[PADL_(char *)]; char * list; char list_r_[PADR_(char *)]; + char list_l_[PADL_(char * __capability)]; char * __capability list; char list_r_[PADR_(char * __capability)]; char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; }; struct linux_removexattr_args { - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; }; struct linux_lremovexattr_args { - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; }; struct linux_fremovexattr_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; }; struct linux_getcwd_args { - char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char buf_l_[PADL_(char * __capability)]; char * __capability buf; char buf_r_[PADR_(char * __capability)]; char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)]; }; struct linux_lookup_dcookie_args { @@ -117,14 +117,14 @@ struct linux_epoll_ctl_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; char op_l_[PADL_(l_int)]; l_int op; char op_r_[PADR_(l_int)]; char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; - char event_l_[PADL_(struct epoll_event *)]; struct epoll_event * event; char event_r_[PADR_(struct epoll_event *)]; + char event_l_[PADL_(struct epoll_event * __capability)]; struct epoll_event * __capability event; char event_r_[PADR_(struct epoll_event * __capability)]; }; struct linux_epoll_pwait_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; - char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; + char events_l_[PADL_(struct epoll_event * __capability)]; struct epoll_event * __capability events; char events_r_[PADR_(struct epoll_event * __capability)]; char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; char timeout_l_[PADL_(l_int)]; l_int timeout; char timeout_r_[PADR_(l_int)]; - char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; + char mask_l_[PADL_(l_sigset_t * __capability)]; l_sigset_t * __capability mask; char mask_r_[PADR_(l_sigset_t * __capability)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_dup3_args { @@ -135,7 +135,7 @@ struct linux_dup3_args { struct linux_fcntl_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; - char arg_l_[PADL_(l_ulong)]; l_ulong arg; char arg_r_[PADR_(l_ulong)]; + char arg_l_[PADL_(l_uintcap_t)]; l_uintcap_t arg; char arg_r_[PADR_(l_uintcap_t)]; }; struct linux_inotify_init1_args { char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; @@ -149,7 +149,7 @@ struct linux_inotify_rm_watch_args { struct linux_ioctl_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; - char arg_l_[PADL_(l_ulong)]; l_ulong arg; char arg_r_[PADR_(l_ulong)]; + char arg_l_[PADL_(l_uintcap_t)]; l_uintcap_t arg; char arg_r_[PADR_(l_uintcap_t)]; }; struct linux_ioprio_set_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; @@ -162,58 +162,58 @@ struct linux_ioprio_get_args { }; struct linux_mknodat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char filename_l_[PADL_(const char * __capability)]; const char * __capability filename; char filename_r_[PADR_(const char * __capability)]; char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; char dev_l_[PADL_(l_dev_t)]; l_dev_t dev; char dev_r_[PADR_(l_dev_t)]; }; struct linux_mkdirat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char pathname_l_[PADL_(const char * __capability)]; const char * __capability pathname; char pathname_r_[PADR_(const char * __capability)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; struct linux_unlinkat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char pathname_l_[PADL_(const char * __capability)]; const char * __capability pathname; char pathname_r_[PADR_(const char * __capability)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_symlinkat_args { - char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char oldname_l_[PADL_(const char * __capability)]; const char * __capability oldname; char oldname_r_[PADR_(const char * __capability)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; - char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char newname_l_[PADL_(const char * __capability)]; const char * __capability newname; char newname_r_[PADR_(const char * __capability)]; }; struct linux_linkat_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; - char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char oldname_l_[PADL_(const char * __capability)]; const char * __capability oldname; char oldname_r_[PADR_(const char * __capability)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; - char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char newname_l_[PADL_(const char * __capability)]; const char * __capability newname; char newname_r_[PADR_(const char * __capability)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_renameat_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; - char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char oldname_l_[PADL_(const char * __capability)]; const char * __capability oldname; char oldname_r_[PADR_(const char * __capability)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; - char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char newname_l_[PADL_(const char * __capability)]; const char * __capability newname; char newname_r_[PADR_(const char * __capability)]; }; struct linux_mount_args { - char specialfile_l_[PADL_(char *)]; char * specialfile; char specialfile_r_[PADR_(char *)]; - char dir_l_[PADL_(char *)]; char * dir; char dir_r_[PADR_(char *)]; - char filesystemtype_l_[PADL_(char *)]; char * filesystemtype; char filesystemtype_r_[PADR_(char *)]; + char specialfile_l_[PADL_(char * __capability)]; char * __capability specialfile; char specialfile_r_[PADR_(char * __capability)]; + char dir_l_[PADL_(char * __capability)]; char * __capability dir; char dir_r_[PADR_(char * __capability)]; + char filesystemtype_l_[PADL_(char * __capability)]; char * __capability filesystemtype; char filesystemtype_r_[PADR_(char * __capability)]; char rwflag_l_[PADL_(l_ulong)]; l_ulong rwflag; char rwflag_r_[PADR_(l_ulong)]; - char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)]; + char data_l_[PADL_(void * __capability)]; void * __capability data; char data_r_[PADR_(void * __capability)]; }; struct linux_pivot_root_args { syscallarg_t dummy; }; struct linux_statfs_args { - char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; - char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; + char path_l_[PADL_(char * __capability)]; char * __capability path; char path_r_[PADR_(char * __capability)]; + char buf_l_[PADL_(struct l_statfs_buf * __capability)]; struct l_statfs_buf * __capability buf; char buf_r_[PADR_(struct l_statfs_buf * __capability)]; }; struct linux_fstatfs_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; - char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; + char buf_l_[PADL_(struct l_statfs_buf * __capability)]; struct l_statfs_buf * __capability buf; char buf_r_[PADR_(struct l_statfs_buf * __capability)]; }; struct linux_truncate_args { - char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char path_l_[PADL_(char * __capability)]; char * __capability path; char path_r_[PADR_(char * __capability)]; char length_l_[PADL_(l_ulong)]; l_ulong length; char length_r_[PADR_(l_ulong)]; }; struct linux_ftruncate_args { @@ -228,27 +228,30 @@ struct linux_fallocate_args { }; struct linux_faccessat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char filename_l_[PADL_(const char * __capability)]; const char * __capability filename; char filename_r_[PADR_(const char * __capability)]; char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; }; struct linux_chdir_args { - char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char path_l_[PADL_(char * __capability)]; char * __capability path; char path_r_[PADR_(char * __capability)]; +}; +struct linux_chroot_args { + char path_l_[PADL_(char * __capability)]; char * __capability path; char path_r_[PADR_(char * __capability)]; }; struct linux_fchmodat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char filename_l_[PADL_(const char * __capability)]; const char * __capability filename; char filename_r_[PADR_(const char * __capability)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; struct linux_fchownat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char filename_l_[PADL_(const char * __capability)]; const char * __capability filename; char filename_r_[PADR_(const char * __capability)]; char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_openat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char filename_l_[PADL_(const char * __capability)]; const char * __capability filename; char filename_r_[PADR_(const char * __capability)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; }; @@ -256,12 +259,12 @@ struct linux_vhangup_args { syscallarg_t dummy; }; struct linux_pipe2_args { - char pipefds_l_[PADL_(l_int *)]; l_int * pipefds; char pipefds_r_[PADR_(l_int *)]; + char pipefds_l_[PADL_(l_int * __capability)]; l_int * __capability pipefds; char pipefds_r_[PADR_(l_int * __capability)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_getdents64_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; - char dirent_l_[PADL_(void *)]; void * dirent; char dirent_r_[PADR_(void *)]; + char dirent_l_[PADL_(void * __capability)]; void * __capability dirent; char dirent_r_[PADR_(void * __capability)]; char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; }; struct linux_lseek_args { @@ -269,38 +272,48 @@ struct linux_lseek_args { char off_l_[PADL_(l_off_t)]; l_off_t off; char off_r_[PADR_(l_off_t)]; char whence_l_[PADL_(l_int)]; l_int whence; char whence_r_[PADR_(l_int)]; }; +struct linux_read_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char buf_l_[PADL_(char * __capability)]; char * __capability buf; char buf_r_[PADR_(char * __capability)]; + char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; +}; struct linux_write_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; - char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char buf_l_[PADL_(char * __capability)]; char * __capability buf; char buf_r_[PADR_(char * __capability)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; }; +struct linux_readv_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char iovp_l_[PADL_(struct iovec * __capability)]; struct iovec * __capability iovp; char iovp_r_[PADR_(struct iovec * __capability)]; + char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)]; +}; struct linux_writev_args { char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; - char iovp_l_[PADL_(struct iovec *)]; struct iovec * iovp; char iovp_r_[PADR_(struct iovec *)]; + char iovp_l_[PADL_(struct iovec * __capability)]; struct iovec * __capability iovp; char iovp_r_[PADR_(struct iovec * __capability)]; char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)]; }; struct linux_pread_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; - char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char buf_l_[PADL_(char * __capability)]; char * __capability buf; char buf_r_[PADR_(char * __capability)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; }; struct linux_pwrite_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; - char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char buf_l_[PADL_(char * __capability)]; char * __capability buf; char buf_r_[PADR_(char * __capability)]; char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; }; struct linux_preadv_args { char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; - char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vec_l_[PADL_(struct iovec * __capability)]; struct iovec * __capability vec; char vec_r_[PADR_(struct iovec * __capability)]; char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; }; struct linux_pwritev_args { char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; - char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vec_l_[PADL_(struct iovec * __capability)]; struct iovec * __capability vec; char vec_r_[PADR_(struct iovec * __capability)]; char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; @@ -308,22 +321,22 @@ struct linux_pwritev_args { struct linux_sendfile_args { char out_l_[PADL_(l_int)]; l_int out; char out_r_[PADR_(l_int)]; char in_l_[PADL_(l_int)]; l_int in; char in_r_[PADR_(l_int)]; - char offset_l_[PADL_(l_off_t *)]; l_off_t * offset; char offset_r_[PADR_(l_off_t *)]; + char offset_l_[PADL_(l_off_t * __capability)]; l_off_t * __capability offset; char offset_r_[PADR_(l_off_t * __capability)]; char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; }; struct linux_pselect6_args { char nfds_l_[PADL_(l_int)]; l_int nfds; char nfds_r_[PADR_(l_int)]; - char readfds_l_[PADL_(l_fd_set *)]; l_fd_set * readfds; char readfds_r_[PADR_(l_fd_set *)]; - char writefds_l_[PADL_(l_fd_set *)]; l_fd_set * writefds; char writefds_r_[PADR_(l_fd_set *)]; - char exceptfds_l_[PADL_(l_fd_set *)]; l_fd_set * exceptfds; char exceptfds_r_[PADR_(l_fd_set *)]; - char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; - char sig_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * sig; char sig_r_[PADR_(l_uintptr_t *)]; + char readfds_l_[PADL_(l_fd_set * __capability)]; l_fd_set * __capability readfds; char readfds_r_[PADR_(l_fd_set * __capability)]; + char writefds_l_[PADL_(l_fd_set * __capability)]; l_fd_set * __capability writefds; char writefds_r_[PADR_(l_fd_set * __capability)]; + char exceptfds_l_[PADL_(l_fd_set * __capability)]; l_fd_set * __capability exceptfds; char exceptfds_r_[PADR_(l_fd_set * __capability)]; + char tsp_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability tsp; char tsp_r_[PADR_(struct l_timespec * __capability)]; + char sig_l_[PADL_(l_uintcap_t * __capability)]; l_uintcap_t * __capability sig; char sig_r_[PADR_(l_uintcap_t * __capability)]; }; struct linux_ppoll_args { - char fds_l_[PADL_(struct pollfd *)]; struct pollfd * fds; char fds_r_[PADR_(struct pollfd *)]; + char fds_l_[PADL_(struct pollfd * __capability)]; struct pollfd * __capability fds; char fds_r_[PADR_(struct pollfd * __capability)]; char nfds_l_[PADL_(l_uint)]; l_uint nfds; char nfds_r_[PADR_(l_uint)]; - char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; - char sset_l_[PADL_(l_sigset_t *)]; l_sigset_t * sset; char sset_r_[PADR_(l_sigset_t *)]; + char tsp_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability tsp; char tsp_r_[PADR_(struct l_timespec * __capability)]; + char sset_l_[PADL_(l_sigset_t * __capability)]; l_sigset_t * __capability sset; char sset_r_[PADR_(l_sigset_t * __capability)]; char ssize_l_[PADL_(l_size_t)]; l_size_t ssize; char ssize_r_[PADR_(l_size_t)]; }; struct linux_signalfd4_args { @@ -334,9 +347,9 @@ struct linux_vmsplice_args { }; struct linux_splice_args { char fd_in_l_[PADL_(int)]; int fd_in; char fd_in_r_[PADR_(int)]; - char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char off_in_l_[PADL_(l_loff_t * __capability)]; l_loff_t * __capability off_in; char off_in_r_[PADR_(l_loff_t * __capability)]; char fd_out_l_[PADL_(int)]; int fd_out; char fd_out_r_[PADR_(int)]; - char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char off_out_l_[PADL_(l_loff_t * __capability)]; l_loff_t * __capability off_out; char off_out_r_[PADR_(l_loff_t * __capability)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; @@ -345,19 +358,19 @@ struct linux_tee_args { }; struct linux_readlinkat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; - char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char path_l_[PADL_(const char * __capability)]; const char * __capability path; char path_r_[PADR_(const char * __capability)]; + char buf_l_[PADL_(char * __capability)]; char * __capability buf; char buf_r_[PADR_(char * __capability)]; char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)]; }; struct linux_newfstatat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)]; - char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; + char pathname_l_[PADL_(char * __capability)]; char * __capability pathname; char pathname_r_[PADR_(char * __capability)]; + char statbuf_l_[PADL_(struct l_newstat * __capability)]; struct l_newstat * __capability statbuf; char statbuf_r_[PADR_(struct l_newstat * __capability)]; char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_newfstat_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; - char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; + char buf_l_[PADL_(struct l_newstat * __capability)]; struct l_newstat * __capability buf; char buf_r_[PADR_(struct l_newstat * __capability)]; }; struct linux_fdatasync_args { char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; @@ -375,26 +388,29 @@ struct linux_timerfd_create_args { struct linux_timerfd_settime_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; - char new_value_l_[PADL_(const struct l_itimerspec *)]; const struct l_itimerspec * new_value; char new_value_r_[PADR_(const struct l_itimerspec *)]; - char old_value_l_[PADL_(struct l_itimerspec *)]; struct l_itimerspec * old_value; char old_value_r_[PADR_(struct l_itimerspec *)]; + char new_value_l_[PADL_(const struct l_itimerspec * __capability)]; const struct l_itimerspec * __capability new_value; char new_value_r_[PADR_(const struct l_itimerspec * __capability)]; + char old_value_l_[PADL_(struct l_itimerspec * __capability)]; struct l_itimerspec * __capability old_value; char old_value_r_[PADR_(struct l_itimerspec * __capability)]; }; struct linux_timerfd_gettime_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; - char old_value_l_[PADL_(struct l_itimerspec *)]; struct l_itimerspec * old_value; char old_value_r_[PADR_(struct l_itimerspec *)]; + char old_value_l_[PADL_(struct l_itimerspec * __capability)]; struct l_itimerspec * __capability old_value; char old_value_r_[PADR_(struct l_itimerspec * __capability)]; }; struct linux_utimensat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; - char times_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * times; char times_r_[PADR_(const struct l_timespec *)]; + char pathname_l_[PADL_(const char * __capability)]; const char * __capability pathname; char pathname_r_[PADR_(const char * __capability)]; + char times_l_[PADL_(const struct l_timespec * __capability)]; const struct l_timespec * __capability times; char times_r_[PADR_(const struct l_timespec * __capability)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; +struct linux_acct_args { + char path_l_[PADL_(char * __capability)]; char * __capability path; char path_r_[PADR_(char * __capability)]; +}; struct linux_capget_args { - char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; - char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; + char hdrp_l_[PADL_(struct l_user_cap_header * __capability)]; struct l_user_cap_header * __capability hdrp; char hdrp_r_[PADR_(struct l_user_cap_header * __capability)]; + char datap_l_[PADL_(struct l_user_cap_data * __capability)]; struct l_user_cap_data * __capability datap; char datap_r_[PADR_(struct l_user_cap_data * __capability)]; }; struct linux_capset_args { - char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; - char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; + char hdrp_l_[PADL_(struct l_user_cap_header * __capability)]; struct l_user_cap_header * __capability hdrp; char hdrp_r_[PADR_(struct l_user_cap_header * __capability)]; + char datap_l_[PADL_(struct l_user_cap_data * __capability)]; struct l_user_cap_data * __capability datap; char datap_r_[PADR_(struct l_user_cap_data * __capability)]; }; struct linux_personality_args { char per_l_[PADL_(l_uint)]; l_uint per; char per_r_[PADR_(l_uint)]; @@ -408,45 +424,45 @@ struct linux_exit_group_args { struct linux_waitid_args { char idtype_l_[PADL_(l_int)]; l_int idtype; char idtype_r_[PADR_(l_int)]; char id_l_[PADL_(l_pid_t)]; l_pid_t id; char id_r_[PADR_(l_pid_t)]; - char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; + char info_l_[PADL_(l_siginfo_t * __capability)]; l_siginfo_t * __capability info; char info_r_[PADR_(l_siginfo_t * __capability)]; char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; - char rusage_l_[PADL_(struct rusage *)]; struct rusage * rusage; char rusage_r_[PADR_(struct rusage *)]; + char rusage_l_[PADL_(struct rusage * __capability)]; struct rusage * __capability rusage; char rusage_r_[PADR_(struct rusage * __capability)]; }; struct linux_set_tid_address_args { - char tidptr_l_[PADL_(l_int *)]; l_int * tidptr; char tidptr_r_[PADR_(l_int *)]; + char tidptr_l_[PADL_(l_int * __capability)]; l_int * __capability tidptr; char tidptr_r_[PADR_(l_int * __capability)]; }; struct linux_unshare_args { syscallarg_t dummy; }; struct linux_sys_futex_args { - char uaddr_l_[PADL_(uint32_t *)]; uint32_t * uaddr; char uaddr_r_[PADR_(uint32_t *)]; + char uaddr_l_[PADL_(uint32_t * __capability)]; uint32_t * __capability uaddr; char uaddr_r_[PADR_(uint32_t * __capability)]; char op_l_[PADL_(l_int)]; l_int op; char op_r_[PADR_(l_int)]; char val_l_[PADL_(uint32_t)]; uint32_t val; char val_r_[PADR_(uint32_t)]; - char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; - char uaddr2_l_[PADL_(uint32_t *)]; uint32_t * uaddr2; char uaddr2_r_[PADR_(uint32_t *)]; + char timeout_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability timeout; char timeout_r_[PADR_(struct l_timespec * __capability)]; + char uaddr2_l_[PADL_(uint32_t * __capability)]; uint32_t * __capability uaddr2; char uaddr2_r_[PADR_(uint32_t * __capability)]; char val3_l_[PADL_(uint32_t)]; uint32_t val3; char val3_r_[PADR_(uint32_t)]; }; struct linux_set_robust_list_args { - char head_l_[PADL_(struct linux_robust_list_head *)]; struct linux_robust_list_head * head; char head_r_[PADR_(struct linux_robust_list_head *)]; + char head_l_[PADL_(struct linux_robust_list_head * __capability)]; struct linux_robust_list_head * __capability head; char head_r_[PADR_(struct linux_robust_list_head * __capability)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; }; struct linux_get_robust_list_args { char pid_l_[PADL_(l_int)]; l_int pid; char pid_r_[PADR_(l_int)]; - char head_l_[PADL_(struct linux_robust_list_head **)]; struct linux_robust_list_head ** head; char head_r_[PADR_(struct linux_robust_list_head **)]; - char len_l_[PADL_(l_size_t *)]; l_size_t * len; char len_r_[PADR_(l_size_t *)]; + char head_l_[PADL_(struct linux_robust_list_head * __capability * __capability)]; struct linux_robust_list_head * __capability * __capability head; char head_r_[PADR_(struct linux_robust_list_head * __capability * __capability)]; + char len_l_[PADL_(l_size_t * __capability)]; l_size_t * __capability len; char len_r_[PADR_(l_size_t * __capability)]; }; struct linux_nanosleep_args { - char rqtp_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * rqtp; char rqtp_r_[PADR_(const struct l_timespec *)]; - char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; + char rqtp_l_[PADL_(const struct l_timespec * __capability)]; const struct l_timespec * __capability rqtp; char rqtp_r_[PADR_(const struct l_timespec * __capability)]; + char rmtp_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability rmtp; char rmtp_r_[PADR_(struct l_timespec * __capability)]; }; struct linux_getitimer_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; - char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; + char itv_l_[PADL_(struct l_itimerval * __capability)]; struct l_itimerval * __capability itv; char itv_r_[PADR_(struct l_itimerval * __capability)]; }; struct linux_setitimer_args { char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; - char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; - char oitv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * oitv; char oitv_r_[PADR_(struct l_itimerval *)]; + char itv_l_[PADL_(struct l_itimerval * __capability)]; struct l_itimerval * __capability itv; char itv_r_[PADR_(struct l_itimerval * __capability)]; + char oitv_l_[PADL_(struct l_itimerval * __capability)]; struct l_itimerval * __capability oitv; char oitv_r_[PADR_(struct l_itimerval * __capability)]; }; struct linux_kexec_load_args { syscallarg_t dummy; @@ -459,12 +475,12 @@ struct linux_delete_module_args { }; struct linux_timer_create_args { char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)]; - char evp_l_[PADL_(struct l_sigevent *)]; struct l_sigevent * evp; char evp_r_[PADR_(struct l_sigevent *)]; - char timerid_l_[PADL_(l_timer_t *)]; l_timer_t * timerid; char timerid_r_[PADR_(l_timer_t *)]; + char evp_l_[PADL_(struct l_sigevent * __capability)]; struct l_sigevent * __capability evp; char evp_r_[PADR_(struct l_sigevent * __capability)]; + char timerid_l_[PADL_(l_timer_t * __capability)]; l_timer_t * __capability timerid; char timerid_r_[PADR_(l_timer_t * __capability)]; }; struct linux_timer_gettime_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; - char setting_l_[PADL_(struct itimerspec *)]; struct itimerspec * setting; char setting_r_[PADR_(struct itimerspec *)]; + char setting_l_[PADL_(struct itimerspec * __capability)]; struct itimerspec * __capability setting; char setting_r_[PADR_(struct itimerspec * __capability)]; }; struct linux_timer_getoverrun_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; @@ -472,66 +488,66 @@ struct linux_timer_getoverrun_args { struct linux_timer_settime_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; - char new_l_[PADL_(const struct itimerspec *)]; const struct itimerspec * new; char new_r_[PADR_(const struct itimerspec *)]; - char old_l_[PADL_(struct itimerspec *)]; struct itimerspec * old; char old_r_[PADR_(struct itimerspec *)]; + char new_l_[PADL_(const struct itimerspec * __capability)]; const struct itimerspec * __capability new; char new_r_[PADR_(const struct itimerspec * __capability)]; + char old_l_[PADL_(struct itimerspec * __capability)]; struct itimerspec * __capability old; char old_r_[PADR_(struct itimerspec * __capability)]; }; struct linux_timer_delete_args { char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; }; struct linux_clock_settime_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; - char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; + char tp_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability tp; char tp_r_[PADR_(struct l_timespec * __capability)]; }; struct linux_clock_gettime_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; - char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; + char tp_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability tp; char tp_r_[PADR_(struct l_timespec * __capability)]; }; struct linux_clock_getres_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; - char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; + char tp_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability tp; char tp_r_[PADR_(struct l_timespec * __capability)]; }; struct linux_clock_nanosleep_args { char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; - char rqtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rqtp; char rqtp_r_[PADR_(struct l_timespec *)]; - char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; + char rqtp_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability rqtp; char rqtp_r_[PADR_(struct l_timespec * __capability)]; + char rmtp_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability rmtp; char rmtp_r_[PADR_(struct l_timespec * __capability)]; }; struct linux_syslog_args { char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; - char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char buf_l_[PADL_(char * __capability)]; char * __capability buf; char buf_r_[PADR_(char * __capability)]; char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; }; struct linux_ptrace_args { char req_l_[PADL_(l_long)]; l_long req; char req_r_[PADR_(l_long)]; char pid_l_[PADL_(l_long)]; l_long pid; char pid_r_[PADR_(l_long)]; - char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; - char data_l_[PADL_(l_ulong)]; l_ulong data; char data_r_[PADR_(l_ulong)]; + char addr_l_[PADL_(l_uintcap_t)]; l_uintcap_t addr; char addr_r_[PADR_(l_uintcap_t)]; + char data_l_[PADL_(l_uintcap_t)]; l_uintcap_t data; char data_r_[PADR_(l_uintcap_t)]; }; struct linux_sched_setparam_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; - char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; + char param_l_[PADL_(struct sched_param * __capability)]; struct sched_param * __capability param; char param_r_[PADR_(struct sched_param * __capability)]; }; struct linux_sched_setscheduler_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; - char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; + char param_l_[PADL_(struct sched_param * __capability)]; struct sched_param * __capability param; char param_r_[PADR_(struct sched_param * __capability)]; }; struct linux_sched_getscheduler_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; }; struct linux_sched_getparam_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; - char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; + char param_l_[PADL_(struct sched_param * __capability)]; struct sched_param * __capability param; char param_r_[PADR_(struct sched_param * __capability)]; }; struct linux_sched_setaffinity_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; - char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; + char user_mask_ptr_l_[PADL_(l_ulong * __capability)]; l_ulong * __capability user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong * __capability)]; }; struct linux_sched_getaffinity_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; - char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; + char user_mask_ptr_l_[PADL_(l_ulong * __capability)]; l_ulong * __capability user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong * __capability)]; }; struct linux_sched_get_priority_max_args { char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; @@ -541,7 +557,7 @@ struct linux_sched_get_priority_min_args { }; struct linux_sched_rr_get_interval_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; - char interval_l_[PADL_(struct l_timespec *)]; struct l_timespec * interval; char interval_r_[PADR_(struct l_timespec *)]; + char interval_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability interval; char interval_r_[PADR_(struct l_timespec * __capability)]; }; struct linux_kill_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; @@ -557,39 +573,39 @@ struct linux_tgkill_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; }; struct linux_sigaltstack_args { - char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)]; - char uoss_l_[PADL_(l_stack_t *)]; l_stack_t * uoss; char uoss_r_[PADR_(l_stack_t *)]; + char uss_l_[PADL_(l_stack_t * __capability)]; l_stack_t * __capability uss; char uss_r_[PADR_(l_stack_t * __capability)]; + char uoss_l_[PADL_(l_stack_t * __capability)]; l_stack_t * __capability uoss; char uoss_r_[PADR_(l_stack_t * __capability)]; }; struct linux_rt_sigsuspend_args { - char newset_l_[PADL_(l_sigset_t *)]; l_sigset_t * newset; char newset_r_[PADR_(l_sigset_t *)]; + char newset_l_[PADL_(l_sigset_t * __capability)]; l_sigset_t * __capability newset; char newset_r_[PADR_(l_sigset_t * __capability)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigaction_args { char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; - char act_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * act; char act_r_[PADR_(l_sigaction_t *)]; - char oact_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * oact; char oact_r_[PADR_(l_sigaction_t *)]; + char act_l_[PADL_(l_sigaction_t * __capability)]; l_sigaction_t * __capability act; char act_r_[PADR_(l_sigaction_t * __capability)]; + char oact_l_[PADL_(l_sigaction_t * __capability)]; l_sigaction_t * __capability oact; char oact_r_[PADR_(l_sigaction_t * __capability)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigprocmask_args { char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; - char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; - char omask_l_[PADL_(l_sigset_t *)]; l_sigset_t * omask; char omask_r_[PADR_(l_sigset_t *)]; + char mask_l_[PADL_(l_sigset_t * __capability)]; l_sigset_t * __capability mask; char mask_r_[PADR_(l_sigset_t * __capability)]; + char omask_l_[PADL_(l_sigset_t * __capability)]; l_sigset_t * __capability omask; char omask_r_[PADR_(l_sigset_t * __capability)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigpending_args { - char set_l_[PADL_(l_sigset_t *)]; l_sigset_t * set; char set_r_[PADR_(l_sigset_t *)]; + char set_l_[PADL_(l_sigset_t * __capability)]; l_sigset_t * __capability set; char set_r_[PADR_(l_sigset_t * __capability)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigtimedwait_args { - char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; - char ptr_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * ptr; char ptr_r_[PADR_(l_siginfo_t *)]; - char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; + char mask_l_[PADL_(l_sigset_t * __capability)]; l_sigset_t * __capability mask; char mask_r_[PADR_(l_sigset_t * __capability)]; + char ptr_l_[PADL_(l_siginfo_t * __capability)]; l_siginfo_t * __capability ptr; char ptr_r_[PADR_(l_siginfo_t * __capability)]; + char timeout_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability timeout; char timeout_r_[PADR_(struct l_timespec * __capability)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_rt_sigqueueinfo_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; - char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; + char info_l_[PADL_(l_siginfo_t * __capability)]; l_siginfo_t * __capability info; char info_r_[PADR_(l_siginfo_t * __capability)]; }; struct linux_rt_sigreturn_args { syscallarg_t dummy; @@ -602,7 +618,17 @@ struct linux_reboot_args { char magic1_l_[PADL_(l_int)]; l_int magic1; char magic1_r_[PADR_(l_int)]; char magic2_l_[PADL_(l_int)]; l_int magic2; char magic2_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; - char arg_l_[PADL_(void *)]; void * arg; char arg_r_[PADR_(void *)]; + char arg_l_[PADL_(void * __capability)]; void * __capability arg; char arg_r_[PADR_(void * __capability)]; +}; +struct linux_getresuid_args { + char ruid_l_[PADL_(l_uid_t * __capability)]; l_uid_t * __capability ruid; char ruid_r_[PADR_(l_uid_t * __capability)]; + char euid_l_[PADL_(l_uid_t * __capability)]; l_uid_t * __capability euid; char euid_r_[PADR_(l_uid_t * __capability)]; + char suid_l_[PADL_(l_uid_t * __capability)]; l_uid_t * __capability suid; char suid_r_[PADR_(l_uid_t * __capability)]; +}; +struct linux_getresgid_args { + char rgid_l_[PADL_(l_gid_t * __capability)]; l_gid_t * __capability rgid; char rgid_r_[PADR_(l_gid_t * __capability)]; + char egid_l_[PADL_(l_gid_t * __capability)]; l_gid_t * __capability egid; char egid_r_[PADR_(l_gid_t * __capability)]; + char sgid_l_[PADL_(l_gid_t * __capability)]; l_gid_t * __capability sgid; char sgid_r_[PADR_(l_gid_t * __capability)]; }; struct linux_setfsuid_args { char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; @@ -611,49 +637,61 @@ struct linux_setfsgid_args { char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; }; struct linux_times_args { - char buf_l_[PADL_(struct l_times_argv *)]; struct l_times_argv * buf; char buf_r_[PADR_(struct l_times_argv *)]; + char buf_l_[PADL_(struct l_times_argv * __capability)]; struct l_times_argv * __capability buf; char buf_r_[PADR_(struct l_times_argv * __capability)]; }; struct linux_getsid_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; }; struct linux_getgroups_args { char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; - char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; + char grouplist_l_[PADL_(l_gid_t * __capability)]; l_gid_t * __capability grouplist; char grouplist_r_[PADR_(l_gid_t * __capability)]; }; struct linux_setgroups_args { char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; - char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; + char grouplist_l_[PADL_(l_gid_t * __capability)]; l_gid_t * __capability grouplist; char grouplist_r_[PADR_(l_gid_t * __capability)]; }; struct linux_newuname_args { - char buf_l_[PADL_(struct l_new_utsname *)]; struct l_new_utsname * buf; char buf_r_[PADR_(struct l_new_utsname *)]; + char buf_l_[PADL_(struct l_new_utsname * __capability)]; struct l_new_utsname * __capability buf; char buf_r_[PADR_(struct l_new_utsname * __capability)]; }; struct linux_sethostname_args { - char hostname_l_[PADL_(char *)]; char * hostname; char hostname_r_[PADR_(char *)]; + char hostname_l_[PADL_(char * __capability)]; char * __capability hostname; char hostname_r_[PADR_(char * __capability)]; char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; }; struct linux_setdomainname_args { - char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; + char name_l_[PADL_(char * __capability)]; char * __capability name; char name_r_[PADR_(char * __capability)]; char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; }; struct linux_getrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; - char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; + char rlim_l_[PADL_(struct l_rlimit * __capability)]; struct l_rlimit * __capability rlim; char rlim_r_[PADR_(struct l_rlimit * __capability)]; }; struct linux_setrlimit_args { char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; - char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; + char rlim_l_[PADL_(struct l_rlimit * __capability)]; struct l_rlimit * __capability rlim; char rlim_r_[PADR_(struct l_rlimit * __capability)]; +}; +struct linux_getrusage_args { + char who_l_[PADL_(l_int)]; l_int who; char who_r_[PADR_(l_int)]; + char rusage_l_[PADL_(struct rusage * __capability)]; struct rusage * __capability rusage; char rusage_r_[PADR_(struct rusage * __capability)]; }; struct linux_prctl_args { char option_l_[PADL_(l_int)]; l_int option; char option_r_[PADR_(l_int)]; - char arg2_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg2; char arg2_r_[PADR_(l_uintptr_t)]; - char arg3_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg3; char arg3_r_[PADR_(l_uintptr_t)]; - char arg4_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg4; char arg4_r_[PADR_(l_uintptr_t)]; - char arg5_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg5; char arg5_r_[PADR_(l_uintptr_t)]; + char arg2_l_[PADL_(l_uintcap_t)]; l_uintcap_t arg2; char arg2_r_[PADR_(l_uintcap_t)]; + char arg3_l_[PADL_(l_uintcap_t)]; l_uintcap_t arg3; char arg3_r_[PADR_(l_uintcap_t)]; + char arg4_l_[PADL_(l_uintcap_t)]; l_uintcap_t arg4; char arg4_r_[PADR_(l_uintcap_t)]; + char arg5_l_[PADL_(l_uintcap_t)]; l_uintcap_t arg5; char arg5_r_[PADR_(l_uintcap_t)]; }; struct linux_getcpu_args { - char cpu_l_[PADL_(l_uint *)]; l_uint * cpu; char cpu_r_[PADR_(l_uint *)]; - char node_l_[PADL_(l_uint *)]; l_uint * node; char node_r_[PADR_(l_uint *)]; - char cache_l_[PADL_(void *)]; void * cache; char cache_r_[PADR_(void *)]; + char cpu_l_[PADL_(l_uint * __capability)]; l_uint * __capability cpu; char cpu_r_[PADR_(l_uint * __capability)]; + char node_l_[PADL_(l_uint * __capability)]; l_uint * __capability node; char node_r_[PADR_(l_uint * __capability)]; + char cache_l_[PADL_(void * __capability)]; void * __capability cache; char cache_r_[PADR_(void * __capability)]; +}; +struct linux_gettimeofday_args { + char tp_l_[PADL_(l_timeval * __capability)]; l_timeval * __capability tp; char tp_r_[PADR_(l_timeval * __capability)]; + char tzp_l_[PADL_(struct timezone * __capability)]; struct timezone * __capability tzp; char tzp_r_[PADR_(struct timezone * __capability)]; +}; +struct linux_settimeofday_args { + char tv_l_[PADL_(l_timeval * __capability)]; l_timeval * __capability tv; char tv_r_[PADR_(l_timeval * __capability)]; + char tzp_l_[PADL_(struct timezone * __capability)]; struct timezone * __capability tzp; char tzp_r_[PADR_(struct timezone * __capability)]; }; struct linux_adjtimex_args { syscallarg_t dummy; @@ -674,39 +712,39 @@ struct linux_gettid_args { syscallarg_t dummy; }; struct linux_sysinfo_args { - char info_l_[PADL_(struct l_sysinfo *)]; struct l_sysinfo * info; char info_r_[PADR_(struct l_sysinfo *)]; + char info_l_[PADL_(struct l_sysinfo * __capability)]; struct l_sysinfo * __capability info; char info_r_[PADR_(struct l_sysinfo * __capability)]; }; struct linux_mq_open_args { - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; char oflag_l_[PADL_(l_int)]; l_int oflag; char oflag_r_[PADR_(l_int)]; char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; - char attr_l_[PADL_(struct mq_attr *)]; struct mq_attr * attr; char attr_r_[PADR_(struct mq_attr *)]; + char attr_l_[PADL_(struct mq_attr * __capability)]; struct mq_attr * __capability attr; char attr_r_[PADR_(struct mq_attr * __capability)]; }; struct linux_mq_unlink_args { - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; }; struct linux_mq_timedsend_args { char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; - char msg_ptr_l_[PADL_(const char *)]; const char * msg_ptr; char msg_ptr_r_[PADR_(const char *)]; + char msg_ptr_l_[PADL_(const char * __capability)]; const char * __capability msg_ptr; char msg_ptr_r_[PADR_(const char * __capability)]; char msg_len_l_[PADL_(l_size_t)]; l_size_t msg_len; char msg_len_r_[PADR_(l_size_t)]; char msg_prio_l_[PADL_(l_uint)]; l_uint msg_prio; char msg_prio_r_[PADR_(l_uint)]; - char abs_timeout_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec *)]; + char abs_timeout_l_[PADL_(const struct l_timespec * __capability)]; const struct l_timespec * __capability abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec * __capability)]; }; struct linux_mq_timedreceive_args { char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; - char msg_ptr_l_[PADL_(char *)]; char * msg_ptr; char msg_ptr_r_[PADR_(char *)]; + char msg_ptr_l_[PADL_(char * __capability)]; char * __capability msg_ptr; char msg_ptr_r_[PADR_(char * __capability)]; char msg_len_l_[PADL_(l_size_t)]; l_size_t msg_len; char msg_len_r_[PADR_(l_size_t)]; - char msg_prio_l_[PADL_(l_uint *)]; l_uint * msg_prio; char msg_prio_r_[PADR_(l_uint *)]; - char abs_timeout_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec *)]; + char msg_prio_l_[PADL_(l_uint * __capability)]; l_uint * __capability msg_prio; char msg_prio_r_[PADR_(l_uint * __capability)]; + char abs_timeout_l_[PADL_(const struct l_timespec * __capability)]; const struct l_timespec * __capability abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec * __capability)]; }; struct linux_mq_notify_args { char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; - char sevp_l_[PADL_(const struct l_sigevent *)]; const struct l_sigevent * sevp; char sevp_r_[PADR_(const struct l_sigevent *)]; + char sevp_l_[PADL_(const struct l_sigevent * __capability)]; const struct l_sigevent * __capability sevp; char sevp_r_[PADR_(const struct l_sigevent * __capability)]; }; struct linux_mq_getsetattr_args { char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; - char attr_l_[PADL_(const struct mq_attr *)]; const struct mq_attr * attr; char attr_r_[PADR_(const struct mq_attr *)]; - char oattr_l_[PADL_(struct mq_attr *)]; struct mq_attr * oattr; char oattr_r_[PADR_(struct mq_attr *)]; + char attr_l_[PADL_(const struct mq_attr * __capability)]; const struct mq_attr * __capability attr; char attr_r_[PADR_(const struct mq_attr * __capability)]; + char oattr_l_[PADL_(struct mq_attr * __capability)]; struct mq_attr * __capability oattr; char oattr_r_[PADR_(struct mq_attr * __capability)]; }; struct linux_msgget_args { char key_l_[PADL_(l_key_t)]; l_key_t key; char key_r_[PADR_(l_key_t)]; @@ -715,18 +753,18 @@ struct linux_msgget_args { struct linux_msgctl_args { char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; - char buf_l_[PADL_(struct l_msqid_ds *)]; struct l_msqid_ds * buf; char buf_r_[PADR_(struct l_msqid_ds *)]; + char buf_l_[PADL_(struct l_msqid_ds * __capability)]; struct l_msqid_ds * __capability buf; char buf_r_[PADR_(struct l_msqid_ds * __capability)]; }; struct linux_msgrcv_args { char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; - char msgp_l_[PADL_(struct l_msgbuf *)]; struct l_msgbuf * msgp; char msgp_r_[PADR_(struct l_msgbuf *)]; + char msgp_l_[PADL_(struct l_msgbuf * __capability)]; struct l_msgbuf * __capability msgp; char msgp_r_[PADR_(struct l_msgbuf * __capability)]; char msgsz_l_[PADL_(l_size_t)]; l_size_t msgsz; char msgsz_r_[PADR_(l_size_t)]; char msgtyp_l_[PADL_(l_long)]; l_long msgtyp; char msgtyp_r_[PADR_(l_long)]; char msgflg_l_[PADL_(l_int)]; l_int msgflg; char msgflg_r_[PADR_(l_int)]; }; struct linux_msgsnd_args { char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; - char msgp_l_[PADL_(struct l_msgbuf *)]; struct l_msgbuf * msgp; char msgp_r_[PADR_(struct l_msgbuf *)]; + char msgp_l_[PADL_(struct l_msgbuf * __capability)]; struct l_msgbuf * __capability msgp; char msgp_r_[PADR_(struct l_msgbuf * __capability)]; char msgsz_l_[PADL_(l_size_t)]; l_size_t msgsz; char msgsz_r_[PADR_(l_size_t)]; char msgflg_l_[PADL_(l_int)]; l_int msgflg; char msgflg_r_[PADR_(l_int)]; }; @@ -743,9 +781,14 @@ struct linux_semctl_args { }; struct linux_semtimedop_args { char semid_l_[PADL_(l_int)]; l_int semid; char semid_r_[PADR_(l_int)]; - char tsops_l_[PADL_(struct sembuf *)]; struct sembuf * tsops; char tsops_r_[PADR_(struct sembuf *)]; + char tsops_l_[PADL_(struct sembuf * __capability)]; struct sembuf * __capability tsops; char tsops_r_[PADR_(struct sembuf * __capability)]; + char nsops_l_[PADL_(l_size_t)]; l_size_t nsops; char nsops_r_[PADR_(l_size_t)]; + char timeout_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability timeout; char timeout_r_[PADR_(struct l_timespec * __capability)]; +}; +struct linux_semop_args { + char semid_l_[PADL_(l_int)]; l_int semid; char semid_r_[PADR_(l_int)]; + char sops_l_[PADL_(struct sembuf * __capability)]; struct sembuf * __capability sops; char sops_r_[PADR_(struct sembuf * __capability)]; char nsops_l_[PADL_(l_size_t)]; l_size_t nsops; char nsops_r_[PADR_(l_size_t)]; - char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; }; struct linux_shmget_args { char key_l_[PADL_(l_key_t)]; l_key_t key; char key_r_[PADR_(l_key_t)]; @@ -755,15 +798,15 @@ struct linux_shmget_args { struct linux_shmctl_args { char shmid_l_[PADL_(l_int)]; l_int shmid; char shmid_r_[PADR_(l_int)]; char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; - char buf_l_[PADL_(struct l_shmid_ds *)]; struct l_shmid_ds * buf; char buf_r_[PADR_(struct l_shmid_ds *)]; + char buf_l_[PADL_(struct l_shmid_ds * __capability)]; struct l_shmid_ds * __capability buf; char buf_r_[PADR_(struct l_shmid_ds * __capability)]; }; struct linux_shmat_args { char shmid_l_[PADL_(l_int)]; l_int shmid; char shmid_r_[PADR_(l_int)]; - char shmaddr_l_[PADL_(char *)]; char * shmaddr; char shmaddr_r_[PADR_(char *)]; + char shmaddr_l_[PADL_(char * __capability)]; char * __capability shmaddr; char shmaddr_r_[PADR_(char * __capability)]; char shmflg_l_[PADL_(l_int)]; l_int shmflg; char shmflg_r_[PADR_(l_int)]; }; struct linux_shmdt_args { - char shmaddr_l_[PADL_(char *)]; char * shmaddr; char shmaddr_r_[PADR_(char *)]; + char shmaddr_l_[PADL_(char * __capability)]; char * __capability shmaddr; char shmaddr_r_[PADR_(char * __capability)]; }; struct linux_socket_args { char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; @@ -774,11 +817,11 @@ struct linux_socketpair_args { char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; - char rsv_l_[PADL_(l_uintptr_t)]; l_uintptr_t rsv; char rsv_r_[PADR_(l_uintptr_t)]; + char rsv_l_[PADL_(l_uintcap_t)]; l_uintcap_t rsv; char rsv_r_[PADR_(l_uintcap_t)]; }; struct linux_bind_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; + char name_l_[PADL_(l_uintcap_t)]; l_uintcap_t name; char name_r_[PADR_(l_uintcap_t)]; char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; }; struct linux_listen_args { @@ -787,53 +830,53 @@ struct linux_listen_args { }; struct linux_accept_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; - char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; + char addr_l_[PADL_(l_uintcap_t)]; l_uintcap_t addr; char addr_r_[PADR_(l_uintcap_t)]; + char namelen_l_[PADL_(l_uintcap_t)]; l_uintcap_t namelen; char namelen_r_[PADR_(l_uintcap_t)]; }; struct linux_connect_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; + char name_l_[PADL_(l_uintcap_t)]; l_uintcap_t name; char name_r_[PADR_(l_uintcap_t)]; char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; }; struct linux_getsockname_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; - char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; + char addr_l_[PADL_(l_uintcap_t)]; l_uintcap_t addr; char addr_r_[PADR_(l_uintcap_t)]; + char namelen_l_[PADL_(l_uintcap_t)]; l_uintcap_t namelen; char namelen_r_[PADR_(l_uintcap_t)]; }; struct linux_getpeername_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; - char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; + char addr_l_[PADL_(l_uintcap_t)]; l_uintcap_t addr; char addr_r_[PADR_(l_uintcap_t)]; + char namelen_l_[PADL_(l_uintcap_t)]; l_uintcap_t namelen; char namelen_r_[PADR_(l_uintcap_t)]; }; struct linux_sendto_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char msg_l_[PADL_(l_uintcap_t)]; l_uintcap_t msg; char msg_r_[PADR_(l_uintcap_t)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; - char to_l_[PADL_(l_uintptr_t)]; l_uintptr_t to; char to_r_[PADR_(l_uintptr_t)]; + char to_l_[PADL_(l_uintcap_t)]; l_uintcap_t to; char to_r_[PADR_(l_uintcap_t)]; char tolen_l_[PADL_(l_int)]; l_int tolen; char tolen_r_[PADR_(l_int)]; }; struct linux_recvfrom_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char buf_l_[PADL_(l_uintptr_t)]; l_uintptr_t buf; char buf_r_[PADR_(l_uintptr_t)]; + char buf_l_[PADL_(l_uintcap_t)]; l_uintcap_t buf; char buf_r_[PADR_(l_uintcap_t)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; - char from_l_[PADL_(l_uintptr_t)]; l_uintptr_t from; char from_r_[PADR_(l_uintptr_t)]; - char fromlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t fromlen; char fromlen_r_[PADR_(l_uintptr_t)]; + char from_l_[PADL_(l_uintcap_t)]; l_uintcap_t from; char from_r_[PADR_(l_uintcap_t)]; + char fromlen_l_[PADL_(l_uintcap_t)]; l_uintcap_t fromlen; char fromlen_r_[PADR_(l_uintcap_t)]; }; struct linux_setsockopt_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; - char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; + char optval_l_[PADL_(l_uintcap_t)]; l_uintcap_t optval; char optval_r_[PADR_(l_uintcap_t)]; char optlen_l_[PADL_(l_int)]; l_int optlen; char optlen_r_[PADR_(l_int)]; }; struct linux_getsockopt_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; - char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; - char optlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t optlen; char optlen_r_[PADR_(l_uintptr_t)]; + char optval_l_[PADL_(l_uintcap_t)]; l_uintcap_t optval; char optval_r_[PADR_(l_uintcap_t)]; + char optlen_l_[PADL_(l_uintcap_t)]; l_uintcap_t optlen; char optlen_r_[PADR_(l_uintcap_t)]; }; struct linux_shutdown_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; @@ -841,23 +884,27 @@ struct linux_shutdown_args { }; struct linux_sendmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char msg_l_[PADL_(l_uintcap_t)]; l_uintcap_t msg; char msg_r_[PADR_(l_uintcap_t)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_recvmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char msg_l_[PADL_(l_uintcap_t)]; l_uintcap_t msg; char msg_r_[PADR_(l_uintcap_t)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_brk_args { char dsend_l_[PADL_(l_ulong)]; l_ulong dsend; char dsend_r_[PADR_(l_ulong)]; }; +struct linux_munmap_args { + char addr_l_[PADL_(void * __capability)]; void * __capability addr; char addr_r_[PADR_(void * __capability)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; +}; struct linux_mremap_args { - char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char addr_l_[PADL_(void * __capability)]; void * __capability addr; char addr_r_[PADR_(void * __capability)]; char old_len_l_[PADL_(l_ulong)]; l_ulong old_len; char old_len_r_[PADR_(l_ulong)]; char new_len_l_[PADL_(l_ulong)]; l_ulong new_len; char new_len_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; - char new_addr_l_[PADL_(l_ulong)]; l_ulong new_addr; char new_addr_r_[PADR_(l_ulong)]; + char new_addr_l_[PADL_(void * __capability)]; void * __capability new_addr; char new_addr_r_[PADR_(void * __capability)]; }; struct linux_add_key_args { syscallarg_t dummy; @@ -870,18 +917,18 @@ struct linux_keyctl_args { }; struct linux_clone_args { char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; - char stack_l_[PADL_(l_ulong)]; l_ulong stack; char stack_r_[PADR_(l_ulong)]; - char parent_tidptr_l_[PADL_(l_int *)]; l_int * parent_tidptr; char parent_tidptr_r_[PADR_(l_int *)]; - char tls_l_[PADL_(l_ulong)]; l_ulong tls; char tls_r_[PADR_(l_ulong)]; - char child_tidptr_l_[PADL_(l_int *)]; l_int * child_tidptr; char child_tidptr_r_[PADR_(l_int *)]; + char stack_l_[PADL_(l_uintcap_t)]; l_uintcap_t stack; char stack_r_[PADR_(l_uintcap_t)]; + char parent_tidptr_l_[PADL_(l_int * __capability)]; l_int * __capability parent_tidptr; char parent_tidptr_r_[PADR_(l_int * __capability)]; + char tls_l_[PADL_(l_uintcap_t)]; l_uintcap_t tls; char tls_r_[PADR_(l_uintcap_t)]; + char child_tidptr_l_[PADL_(l_int * __capability)]; l_int * __capability child_tidptr; char child_tidptr_r_[PADR_(l_int * __capability)]; }; struct linux_execve_args { - char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; - char argp_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * argp; char argp_r_[PADR_(l_uintptr_t *)]; - char envp_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * envp; char envp_r_[PADR_(l_uintptr_t *)]; + char path_l_[PADL_(char * __capability)]; char * __capability path; char path_r_[PADR_(char * __capability)]; + char argp_l_[PADL_(l_uintcap_t * __capability)]; l_uintcap_t * __capability argp; char argp_r_[PADR_(l_uintcap_t * __capability)]; + char envp_l_[PADL_(l_uintcap_t * __capability)]; l_uintcap_t * __capability envp; char envp_r_[PADR_(l_uintcap_t * __capability)]; }; struct linux_mmap2_args { - char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char addr_l_[PADL_(void * __capability)]; void * __capability addr; char addr_r_[PADR_(void * __capability)]; char len_l_[PADL_(l_ulong)]; l_ulong len; char len_r_[PADR_(l_ulong)]; char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; @@ -894,26 +941,37 @@ struct linux_fadvise64_args { char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char advice_l_[PADL_(l_int)]; l_int advice; char advice_r_[PADR_(l_int)]; }; +struct linux_swapon_args { + char name_l_[PADL_(char * __capability)]; char * __capability name; char name_r_[PADR_(char * __capability)]; +}; struct linux_swapoff_args { syscallarg_t dummy; }; struct linux_mprotect_args { - char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char addr_l_[PADL_(void * __capability)]; void * __capability addr; char addr_r_[PADR_(void * __capability)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; }; struct linux_msync_args { - char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char addr_l_[PADL_(void * __capability)]; void * __capability addr; char addr_r_[PADR_(void * __capability)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char fl_l_[PADL_(l_int)]; l_int fl; char fl_r_[PADR_(l_int)]; }; +struct linux_mlock_args { + char addr_l_[PADL_(const void * __capability)]; const void * __capability addr; char addr_r_[PADR_(const void * __capability)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; +}; +struct linux_munlock_args { + char addr_l_[PADL_(const void * __capability)]; const void * __capability addr; char addr_r_[PADR_(const void * __capability)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; +}; struct linux_mincore_args { - char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char start_l_[PADL_(void * __capability)]; void * __capability start; char start_r_[PADR_(void * __capability)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; - char vec_l_[PADL_(u_char *)]; u_char * vec; char vec_r_[PADR_(u_char *)]; + char vec_l_[PADL_(u_char * __capability)]; u_char * __capability vec; char vec_r_[PADR_(u_char * __capability)]; }; struct linux_madvise_args { - char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char addr_l_[PADL_(void * __capability)]; void * __capability addr; char addr_r_[PADR_(void * __capability)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char behav_l_[PADL_(l_int)]; l_int behav; char behav_r_[PADR_(l_int)]; }; @@ -939,35 +997,35 @@ struct linux_rt_tgsigqueueinfo_args { char tgid_l_[PADL_(l_pid_t)]; l_pid_t tgid; char tgid_r_[PADR_(l_pid_t)]; char tid_l_[PADL_(l_pid_t)]; l_pid_t tid; char tid_r_[PADR_(l_pid_t)]; char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; - char uinfo_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * uinfo; char uinfo_r_[PADR_(l_siginfo_t *)]; + char uinfo_l_[PADL_(l_siginfo_t * __capability)]; l_siginfo_t * __capability uinfo; char uinfo_r_[PADR_(l_siginfo_t * __capability)]; }; struct linux_perf_event_open_args { syscallarg_t dummy; }; struct linux_accept4_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; - char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; + char addr_l_[PADL_(l_uintcap_t)]; l_uintcap_t addr; char addr_r_[PADR_(l_uintcap_t)]; + char namelen_l_[PADL_(l_uintcap_t)]; l_uintcap_t namelen; char namelen_r_[PADR_(l_uintcap_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_recvmmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; + char msg_l_[PADL_(struct l_mmsghdr * __capability)]; struct l_mmsghdr * __capability msg; char msg_r_[PADR_(struct l_mmsghdr * __capability)]; char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; - char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; + char timeout_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability timeout; char timeout_r_[PADR_(struct l_timespec * __capability)]; }; struct linux_wait4_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; - char status_l_[PADL_(l_int *)]; l_int * status; char status_r_[PADR_(l_int *)]; + char status_l_[PADL_(l_int * __capability)]; l_int * __capability status; char status_r_[PADR_(l_int * __capability)]; char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; - char rusage_l_[PADL_(struct rusage *)]; struct rusage * rusage; char rusage_r_[PADR_(struct rusage *)]; + char rusage_l_[PADL_(struct rusage * __capability)]; struct rusage * __capability rusage; char rusage_r_[PADR_(struct rusage * __capability)]; }; struct linux_prlimit64_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; - char new_l_[PADL_(struct rlimit *)]; struct rlimit * new; char new_r_[PADR_(struct rlimit *)]; - char old_l_[PADL_(struct rlimit *)]; struct rlimit * old; char old_r_[PADR_(struct rlimit *)]; + char new_l_[PADL_(struct rlimit * __capability)]; struct rlimit * __capability new; char new_r_[PADR_(struct rlimit * __capability)]; + char old_l_[PADL_(struct rlimit * __capability)]; struct rlimit * __capability old; char old_r_[PADR_(struct rlimit * __capability)]; }; struct linux_fanotify_init_args { syscallarg_t dummy; @@ -977,14 +1035,14 @@ struct linux_fanotify_mark_args { }; struct linux_name_to_handle_at_args { char dirfd_l_[PADL_(l_int)]; l_int dirfd; char dirfd_r_[PADR_(l_int)]; - char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; - char handle_l_[PADL_(struct l_file_handle *)]; struct l_file_handle * handle; char handle_r_[PADR_(struct l_file_handle *)]; - char mnt_id_l_[PADL_(l_int *)]; l_int * mnt_id; char mnt_id_r_[PADR_(l_int *)]; + char name_l_[PADL_(const char * __capability)]; const char * __capability name; char name_r_[PADR_(const char * __capability)]; + char handle_l_[PADL_(struct l_file_handle * __capability)]; struct l_file_handle * __capability handle; char handle_r_[PADR_(struct l_file_handle * __capability)]; + char mnt_id_l_[PADL_(l_int * __capability)]; l_int * __capability mnt_id; char mnt_id_r_[PADR_(l_int * __capability)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_open_by_handle_at_args { char mountdirfd_l_[PADL_(l_int)]; l_int mountdirfd; char mountdirfd_r_[PADR_(l_int)]; - char handle_l_[PADL_(struct l_file_handle *)]; struct l_file_handle * handle; char handle_r_[PADR_(struct l_file_handle *)]; + char handle_l_[PADL_(struct l_file_handle * __capability)]; struct l_file_handle * __capability handle; char handle_r_[PADR_(struct l_file_handle * __capability)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_clock_adjtime_args { @@ -999,23 +1057,23 @@ struct linux_setns_args { }; struct linux_sendmmsg_args { char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; - char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; + char msg_l_[PADL_(struct l_mmsghdr * __capability)]; struct l_mmsghdr * __capability msg; char msg_r_[PADR_(struct l_mmsghdr * __capability)]; char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_process_vm_readv_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; - char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char lvec_l_[PADL_(const struct iovec * __capability)]; const struct iovec * __capability lvec; char lvec_r_[PADR_(const struct iovec * __capability)]; char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; - char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char rvec_l_[PADL_(const struct iovec * __capability)]; const struct iovec * __capability rvec; char rvec_r_[PADR_(const struct iovec * __capability)]; char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; }; struct linux_process_vm_writev_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; - char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char lvec_l_[PADL_(const struct iovec * __capability)]; const struct iovec * __capability lvec; char lvec_r_[PADR_(const struct iovec * __capability)]; char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; - char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char rvec_l_[PADL_(const struct iovec * __capability)]; const struct iovec * __capability rvec; char rvec_r_[PADR_(const struct iovec * __capability)]; char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; }; @@ -1028,51 +1086,51 @@ struct linux_kcmp_args { }; struct linux_finit_module_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; - char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; + char uargs_l_[PADL_(const char * __capability)]; const char * __capability uargs; char uargs_r_[PADR_(const char * __capability)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_sched_setattr_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; - char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char attr_l_[PADL_(void * __capability)]; void * __capability attr; char attr_r_[PADR_(void * __capability)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_sched_getattr_args { char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; - char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char attr_l_[PADL_(void * __capability)]; void * __capability attr; char attr_r_[PADR_(void * __capability)]; char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_renameat2_args { char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; - char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char oldname_l_[PADL_(const char * __capability)]; const char * __capability oldname; char oldname_r_[PADR_(const char * __capability)]; char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; - char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char newname_l_[PADL_(const char * __capability)]; const char * __capability newname; char newname_r_[PADR_(const char * __capability)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_seccomp_args { char op_l_[PADL_(l_uint)]; l_uint op; char op_r_[PADR_(l_uint)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; - char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; + char uargs_l_[PADL_(const char * __capability)]; const char * __capability uargs; char uargs_r_[PADR_(const char * __capability)]; }; struct linux_getrandom_args { - char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char buf_l_[PADL_(char * __capability)]; char * __capability buf; char buf_r_[PADR_(char * __capability)]; char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_memfd_create_args { - char uname_ptr_l_[PADL_(const char *)]; const char * uname_ptr; char uname_ptr_r_[PADR_(const char *)]; + char uname_ptr_l_[PADL_(const char * __capability)]; const char * __capability uname_ptr; char uname_ptr_r_[PADR_(const char * __capability)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_bpf_args { char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; - char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char attr_l_[PADL_(void * __capability)]; void * __capability attr; char attr_r_[PADR_(void * __capability)]; char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; }; struct linux_execveat_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; - char argv_l_[PADL_(const char **)]; const char ** argv; char argv_r_[PADR_(const char **)]; - char envp_l_[PADL_(const char **)]; const char ** envp; char envp_r_[PADR_(const char **)]; + char filename_l_[PADL_(const char * __capability)]; const char * __capability filename; char filename_r_[PADR_(const char * __capability)]; + char argv_l_[PADL_(const char * __capability * __capability)]; const char * __capability * __capability argv; char argv_r_[PADR_(const char * __capability * __capability)]; + char envp_l_[PADL_(const char * __capability * __capability)]; const char * __capability * __capability envp; char envp_r_[PADR_(const char * __capability * __capability)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_userfaultfd_args { @@ -1083,21 +1141,21 @@ struct linux_membarrier_args { char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_mlock2_args { - char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char start_l_[PADL_(void * __capability)]; void * __capability start; char start_r_[PADR_(void * __capability)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_copy_file_range_args { char fd_in_l_[PADL_(l_int)]; l_int fd_in; char fd_in_r_[PADR_(l_int)]; - char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char off_in_l_[PADL_(l_loff_t * __capability)]; l_loff_t * __capability off_in; char off_in_r_[PADR_(l_loff_t * __capability)]; char fd_out_l_[PADL_(l_int)]; l_int fd_out; char fd_out_r_[PADR_(l_int)]; - char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char off_out_l_[PADL_(l_loff_t * __capability)]; l_loff_t * __capability off_out; char off_out_r_[PADR_(l_loff_t * __capability)]; char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_preadv2_args { char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; - char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vec_l_[PADL_(const struct iovec * __capability)]; const struct iovec * __capability vec; char vec_r_[PADR_(const struct iovec * __capability)]; char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; @@ -1105,7 +1163,7 @@ struct linux_preadv2_args { }; struct linux_pwritev2_args { char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; - char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vec_l_[PADL_(const struct iovec * __capability)]; const struct iovec * __capability vec; char vec_r_[PADR_(const struct iovec * __capability)]; char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; @@ -1126,16 +1184,16 @@ struct linux_pkey_free_args { }; struct linux_statx_args { char dirfd_l_[PADL_(l_int)]; l_int dirfd; char dirfd_r_[PADR_(l_int)]; - char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char pathname_l_[PADL_(const char * __capability)]; const char * __capability pathname; char pathname_r_[PADR_(const char * __capability)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; char mask_l_[PADL_(l_uint)]; l_uint mask; char mask_r_[PADR_(l_uint)]; - char statxbuf_l_[PADL_(void *)]; void * statxbuf; char statxbuf_r_[PADR_(void *)]; + char statxbuf_l_[PADL_(void * __capability)]; void * __capability statxbuf; char statxbuf_r_[PADR_(void * __capability)]; }; struct linux_io_pgetevents_args { syscallarg_t dummy; }; struct linux_rseq_args { - char rseq_l_[PADL_(struct linux_rseq *)]; struct linux_rseq * rseq; char rseq_r_[PADR_(struct linux_rseq *)]; + char rseq_l_[PADL_(struct linux_rseq * __capability)]; struct linux_rseq * __capability rseq; char rseq_r_[PADR_(struct linux_rseq * __capability)]; char rseq_len_l_[PADL_(uint32_t)]; uint32_t rseq_len; char rseq_len_r_[PADR_(uint32_t)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; char sig_l_[PADL_(uint32_t)]; uint32_t sig; char sig_r_[PADR_(uint32_t)]; @@ -1146,7 +1204,7 @@ struct linux_kexec_file_load_args { struct linux_pidfd_send_signal_args { char pidfd_l_[PADL_(l_int)]; l_int pidfd; char pidfd_r_[PADR_(l_int)]; char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; - char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; + char info_l_[PADL_(l_siginfo_t * __capability)]; l_siginfo_t * __capability info; char info_r_[PADR_(l_siginfo_t * __capability)]; char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_io_uring_setup_args { @@ -1180,7 +1238,7 @@ struct linux_pidfd_open_args { syscallarg_t dummy; }; struct linux_clone3_args { - char uargs_l_[PADL_(struct l_user_clone_args *)]; struct l_user_clone_args * uargs; char uargs_r_[PADR_(struct l_user_clone_args *)]; + char uargs_l_[PADL_(struct l_user_clone_args * __capability)]; struct l_user_clone_args * __capability uargs; char uargs_r_[PADR_(struct l_user_clone_args * __capability)]; char usize_l_[PADL_(l_size_t)]; l_size_t usize; char usize_r_[PADR_(l_size_t)]; }; struct linux_close_range_args { @@ -1196,7 +1254,7 @@ struct linux_pidfd_getfd_args { }; struct linux_faccessat2_args { char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; - char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char filename_l_[PADL_(const char * __capability)]; const char * __capability filename; char filename_r_[PADR_(const char * __capability)]; char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; @@ -1205,10 +1263,10 @@ struct linux_process_madvise_args { }; struct linux_epoll_pwait2_args { char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; - char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; + char events_l_[PADL_(struct epoll_event * __capability)]; struct epoll_event * __capability events; char events_r_[PADR_(struct epoll_event * __capability)]; char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; - char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; - char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; + char timeout_l_[PADL_(struct l_timespec * __capability)]; struct l_timespec * __capability timeout; char timeout_r_[PADR_(struct l_timespec * __capability)]; + char mask_l_[PADL_(l_sigset_t * __capability)]; l_sigset_t * __capability mask; char mask_r_[PADR_(l_sigset_t * __capability)]; char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; }; struct linux_mount_setattr_args { @@ -1285,6 +1343,7 @@ int linux_ftruncate(struct thread *, struct linux_ftruncate_args *); int linux_fallocate(struct thread *, struct linux_fallocate_args *); int linux_faccessat(struct thread *, struct linux_faccessat_args *); int linux_chdir(struct thread *, struct linux_chdir_args *); +int linux_chroot(struct thread *, struct linux_chroot_args *); int linux_fchmodat(struct thread *, struct linux_fchmodat_args *); int linux_fchownat(struct thread *, struct linux_fchownat_args *); int linux_openat(struct thread *, struct linux_openat_args *); @@ -1292,7 +1351,9 @@ int linux_vhangup(struct thread *, struct linux_vhangup_args *); int linux_pipe2(struct thread *, struct linux_pipe2_args *); int linux_getdents64(struct thread *, struct linux_getdents64_args *); int linux_lseek(struct thread *, struct linux_lseek_args *); +int linux_read(struct thread *, struct linux_read_args *); int linux_write(struct thread *, struct linux_write_args *); +int linux_readv(struct thread *, struct linux_readv_args *); int linux_writev(struct thread *, struct linux_writev_args *); int linux_pread(struct thread *, struct linux_pread_args *); int linux_pwrite(struct thread *, struct linux_pwrite_args *); @@ -1314,6 +1375,7 @@ int linux_timerfd_create(struct thread *, struct linux_timerfd_create_args *); int linux_timerfd_settime(struct thread *, struct linux_timerfd_settime_args *); int linux_timerfd_gettime(struct thread *, struct linux_timerfd_gettime_args *); int linux_utimensat(struct thread *, struct linux_utimensat_args *); +int linux_acct(struct thread *, struct linux_acct_args *); int linux_capget(struct thread *, struct linux_capget_args *); int linux_capset(struct thread *, struct linux_capset_args *); int linux_personality(struct thread *, struct linux_personality_args *); @@ -1364,6 +1426,8 @@ int linux_rt_sigqueueinfo(struct thread *, struct linux_rt_sigqueueinfo_args *); int linux_rt_sigreturn(struct thread *, struct linux_rt_sigreturn_args *); int linux_getpriority(struct thread *, struct linux_getpriority_args *); int linux_reboot(struct thread *, struct linux_reboot_args *); +int linux_getresuid(struct thread *, struct linux_getresuid_args *); +int linux_getresgid(struct thread *, struct linux_getresgid_args *); int linux_setfsuid(struct thread *, struct linux_setfsuid_args *); int linux_setfsgid(struct thread *, struct linux_setfsgid_args *); int linux_times(struct thread *, struct linux_times_args *); @@ -1375,8 +1439,11 @@ int linux_sethostname(struct thread *, struct linux_sethostname_args *); int linux_setdomainname(struct thread *, struct linux_setdomainname_args *); int linux_getrlimit(struct thread *, struct linux_getrlimit_args *); int linux_setrlimit(struct thread *, struct linux_setrlimit_args *); +int linux_getrusage(struct thread *, struct linux_getrusage_args *); int linux_prctl(struct thread *, struct linux_prctl_args *); int linux_getcpu(struct thread *, struct linux_getcpu_args *); +int linux_gettimeofday(struct thread *, struct linux_gettimeofday_args *); +int linux_settimeofday(struct thread *, struct linux_settimeofday_args *); int linux_adjtimex(struct thread *, struct linux_adjtimex_args *); int linux_getpid(struct thread *, struct linux_getpid_args *); int linux_getppid(struct thread *, struct linux_getppid_args *); @@ -1397,6 +1464,7 @@ int linux_msgsnd(struct thread *, struct linux_msgsnd_args *); int linux_semget(struct thread *, struct linux_semget_args *); int linux_semctl(struct thread *, struct linux_semctl_args *); int linux_semtimedop(struct thread *, struct linux_semtimedop_args *); +int linux_semop(struct thread *, struct linux_semop_args *); int linux_shmget(struct thread *, struct linux_shmget_args *); int linux_shmctl(struct thread *, struct linux_shmctl_args *); int linux_shmat(struct thread *, struct linux_shmat_args *); @@ -1417,6 +1485,7 @@ int linux_shutdown(struct thread *, struct linux_shutdown_args *); int linux_sendmsg(struct thread *, struct linux_sendmsg_args *); int linux_recvmsg(struct thread *, struct linux_recvmsg_args *); int linux_brk(struct thread *, struct linux_brk_args *); +int linux_munmap(struct thread *, struct linux_munmap_args *); int linux_mremap(struct thread *, struct linux_mremap_args *); int linux_add_key(struct thread *, struct linux_add_key_args *); int linux_request_key(struct thread *, struct linux_request_key_args *); @@ -1425,9 +1494,12 @@ int linux_clone(struct thread *, struct linux_clone_args *); int linux_execve(struct thread *, struct linux_execve_args *); int linux_mmap2(struct thread *, struct linux_mmap2_args *); int linux_fadvise64(struct thread *, struct linux_fadvise64_args *); +int linux_swapon(struct thread *, struct linux_swapon_args *); int linux_swapoff(struct thread *, struct linux_swapoff_args *); int linux_mprotect(struct thread *, struct linux_mprotect_args *); int linux_msync(struct thread *, struct linux_msync_args *); +int linux_mlock(struct thread *, struct linux_mlock_args *); +int linux_munlock(struct thread *, struct linux_munlock_args *); int linux_mincore(struct thread *, struct linux_mincore_args *); int linux_madvise(struct thread *, struct linux_madvise_args *); int linux_remap_file_pages(struct thread *, struct linux_remap_file_pages_args *); @@ -1545,6 +1617,7 @@ int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); #define LINUX_SYS_AUE_linux_fallocate AUE_NULL #define LINUX_SYS_AUE_linux_faccessat AUE_FACCESSAT #define LINUX_SYS_AUE_linux_chdir AUE_CHDIR +#define LINUX_SYS_AUE_linux_chroot AUE_CHROOT #define LINUX_SYS_AUE_linux_fchmodat AUE_FCHMODAT #define LINUX_SYS_AUE_linux_fchownat AUE_FCHOWNAT #define LINUX_SYS_AUE_linux_openat AUE_OPEN_RWTC @@ -1552,7 +1625,9 @@ int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); #define LINUX_SYS_AUE_linux_pipe2 AUE_NULL #define LINUX_SYS_AUE_linux_getdents64 AUE_GETDIRENTRIES #define LINUX_SYS_AUE_linux_lseek AUE_LSEEK +#define LINUX_SYS_AUE_linux_read AUE_NULL #define LINUX_SYS_AUE_linux_write AUE_NULL +#define LINUX_SYS_AUE_linux_readv AUE_READV #define LINUX_SYS_AUE_linux_writev AUE_WRITEV #define LINUX_SYS_AUE_linux_pread AUE_PREAD #define LINUX_SYS_AUE_linux_pwrite AUE_PWRITE @@ -1574,6 +1649,7 @@ int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); #define LINUX_SYS_AUE_linux_timerfd_settime AUE_NULL #define LINUX_SYS_AUE_linux_timerfd_gettime AUE_NULL #define LINUX_SYS_AUE_linux_utimensat AUE_FUTIMESAT +#define LINUX_SYS_AUE_linux_acct AUE_ACCT #define LINUX_SYS_AUE_linux_capget AUE_CAPGET #define LINUX_SYS_AUE_linux_capset AUE_CAPSET #define LINUX_SYS_AUE_linux_personality AUE_PERSONALITY @@ -1624,6 +1700,8 @@ int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); #define LINUX_SYS_AUE_linux_rt_sigreturn AUE_NULL #define LINUX_SYS_AUE_linux_getpriority AUE_GETPRIORITY #define LINUX_SYS_AUE_linux_reboot AUE_REBOOT +#define LINUX_SYS_AUE_linux_getresuid AUE_GETRESUID +#define LINUX_SYS_AUE_linux_getresgid AUE_GETRESGID #define LINUX_SYS_AUE_linux_setfsuid AUE_SETFSUID #define LINUX_SYS_AUE_linux_setfsgid AUE_SETFSGID #define LINUX_SYS_AUE_linux_times AUE_NULL @@ -1635,8 +1713,11 @@ int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); #define LINUX_SYS_AUE_linux_setdomainname AUE_SYSCTL #define LINUX_SYS_AUE_linux_getrlimit AUE_GETRLIMIT #define LINUX_SYS_AUE_linux_setrlimit AUE_SETRLIMIT +#define LINUX_SYS_AUE_linux_getrusage AUE_GETRUSAGE #define LINUX_SYS_AUE_linux_prctl AUE_PRCTL #define LINUX_SYS_AUE_linux_getcpu AUE_NULL +#define LINUX_SYS_AUE_linux_gettimeofday AUE_NULL +#define LINUX_SYS_AUE_linux_settimeofday AUE_SETTIMEOFDAY #define LINUX_SYS_AUE_linux_adjtimex AUE_ADJTIME #define LINUX_SYS_AUE_linux_getpid AUE_GETPID #define LINUX_SYS_AUE_linux_getppid AUE_GETPPID @@ -1657,6 +1738,7 @@ int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); #define LINUX_SYS_AUE_linux_semget AUE_NULL #define LINUX_SYS_AUE_linux_semctl AUE_NULL #define LINUX_SYS_AUE_linux_semtimedop AUE_NULL +#define LINUX_SYS_AUE_linux_semop AUE_NULL #define LINUX_SYS_AUE_linux_shmget AUE_NULL #define LINUX_SYS_AUE_linux_shmctl AUE_NULL #define LINUX_SYS_AUE_linux_shmat AUE_NULL @@ -1677,6 +1759,7 @@ int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); #define LINUX_SYS_AUE_linux_sendmsg AUE_SENDMSG #define LINUX_SYS_AUE_linux_recvmsg AUE_RECVMSG #define LINUX_SYS_AUE_linux_brk AUE_NULL +#define LINUX_SYS_AUE_linux_munmap AUE_MUNMAP #define LINUX_SYS_AUE_linux_mremap AUE_NULL #define LINUX_SYS_AUE_linux_add_key AUE_NULL #define LINUX_SYS_AUE_linux_request_key AUE_NULL @@ -1685,9 +1768,12 @@ int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); #define LINUX_SYS_AUE_linux_execve AUE_EXECVE #define LINUX_SYS_AUE_linux_mmap2 AUE_MMAP #define LINUX_SYS_AUE_linux_fadvise64 AUE_NULL +#define LINUX_SYS_AUE_linux_swapon AUE_SWAPON #define LINUX_SYS_AUE_linux_swapoff AUE_SWAPOFF #define LINUX_SYS_AUE_linux_mprotect AUE_MPROTECT #define LINUX_SYS_AUE_linux_msync AUE_MSYNC +#define LINUX_SYS_AUE_linux_mlock AUE_MLOCK +#define LINUX_SYS_AUE_linux_munlock AUE_MUNLOCK #define LINUX_SYS_AUE_linux_mincore AUE_MINCORE #define LINUX_SYS_AUE_linux_madvise AUE_MADVISE #define LINUX_SYS_AUE_linux_remap_file_pages AUE_NULL diff --git a/sys/arm64/linux/linux_sigframe.h b/sys/arm64/linux/linux_sigframe.h index 2a004f4db74d..26aca51f803b 100644 --- a/sys/arm64/linux/linux_sigframe.h +++ b/sys/arm64/linux/linux_sigframe.h @@ -48,6 +48,18 @@ struct l_esr_context { uint64_t esr; }; +#if __has_feature(capabilities) +#define L_MORELLO_MAGIC 0x4d524c01 +struct l_morello_context { + struct _l_aarch64_ctx head; + uint64_t __pad; + uintcap_t cregs[31]; + uintcap_t csp; + uintcap_t rcsp; + uintcap_t pcc; +}; +#endif + struct l_sigcontext { uint64_t fault_address; uint64_t regs[31]; @@ -74,8 +86,13 @@ struct l_rt_sigframe { struct l_sigframe { struct l_rt_sigframe sf; /* frame_record */ +#if __has_feature(capabilities) + uintcap_t fp; + uintcap_t lr; +#else uint64_t fp; uint64_t lr; +#endif }; #define LINUX_MINSIGSTKSZ roundup(sizeof(struct l_sigframe), 16) diff --git a/sys/arm64/linux/linux_support.S b/sys/arm64/linux/linux_support.S index 3b16583e9d54..6727893a5b78 100644 --- a/sys/arm64/linux/linux_support.S +++ b/sys/arm64/linux/linux_support.S @@ -37,14 +37,19 @@ #include "assym.inc" .macro check_user_access user_arg, limit, bad_addr_func +#if __has_feature(capabilities) + gcvalue x6, c\user_arg +#else + mov x6, x\user_arg +#endif ldr x7, =(\limit) - cmp x\user_arg, x7 + cmp x6, x7 b.cs \bad_addr_func .endm futex_fault: - SET_FAULT_HANDLER(xzr, x1) - EXIT_USER_ACCESS_CHECK(w0, x1) + SET_FAULT_HANDLER(xzr, PTR(1)) + EXIT_USER_ACCESS_CHECK(w0, PTR(1)) futex_fault_nopcb: mov x0, #EFAULT ret @@ -52,7 +57,7 @@ futex_fault_nopcb: #define LINUX_FUTEX_MAX_LOOPS 128 /* - * int oparg, uint32_t *uaddr, int *oldval + * int oparg, uint32_t * __capability uaddr, int *oldval * * Return 0 on success, errno on failure, * EAGAIN is returned if LL/SC operation fails. @@ -64,114 +69,144 @@ futex_fault_nopcb: /* (int *)uaddr2 = oparg */ ENTRY(futex_xchgl) check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb - adr x9, futex_fault /* Load the fault handler */ - SET_FAULT_HANDLER(x9, x4) /* And set it */ - ENTER_USER_ACCESS(w9, x4) +#if __has_feature(capabilities) && !defined(__CHERI_PURE_CAPABILITY__) + cvtd c2, x2 /* Store through a capability */ + scbnds c2, c2, #4 /* Set the bounds */ +#endif + adr PTR(9), futex_fault /* Load the fault handler */ + SET_FAULT_HANDLER(PTR(9), PTR(4)) /* And set it */ + ENTER_USER_ACCESS(w9, PTR(4)) mov w5, #LINUX_FUTEX_MAX_LOOPS - prfm pstl1strm, [x1] + ENTER_C64 + prfm pstl1strm, [CAP(1)] mov w6, w0 /* Save oparg */ -1: ldxr w4, [x1] /* Load oldval from uaddr */ - stlxr w0, w6, [x1] /* Store oparg to uaddr */ +1: ldxr w4, [CAP(1)] /* Load oldval from uaddr */ + stlxr w0, w6, [CAP(1)] /* Store oparg to uaddr */ cbz w0, 3f /* Exit on success */ sub w5, w5, w0 /* Dec loop counter, w0 is 1 */ cbnz w5, 1b /* Loop */ mov x0, #EAGAIN /* Store of newval failed */ 3: dmb ish + EXIT_C64 EXIT_USER_ACCESS(w9) - SET_FAULT_HANDLER(xzr, x9) /* Reset the fault handler */ - str w4, [x2] /* Store oldval */ + SET_FAULT_HANDLER(xzr, PTR(9)) /* Reset the fault handler */ + str w4, [CAP(2)] /* Store oldval */ ret END(futex_xchgl) /* (int *)uaddr2 += oparg */ ENTRY(futex_addl) check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb - adr x9, futex_fault - SET_FAULT_HANDLER(x9, x4) - ENTER_USER_ACCESS(w9, x4) +#if __has_feature(capabilities) && !defined(__CHERI_PURE_CAPABILITY__) + cvtd c2, x2 /* Store through a capability */ + scbnds c2, c2, #4 /* Set the bounds */ +#endif + adr PTR(9), futex_fault + SET_FAULT_HANDLER(PTR(9), PTR(4)) + ENTER_USER_ACCESS(w9, PTR(4)) mov w5, #LINUX_FUTEX_MAX_LOOPS - prfm pstl1strm, [x1] + ENTER_C64 + prfm pstl1strm, [CAP(1)] mov w6, w0 -1: ldxr w4, [x1] +1: ldxr w4, [CAP(1)] add w3, w4, w6 /* oldval + oparg */ - stlxr w0, w3, [x1] + stlxr w0, w3, [CAP(1)] cbz w0, 3f sub w5, w5, w0 cbnz w5, 1b mov x0, #EAGAIN 3: dmb ish + EXIT_C64 EXIT_USER_ACCESS(w9) - SET_FAULT_HANDLER(xzr, x9) - str w4, [x2] + SET_FAULT_HANDLER(xzr, PTR(9)) + str w4, [CAP(2)] ret END(futex_addl) /* (int *)uaddr2 |= oparg */ ENTRY(futex_orl) check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb - adr x9, futex_fault - SET_FAULT_HANDLER(x9, x4) - ENTER_USER_ACCESS(w9, x4) +#if __has_feature(capabilities) && !defined(__CHERI_PURE_CAPABILITY__) + cvtd c2, x2 /* Store through a capability */ + scbnds c2, c2, #4 /* Set the bounds */ +#endif + adr PTR(9), futex_fault + SET_FAULT_HANDLER(PTR(9), PTR(4)) + ENTER_USER_ACCESS(w9, PTR(4)) mov w5, #LINUX_FUTEX_MAX_LOOPS - prfm pstl1strm, [x1] + ENTER_C64 + prfm pstl1strm, [CAP(1)] mov w6, w0 -1: ldxr w4, [x1] +1: ldxr w4, [CAP(1)] orr w3, w4, w6 /* oldavl |= oparg */ - stlxr w0, w3, [x1] + stlxr w0, w3, [CAP(1)] cbz w0, 3f sub w5, w5, w0 cbnz w5, 1b mov x0, #EAGAIN 3: dmb ish + EXIT_C64 EXIT_USER_ACCESS(w9) - SET_FAULT_HANDLER(xzr, x9) - str w4, [x2] + SET_FAULT_HANDLER(xzr, PTR(9)) + str w4, [CAP(2)] ret END(futex_orl) /* (int *)uaddr2 &= oparg */ ENTRY(futex_andl) check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb - adr x9, futex_fault - SET_FAULT_HANDLER(x9, x4) - ENTER_USER_ACCESS(w9, x4) +#if __has_feature(capabilities) && !defined(__CHERI_PURE_CAPABILITY__) + cvtd c2, x2 /* Store through a capability */ + scbnds c2, c2, #4 /* Set the bounds */ +#endif + adr PTR(9), futex_fault + SET_FAULT_HANDLER(PTR(9), PTR(4)) + ENTER_USER_ACCESS(w9, PTR(4)) mov w5, #LINUX_FUTEX_MAX_LOOPS - prfm pstl1strm, [x1] + ENTER_C64 + prfm pstl1strm, [CAP(1)] mov w6, w0 -1: ldxr w4, [x1] +1: ldxr w4, [CAP(1)] and w3, w4, w6 /* oldval &= oparg */ - stlxr w0, w3, [x1] + stlxr w0, w3, [CAP(1)] cbz w0, 3f sub w5, w5, w0 cbnz w5, 1b mov x0, #EAGAIN 3: dmb ish + EXIT_C64 EXIT_USER_ACCESS(w9) - SET_FAULT_HANDLER(xzr, x9) - str w4, [x2] + SET_FAULT_HANDLER(xzr, PTR(9)) + str w4, [CAP(2)] ret END(futex_andl) /* (int *)uaddr2 ^= oparg */ ENTRY(futex_xorl) check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb - adr x9, futex_fault - SET_FAULT_HANDLER(x9, x4) - ENTER_USER_ACCESS(w9, x4) +#if __has_feature(capabilities) && !defined(__CHERI_PURE_CAPABILITY__) + cvtd c2, x2 /* Store through a capability */ + scbnds c2, c2, #4 /* Set the bounds */ +#endif + adr PTR(9), futex_fault + SET_FAULT_HANDLER(PTR(9), PTR(4)) + ENTER_USER_ACCESS(w9, PTR(4)) mov w5, #LINUX_FUTEX_MAX_LOOPS - prfm pstl1strm, [x1] + ENTER_C64 + prfm pstl1strm, [CAP(1)] mov w6, w0 -1: ldxr w4, [x1] +1: ldxr w4, [CAP(1)] eor w3, w4, w6 /* oldval ^= oparg */ - stlxr w0, w3, [x1] + stlxr w0, w3, [CAP(1)] cbz w0, 3f sub w5, w5, w0 cbnz w5, 1b mov x0, #EAGAIN 3: dmb ish + EXIT_C64 EXIT_USER_ACCESS(w9) - SET_FAULT_HANDLER(xzr, x9) - str w4, [x2] + SET_FAULT_HANDLER(xzr, PTR(9)) + str w4, [CAP(2)] ret END(futex_xorl) diff --git a/sys/arm64/linux/linux_syscall.h b/sys/arm64/linux/linux_syscall.h index 5ddc0608aff8..f3ad9989ef4e 100644 --- a/sys/arm64/linux/linux_syscall.h +++ b/sys/arm64/linux/linux_syscall.h @@ -48,7 +48,7 @@ #define LINUX_SYS_linux_faccessat 48 #define LINUX_SYS_linux_chdir 49 #define LINUX_SYS_fchdir 50 -#define LINUX_SYS_chroot 51 +#define LINUX_SYS_linux_chroot 51 #define LINUX_SYS_fchmod 52 #define LINUX_SYS_linux_fchmodat 53 #define LINUX_SYS_linux_fchownat 54 @@ -59,9 +59,9 @@ #define LINUX_SYS_linux_pipe2 59 #define LINUX_SYS_linux_getdents64 61 #define LINUX_SYS_linux_lseek 62 -#define LINUX_SYS_read 63 +#define LINUX_SYS_linux_read 63 #define LINUX_SYS_linux_write 64 -#define LINUX_SYS_readv 65 +#define LINUX_SYS_linux_readv 65 #define LINUX_SYS_linux_writev 66 #define LINUX_SYS_linux_pread 67 #define LINUX_SYS_linux_pwrite 68 @@ -84,7 +84,7 @@ #define LINUX_SYS_linux_timerfd_settime 86 #define LINUX_SYS_linux_timerfd_gettime 87 #define LINUX_SYS_linux_utimensat 88 -#define LINUX_SYS_acct 89 +#define LINUX_SYS_linux_acct 89 #define LINUX_SYS_linux_capget 90 #define LINUX_SYS_linux_capset 91 #define LINUX_SYS_linux_personality 92 @@ -142,9 +142,9 @@ #define LINUX_SYS_setreuid 145 #define LINUX_SYS_setuid 146 #define LINUX_SYS_setresuid 147 -#define LINUX_SYS_getresuid 148 +#define LINUX_SYS_linux_getresuid 148 #define LINUX_SYS_setresgid 149 -#define LINUX_SYS_getresgid 150 +#define LINUX_SYS_linux_getresgid 150 #define LINUX_SYS_linux_setfsuid 151 #define LINUX_SYS_linux_setfsgid 152 #define LINUX_SYS_linux_times 153 @@ -159,12 +159,12 @@ #define LINUX_SYS_linux_setdomainname 162 #define LINUX_SYS_linux_getrlimit 163 #define LINUX_SYS_linux_setrlimit 164 -#define LINUX_SYS_getrusage 165 +#define LINUX_SYS_linux_getrusage 165 #define LINUX_SYS_umask 166 #define LINUX_SYS_linux_prctl 167 #define LINUX_SYS_linux_getcpu 168 -#define LINUX_SYS_gettimeofday 169 -#define LINUX_SYS_settimeofday 170 +#define LINUX_SYS_linux_gettimeofday 169 +#define LINUX_SYS_linux_settimeofday 170 #define LINUX_SYS_linux_adjtimex 171 #define LINUX_SYS_linux_getpid 172 #define LINUX_SYS_linux_getppid 173 @@ -187,7 +187,7 @@ #define LINUX_SYS_linux_semget 190 #define LINUX_SYS_linux_semctl 191 #define LINUX_SYS_linux_semtimedop 192 -#define LINUX_SYS_semop 193 +#define LINUX_SYS_linux_semop 193 #define LINUX_SYS_linux_shmget 194 #define LINUX_SYS_linux_shmctl 195 #define LINUX_SYS_linux_shmat 196 @@ -208,7 +208,7 @@ #define LINUX_SYS_linux_sendmsg 211 #define LINUX_SYS_linux_recvmsg 212 #define LINUX_SYS_linux_brk 214 -#define LINUX_SYS_munmap 215 +#define LINUX_SYS_linux_munmap 215 #define LINUX_SYS_linux_mremap 216 #define LINUX_SYS_linux_add_key 217 #define LINUX_SYS_linux_request_key 218 @@ -217,12 +217,12 @@ #define LINUX_SYS_linux_execve 221 #define LINUX_SYS_linux_mmap2 222 #define LINUX_SYS_linux_fadvise64 223 -#define LINUX_SYS_swapon 224 +#define LINUX_SYS_linux_swapon 224 #define LINUX_SYS_linux_swapoff 225 #define LINUX_SYS_linux_mprotect 226 #define LINUX_SYS_linux_msync 227 -#define LINUX_SYS_mlock 228 -#define LINUX_SYS_munlock 229 +#define LINUX_SYS_linux_mlock 228 +#define LINUX_SYS_linux_munlock 229 #define LINUX_SYS_mlockall 230 #define LINUX_SYS_munlockall 231 #define LINUX_SYS_linux_mincore 232 diff --git a/sys/arm64/linux/linux_syscalls.c b/sys/arm64/linux/linux_syscalls.c index c26519dc0a52..4cfffc61ddac 100644 --- a/sys/arm64/linux/linux_syscalls.c +++ b/sys/arm64/linux/linux_syscalls.c @@ -56,7 +56,7 @@ const char *linux_syscallnames[] = { "linux_faccessat", /* 48 = linux_faccessat */ "linux_chdir", /* 49 = linux_chdir */ "fchdir", /* 50 = fchdir */ - "chroot", /* 51 = chroot */ + "linux_chroot", /* 51 = linux_chroot */ "fchmod", /* 52 = fchmod */ "linux_fchmodat", /* 53 = linux_fchmodat */ "linux_fchownat", /* 54 = linux_fchownat */ @@ -68,9 +68,9 @@ const char *linux_syscallnames[] = { "#60", /* 60 = linux_quotactl */ "linux_getdents64", /* 61 = linux_getdents64 */ "linux_lseek", /* 62 = linux_lseek */ - "read", /* 63 = read */ + "linux_read", /* 63 = linux_read */ "linux_write", /* 64 = linux_write */ - "readv", /* 65 = readv */ + "linux_readv", /* 65 = linux_readv */ "linux_writev", /* 66 = linux_writev */ "linux_pread", /* 67 = linux_pread */ "linux_pwrite", /* 68 = linux_pwrite */ @@ -94,7 +94,7 @@ const char *linux_syscallnames[] = { "linux_timerfd_settime", /* 86 = linux_timerfd_settime */ "linux_timerfd_gettime", /* 87 = linux_timerfd_gettime */ "linux_utimensat", /* 88 = linux_utimensat */ - "acct", /* 89 = acct */ + "linux_acct", /* 89 = linux_acct */ "linux_capget", /* 90 = linux_capget */ "linux_capset", /* 91 = linux_capset */ "linux_personality", /* 92 = linux_personality */ @@ -153,9 +153,9 @@ const char *linux_syscallnames[] = { "setreuid", /* 145 = setreuid */ "setuid", /* 146 = setuid */ "setresuid", /* 147 = setresuid */ - "getresuid", /* 148 = getresuid */ + "linux_getresuid", /* 148 = linux_getresuid */ "setresgid", /* 149 = setresgid */ - "getresgid", /* 150 = getresgid */ + "linux_getresgid", /* 150 = linux_getresgid */ "linux_setfsuid", /* 151 = linux_setfsuid */ "linux_setfsgid", /* 152 = linux_setfsgid */ "linux_times", /* 153 = linux_times */ @@ -170,12 +170,12 @@ const char *linux_syscallnames[] = { "linux_setdomainname", /* 162 = linux_setdomainname */ "linux_getrlimit", /* 163 = linux_getrlimit */ "linux_setrlimit", /* 164 = linux_setrlimit */ - "getrusage", /* 165 = getrusage */ + "linux_getrusage", /* 165 = linux_getrusage */ "umask", /* 166 = umask */ "linux_prctl", /* 167 = linux_prctl */ "linux_getcpu", /* 168 = linux_getcpu */ - "gettimeofday", /* 169 = gettimeofday */ - "settimeofday", /* 170 = settimeofday */ + "linux_gettimeofday", /* 169 = linux_gettimeofday */ + "linux_settimeofday", /* 170 = linux_settimeofday */ "linux_adjtimex", /* 171 = linux_adjtimex */ "linux_getpid", /* 172 = linux_getpid */ "linux_getppid", /* 173 = linux_getppid */ @@ -198,7 +198,7 @@ const char *linux_syscallnames[] = { "linux_semget", /* 190 = linux_semget */ "linux_semctl", /* 191 = linux_semctl */ "linux_semtimedop", /* 192 = linux_semtimedop */ - "semop", /* 193 = semop */ + "linux_semop", /* 193 = linux_semop */ "linux_shmget", /* 194 = linux_shmget */ "linux_shmctl", /* 195 = linux_shmctl */ "linux_shmat", /* 196 = linux_shmat */ @@ -220,7 +220,7 @@ const char *linux_syscallnames[] = { "linux_recvmsg", /* 212 = linux_recvmsg */ "#213", /* 213 = linux_readahead */ "linux_brk", /* 214 = linux_brk */ - "munmap", /* 215 = munmap */ + "linux_munmap", /* 215 = linux_munmap */ "linux_mremap", /* 216 = linux_mremap */ "linux_add_key", /* 217 = linux_add_key */ "linux_request_key", /* 218 = linux_request_key */ @@ -229,12 +229,12 @@ const char *linux_syscallnames[] = { "linux_execve", /* 221 = linux_execve */ "linux_mmap2", /* 222 = linux_mmap2 */ "linux_fadvise64", /* 223 = linux_fadvise64 */ - "swapon", /* 224 = swapon */ + "linux_swapon", /* 224 = linux_swapon */ "linux_swapoff", /* 225 = linux_swapoff */ "linux_mprotect", /* 226 = linux_mprotect */ "linux_msync", /* 227 = linux_msync */ - "mlock", /* 228 = mlock */ - "munlock", /* 229 = munlock */ + "linux_mlock", /* 228 = linux_mlock */ + "linux_munlock", /* 229 = linux_munlock */ "mlockall", /* 230 = mlockall */ "munlockall", /* 231 = munlockall */ "linux_mincore", /* 232 = linux_mincore */ diff --git a/sys/arm64/linux/linux_sysent.c b/sys/arm64/linux/linux_sysent.c index ac93f9bb3a54..7c9894a369c9 100644 --- a/sys/arm64/linux/linux_sysent.c +++ b/sys/arm64/linux/linux_sysent.c @@ -65,7 +65,7 @@ struct sysent linux_sysent[] = { { .sy_narg = AS(linux_faccessat_args), .sy_call = (sy_call_t *)linux_faccessat, .sy_auevent = AUE_FACCESSAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 48 = linux_faccessat */ { .sy_narg = AS(linux_chdir_args), .sy_call = (sy_call_t *)linux_chdir, .sy_auevent = AUE_CHDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 49 = linux_chdir */ { .sy_narg = AS(fchdir_args), .sy_call = (sy_call_t *)sys_fchdir, .sy_auevent = AUE_FCHDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 50 = fchdir */ - { .sy_narg = AS(chroot_args), .sy_call = (sy_call_t *)sys_chroot, .sy_auevent = AUE_CHROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 51 = chroot */ + { .sy_narg = AS(linux_chroot_args), .sy_call = (sy_call_t *)linux_chroot, .sy_auevent = AUE_CHROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 51 = linux_chroot */ { .sy_narg = AS(fchmod_args), .sy_call = (sy_call_t *)sys_fchmod, .sy_auevent = AUE_FCHMOD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 52 = fchmod */ { .sy_narg = AS(linux_fchmodat_args), .sy_call = (sy_call_t *)linux_fchmodat, .sy_auevent = AUE_FCHMODAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 53 = linux_fchmodat */ { .sy_narg = AS(linux_fchownat_args), .sy_call = (sy_call_t *)linux_fchownat, .sy_auevent = AUE_FCHOWNAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 54 = linux_fchownat */ @@ -77,9 +77,9 @@ struct sysent linux_sysent[] = { { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 60 = linux_quotactl */ { .sy_narg = AS(linux_getdents64_args), .sy_call = (sy_call_t *)linux_getdents64, .sy_auevent = AUE_GETDIRENTRIES, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 61 = linux_getdents64 */ { .sy_narg = AS(linux_lseek_args), .sy_call = (sy_call_t *)linux_lseek, .sy_auevent = AUE_LSEEK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 62 = linux_lseek */ - { .sy_narg = AS(read_args), .sy_call = (sy_call_t *)sys_read, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 63 = read */ + { .sy_narg = AS(linux_read_args), .sy_call = (sy_call_t *)linux_read, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 63 = linux_read */ { .sy_narg = AS(linux_write_args), .sy_call = (sy_call_t *)linux_write, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 64 = linux_write */ - { .sy_narg = AS(readv_args), .sy_call = (sy_call_t *)sys_readv, .sy_auevent = AUE_READV, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 65 = readv */ + { .sy_narg = AS(linux_readv_args), .sy_call = (sy_call_t *)linux_readv, .sy_auevent = AUE_READV, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 65 = linux_readv */ { .sy_narg = AS(linux_writev_args), .sy_call = (sy_call_t *)linux_writev, .sy_auevent = AUE_WRITEV, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 66 = linux_writev */ { .sy_narg = AS(linux_pread_args), .sy_call = (sy_call_t *)linux_pread, .sy_auevent = AUE_PREAD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 67 = linux_pread */ { .sy_narg = AS(linux_pwrite_args), .sy_call = (sy_call_t *)linux_pwrite, .sy_auevent = AUE_PWRITE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 68 = linux_pwrite */ @@ -103,7 +103,7 @@ struct sysent linux_sysent[] = { { .sy_narg = AS(linux_timerfd_settime_args), .sy_call = (sy_call_t *)linux_timerfd_settime, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 86 = linux_timerfd_settime */ { .sy_narg = AS(linux_timerfd_gettime_args), .sy_call = (sy_call_t *)linux_timerfd_gettime, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 87 = linux_timerfd_gettime */ { .sy_narg = AS(linux_utimensat_args), .sy_call = (sy_call_t *)linux_utimensat, .sy_auevent = AUE_FUTIMESAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 88 = linux_utimensat */ - { .sy_narg = AS(acct_args), .sy_call = (sy_call_t *)sys_acct, .sy_auevent = AUE_ACCT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 89 = acct */ + { .sy_narg = AS(linux_acct_args), .sy_call = (sy_call_t *)linux_acct, .sy_auevent = AUE_ACCT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 89 = linux_acct */ { .sy_narg = AS(linux_capget_args), .sy_call = (sy_call_t *)linux_capget, .sy_auevent = AUE_CAPGET, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 90 = linux_capget */ { .sy_narg = AS(linux_capset_args), .sy_call = (sy_call_t *)linux_capset, .sy_auevent = AUE_CAPSET, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 91 = linux_capset */ { .sy_narg = AS(linux_personality_args), .sy_call = (sy_call_t *)linux_personality, .sy_auevent = AUE_PERSONALITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 92 = linux_personality */ @@ -162,9 +162,9 @@ struct sysent linux_sysent[] = { { .sy_narg = AS(setreuid_args), .sy_call = (sy_call_t *)sys_setreuid, .sy_auevent = AUE_SETREUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 145 = setreuid */ { .sy_narg = AS(setuid_args), .sy_call = (sy_call_t *)sys_setuid, .sy_auevent = AUE_SETUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 146 = setuid */ { .sy_narg = AS(setresuid_args), .sy_call = (sy_call_t *)sys_setresuid, .sy_auevent = AUE_SETRESUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 147 = setresuid */ - { .sy_narg = AS(getresuid_args), .sy_call = (sy_call_t *)sys_getresuid, .sy_auevent = AUE_GETRESUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 148 = getresuid */ + { .sy_narg = AS(linux_getresuid_args), .sy_call = (sy_call_t *)linux_getresuid, .sy_auevent = AUE_GETRESUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 148 = linux_getresuid */ { .sy_narg = AS(setresgid_args), .sy_call = (sy_call_t *)sys_setresgid, .sy_auevent = AUE_SETRESGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 149 = setresgid */ - { .sy_narg = AS(getresgid_args), .sy_call = (sy_call_t *)sys_getresgid, .sy_auevent = AUE_GETRESGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 150 = getresgid */ + { .sy_narg = AS(linux_getresgid_args), .sy_call = (sy_call_t *)linux_getresgid, .sy_auevent = AUE_GETRESGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 150 = linux_getresgid */ { .sy_narg = AS(linux_setfsuid_args), .sy_call = (sy_call_t *)linux_setfsuid, .sy_auevent = AUE_SETFSUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 151 = linux_setfsuid */ { .sy_narg = AS(linux_setfsgid_args), .sy_call = (sy_call_t *)linux_setfsgid, .sy_auevent = AUE_SETFSGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 152 = linux_setfsgid */ { .sy_narg = AS(linux_times_args), .sy_call = (sy_call_t *)linux_times, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 153 = linux_times */ @@ -179,12 +179,12 @@ struct sysent linux_sysent[] = { { .sy_narg = AS(linux_setdomainname_args), .sy_call = (sy_call_t *)linux_setdomainname, .sy_auevent = AUE_SYSCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 162 = linux_setdomainname */ { .sy_narg = AS(linux_getrlimit_args), .sy_call = (sy_call_t *)linux_getrlimit, .sy_auevent = AUE_GETRLIMIT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 163 = linux_getrlimit */ { .sy_narg = AS(linux_setrlimit_args), .sy_call = (sy_call_t *)linux_setrlimit, .sy_auevent = AUE_SETRLIMIT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 164 = linux_setrlimit */ - { .sy_narg = AS(getrusage_args), .sy_call = (sy_call_t *)sys_getrusage, .sy_auevent = AUE_GETRUSAGE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 165 = getrusage */ + { .sy_narg = AS(linux_getrusage_args), .sy_call = (sy_call_t *)linux_getrusage, .sy_auevent = AUE_GETRUSAGE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 165 = linux_getrusage */ { .sy_narg = AS(umask_args), .sy_call = (sy_call_t *)sys_umask, .sy_auevent = AUE_UMASK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 166 = umask */ { .sy_narg = AS(linux_prctl_args), .sy_call = (sy_call_t *)linux_prctl, .sy_auevent = AUE_PRCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 167 = linux_prctl */ { .sy_narg = AS(linux_getcpu_args), .sy_call = (sy_call_t *)linux_getcpu, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 168 = linux_getcpu */ - { .sy_narg = AS(gettimeofday_args), .sy_call = (sy_call_t *)sys_gettimeofday, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 169 = gettimeofday */ - { .sy_narg = AS(settimeofday_args), .sy_call = (sy_call_t *)sys_settimeofday, .sy_auevent = AUE_SETTIMEOFDAY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 170 = settimeofday */ + { .sy_narg = AS(linux_gettimeofday_args), .sy_call = (sy_call_t *)linux_gettimeofday, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 169 = linux_gettimeofday */ + { .sy_narg = AS(linux_settimeofday_args), .sy_call = (sy_call_t *)linux_settimeofday, .sy_auevent = AUE_SETTIMEOFDAY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 170 = linux_settimeofday */ { .sy_narg = 0, .sy_call = (sy_call_t *)linux_adjtimex, .sy_auevent = AUE_ADJTIME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 171 = linux_adjtimex */ { .sy_narg = 0, .sy_call = (sy_call_t *)linux_getpid, .sy_auevent = AUE_GETPID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 172 = linux_getpid */ { .sy_narg = 0, .sy_call = (sy_call_t *)linux_getppid, .sy_auevent = AUE_GETPPID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 173 = linux_getppid */ @@ -207,7 +207,7 @@ struct sysent linux_sysent[] = { { .sy_narg = AS(linux_semget_args), .sy_call = (sy_call_t *)linux_semget, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 190 = linux_semget */ { .sy_narg = AS(linux_semctl_args), .sy_call = (sy_call_t *)linux_semctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 191 = linux_semctl */ { .sy_narg = AS(linux_semtimedop_args), .sy_call = (sy_call_t *)linux_semtimedop, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 192 = linux_semtimedop */ - { .sy_narg = AS(semop_args), .sy_call = (sy_call_t *)sys_semop, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 193 = semop */ + { .sy_narg = AS(linux_semop_args), .sy_call = (sy_call_t *)linux_semop, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 193 = linux_semop */ { .sy_narg = AS(linux_shmget_args), .sy_call = (sy_call_t *)linux_shmget, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 194 = linux_shmget */ { .sy_narg = AS(linux_shmctl_args), .sy_call = (sy_call_t *)linux_shmctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 195 = linux_shmctl */ { .sy_narg = AS(linux_shmat_args), .sy_call = (sy_call_t *)linux_shmat, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 196 = linux_shmat */ @@ -229,7 +229,7 @@ struct sysent linux_sysent[] = { { .sy_narg = AS(linux_recvmsg_args), .sy_call = (sy_call_t *)linux_recvmsg, .sy_auevent = AUE_RECVMSG, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 212 = linux_recvmsg */ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 213 = linux_readahead */ { .sy_narg = AS(linux_brk_args), .sy_call = (sy_call_t *)linux_brk, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 214 = linux_brk */ - { .sy_narg = AS(munmap_args), .sy_call = (sy_call_t *)sys_munmap, .sy_auevent = AUE_MUNMAP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 215 = munmap */ + { .sy_narg = AS(linux_munmap_args), .sy_call = (sy_call_t *)linux_munmap, .sy_auevent = AUE_MUNMAP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 215 = linux_munmap */ { .sy_narg = AS(linux_mremap_args), .sy_call = (sy_call_t *)linux_mremap, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 216 = linux_mremap */ { .sy_narg = 0, .sy_call = (sy_call_t *)linux_add_key, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 217 = linux_add_key */ { .sy_narg = 0, .sy_call = (sy_call_t *)linux_request_key, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 218 = linux_request_key */ @@ -238,12 +238,12 @@ struct sysent linux_sysent[] = { { .sy_narg = AS(linux_execve_args), .sy_call = (sy_call_t *)linux_execve, .sy_auevent = AUE_EXECVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 221 = linux_execve */ { .sy_narg = AS(linux_mmap2_args), .sy_call = (sy_call_t *)linux_mmap2, .sy_auevent = AUE_MMAP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 222 = linux_mmap2 */ { .sy_narg = AS(linux_fadvise64_args), .sy_call = (sy_call_t *)linux_fadvise64, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 223 = linux_fadvise64 */ - { .sy_narg = AS(swapon_args), .sy_call = (sy_call_t *)sys_swapon, .sy_auevent = AUE_SWAPON, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 224 = swapon */ + { .sy_narg = AS(linux_swapon_args), .sy_call = (sy_call_t *)linux_swapon, .sy_auevent = AUE_SWAPON, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 224 = linux_swapon */ { .sy_narg = 0, .sy_call = (sy_call_t *)linux_swapoff, .sy_auevent = AUE_SWAPOFF, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 225 = linux_swapoff */ { .sy_narg = AS(linux_mprotect_args), .sy_call = (sy_call_t *)linux_mprotect, .sy_auevent = AUE_MPROTECT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 226 = linux_mprotect */ { .sy_narg = AS(linux_msync_args), .sy_call = (sy_call_t *)linux_msync, .sy_auevent = AUE_MSYNC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 227 = linux_msync */ - { .sy_narg = AS(mlock_args), .sy_call = (sy_call_t *)sys_mlock, .sy_auevent = AUE_MLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 228 = mlock */ - { .sy_narg = AS(munlock_args), .sy_call = (sy_call_t *)sys_munlock, .sy_auevent = AUE_MUNLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 229 = munlock */ + { .sy_narg = AS(linux_mlock_args), .sy_call = (sy_call_t *)linux_mlock, .sy_auevent = AUE_MLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 228 = linux_mlock */ + { .sy_narg = AS(linux_munlock_args), .sy_call = (sy_call_t *)linux_munlock, .sy_auevent = AUE_MUNLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 229 = linux_munlock */ { .sy_narg = AS(mlockall_args), .sy_call = (sy_call_t *)sys_mlockall, .sy_auevent = AUE_MLOCKALL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 230 = mlockall */ { .sy_narg = 0, .sy_call = (sy_call_t *)sys_munlockall, .sy_auevent = AUE_MUNLOCKALL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 231 = munlockall */ { .sy_narg = AS(linux_mincore_args), .sy_call = (sy_call_t *)linux_mincore, .sy_auevent = AUE_MINCORE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 232 = linux_mincore */ diff --git a/sys/arm64/linux/linux_systrace_args.c b/sys/arm64/linux/linux_systrace_args.c index 73b3bf107486..d43093415ecf 100644 --- a/sys/arm64/linux/linux_systrace_args.c +++ b/sys/arm64/linux/linux_systrace_args.c @@ -14,9 +14,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_setxattr */ case 5: { struct linux_setxattr_args *p = params; - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->name; /* const char * */ - uarg[a++] = (intptr_t)p->value; /* void * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ + uarg[a++] = (intptr_t)p->value; /* void * __capability */ iarg[a++] = p->size; /* l_size_t */ iarg[a++] = p->flags; /* l_int */ *n_args = 5; @@ -25,9 +25,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_lsetxattr */ case 6: { struct linux_lsetxattr_args *p = params; - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->name; /* const char * */ - uarg[a++] = (intptr_t)p->value; /* void * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ + uarg[a++] = (intptr_t)p->value; /* void * __capability */ iarg[a++] = p->size; /* l_size_t */ iarg[a++] = p->flags; /* l_int */ *n_args = 5; @@ -37,8 +37,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 7: { struct linux_fsetxattr_args *p = params; iarg[a++] = p->fd; /* l_int */ - uarg[a++] = (intptr_t)p->name; /* const char * */ - uarg[a++] = (intptr_t)p->value; /* void * */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ + uarg[a++] = (intptr_t)p->value; /* void * __capability */ iarg[a++] = p->size; /* l_size_t */ iarg[a++] = p->flags; /* l_int */ *n_args = 5; @@ -47,9 +47,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_getxattr */ case 8: { struct linux_getxattr_args *p = params; - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->name; /* const char * */ - uarg[a++] = (intptr_t)p->value; /* void * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ + uarg[a++] = (intptr_t)p->value; /* void * __capability */ iarg[a++] = p->size; /* l_size_t */ *n_args = 4; break; @@ -57,9 +57,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_lgetxattr */ case 9: { struct linux_lgetxattr_args *p = params; - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->name; /* const char * */ - uarg[a++] = (intptr_t)p->value; /* void * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ + uarg[a++] = (intptr_t)p->value; /* void * __capability */ iarg[a++] = p->size; /* l_size_t */ *n_args = 4; break; @@ -68,8 +68,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 10: { struct linux_fgetxattr_args *p = params; iarg[a++] = p->fd; /* l_int */ - uarg[a++] = (intptr_t)p->name; /* const char * */ - uarg[a++] = (intptr_t)p->value; /* void * */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ + uarg[a++] = (intptr_t)p->value; /* void * __capability */ iarg[a++] = p->size; /* l_size_t */ *n_args = 4; break; @@ -77,8 +77,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_listxattr */ case 11: { struct linux_listxattr_args *p = params; - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->list; /* char * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->list; /* char * __capability */ iarg[a++] = p->size; /* l_size_t */ *n_args = 3; break; @@ -86,8 +86,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_llistxattr */ case 12: { struct linux_llistxattr_args *p = params; - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->list; /* char * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->list; /* char * __capability */ iarg[a++] = p->size; /* l_size_t */ *n_args = 3; break; @@ -96,7 +96,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 13: { struct linux_flistxattr_args *p = params; iarg[a++] = p->fd; /* l_int */ - uarg[a++] = (intptr_t)p->list; /* char * */ + uarg[a++] = (intptr_t)p->list; /* char * __capability */ iarg[a++] = p->size; /* l_size_t */ *n_args = 3; break; @@ -104,16 +104,16 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_removexattr */ case 14: { struct linux_removexattr_args *p = params; - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ *n_args = 2; break; } /* linux_lremovexattr */ case 15: { struct linux_lremovexattr_args *p = params; - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ *n_args = 2; break; } @@ -121,14 +121,14 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 16: { struct linux_fremovexattr_args *p = params; iarg[a++] = p->fd; /* l_int */ - uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ *n_args = 2; break; } /* linux_getcwd */ case 17: { struct linux_getcwd_args *p = params; - uarg[a++] = (intptr_t)p->buf; /* char * */ + uarg[a++] = (intptr_t)p->buf; /* char * __capability */ iarg[a++] = p->bufsize; /* l_ulong */ *n_args = 2; break; @@ -159,7 +159,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[a++] = p->epfd; /* l_int */ iarg[a++] = p->op; /* l_int */ iarg[a++] = p->fd; /* l_int */ - uarg[a++] = (intptr_t)p->event; /* struct epoll_event * */ + uarg[a++] = (intptr_t)p->event; /* struct epoll_event * __capability */ *n_args = 4; break; } @@ -167,10 +167,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 22: { struct linux_epoll_pwait_args *p = params; iarg[a++] = p->epfd; /* l_int */ - uarg[a++] = (intptr_t)p->events; /* struct epoll_event * */ + uarg[a++] = (intptr_t)p->events; /* struct epoll_event * __capability */ iarg[a++] = p->maxevents; /* l_int */ iarg[a++] = p->timeout; /* l_int */ - uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * */ + uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * __capability */ iarg[a++] = p->sigsetsize; /* l_size_t */ *n_args = 6; break; @@ -196,7 +196,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_fcntl_args *p = params; iarg[a++] = p->fd; /* l_uint */ iarg[a++] = p->cmd; /* l_uint */ - iarg[a++] = p->arg; /* l_ulong */ + uarg[a++] = (intptr_t)p->arg; /* l_uintcap_t */ *n_args = 3; break; } @@ -222,7 +222,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_ioctl_args *p = params; iarg[a++] = p->fd; /* l_uint */ iarg[a++] = p->cmd; /* l_uint */ - iarg[a++] = p->arg; /* l_ulong */ + uarg[a++] = (intptr_t)p->arg; /* l_uintcap_t */ *n_args = 3; break; } @@ -255,7 +255,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 33: { struct linux_mknodat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->filename; /* const char * */ + uarg[a++] = (intptr_t)p->filename; /* const char * __capability */ iarg[a++] = p->mode; /* l_int */ iarg[a++] = p->dev; /* l_dev_t */ *n_args = 4; @@ -265,7 +265,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 34: { struct linux_mkdirat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->pathname; /* const char * */ + uarg[a++] = (intptr_t)p->pathname; /* const char * __capability */ iarg[a++] = p->mode; /* l_mode_t */ *n_args = 3; break; @@ -274,7 +274,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 35: { struct linux_unlinkat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->pathname; /* const char * */ + uarg[a++] = (intptr_t)p->pathname; /* const char * __capability */ iarg[a++] = p->flag; /* l_int */ *n_args = 3; break; @@ -282,9 +282,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_symlinkat */ case 36: { struct linux_symlinkat_args *p = params; - uarg[a++] = (intptr_t)p->oldname; /* const char * */ + uarg[a++] = (intptr_t)p->oldname; /* const char * __capability */ iarg[a++] = p->newdfd; /* l_int */ - uarg[a++] = (intptr_t)p->newname; /* const char * */ + uarg[a++] = (intptr_t)p->newname; /* const char * __capability */ *n_args = 3; break; } @@ -292,9 +292,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 37: { struct linux_linkat_args *p = params; iarg[a++] = p->olddfd; /* l_int */ - uarg[a++] = (intptr_t)p->oldname; /* const char * */ + uarg[a++] = (intptr_t)p->oldname; /* const char * __capability */ iarg[a++] = p->newdfd; /* l_int */ - uarg[a++] = (intptr_t)p->newname; /* const char * */ + uarg[a++] = (intptr_t)p->newname; /* const char * __capability */ iarg[a++] = p->flag; /* l_int */ *n_args = 5; break; @@ -303,20 +303,20 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 38: { struct linux_renameat_args *p = params; iarg[a++] = p->olddfd; /* l_int */ - uarg[a++] = (intptr_t)p->oldname; /* const char * */ + uarg[a++] = (intptr_t)p->oldname; /* const char * __capability */ iarg[a++] = p->newdfd; /* l_int */ - uarg[a++] = (intptr_t)p->newname; /* const char * */ + uarg[a++] = (intptr_t)p->newname; /* const char * __capability */ *n_args = 4; break; } /* linux_mount */ case 40: { struct linux_mount_args *p = params; - uarg[a++] = (intptr_t)p->specialfile; /* char * */ - uarg[a++] = (intptr_t)p->dir; /* char * */ - uarg[a++] = (intptr_t)p->filesystemtype; /* char * */ + uarg[a++] = (intptr_t)p->specialfile; /* char * __capability */ + uarg[a++] = (intptr_t)p->dir; /* char * __capability */ + uarg[a++] = (intptr_t)p->filesystemtype; /* char * __capability */ iarg[a++] = p->rwflag; /* l_ulong */ - uarg[a++] = (intptr_t)p->data; /* void * */ + uarg[a++] = (intptr_t)p->data; /* void * __capability */ *n_args = 5; break; } @@ -328,8 +328,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_statfs */ case 43: { struct linux_statfs_args *p = params; - uarg[a++] = (intptr_t)p->path; /* char * */ - uarg[a++] = (intptr_t)p->buf; /* struct l_statfs_buf * */ + uarg[a++] = (intptr_t)p->path; /* char * __capability */ + uarg[a++] = (intptr_t)p->buf; /* struct l_statfs_buf * __capability */ *n_args = 2; break; } @@ -337,14 +337,14 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 44: { struct linux_fstatfs_args *p = params; iarg[a++] = p->fd; /* l_uint */ - uarg[a++] = (intptr_t)p->buf; /* struct l_statfs_buf * */ + uarg[a++] = (intptr_t)p->buf; /* struct l_statfs_buf * __capability */ *n_args = 2; break; } /* linux_truncate */ case 45: { struct linux_truncate_args *p = params; - uarg[a++] = (intptr_t)p->path; /* char * */ + uarg[a++] = (intptr_t)p->path; /* char * __capability */ iarg[a++] = p->length; /* l_ulong */ *n_args = 2; break; @@ -371,7 +371,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 48: { struct linux_faccessat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->filename; /* const char * */ + uarg[a++] = (intptr_t)p->filename; /* const char * __capability */ iarg[a++] = p->amode; /* l_int */ *n_args = 3; break; @@ -379,7 +379,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_chdir */ case 49: { struct linux_chdir_args *p = params; - uarg[a++] = (intptr_t)p->path; /* char * */ + uarg[a++] = (intptr_t)p->path; /* char * __capability */ *n_args = 1; break; } @@ -390,10 +390,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 1; break; } - /* chroot */ + /* linux_chroot */ case 51: { - struct chroot_args *p = params; - uarg[a++] = (intptr_t)p->path; /* char * */ + struct linux_chroot_args *p = params; + uarg[a++] = (intptr_t)p->path; /* char * __capability */ *n_args = 1; break; } @@ -409,7 +409,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 53: { struct linux_fchmodat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->filename; /* const char * */ + uarg[a++] = (intptr_t)p->filename; /* const char * __capability */ iarg[a++] = p->mode; /* l_mode_t */ *n_args = 3; break; @@ -418,7 +418,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 54: { struct linux_fchownat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->filename; /* const char * */ + uarg[a++] = (intptr_t)p->filename; /* const char * __capability */ iarg[a++] = p->uid; /* l_uid_t */ iarg[a++] = p->gid; /* l_gid_t */ iarg[a++] = p->flag; /* l_int */ @@ -438,7 +438,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 56: { struct linux_openat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->filename; /* const char * */ + uarg[a++] = (intptr_t)p->filename; /* const char * __capability */ iarg[a++] = p->flags; /* l_int */ iarg[a++] = p->mode; /* l_mode_t */ *n_args = 4; @@ -459,7 +459,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_pipe2 */ case 59: { struct linux_pipe2_args *p = params; - uarg[a++] = (intptr_t)p->pipefds; /* l_int * */ + uarg[a++] = (intptr_t)p->pipefds; /* l_int * __capability */ iarg[a++] = p->flags; /* l_int */ *n_args = 2; break; @@ -468,7 +468,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 61: { struct linux_getdents64_args *p = params; iarg[a++] = p->fd; /* l_uint */ - uarg[a++] = (intptr_t)p->dirent; /* void * */ + uarg[a++] = (intptr_t)p->dirent; /* void * __capability */ iarg[a++] = p->count; /* l_uint */ *n_args = 3; break; @@ -482,11 +482,11 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 3; break; } - /* read */ + /* linux_read */ case 63: { - struct read_args *p = params; + struct linux_read_args *p = params; iarg[a++] = p->fd; /* int */ - uarg[a++] = (intptr_t)p->buf; /* char * */ + uarg[a++] = (intptr_t)p->buf; /* char * __capability */ iarg[a++] = p->nbyte; /* l_size_t */ *n_args = 3; break; @@ -495,16 +495,16 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 64: { struct linux_write_args *p = params; iarg[a++] = p->fd; /* int */ - uarg[a++] = (intptr_t)p->buf; /* char * */ + uarg[a++] = (intptr_t)p->buf; /* char * __capability */ iarg[a++] = p->nbyte; /* l_size_t */ *n_args = 3; break; } - /* readv */ + /* linux_readv */ case 65: { - struct readv_args *p = params; + struct linux_readv_args *p = params; iarg[a++] = p->fd; /* int */ - uarg[a++] = (intptr_t)p->iovp; /* struct iovec * */ + uarg[a++] = (intptr_t)p->iovp; /* struct iovec * __capability */ uarg[a++] = p->iovcnt; /* u_int */ *n_args = 3; break; @@ -513,7 +513,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 66: { struct linux_writev_args *p = params; iarg[a++] = p->fd; /* int */ - uarg[a++] = (intptr_t)p->iovp; /* struct iovec * */ + uarg[a++] = (intptr_t)p->iovp; /* struct iovec * __capability */ uarg[a++] = p->iovcnt; /* u_int */ *n_args = 3; break; @@ -522,7 +522,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 67: { struct linux_pread_args *p = params; iarg[a++] = p->fd; /* l_uint */ - uarg[a++] = (intptr_t)p->buf; /* char * */ + uarg[a++] = (intptr_t)p->buf; /* char * __capability */ iarg[a++] = p->nbyte; /* l_size_t */ iarg[a++] = p->offset; /* l_loff_t */ *n_args = 4; @@ -532,7 +532,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 68: { struct linux_pwrite_args *p = params; iarg[a++] = p->fd; /* l_uint */ - uarg[a++] = (intptr_t)p->buf; /* char * */ + uarg[a++] = (intptr_t)p->buf; /* char * __capability */ iarg[a++] = p->nbyte; /* l_size_t */ iarg[a++] = p->offset; /* l_loff_t */ *n_args = 4; @@ -542,7 +542,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 69: { struct linux_preadv_args *p = params; iarg[a++] = p->fd; /* l_ulong */ - uarg[a++] = (intptr_t)p->vec; /* struct iovec * */ + uarg[a++] = (intptr_t)p->vec; /* struct iovec * __capability */ iarg[a++] = p->vlen; /* l_ulong */ iarg[a++] = p->pos_l; /* l_ulong */ iarg[a++] = p->pos_h; /* l_ulong */ @@ -553,7 +553,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 70: { struct linux_pwritev_args *p = params; iarg[a++] = p->fd; /* l_ulong */ - uarg[a++] = (intptr_t)p->vec; /* struct iovec * */ + uarg[a++] = (intptr_t)p->vec; /* struct iovec * __capability */ iarg[a++] = p->vlen; /* l_ulong */ iarg[a++] = p->pos_l; /* l_ulong */ iarg[a++] = p->pos_h; /* l_ulong */ @@ -565,7 +565,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_sendfile_args *p = params; iarg[a++] = p->out; /* l_int */ iarg[a++] = p->in; /* l_int */ - uarg[a++] = (intptr_t)p->offset; /* l_off_t * */ + uarg[a++] = (intptr_t)p->offset; /* l_off_t * __capability */ iarg[a++] = p->count; /* l_size_t */ *n_args = 4; break; @@ -574,21 +574,21 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 72: { struct linux_pselect6_args *p = params; iarg[a++] = p->nfds; /* l_int */ - uarg[a++] = (intptr_t)p->readfds; /* l_fd_set * */ - uarg[a++] = (intptr_t)p->writefds; /* l_fd_set * */ - uarg[a++] = (intptr_t)p->exceptfds; /* l_fd_set * */ - uarg[a++] = (intptr_t)p->tsp; /* struct l_timespec * */ - uarg[a++] = (intptr_t)p->sig; /* l_uintptr_t * */ + uarg[a++] = (intptr_t)p->readfds; /* l_fd_set * __capability */ + uarg[a++] = (intptr_t)p->writefds; /* l_fd_set * __capability */ + uarg[a++] = (intptr_t)p->exceptfds; /* l_fd_set * __capability */ + uarg[a++] = (intptr_t)p->tsp; /* struct l_timespec * __capability */ + uarg[a++] = (intptr_t)p->sig; /* l_uintcap_t * __capability */ *n_args = 6; break; } /* linux_ppoll */ case 73: { struct linux_ppoll_args *p = params; - uarg[a++] = (intptr_t)p->fds; /* struct pollfd * */ + uarg[a++] = (intptr_t)p->fds; /* struct pollfd * __capability */ iarg[a++] = p->nfds; /* l_uint */ - uarg[a++] = (intptr_t)p->tsp; /* struct l_timespec * */ - uarg[a++] = (intptr_t)p->sset; /* l_sigset_t * */ + uarg[a++] = (intptr_t)p->tsp; /* struct l_timespec * __capability */ + uarg[a++] = (intptr_t)p->sset; /* l_sigset_t * __capability */ iarg[a++] = p->ssize; /* l_size_t */ *n_args = 5; break; @@ -607,9 +607,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 76: { struct linux_splice_args *p = params; iarg[a++] = p->fd_in; /* int */ - uarg[a++] = (intptr_t)p->off_in; /* l_loff_t * */ + uarg[a++] = (intptr_t)p->off_in; /* l_loff_t * __capability */ iarg[a++] = p->fd_out; /* int */ - uarg[a++] = (intptr_t)p->off_out; /* l_loff_t * */ + uarg[a++] = (intptr_t)p->off_out; /* l_loff_t * __capability */ iarg[a++] = p->len; /* l_size_t */ iarg[a++] = p->flags; /* l_uint */ *n_args = 6; @@ -624,8 +624,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 78: { struct linux_readlinkat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->path; /* const char * */ - uarg[a++] = (intptr_t)p->buf; /* char * */ + uarg[a++] = (intptr_t)p->path; /* const char * __capability */ + uarg[a++] = (intptr_t)p->buf; /* char * __capability */ iarg[a++] = p->bufsiz; /* l_int */ *n_args = 4; break; @@ -634,8 +634,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 79: { struct linux_newfstatat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->pathname; /* char * */ - uarg[a++] = (intptr_t)p->statbuf; /* struct l_stat64 * */ + uarg[a++] = (intptr_t)p->pathname; /* char * __capability */ + uarg[a++] = (intptr_t)p->statbuf; /* struct l_newstat * __capability */ iarg[a++] = p->flag; /* l_int */ *n_args = 4; break; @@ -644,7 +644,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 80: { struct linux_newfstat_args *p = params; iarg[a++] = p->fd; /* l_uint */ - uarg[a++] = (intptr_t)p->buf; /* struct l_newstat * */ + uarg[a++] = (intptr_t)p->buf; /* struct l_newstat * __capability */ *n_args = 2; break; } @@ -685,8 +685,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_timerfd_settime_args *p = params; iarg[a++] = p->fd; /* l_int */ iarg[a++] = p->flags; /* l_int */ - uarg[a++] = (intptr_t)p->new_value; /* const struct l_itimerspec * */ - uarg[a++] = (intptr_t)p->old_value; /* struct l_itimerspec * */ + uarg[a++] = (intptr_t)p->new_value; /* const struct l_itimerspec * __capability */ + uarg[a++] = (intptr_t)p->old_value; /* struct l_itimerspec * __capability */ *n_args = 4; break; } @@ -694,7 +694,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 87: { struct linux_timerfd_gettime_args *p = params; iarg[a++] = p->fd; /* l_int */ - uarg[a++] = (intptr_t)p->old_value; /* struct l_itimerspec * */ + uarg[a++] = (intptr_t)p->old_value; /* struct l_itimerspec * __capability */ *n_args = 2; break; } @@ -702,32 +702,32 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 88: { struct linux_utimensat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->pathname; /* const char * */ - uarg[a++] = (intptr_t)p->times; /* const struct l_timespec * */ + uarg[a++] = (intptr_t)p->pathname; /* const char * __capability */ + uarg[a++] = (intptr_t)p->times; /* const struct l_timespec * __capability */ iarg[a++] = p->flags; /* l_int */ *n_args = 4; break; } - /* acct */ + /* linux_acct */ case 89: { - struct acct_args *p = params; - uarg[a++] = (intptr_t)p->path; /* char * */ + struct linux_acct_args *p = params; + uarg[a++] = (intptr_t)p->path; /* char * __capability */ *n_args = 1; break; } /* linux_capget */ case 90: { struct linux_capget_args *p = params; - uarg[a++] = (intptr_t)p->hdrp; /* struct l_user_cap_header * */ - uarg[a++] = (intptr_t)p->datap; /* struct l_user_cap_data * */ + uarg[a++] = (intptr_t)p->hdrp; /* struct l_user_cap_header * __capability */ + uarg[a++] = (intptr_t)p->datap; /* struct l_user_cap_data * __capability */ *n_args = 2; break; } /* linux_capset */ case 91: { struct linux_capset_args *p = params; - uarg[a++] = (intptr_t)p->hdrp; /* struct l_user_cap_header * */ - uarg[a++] = (intptr_t)p->datap; /* struct l_user_cap_data * */ + uarg[a++] = (intptr_t)p->hdrp; /* struct l_user_cap_header * __capability */ + uarg[a++] = (intptr_t)p->datap; /* struct l_user_cap_data * __capability */ *n_args = 2; break; } @@ -757,16 +757,16 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_waitid_args *p = params; iarg[a++] = p->idtype; /* l_int */ iarg[a++] = p->id; /* l_pid_t */ - uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * */ + uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * __capability */ iarg[a++] = p->options; /* l_int */ - uarg[a++] = (intptr_t)p->rusage; /* struct rusage * */ + uarg[a++] = (intptr_t)p->rusage; /* struct rusage * __capability */ *n_args = 5; break; } /* linux_set_tid_address */ case 96: { struct linux_set_tid_address_args *p = params; - uarg[a++] = (intptr_t)p->tidptr; /* l_int * */ + uarg[a++] = (intptr_t)p->tidptr; /* l_int * __capability */ *n_args = 1; break; } @@ -778,11 +778,11 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_sys_futex */ case 98: { struct linux_sys_futex_args *p = params; - uarg[a++] = (intptr_t)p->uaddr; /* uint32_t * */ + uarg[a++] = (intptr_t)p->uaddr; /* uint32_t * __capability */ iarg[a++] = p->op; /* l_int */ uarg[a++] = p->val; /* uint32_t */ - uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ - uarg[a++] = (intptr_t)p->uaddr2; /* uint32_t * */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * __capability */ + uarg[a++] = (intptr_t)p->uaddr2; /* uint32_t * __capability */ uarg[a++] = p->val3; /* uint32_t */ *n_args = 6; break; @@ -790,7 +790,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_set_robust_list */ case 99: { struct linux_set_robust_list_args *p = params; - uarg[a++] = (intptr_t)p->head; /* struct linux_robust_list_head * */ + uarg[a++] = (intptr_t)p->head; /* struct linux_robust_list_head * __capability */ iarg[a++] = p->len; /* l_size_t */ *n_args = 2; break; @@ -799,16 +799,16 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 100: { struct linux_get_robust_list_args *p = params; iarg[a++] = p->pid; /* l_int */ - uarg[a++] = (intptr_t)p->head; /* struct linux_robust_list_head ** */ - uarg[a++] = (intptr_t)p->len; /* l_size_t * */ + uarg[a++] = (intptr_t)p->head; /* struct linux_robust_list_head * __capability * __capability */ + uarg[a++] = (intptr_t)p->len; /* l_size_t * __capability */ *n_args = 3; break; } /* linux_nanosleep */ case 101: { struct linux_nanosleep_args *p = params; - uarg[a++] = (intptr_t)p->rqtp; /* const struct l_timespec * */ - uarg[a++] = (intptr_t)p->rmtp; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->rqtp; /* const struct l_timespec * __capability */ + uarg[a++] = (intptr_t)p->rmtp; /* struct l_timespec * __capability */ *n_args = 2; break; } @@ -816,7 +816,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 102: { struct linux_getitimer_args *p = params; iarg[a++] = p->which; /* l_int */ - uarg[a++] = (intptr_t)p->itv; /* struct l_itimerval * */ + uarg[a++] = (intptr_t)p->itv; /* struct l_itimerval * __capability */ *n_args = 2; break; } @@ -824,8 +824,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 103: { struct linux_setitimer_args *p = params; iarg[a++] = p->which; /* l_int */ - uarg[a++] = (intptr_t)p->itv; /* struct l_itimerval * */ - uarg[a++] = (intptr_t)p->oitv; /* struct l_itimerval * */ + uarg[a++] = (intptr_t)p->itv; /* struct l_itimerval * __capability */ + uarg[a++] = (intptr_t)p->oitv; /* struct l_itimerval * __capability */ *n_args = 3; break; } @@ -848,8 +848,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 107: { struct linux_timer_create_args *p = params; iarg[a++] = p->clock_id; /* clockid_t */ - uarg[a++] = (intptr_t)p->evp; /* struct l_sigevent * */ - uarg[a++] = (intptr_t)p->timerid; /* l_timer_t * */ + uarg[a++] = (intptr_t)p->evp; /* struct l_sigevent * __capability */ + uarg[a++] = (intptr_t)p->timerid; /* l_timer_t * __capability */ *n_args = 3; break; } @@ -857,7 +857,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 108: { struct linux_timer_gettime_args *p = params; iarg[a++] = p->timerid; /* l_timer_t */ - uarg[a++] = (intptr_t)p->setting; /* struct itimerspec * */ + uarg[a++] = (intptr_t)p->setting; /* struct itimerspec * __capability */ *n_args = 2; break; } @@ -873,8 +873,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_timer_settime_args *p = params; iarg[a++] = p->timerid; /* l_timer_t */ iarg[a++] = p->flags; /* l_int */ - uarg[a++] = (intptr_t)p->new; /* const struct itimerspec * */ - uarg[a++] = (intptr_t)p->old; /* struct itimerspec * */ + uarg[a++] = (intptr_t)p->new; /* const struct itimerspec * __capability */ + uarg[a++] = (intptr_t)p->old; /* struct itimerspec * __capability */ *n_args = 4; break; } @@ -889,7 +889,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 112: { struct linux_clock_settime_args *p = params; iarg[a++] = p->which; /* clockid_t */ - uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * __capability */ *n_args = 2; break; } @@ -897,7 +897,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 113: { struct linux_clock_gettime_args *p = params; iarg[a++] = p->which; /* clockid_t */ - uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * __capability */ *n_args = 2; break; } @@ -905,7 +905,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 114: { struct linux_clock_getres_args *p = params; iarg[a++] = p->which; /* clockid_t */ - uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * __capability */ *n_args = 2; break; } @@ -914,8 +914,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_clock_nanosleep_args *p = params; iarg[a++] = p->which; /* clockid_t */ iarg[a++] = p->flags; /* l_int */ - uarg[a++] = (intptr_t)p->rqtp; /* struct l_timespec * */ - uarg[a++] = (intptr_t)p->rmtp; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->rqtp; /* struct l_timespec * __capability */ + uarg[a++] = (intptr_t)p->rmtp; /* struct l_timespec * __capability */ *n_args = 4; break; } @@ -923,7 +923,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 116: { struct linux_syslog_args *p = params; iarg[a++] = p->type; /* l_int */ - uarg[a++] = (intptr_t)p->buf; /* char * */ + uarg[a++] = (intptr_t)p->buf; /* char * __capability */ iarg[a++] = p->len; /* l_int */ *n_args = 3; break; @@ -933,8 +933,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_ptrace_args *p = params; iarg[a++] = p->req; /* l_long */ iarg[a++] = p->pid; /* l_long */ - iarg[a++] = p->addr; /* l_ulong */ - iarg[a++] = p->data; /* l_ulong */ + uarg[a++] = (intptr_t)p->addr; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->data; /* l_uintcap_t */ *n_args = 4; break; } @@ -942,7 +942,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 118: { struct linux_sched_setparam_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ - uarg[a++] = (intptr_t)p->param; /* struct sched_param * */ + uarg[a++] = (intptr_t)p->param; /* struct sched_param * __capability */ *n_args = 2; break; } @@ -951,7 +951,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_sched_setscheduler_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ iarg[a++] = p->policy; /* l_int */ - uarg[a++] = (intptr_t)p->param; /* struct sched_param * */ + uarg[a++] = (intptr_t)p->param; /* struct sched_param * __capability */ *n_args = 3; break; } @@ -966,7 +966,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 121: { struct linux_sched_getparam_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ - uarg[a++] = (intptr_t)p->param; /* struct sched_param * */ + uarg[a++] = (intptr_t)p->param; /* struct sched_param * __capability */ *n_args = 2; break; } @@ -975,7 +975,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_sched_setaffinity_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ iarg[a++] = p->len; /* l_uint */ - uarg[a++] = (intptr_t)p->user_mask_ptr; /* l_ulong * */ + uarg[a++] = (intptr_t)p->user_mask_ptr; /* l_ulong * __capability */ *n_args = 3; break; } @@ -984,7 +984,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_sched_getaffinity_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ iarg[a++] = p->len; /* l_uint */ - uarg[a++] = (intptr_t)p->user_mask_ptr; /* l_ulong * */ + uarg[a++] = (intptr_t)p->user_mask_ptr; /* l_ulong * __capability */ *n_args = 3; break; } @@ -1011,7 +1011,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 127: { struct linux_sched_rr_get_interval_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ - uarg[a++] = (intptr_t)p->interval; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->interval; /* struct l_timespec * __capability */ *n_args = 2; break; } @@ -1043,15 +1043,15 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_sigaltstack */ case 132: { struct linux_sigaltstack_args *p = params; - uarg[a++] = (intptr_t)p->uss; /* l_stack_t * */ - uarg[a++] = (intptr_t)p->uoss; /* l_stack_t * */ + uarg[a++] = (intptr_t)p->uss; /* l_stack_t * __capability */ + uarg[a++] = (intptr_t)p->uoss; /* l_stack_t * __capability */ *n_args = 2; break; } /* linux_rt_sigsuspend */ case 133: { struct linux_rt_sigsuspend_args *p = params; - uarg[a++] = (intptr_t)p->newset; /* l_sigset_t * */ + uarg[a++] = (intptr_t)p->newset; /* l_sigset_t * __capability */ iarg[a++] = p->sigsetsize; /* l_size_t */ *n_args = 2; break; @@ -1060,8 +1060,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 134: { struct linux_rt_sigaction_args *p = params; iarg[a++] = p->sig; /* l_int */ - uarg[a++] = (intptr_t)p->act; /* l_sigaction_t * */ - uarg[a++] = (intptr_t)p->oact; /* l_sigaction_t * */ + uarg[a++] = (intptr_t)p->act; /* l_sigaction_t * __capability */ + uarg[a++] = (intptr_t)p->oact; /* l_sigaction_t * __capability */ iarg[a++] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; @@ -1070,8 +1070,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 135: { struct linux_rt_sigprocmask_args *p = params; iarg[a++] = p->how; /* l_int */ - uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * */ - uarg[a++] = (intptr_t)p->omask; /* l_sigset_t * */ + uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * __capability */ + uarg[a++] = (intptr_t)p->omask; /* l_sigset_t * __capability */ iarg[a++] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; @@ -1079,7 +1079,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_rt_sigpending */ case 136: { struct linux_rt_sigpending_args *p = params; - uarg[a++] = (intptr_t)p->set; /* l_sigset_t * */ + uarg[a++] = (intptr_t)p->set; /* l_sigset_t * __capability */ iarg[a++] = p->sigsetsize; /* l_size_t */ *n_args = 2; break; @@ -1087,9 +1087,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_rt_sigtimedwait */ case 137: { struct linux_rt_sigtimedwait_args *p = params; - uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * */ - uarg[a++] = (intptr_t)p->ptr; /* l_siginfo_t * */ - uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * __capability */ + uarg[a++] = (intptr_t)p->ptr; /* l_siginfo_t * __capability */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * __capability */ iarg[a++] = p->sigsetsize; /* l_size_t */ *n_args = 4; break; @@ -1099,7 +1099,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_rt_sigqueueinfo_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ iarg[a++] = p->sig; /* l_int */ - uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * */ + uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * __capability */ *n_args = 3; break; } @@ -1131,7 +1131,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[a++] = p->magic1; /* l_int */ iarg[a++] = p->magic2; /* l_int */ iarg[a++] = p->cmd; /* l_uint */ - uarg[a++] = (intptr_t)p->arg; /* void * */ + uarg[a++] = (intptr_t)p->arg; /* void * __capability */ *n_args = 4; break; } @@ -1174,12 +1174,12 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 3; break; } - /* getresuid */ + /* linux_getresuid */ case 148: { - struct getresuid_args *p = params; - uarg[a++] = (intptr_t)p->ruid; /* uid_t * */ - uarg[a++] = (intptr_t)p->euid; /* uid_t * */ - uarg[a++] = (intptr_t)p->suid; /* uid_t * */ + struct linux_getresuid_args *p = params; + uarg[a++] = (intptr_t)p->ruid; /* l_uid_t * __capability */ + uarg[a++] = (intptr_t)p->euid; /* l_uid_t * __capability */ + uarg[a++] = (intptr_t)p->suid; /* l_uid_t * __capability */ *n_args = 3; break; } @@ -1192,12 +1192,12 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 3; break; } - /* getresgid */ + /* linux_getresgid */ case 150: { - struct getresgid_args *p = params; - uarg[a++] = (intptr_t)p->rgid; /* gid_t * */ - uarg[a++] = (intptr_t)p->egid; /* gid_t * */ - uarg[a++] = (intptr_t)p->sgid; /* gid_t * */ + struct linux_getresgid_args *p = params; + uarg[a++] = (intptr_t)p->rgid; /* l_gid_t * __capability */ + uarg[a++] = (intptr_t)p->egid; /* l_gid_t * __capability */ + uarg[a++] = (intptr_t)p->sgid; /* l_gid_t * __capability */ *n_args = 3; break; } @@ -1218,7 +1218,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_times */ case 153: { struct linux_times_args *p = params; - uarg[a++] = (intptr_t)p->buf; /* struct l_times_argv * */ + uarg[a++] = (intptr_t)p->buf; /* struct l_times_argv * __capability */ *n_args = 1; break; } @@ -1253,7 +1253,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 158: { struct linux_getgroups_args *p = params; iarg[a++] = p->gidsetsize; /* l_int */ - uarg[a++] = (intptr_t)p->grouplist; /* l_gid_t * */ + uarg[a++] = (intptr_t)p->grouplist; /* l_gid_t * __capability */ *n_args = 2; break; } @@ -1261,21 +1261,21 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 159: { struct linux_setgroups_args *p = params; iarg[a++] = p->gidsetsize; /* l_int */ - uarg[a++] = (intptr_t)p->grouplist; /* l_gid_t * */ + uarg[a++] = (intptr_t)p->grouplist; /* l_gid_t * __capability */ *n_args = 2; break; } /* linux_newuname */ case 160: { struct linux_newuname_args *p = params; - uarg[a++] = (intptr_t)p->buf; /* struct l_new_utsname * */ + uarg[a++] = (intptr_t)p->buf; /* struct l_new_utsname * __capability */ *n_args = 1; break; } /* linux_sethostname */ case 161: { struct linux_sethostname_args *p = params; - uarg[a++] = (intptr_t)p->hostname; /* char * */ + uarg[a++] = (intptr_t)p->hostname; /* char * __capability */ iarg[a++] = p->len; /* l_uint */ *n_args = 2; break; @@ -1283,7 +1283,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_setdomainname */ case 162: { struct linux_setdomainname_args *p = params; - uarg[a++] = (intptr_t)p->name; /* char * */ + uarg[a++] = (intptr_t)p->name; /* char * __capability */ iarg[a++] = p->len; /* l_int */ *n_args = 2; break; @@ -1292,7 +1292,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 163: { struct linux_getrlimit_args *p = params; iarg[a++] = p->resource; /* l_uint */ - uarg[a++] = (intptr_t)p->rlim; /* struct l_rlimit * */ + uarg[a++] = (intptr_t)p->rlim; /* struct l_rlimit * __capability */ *n_args = 2; break; } @@ -1300,15 +1300,15 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 164: { struct linux_setrlimit_args *p = params; iarg[a++] = p->resource; /* l_uint */ - uarg[a++] = (intptr_t)p->rlim; /* struct l_rlimit * */ + uarg[a++] = (intptr_t)p->rlim; /* struct l_rlimit * __capability */ *n_args = 2; break; } - /* getrusage */ + /* linux_getrusage */ case 165: { - struct getrusage_args *p = params; - iarg[a++] = p->who; /* int */ - uarg[a++] = (intptr_t)p->rusage; /* struct rusage * */ + struct linux_getrusage_args *p = params; + iarg[a++] = p->who; /* l_int */ + uarg[a++] = (intptr_t)p->rusage; /* struct rusage * __capability */ *n_args = 2; break; } @@ -1323,35 +1323,35 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 167: { struct linux_prctl_args *p = params; iarg[a++] = p->option; /* l_int */ - uarg[a++] = (intptr_t)p->arg2; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->arg3; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->arg4; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->arg5; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->arg2; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->arg3; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->arg4; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->arg5; /* l_uintcap_t */ *n_args = 5; break; } /* linux_getcpu */ case 168: { struct linux_getcpu_args *p = params; - uarg[a++] = (intptr_t)p->cpu; /* l_uint * */ - uarg[a++] = (intptr_t)p->node; /* l_uint * */ - uarg[a++] = (intptr_t)p->cache; /* void * */ + uarg[a++] = (intptr_t)p->cpu; /* l_uint * __capability */ + uarg[a++] = (intptr_t)p->node; /* l_uint * __capability */ + uarg[a++] = (intptr_t)p->cache; /* void * __capability */ *n_args = 3; break; } - /* gettimeofday */ + /* linux_gettimeofday */ case 169: { - struct gettimeofday_args *p = params; - uarg[a++] = (intptr_t)p->tp; /* struct l_timeval * */ - uarg[a++] = (intptr_t)p->tzp; /* struct timezone * */ + struct linux_gettimeofday_args *p = params; + uarg[a++] = (intptr_t)p->tp; /* l_timeval * __capability */ + uarg[a++] = (intptr_t)p->tzp; /* struct timezone * __capability */ *n_args = 2; break; } - /* settimeofday */ + /* linux_settimeofday */ case 170: { - struct settimeofday_args *p = params; - uarg[a++] = (intptr_t)p->tv; /* struct l_timeval * */ - uarg[a++] = (intptr_t)p->tzp; /* struct timezone * */ + struct linux_settimeofday_args *p = params; + uarg[a++] = (intptr_t)p->tv; /* l_timeval * __capability */ + uarg[a++] = (intptr_t)p->tzp; /* struct timezone * __capability */ *n_args = 2; break; } @@ -1398,24 +1398,24 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_sysinfo */ case 179: { struct linux_sysinfo_args *p = params; - uarg[a++] = (intptr_t)p->info; /* struct l_sysinfo * */ + uarg[a++] = (intptr_t)p->info; /* struct l_sysinfo * __capability */ *n_args = 1; break; } /* linux_mq_open */ case 180: { struct linux_mq_open_args *p = params; - uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ iarg[a++] = p->oflag; /* l_int */ iarg[a++] = p->mode; /* l_mode_t */ - uarg[a++] = (intptr_t)p->attr; /* struct mq_attr * */ + uarg[a++] = (intptr_t)p->attr; /* struct mq_attr * __capability */ *n_args = 4; break; } /* linux_mq_unlink */ case 181: { struct linux_mq_unlink_args *p = params; - uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ *n_args = 1; break; } @@ -1423,10 +1423,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 182: { struct linux_mq_timedsend_args *p = params; iarg[a++] = p->mqd; /* l_mqd_t */ - uarg[a++] = (intptr_t)p->msg_ptr; /* const char * */ + uarg[a++] = (intptr_t)p->msg_ptr; /* const char * __capability */ iarg[a++] = p->msg_len; /* l_size_t */ iarg[a++] = p->msg_prio; /* l_uint */ - uarg[a++] = (intptr_t)p->abs_timeout; /* const struct l_timespec * */ + uarg[a++] = (intptr_t)p->abs_timeout; /* const struct l_timespec * __capability */ *n_args = 5; break; } @@ -1434,10 +1434,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 183: { struct linux_mq_timedreceive_args *p = params; iarg[a++] = p->mqd; /* l_mqd_t */ - uarg[a++] = (intptr_t)p->msg_ptr; /* char * */ + uarg[a++] = (intptr_t)p->msg_ptr; /* char * __capability */ iarg[a++] = p->msg_len; /* l_size_t */ - uarg[a++] = (intptr_t)p->msg_prio; /* l_uint * */ - uarg[a++] = (intptr_t)p->abs_timeout; /* const struct l_timespec * */ + uarg[a++] = (intptr_t)p->msg_prio; /* l_uint * __capability */ + uarg[a++] = (intptr_t)p->abs_timeout; /* const struct l_timespec * __capability */ *n_args = 5; break; } @@ -1445,7 +1445,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 184: { struct linux_mq_notify_args *p = params; iarg[a++] = p->mqd; /* l_mqd_t */ - uarg[a++] = (intptr_t)p->sevp; /* const struct l_sigevent * */ + uarg[a++] = (intptr_t)p->sevp; /* const struct l_sigevent * __capability */ *n_args = 2; break; } @@ -1453,8 +1453,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 185: { struct linux_mq_getsetattr_args *p = params; iarg[a++] = p->mqd; /* l_mqd_t */ - uarg[a++] = (intptr_t)p->attr; /* const struct mq_attr * */ - uarg[a++] = (intptr_t)p->oattr; /* struct mq_attr * */ + uarg[a++] = (intptr_t)p->attr; /* const struct mq_attr * __capability */ + uarg[a++] = (intptr_t)p->oattr; /* struct mq_attr * __capability */ *n_args = 3; break; } @@ -1471,7 +1471,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_msgctl_args *p = params; iarg[a++] = p->msqid; /* l_int */ iarg[a++] = p->cmd; /* l_int */ - uarg[a++] = (intptr_t)p->buf; /* struct l_msqid_ds * */ + uarg[a++] = (intptr_t)p->buf; /* struct l_msqid_ds * __capability */ *n_args = 3; break; } @@ -1479,7 +1479,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 188: { struct linux_msgrcv_args *p = params; iarg[a++] = p->msqid; /* l_int */ - uarg[a++] = (intptr_t)p->msgp; /* struct l_msgbuf * */ + uarg[a++] = (intptr_t)p->msgp; /* struct l_msgbuf * __capability */ iarg[a++] = p->msgsz; /* l_size_t */ iarg[a++] = p->msgtyp; /* l_long */ iarg[a++] = p->msgflg; /* l_int */ @@ -1490,7 +1490,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 189: { struct linux_msgsnd_args *p = params; iarg[a++] = p->msqid; /* l_int */ - uarg[a++] = (intptr_t)p->msgp; /* struct l_msgbuf * */ + uarg[a++] = (intptr_t)p->msgp; /* struct l_msgbuf * __capability */ iarg[a++] = p->msgsz; /* l_size_t */ iarg[a++] = p->msgflg; /* l_int */ *n_args = 4; @@ -1519,17 +1519,17 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 192: { struct linux_semtimedop_args *p = params; iarg[a++] = p->semid; /* l_int */ - uarg[a++] = (intptr_t)p->tsops; /* struct sembuf * */ + uarg[a++] = (intptr_t)p->tsops; /* struct sembuf * __capability */ iarg[a++] = p->nsops; /* l_size_t */ - uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * __capability */ *n_args = 4; break; } - /* semop */ + /* linux_semop */ case 193: { - struct semop_args *p = params; + struct linux_semop_args *p = params; iarg[a++] = p->semid; /* l_int */ - uarg[a++] = (intptr_t)p->sops; /* struct sembuf * */ + uarg[a++] = (intptr_t)p->sops; /* struct sembuf * __capability */ iarg[a++] = p->nsops; /* l_size_t */ *n_args = 3; break; @@ -1548,7 +1548,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_shmctl_args *p = params; iarg[a++] = p->shmid; /* l_int */ iarg[a++] = p->cmd; /* l_int */ - uarg[a++] = (intptr_t)p->buf; /* struct l_shmid_ds * */ + uarg[a++] = (intptr_t)p->buf; /* struct l_shmid_ds * __capability */ *n_args = 3; break; } @@ -1556,7 +1556,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 196: { struct linux_shmat_args *p = params; iarg[a++] = p->shmid; /* l_int */ - uarg[a++] = (intptr_t)p->shmaddr; /* char * */ + uarg[a++] = (intptr_t)p->shmaddr; /* char * __capability */ iarg[a++] = p->shmflg; /* l_int */ *n_args = 3; break; @@ -1564,7 +1564,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_shmdt */ case 197: { struct linux_shmdt_args *p = params; - uarg[a++] = (intptr_t)p->shmaddr; /* char * */ + uarg[a++] = (intptr_t)p->shmaddr; /* char * __capability */ *n_args = 1; break; } @@ -1583,7 +1583,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[a++] = p->domain; /* l_int */ iarg[a++] = p->type; /* l_int */ iarg[a++] = p->protocol; /* l_int */ - uarg[a++] = (intptr_t)p->rsv; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->rsv; /* l_uintcap_t */ *n_args = 4; break; } @@ -1591,7 +1591,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 200: { struct linux_bind_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->name; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->name; /* l_uintcap_t */ iarg[a++] = p->namelen; /* l_int */ *n_args = 3; break; @@ -1608,8 +1608,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 202: { struct linux_accept_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->namelen; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->addr; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->namelen; /* l_uintcap_t */ *n_args = 3; break; } @@ -1617,7 +1617,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 203: { struct linux_connect_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->name; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->name; /* l_uintcap_t */ iarg[a++] = p->namelen; /* l_int */ *n_args = 3; break; @@ -1626,8 +1626,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 204: { struct linux_getsockname_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->namelen; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->addr; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->namelen; /* l_uintcap_t */ *n_args = 3; break; } @@ -1635,8 +1635,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 205: { struct linux_getpeername_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->namelen; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->addr; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->namelen; /* l_uintcap_t */ *n_args = 3; break; } @@ -1644,10 +1644,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 206: { struct linux_sendto_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->msg; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->msg; /* l_uintcap_t */ iarg[a++] = p->len; /* l_size_t */ iarg[a++] = p->flags; /* l_uint */ - uarg[a++] = (intptr_t)p->to; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->to; /* l_uintcap_t */ iarg[a++] = p->tolen; /* l_int */ *n_args = 6; break; @@ -1656,11 +1656,11 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 207: { struct linux_recvfrom_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->buf; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->buf; /* l_uintcap_t */ iarg[a++] = p->len; /* l_size_t */ iarg[a++] = p->flags; /* l_uint */ - uarg[a++] = (intptr_t)p->from; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->fromlen; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->from; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->fromlen; /* l_uintcap_t */ *n_args = 6; break; } @@ -1670,7 +1670,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[a++] = p->s; /* l_int */ iarg[a++] = p->level; /* l_int */ iarg[a++] = p->optname; /* l_int */ - uarg[a++] = (intptr_t)p->optval; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->optval; /* l_uintcap_t */ iarg[a++] = p->optlen; /* l_int */ *n_args = 5; break; @@ -1681,8 +1681,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[a++] = p->s; /* l_int */ iarg[a++] = p->level; /* l_int */ iarg[a++] = p->optname; /* l_int */ - uarg[a++] = (intptr_t)p->optval; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->optlen; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->optval; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->optlen; /* l_uintcap_t */ *n_args = 5; break; } @@ -1698,7 +1698,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 211: { struct linux_sendmsg_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->msg; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->msg; /* l_uintcap_t */ iarg[a++] = p->flags; /* l_uint */ *n_args = 3; break; @@ -1707,7 +1707,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 212: { struct linux_recvmsg_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->msg; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->msg; /* l_uintcap_t */ iarg[a++] = p->flags; /* l_uint */ *n_args = 3; break; @@ -1719,10 +1719,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 1; break; } - /* munmap */ + /* linux_munmap */ case 215: { - struct munmap_args *p = params; - uarg[a++] = (intptr_t)p->addr; /* void * */ + struct linux_munmap_args *p = params; + uarg[a++] = (intptr_t)p->addr; /* void * __capability */ iarg[a++] = p->len; /* l_size_t */ *n_args = 2; break; @@ -1730,11 +1730,11 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_mremap */ case 216: { struct linux_mremap_args *p = params; - iarg[a++] = p->addr; /* l_ulong */ + uarg[a++] = (intptr_t)p->addr; /* void * __capability */ iarg[a++] = p->old_len; /* l_ulong */ iarg[a++] = p->new_len; /* l_ulong */ iarg[a++] = p->flags; /* l_ulong */ - iarg[a++] = p->new_addr; /* l_ulong */ + uarg[a++] = (intptr_t)p->new_addr; /* void * __capability */ *n_args = 5; break; } @@ -1757,26 +1757,26 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 220: { struct linux_clone_args *p = params; iarg[a++] = p->flags; /* l_ulong */ - iarg[a++] = p->stack; /* l_ulong */ - uarg[a++] = (intptr_t)p->parent_tidptr; /* l_int * */ - iarg[a++] = p->tls; /* l_ulong */ - uarg[a++] = (intptr_t)p->child_tidptr; /* l_int * */ + uarg[a++] = (intptr_t)p->stack; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->parent_tidptr; /* l_int * __capability */ + uarg[a++] = (intptr_t)p->tls; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->child_tidptr; /* l_int * __capability */ *n_args = 5; break; } /* linux_execve */ case 221: { struct linux_execve_args *p = params; - uarg[a++] = (intptr_t)p->path; /* char * */ - uarg[a++] = (intptr_t)p->argp; /* l_uintptr_t * */ - uarg[a++] = (intptr_t)p->envp; /* l_uintptr_t * */ + uarg[a++] = (intptr_t)p->path; /* char * __capability */ + uarg[a++] = (intptr_t)p->argp; /* l_uintcap_t * __capability */ + uarg[a++] = (intptr_t)p->envp; /* l_uintcap_t * __capability */ *n_args = 3; break; } /* linux_mmap2 */ case 222: { struct linux_mmap2_args *p = params; - iarg[a++] = p->addr; /* l_ulong */ + uarg[a++] = (intptr_t)p->addr; /* void * __capability */ iarg[a++] = p->len; /* l_ulong */ iarg[a++] = p->prot; /* l_ulong */ iarg[a++] = p->flags; /* l_ulong */ @@ -1795,10 +1795,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 4; break; } - /* swapon */ + /* linux_swapon */ case 224: { - struct swapon_args *p = params; - uarg[a++] = (intptr_t)p->name; /* char * */ + struct linux_swapon_args *p = params; + uarg[a++] = (intptr_t)p->name; /* char * __capability */ *n_args = 1; break; } @@ -1810,7 +1810,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_mprotect */ case 226: { struct linux_mprotect_args *p = params; - iarg[a++] = p->addr; /* l_ulong */ + uarg[a++] = (intptr_t)p->addr; /* void * __capability */ iarg[a++] = p->len; /* l_size_t */ iarg[a++] = p->prot; /* l_ulong */ *n_args = 3; @@ -1819,25 +1819,25 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_msync */ case 227: { struct linux_msync_args *p = params; - iarg[a++] = p->addr; /* l_ulong */ + uarg[a++] = (intptr_t)p->addr; /* void * __capability */ iarg[a++] = p->len; /* l_size_t */ iarg[a++] = p->fl; /* l_int */ *n_args = 3; break; } - /* mlock */ + /* linux_mlock */ case 228: { - struct mlock_args *p = params; - uarg[a++] = (intptr_t)p->addr; /* const void * */ - uarg[a++] = p->len; /* size_t */ + struct linux_mlock_args *p = params; + uarg[a++] = (intptr_t)p->addr; /* const void * __capability */ + iarg[a++] = p->len; /* l_size_t */ *n_args = 2; break; } - /* munlock */ + /* linux_munlock */ case 229: { - struct munlock_args *p = params; - uarg[a++] = (intptr_t)p->addr; /* const void * */ - uarg[a++] = p->len; /* size_t */ + struct linux_munlock_args *p = params; + uarg[a++] = (intptr_t)p->addr; /* const void * __capability */ + iarg[a++] = p->len; /* l_size_t */ *n_args = 2; break; } @@ -1856,16 +1856,16 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_mincore */ case 232: { struct linux_mincore_args *p = params; - iarg[a++] = p->start; /* l_ulong */ + uarg[a++] = (intptr_t)p->start; /* void * __capability */ iarg[a++] = p->len; /* l_size_t */ - uarg[a++] = (intptr_t)p->vec; /* u_char * */ + uarg[a++] = (intptr_t)p->vec; /* u_char * __capability */ *n_args = 3; break; } /* linux_madvise */ case 233: { struct linux_madvise_args *p = params; - iarg[a++] = p->addr; /* l_ulong */ + uarg[a++] = (intptr_t)p->addr; /* void * __capability */ iarg[a++] = p->len; /* l_size_t */ iarg[a++] = p->behav; /* l_int */ *n_args = 3; @@ -1907,7 +1907,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) iarg[a++] = p->tgid; /* l_pid_t */ iarg[a++] = p->tid; /* l_pid_t */ iarg[a++] = p->sig; /* l_int */ - uarg[a++] = (intptr_t)p->uinfo; /* l_siginfo_t * */ + uarg[a++] = (intptr_t)p->uinfo; /* l_siginfo_t * __capability */ *n_args = 4; break; } @@ -1920,8 +1920,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 242: { struct linux_accept4_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ - uarg[a++] = (intptr_t)p->namelen; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->addr; /* l_uintcap_t */ + uarg[a++] = (intptr_t)p->namelen; /* l_uintcap_t */ iarg[a++] = p->flags; /* l_int */ *n_args = 4; break; @@ -1930,10 +1930,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 243: { struct linux_recvmmsg_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->msg; /* struct l_mmsghdr * */ + uarg[a++] = (intptr_t)p->msg; /* struct l_mmsghdr * __capability */ iarg[a++] = p->vlen; /* l_uint */ iarg[a++] = p->flags; /* l_uint */ - uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * __capability */ *n_args = 5; break; } @@ -1941,9 +1941,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 260: { struct linux_wait4_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ - uarg[a++] = (intptr_t)p->status; /* l_int * */ + uarg[a++] = (intptr_t)p->status; /* l_int * __capability */ iarg[a++] = p->options; /* l_int */ - uarg[a++] = (intptr_t)p->rusage; /* struct rusage * */ + uarg[a++] = (intptr_t)p->rusage; /* struct rusage * __capability */ *n_args = 4; break; } @@ -1952,8 +1952,8 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_prlimit64_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ iarg[a++] = p->resource; /* l_uint */ - uarg[a++] = (intptr_t)p->new; /* struct rlimit * */ - uarg[a++] = (intptr_t)p->old; /* struct rlimit * */ + uarg[a++] = (intptr_t)p->new; /* struct rlimit * __capability */ + uarg[a++] = (intptr_t)p->old; /* struct rlimit * __capability */ *n_args = 4; break; } @@ -1971,9 +1971,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 264: { struct linux_name_to_handle_at_args *p = params; iarg[a++] = p->dirfd; /* l_int */ - uarg[a++] = (intptr_t)p->name; /* const char * */ - uarg[a++] = (intptr_t)p->handle; /* struct l_file_handle * */ - uarg[a++] = (intptr_t)p->mnt_id; /* l_int * */ + uarg[a++] = (intptr_t)p->name; /* const char * __capability */ + uarg[a++] = (intptr_t)p->handle; /* struct l_file_handle * __capability */ + uarg[a++] = (intptr_t)p->mnt_id; /* l_int * __capability */ iarg[a++] = p->flags; /* l_int */ *n_args = 5; break; @@ -1982,7 +1982,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 265: { struct linux_open_by_handle_at_args *p = params; iarg[a++] = p->mountdirfd; /* l_int */ - uarg[a++] = (intptr_t)p->handle; /* struct l_file_handle * */ + uarg[a++] = (intptr_t)p->handle; /* struct l_file_handle * __capability */ iarg[a++] = p->flags; /* l_int */ *n_args = 3; break; @@ -2011,7 +2011,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 269: { struct linux_sendmmsg_args *p = params; iarg[a++] = p->s; /* l_int */ - uarg[a++] = (intptr_t)p->msg; /* struct l_mmsghdr * */ + uarg[a++] = (intptr_t)p->msg; /* struct l_mmsghdr * __capability */ iarg[a++] = p->vlen; /* l_uint */ iarg[a++] = p->flags; /* l_uint */ *n_args = 4; @@ -2021,9 +2021,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 270: { struct linux_process_vm_readv_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ - uarg[a++] = (intptr_t)p->lvec; /* const struct iovec * */ + uarg[a++] = (intptr_t)p->lvec; /* const struct iovec * __capability */ iarg[a++] = p->liovcnt; /* l_ulong */ - uarg[a++] = (intptr_t)p->rvec; /* const struct iovec * */ + uarg[a++] = (intptr_t)p->rvec; /* const struct iovec * __capability */ iarg[a++] = p->riovcnt; /* l_ulong */ iarg[a++] = p->flags; /* l_ulong */ *n_args = 6; @@ -2033,9 +2033,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 271: { struct linux_process_vm_writev_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ - uarg[a++] = (intptr_t)p->lvec; /* const struct iovec * */ + uarg[a++] = (intptr_t)p->lvec; /* const struct iovec * __capability */ iarg[a++] = p->liovcnt; /* l_ulong */ - uarg[a++] = (intptr_t)p->rvec; /* const struct iovec * */ + uarg[a++] = (intptr_t)p->rvec; /* const struct iovec * __capability */ iarg[a++] = p->riovcnt; /* l_ulong */ iarg[a++] = p->flags; /* l_ulong */ *n_args = 6; @@ -2056,7 +2056,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 273: { struct linux_finit_module_args *p = params; iarg[a++] = p->fd; /* l_int */ - uarg[a++] = (intptr_t)p->uargs; /* const char * */ + uarg[a++] = (intptr_t)p->uargs; /* const char * __capability */ iarg[a++] = p->flags; /* l_int */ *n_args = 3; break; @@ -2065,7 +2065,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 274: { struct linux_sched_setattr_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ - uarg[a++] = (intptr_t)p->attr; /* void * */ + uarg[a++] = (intptr_t)p->attr; /* void * __capability */ iarg[a++] = p->flags; /* l_uint */ *n_args = 3; break; @@ -2074,7 +2074,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 275: { struct linux_sched_getattr_args *p = params; iarg[a++] = p->pid; /* l_pid_t */ - uarg[a++] = (intptr_t)p->attr; /* void * */ + uarg[a++] = (intptr_t)p->attr; /* void * __capability */ iarg[a++] = p->size; /* l_uint */ iarg[a++] = p->flags; /* l_uint */ *n_args = 4; @@ -2084,9 +2084,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 276: { struct linux_renameat2_args *p = params; iarg[a++] = p->olddfd; /* l_int */ - uarg[a++] = (intptr_t)p->oldname; /* const char * */ + uarg[a++] = (intptr_t)p->oldname; /* const char * __capability */ iarg[a++] = p->newdfd; /* l_int */ - uarg[a++] = (intptr_t)p->newname; /* const char * */ + uarg[a++] = (intptr_t)p->newname; /* const char * __capability */ iarg[a++] = p->flags; /* l_uint */ *n_args = 5; break; @@ -2096,14 +2096,14 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_seccomp_args *p = params; iarg[a++] = p->op; /* l_uint */ iarg[a++] = p->flags; /* l_uint */ - uarg[a++] = (intptr_t)p->uargs; /* const char * */ + uarg[a++] = (intptr_t)p->uargs; /* const char * __capability */ *n_args = 3; break; } /* linux_getrandom */ case 278: { struct linux_getrandom_args *p = params; - uarg[a++] = (intptr_t)p->buf; /* char * */ + uarg[a++] = (intptr_t)p->buf; /* char * __capability */ iarg[a++] = p->count; /* l_size_t */ iarg[a++] = p->flags; /* l_uint */ *n_args = 3; @@ -2112,7 +2112,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_memfd_create */ case 279: { struct linux_memfd_create_args *p = params; - uarg[a++] = (intptr_t)p->uname_ptr; /* const char * */ + uarg[a++] = (intptr_t)p->uname_ptr; /* const char * __capability */ iarg[a++] = p->flags; /* l_uint */ *n_args = 2; break; @@ -2121,7 +2121,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 280: { struct linux_bpf_args *p = params; iarg[a++] = p->cmd; /* l_int */ - uarg[a++] = (intptr_t)p->attr; /* void * */ + uarg[a++] = (intptr_t)p->attr; /* void * __capability */ iarg[a++] = p->size; /* l_uint */ *n_args = 3; break; @@ -2130,9 +2130,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 281: { struct linux_execveat_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->filename; /* const char * */ - uarg[a++] = (intptr_t)p->argv; /* const char ** */ - uarg[a++] = (intptr_t)p->envp; /* const char ** */ + uarg[a++] = (intptr_t)p->filename; /* const char * __capability */ + uarg[a++] = (intptr_t)p->argv; /* const char * __capability * __capability */ + uarg[a++] = (intptr_t)p->envp; /* const char * __capability * __capability */ iarg[a++] = p->flags; /* l_int */ *n_args = 5; break; @@ -2155,7 +2155,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_mlock2 */ case 284: { struct linux_mlock2_args *p = params; - iarg[a++] = p->start; /* l_ulong */ + uarg[a++] = (intptr_t)p->start; /* void * __capability */ iarg[a++] = p->len; /* l_size_t */ iarg[a++] = p->flags; /* l_int */ *n_args = 3; @@ -2165,9 +2165,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 285: { struct linux_copy_file_range_args *p = params; iarg[a++] = p->fd_in; /* l_int */ - uarg[a++] = (intptr_t)p->off_in; /* l_loff_t * */ + uarg[a++] = (intptr_t)p->off_in; /* l_loff_t * __capability */ iarg[a++] = p->fd_out; /* l_int */ - uarg[a++] = (intptr_t)p->off_out; /* l_loff_t * */ + uarg[a++] = (intptr_t)p->off_out; /* l_loff_t * __capability */ iarg[a++] = p->len; /* l_size_t */ iarg[a++] = p->flags; /* l_uint */ *n_args = 6; @@ -2177,7 +2177,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 286: { struct linux_preadv2_args *p = params; iarg[a++] = p->fd; /* l_ulong */ - uarg[a++] = (intptr_t)p->vec; /* const struct iovec * */ + uarg[a++] = (intptr_t)p->vec; /* const struct iovec * __capability */ iarg[a++] = p->vlen; /* l_ulong */ iarg[a++] = p->pos_l; /* l_ulong */ iarg[a++] = p->pos_h; /* l_ulong */ @@ -2189,7 +2189,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 287: { struct linux_pwritev2_args *p = params; iarg[a++] = p->fd; /* l_ulong */ - uarg[a++] = (intptr_t)p->vec; /* const struct iovec * */ + uarg[a++] = (intptr_t)p->vec; /* const struct iovec * __capability */ iarg[a++] = p->vlen; /* l_ulong */ iarg[a++] = p->pos_l; /* l_ulong */ iarg[a++] = p->pos_h; /* l_ulong */ @@ -2226,10 +2226,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 291: { struct linux_statx_args *p = params; iarg[a++] = p->dirfd; /* l_int */ - uarg[a++] = (intptr_t)p->pathname; /* const char * */ + uarg[a++] = (intptr_t)p->pathname; /* const char * __capability */ iarg[a++] = p->flags; /* l_uint */ iarg[a++] = p->mask; /* l_uint */ - uarg[a++] = (intptr_t)p->statxbuf; /* void * */ + uarg[a++] = (intptr_t)p->statxbuf; /* void * __capability */ *n_args = 5; break; } @@ -2241,7 +2241,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_rseq */ case 293: { struct linux_rseq_args *p = params; - uarg[a++] = (intptr_t)p->rseq; /* struct linux_rseq * */ + uarg[a++] = (intptr_t)p->rseq; /* struct linux_rseq * __capability */ uarg[a++] = p->rseq_len; /* uint32_t */ iarg[a++] = p->flags; /* l_int */ uarg[a++] = p->sig; /* uint32_t */ @@ -2258,7 +2258,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) struct linux_pidfd_send_signal_args *p = params; iarg[a++] = p->pidfd; /* l_int */ iarg[a++] = p->sig; /* l_int */ - uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * */ + uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * __capability */ iarg[a++] = p->flags; /* l_uint */ *n_args = 4; break; @@ -2316,7 +2316,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) /* linux_clone3 */ case 435: { struct linux_clone3_args *p = params; - uarg[a++] = (intptr_t)p->uargs; /* struct l_user_clone_args * */ + uarg[a++] = (intptr_t)p->uargs; /* struct l_user_clone_args * __capability */ iarg[a++] = p->usize; /* l_size_t */ *n_args = 2; break; @@ -2344,7 +2344,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 439: { struct linux_faccessat2_args *p = params; iarg[a++] = p->dfd; /* l_int */ - uarg[a++] = (intptr_t)p->filename; /* const char * */ + uarg[a++] = (intptr_t)p->filename; /* const char * __capability */ iarg[a++] = p->amode; /* l_int */ iarg[a++] = p->flags; /* l_int */ *n_args = 4; @@ -2359,10 +2359,10 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) case 441: { struct linux_epoll_pwait2_args *p = params; iarg[a++] = p->epfd; /* l_int */ - uarg[a++] = (intptr_t)p->events; /* struct epoll_event * */ + uarg[a++] = (intptr_t)p->events; /* struct epoll_event * __capability */ iarg[a++] = p->maxevents; /* l_int */ - uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ - uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * __capability */ + uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * __capability */ iarg[a++] = p->sigsetsize; /* l_size_t */ *n_args = 6; break; @@ -2436,13 +2436,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 5: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland void *"; + p = "userland void * __capability"; break; case 3: p = "l_size_t"; @@ -2458,13 +2458,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 6: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland void *"; + p = "userland void * __capability"; break; case 3: p = "l_size_t"; @@ -2483,10 +2483,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland void *"; + p = "userland void * __capability"; break; case 3: p = "l_size_t"; @@ -2502,13 +2502,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 8: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland void *"; + p = "userland void * __capability"; break; case 3: p = "l_size_t"; @@ -2521,13 +2521,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 9: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland void *"; + p = "userland void * __capability"; break; case 3: p = "l_size_t"; @@ -2543,10 +2543,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland void *"; + p = "userland void * __capability"; break; case 3: p = "l_size_t"; @@ -2559,10 +2559,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 11: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_size_t"; @@ -2575,10 +2575,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 12: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_size_t"; @@ -2594,7 +2594,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_size_t"; @@ -2607,10 +2607,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 14: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; default: break; @@ -2620,10 +2620,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 15: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; default: break; @@ -2636,7 +2636,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; default: break; @@ -2646,7 +2646,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 17: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; case 1: p = "l_ulong"; @@ -2694,7 +2694,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 3: - p = "userland struct epoll_event *"; + p = "userland struct epoll_event * __capability"; break; default: break; @@ -2707,7 +2707,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct epoll_event *"; + p = "userland struct epoll_event * __capability"; break; case 2: p = "l_int"; @@ -2716,7 +2716,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 4: - p = "userland l_sigset_t *"; + p = "userland l_sigset_t * __capability"; break; case 5: p = "l_size_t"; @@ -2761,7 +2761,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 2: - p = "l_ulong"; + p = "l_uintcap_t"; break; default: break; @@ -2793,7 +2793,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 2: - p = "l_ulong"; + p = "l_uintcap_t"; break; default: break; @@ -2848,7 +2848,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; @@ -2867,7 +2867,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_mode_t"; @@ -2883,7 +2883,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; @@ -2896,13 +2896,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 36: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: p = "l_int"; break; case 2: - p = "userland const char *"; + p = "userland const char * __capability"; break; default: break; @@ -2915,13 +2915,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; break; case 3: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 4: p = "l_int"; @@ -2937,13 +2937,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; break; case 3: - p = "userland const char *"; + p = "userland const char * __capability"; break; default: break; @@ -2953,19 +2953,19 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 40: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: - p = "userland char *"; + p = "userland char * __capability"; break; case 3: p = "l_ulong"; break; case 4: - p = "userland void *"; + p = "userland void * __capability"; break; default: break; @@ -2978,10 +2978,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 43: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; case 1: - p = "userland struct l_statfs_buf *"; + p = "userland struct l_statfs_buf * __capability"; break; default: break; @@ -2994,7 +2994,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 1: - p = "userland struct l_statfs_buf *"; + p = "userland struct l_statfs_buf * __capability"; break; default: break; @@ -3004,7 +3004,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 45: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; case 1: p = "l_ulong"; @@ -3052,7 +3052,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; @@ -3065,7 +3065,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 49: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; default: break; @@ -3081,11 +3081,11 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* chroot */ + /* linux_chroot */ case 51: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; default: break; @@ -3111,7 +3111,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_mode_t"; @@ -3127,7 +3127,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_uid_t"; @@ -3165,7 +3165,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; @@ -3194,7 +3194,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 59: switch (ndx) { case 0: - p = "userland l_int *"; + p = "userland l_int * __capability"; break; case 1: p = "l_int"; @@ -3210,7 +3210,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 1: - p = "userland void *"; + p = "userland void * __capability"; break; case 2: p = "l_uint"; @@ -3235,14 +3235,14 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* read */ + /* linux_read */ case 63: switch (ndx) { case 0: p = "int"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_size_t"; @@ -3258,7 +3258,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_size_t"; @@ -3267,14 +3267,14 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* readv */ + /* linux_readv */ case 65: switch (ndx) { case 0: p = "int"; break; case 1: - p = "userland struct iovec *"; + p = "userland struct iovec * __capability"; break; case 2: p = "u_int"; @@ -3290,7 +3290,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "userland struct iovec *"; + p = "userland struct iovec * __capability"; break; case 2: p = "u_int"; @@ -3306,7 +3306,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_size_t"; @@ -3325,7 +3325,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_size_t"; @@ -3344,7 +3344,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_ulong"; break; case 1: - p = "userland struct iovec *"; + p = "userland struct iovec * __capability"; break; case 2: p = "l_ulong"; @@ -3366,7 +3366,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_ulong"; break; case 1: - p = "userland struct iovec *"; + p = "userland struct iovec * __capability"; break; case 2: p = "l_ulong"; @@ -3391,7 +3391,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland l_off_t *"; + p = "userland l_off_t * __capability"; break; case 3: p = "l_size_t"; @@ -3407,19 +3407,19 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland l_fd_set *"; + p = "userland l_fd_set * __capability"; break; case 2: - p = "userland l_fd_set *"; + p = "userland l_fd_set * __capability"; break; case 3: - p = "userland l_fd_set *"; + p = "userland l_fd_set * __capability"; break; case 4: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; case 5: - p = "userland l_uintptr_t *"; + p = "userland l_uintcap_t * __capability"; break; default: break; @@ -3429,16 +3429,16 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 73: switch (ndx) { case 0: - p = "userland struct pollfd *"; + p = "userland struct pollfd * __capability"; break; case 1: p = "l_uint"; break; case 2: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; case 3: - p = "userland l_sigset_t *"; + p = "userland l_sigset_t * __capability"; break; case 4: p = "l_size_t"; @@ -3460,13 +3460,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "int"; break; case 1: - p = "userland l_loff_t *"; + p = "userland l_loff_t * __capability"; break; case 2: p = "int"; break; case 3: - p = "userland l_loff_t *"; + p = "userland l_loff_t * __capability"; break; case 4: p = "l_size_t"; @@ -3488,10 +3488,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland char *"; + p = "userland char * __capability"; break; case 3: p = "l_int"; @@ -3507,10 +3507,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: - p = "userland struct l_stat64 *"; + p = "userland struct l_newstat * __capability"; break; case 3: p = "l_int"; @@ -3526,7 +3526,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 1: - p = "userland struct l_newstat *"; + p = "userland struct l_newstat * __capability"; break; default: break; @@ -3594,10 +3594,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland const struct l_itimerspec *"; + p = "userland const struct l_itimerspec * __capability"; break; case 3: - p = "userland struct l_itimerspec *"; + p = "userland struct l_itimerspec * __capability"; break; default: break; @@ -3610,7 +3610,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct l_itimerspec *"; + p = "userland struct l_itimerspec * __capability"; break; default: break; @@ -3623,10 +3623,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland const struct l_timespec *"; + p = "userland const struct l_timespec * __capability"; break; case 3: p = "l_int"; @@ -3635,11 +3635,11 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* acct */ + /* linux_acct */ case 89: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; default: break; @@ -3649,10 +3649,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 90: switch (ndx) { case 0: - p = "userland struct l_user_cap_header *"; + p = "userland struct l_user_cap_header * __capability"; break; case 1: - p = "userland struct l_user_cap_data *"; + p = "userland struct l_user_cap_data * __capability"; break; default: break; @@ -3662,10 +3662,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 91: switch (ndx) { case 0: - p = "userland struct l_user_cap_header *"; + p = "userland struct l_user_cap_header * __capability"; break; case 1: - p = "userland struct l_user_cap_data *"; + p = "userland struct l_user_cap_data * __capability"; break; default: break; @@ -3711,13 +3711,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 2: - p = "userland l_siginfo_t *"; + p = "userland l_siginfo_t * __capability"; break; case 3: p = "l_int"; break; case 4: - p = "userland struct rusage *"; + p = "userland struct rusage * __capability"; break; default: break; @@ -3727,7 +3727,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 96: switch (ndx) { case 0: - p = "userland l_int *"; + p = "userland l_int * __capability"; break; default: break; @@ -3740,7 +3740,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 98: switch (ndx) { case 0: - p = "userland uint32_t *"; + p = "userland uint32_t * __capability"; break; case 1: p = "l_int"; @@ -3749,10 +3749,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "uint32_t"; break; case 3: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; case 4: - p = "userland uint32_t *"; + p = "userland uint32_t * __capability"; break; case 5: p = "uint32_t"; @@ -3765,7 +3765,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 99: switch (ndx) { case 0: - p = "userland struct linux_robust_list_head *"; + p = "userland struct linux_robust_list_head * __capability"; break; case 1: p = "l_size_t"; @@ -3781,10 +3781,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct linux_robust_list_head **"; + p = "userland struct linux_robust_list_head * __capability * __capability"; break; case 2: - p = "userland l_size_t *"; + p = "userland l_size_t * __capability"; break; default: break; @@ -3794,10 +3794,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 101: switch (ndx) { case 0: - p = "userland const struct l_timespec *"; + p = "userland const struct l_timespec * __capability"; break; case 1: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; default: break; @@ -3810,7 +3810,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct l_itimerval *"; + p = "userland struct l_itimerval * __capability"; break; default: break; @@ -3823,10 +3823,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct l_itimerval *"; + p = "userland struct l_itimerval * __capability"; break; case 2: - p = "userland struct l_itimerval *"; + p = "userland struct l_itimerval * __capability"; break; default: break; @@ -3848,10 +3848,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "clockid_t"; break; case 1: - p = "userland struct l_sigevent *"; + p = "userland struct l_sigevent * __capability"; break; case 2: - p = "userland l_timer_t *"; + p = "userland l_timer_t * __capability"; break; default: break; @@ -3864,7 +3864,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_timer_t"; break; case 1: - p = "userland struct itimerspec *"; + p = "userland struct itimerspec * __capability"; break; default: break; @@ -3890,10 +3890,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland const struct itimerspec *"; + p = "userland const struct itimerspec * __capability"; break; case 3: - p = "userland struct itimerspec *"; + p = "userland struct itimerspec * __capability"; break; default: break; @@ -3916,7 +3916,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "clockid_t"; break; case 1: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; default: break; @@ -3929,7 +3929,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "clockid_t"; break; case 1: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; default: break; @@ -3942,7 +3942,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "clockid_t"; break; case 1: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; default: break; @@ -3958,10 +3958,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; case 3: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; default: break; @@ -3974,7 +3974,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_int"; @@ -3993,10 +3993,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_long"; break; case 2: - p = "l_ulong"; + p = "l_uintcap_t"; break; case 3: - p = "l_ulong"; + p = "l_uintcap_t"; break; default: break; @@ -4009,7 +4009,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 1: - p = "userland struct sched_param *"; + p = "userland struct sched_param * __capability"; break; default: break; @@ -4025,7 +4025,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland struct sched_param *"; + p = "userland struct sched_param * __capability"; break; default: break; @@ -4048,7 +4048,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 1: - p = "userland struct sched_param *"; + p = "userland struct sched_param * __capability"; break; default: break; @@ -4064,7 +4064,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 2: - p = "userland l_ulong *"; + p = "userland l_ulong * __capability"; break; default: break; @@ -4080,7 +4080,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 2: - p = "userland l_ulong *"; + p = "userland l_ulong * __capability"; break; default: break; @@ -4116,7 +4116,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 1: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; default: break; @@ -4168,10 +4168,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 132: switch (ndx) { case 0: - p = "userland l_stack_t *"; + p = "userland l_stack_t * __capability"; break; case 1: - p = "userland l_stack_t *"; + p = "userland l_stack_t * __capability"; break; default: break; @@ -4181,7 +4181,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 133: switch (ndx) { case 0: - p = "userland l_sigset_t *"; + p = "userland l_sigset_t * __capability"; break; case 1: p = "l_size_t"; @@ -4197,10 +4197,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland l_sigaction_t *"; + p = "userland l_sigaction_t * __capability"; break; case 2: - p = "userland l_sigaction_t *"; + p = "userland l_sigaction_t * __capability"; break; case 3: p = "l_size_t"; @@ -4216,10 +4216,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland l_sigset_t *"; + p = "userland l_sigset_t * __capability"; break; case 2: - p = "userland l_sigset_t *"; + p = "userland l_sigset_t * __capability"; break; case 3: p = "l_size_t"; @@ -4232,7 +4232,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 136: switch (ndx) { case 0: - p = "userland l_sigset_t *"; + p = "userland l_sigset_t * __capability"; break; case 1: p = "l_size_t"; @@ -4245,13 +4245,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 137: switch (ndx) { case 0: - p = "userland l_sigset_t *"; + p = "userland l_sigset_t * __capability"; break; case 1: - p = "userland l_siginfo_t *"; + p = "userland l_siginfo_t * __capability"; break; case 2: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; case 3: p = "l_size_t"; @@ -4270,7 +4270,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland l_siginfo_t *"; + p = "userland l_siginfo_t * __capability"; break; default: break; @@ -4321,7 +4321,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 3: - p = "userland void *"; + p = "userland void * __capability"; break; default: break; @@ -4389,17 +4389,17 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* getresuid */ + /* linux_getresuid */ case 148: switch (ndx) { case 0: - p = "userland uid_t *"; + p = "userland l_uid_t * __capability"; break; case 1: - p = "userland uid_t *"; + p = "userland l_uid_t * __capability"; break; case 2: - p = "userland uid_t *"; + p = "userland l_uid_t * __capability"; break; default: break; @@ -4421,17 +4421,17 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* getresgid */ + /* linux_getresgid */ case 150: switch (ndx) { case 0: - p = "userland gid_t *"; + p = "userland l_gid_t * __capability"; break; case 1: - p = "userland gid_t *"; + p = "userland l_gid_t * __capability"; break; case 2: - p = "userland gid_t *"; + p = "userland l_gid_t * __capability"; break; default: break; @@ -4461,7 +4461,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 153: switch (ndx) { case 0: - p = "userland struct l_times_argv *"; + p = "userland struct l_times_argv * __capability"; break; default: break; @@ -4510,7 +4510,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland l_gid_t *"; + p = "userland l_gid_t * __capability"; break; default: break; @@ -4523,7 +4523,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland l_gid_t *"; + p = "userland l_gid_t * __capability"; break; default: break; @@ -4533,7 +4533,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 160: switch (ndx) { case 0: - p = "userland struct l_new_utsname *"; + p = "userland struct l_new_utsname * __capability"; break; default: break; @@ -4543,7 +4543,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 161: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; case 1: p = "l_uint"; @@ -4556,7 +4556,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 162: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; case 1: p = "l_int"; @@ -4572,7 +4572,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 1: - p = "userland struct l_rlimit *"; + p = "userland struct l_rlimit * __capability"; break; default: break; @@ -4585,20 +4585,20 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 1: - p = "userland struct l_rlimit *"; + p = "userland struct l_rlimit * __capability"; break; default: break; }; break; - /* getrusage */ + /* linux_getrusage */ case 165: switch (ndx) { case 0: - p = "int"; + p = "l_int"; break; case 1: - p = "userland struct rusage *"; + p = "userland struct rusage * __capability"; break; default: break; @@ -4621,16 +4621,16 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 3: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 4: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; default: break; @@ -4640,39 +4640,39 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 168: switch (ndx) { case 0: - p = "userland l_uint *"; + p = "userland l_uint * __capability"; break; case 1: - p = "userland l_uint *"; + p = "userland l_uint * __capability"; break; case 2: - p = "userland void *"; + p = "userland void * __capability"; break; default: break; }; break; - /* gettimeofday */ + /* linux_gettimeofday */ case 169: switch (ndx) { case 0: - p = "userland struct l_timeval *"; + p = "userland l_timeval * __capability"; break; case 1: - p = "userland struct timezone *"; + p = "userland struct timezone * __capability"; break; default: break; }; break; - /* settimeofday */ + /* linux_settimeofday */ case 170: switch (ndx) { case 0: - p = "userland struct l_timeval *"; + p = "userland l_timeval * __capability"; break; case 1: - p = "userland struct timezone *"; + p = "userland struct timezone * __capability"; break; default: break; @@ -4706,7 +4706,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 179: switch (ndx) { case 0: - p = "userland struct l_sysinfo *"; + p = "userland struct l_sysinfo * __capability"; break; default: break; @@ -4716,7 +4716,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 180: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: p = "l_int"; @@ -4725,7 +4725,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_mode_t"; break; case 3: - p = "userland struct mq_attr *"; + p = "userland struct mq_attr * __capability"; break; default: break; @@ -4735,7 +4735,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 181: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; default: break; @@ -4748,7 +4748,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_mqd_t"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_size_t"; @@ -4757,7 +4757,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 4: - p = "userland const struct l_timespec *"; + p = "userland const struct l_timespec * __capability"; break; default: break; @@ -4770,16 +4770,16 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_mqd_t"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_size_t"; break; case 3: - p = "userland l_uint *"; + p = "userland l_uint * __capability"; break; case 4: - p = "userland const struct l_timespec *"; + p = "userland const struct l_timespec * __capability"; break; default: break; @@ -4792,7 +4792,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_mqd_t"; break; case 1: - p = "userland const struct l_sigevent *"; + p = "userland const struct l_sigevent * __capability"; break; default: break; @@ -4805,10 +4805,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_mqd_t"; break; case 1: - p = "userland const struct mq_attr *"; + p = "userland const struct mq_attr * __capability"; break; case 2: - p = "userland struct mq_attr *"; + p = "userland struct mq_attr * __capability"; break; default: break; @@ -4837,7 +4837,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland struct l_msqid_ds *"; + p = "userland struct l_msqid_ds * __capability"; break; default: break; @@ -4850,7 +4850,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct l_msgbuf *"; + p = "userland struct l_msgbuf * __capability"; break; case 2: p = "l_size_t"; @@ -4872,7 +4872,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct l_msgbuf *"; + p = "userland struct l_msgbuf * __capability"; break; case 2: p = "l_size_t"; @@ -4926,26 +4926,26 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct sembuf *"; + p = "userland struct sembuf * __capability"; break; case 2: p = "l_size_t"; break; case 3: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; default: break; }; break; - /* semop */ + /* linux_semop */ case 193: switch (ndx) { case 0: p = "l_int"; break; case 1: - p = "userland struct sembuf *"; + p = "userland struct sembuf * __capability"; break; case 2: p = "l_size_t"; @@ -4980,7 +4980,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland struct l_shmid_ds *"; + p = "userland struct l_shmid_ds * __capability"; break; default: break; @@ -4993,7 +4993,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland char *"; + p = "userland char * __capability"; break; case 2: p = "l_int"; @@ -5006,7 +5006,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 197: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; default: break; @@ -5041,7 +5041,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 3: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; default: break; @@ -5054,7 +5054,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: p = "l_int"; @@ -5083,10 +5083,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; default: break; @@ -5099,7 +5099,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: p = "l_int"; @@ -5115,10 +5115,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; default: break; @@ -5131,10 +5131,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; default: break; @@ -5147,7 +5147,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: p = "l_size_t"; @@ -5156,7 +5156,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 4: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 5: p = "l_int"; @@ -5172,7 +5172,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: p = "l_size_t"; @@ -5181,10 +5181,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 4: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 5: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; default: break; @@ -5203,7 +5203,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 3: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 4: p = "l_int"; @@ -5225,10 +5225,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 3: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 4: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; default: break; @@ -5254,7 +5254,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: p = "l_uint"; @@ -5270,7 +5270,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: p = "l_uint"; @@ -5289,11 +5289,11 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* munmap */ + /* linux_munmap */ case 215: switch (ndx) { case 0: - p = "userland void *"; + p = "userland void * __capability"; break; case 1: p = "l_size_t"; @@ -5306,7 +5306,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 216: switch (ndx) { case 0: - p = "l_ulong"; + p = "userland void * __capability"; break; case 1: p = "l_ulong"; @@ -5318,7 +5318,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_ulong"; break; case 4: - p = "l_ulong"; + p = "userland void * __capability"; break; default: break; @@ -5340,16 +5340,16 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_ulong"; break; case 1: - p = "l_ulong"; + p = "l_uintcap_t"; break; case 2: - p = "userland l_int *"; + p = "userland l_int * __capability"; break; case 3: - p = "l_ulong"; + p = "l_uintcap_t"; break; case 4: - p = "userland l_int *"; + p = "userland l_int * __capability"; break; default: break; @@ -5359,13 +5359,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 221: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; case 1: - p = "userland l_uintptr_t *"; + p = "userland l_uintcap_t * __capability"; break; case 2: - p = "userland l_uintptr_t *"; + p = "userland l_uintcap_t * __capability"; break; default: break; @@ -5375,7 +5375,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 222: switch (ndx) { case 0: - p = "l_ulong"; + p = "userland void * __capability"; break; case 1: p = "l_ulong"; @@ -5415,11 +5415,11 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* swapon */ + /* linux_swapon */ case 224: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; default: break; @@ -5432,7 +5432,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 226: switch (ndx) { case 0: - p = "l_ulong"; + p = "userland void * __capability"; break; case 1: p = "l_size_t"; @@ -5448,7 +5448,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 227: switch (ndx) { case 0: - p = "l_ulong"; + p = "userland void * __capability"; break; case 1: p = "l_size_t"; @@ -5460,27 +5460,27 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; - /* mlock */ + /* linux_mlock */ case 228: switch (ndx) { case 0: - p = "userland const void *"; + p = "userland const void * __capability"; break; case 1: - p = "size_t"; + p = "l_size_t"; break; default: break; }; break; - /* munlock */ + /* linux_munlock */ case 229: switch (ndx) { case 0: - p = "userland const void *"; + p = "userland const void * __capability"; break; case 1: - p = "size_t"; + p = "l_size_t"; break; default: break; @@ -5503,13 +5503,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 232: switch (ndx) { case 0: - p = "l_ulong"; + p = "userland void * __capability"; break; case 1: p = "l_size_t"; break; case 2: - p = "userland u_char *"; + p = "userland u_char * __capability"; break; default: break; @@ -5519,7 +5519,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 233: switch (ndx) { case 0: - p = "l_ulong"; + p = "userland void * __capability"; break; case 1: p = "l_size_t"; @@ -5562,7 +5562,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 3: - p = "userland l_siginfo_t *"; + p = "userland l_siginfo_t * __capability"; break; default: break; @@ -5578,10 +5578,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 2: - p = "l_uintptr_t"; + p = "l_uintcap_t"; break; case 3: p = "l_int"; @@ -5597,7 +5597,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct l_mmsghdr *"; + p = "userland struct l_mmsghdr * __capability"; break; case 2: p = "l_uint"; @@ -5606,7 +5606,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 4: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; default: break; @@ -5619,13 +5619,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 1: - p = "userland l_int *"; + p = "userland l_int * __capability"; break; case 2: p = "l_int"; break; case 3: - p = "userland struct rusage *"; + p = "userland struct rusage * __capability"; break; default: break; @@ -5641,10 +5641,10 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 2: - p = "userland struct rlimit *"; + p = "userland struct rlimit * __capability"; break; case 3: - p = "userland struct rlimit *"; + p = "userland struct rlimit * __capability"; break; default: break; @@ -5663,13 +5663,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland struct l_file_handle *"; + p = "userland struct l_file_handle * __capability"; break; case 3: - p = "userland l_int *"; + p = "userland l_int * __capability"; break; case 4: p = "l_int"; @@ -5685,7 +5685,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct l_file_handle *"; + p = "userland struct l_file_handle * __capability"; break; case 2: p = "l_int"; @@ -5727,7 +5727,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct l_mmsghdr *"; + p = "userland struct l_mmsghdr * __capability"; break; case 2: p = "l_uint"; @@ -5746,13 +5746,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 1: - p = "userland const struct iovec *"; + p = "userland const struct iovec * __capability"; break; case 2: p = "l_ulong"; break; case 3: - p = "userland const struct iovec *"; + p = "userland const struct iovec * __capability"; break; case 4: p = "l_ulong"; @@ -5771,13 +5771,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 1: - p = "userland const struct iovec *"; + p = "userland const struct iovec * __capability"; break; case 2: p = "l_ulong"; break; case 3: - p = "userland const struct iovec *"; + p = "userland const struct iovec * __capability"; break; case 4: p = "l_ulong"; @@ -5818,7 +5818,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; @@ -5834,7 +5834,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 1: - p = "userland void *"; + p = "userland void * __capability"; break; case 2: p = "l_uint"; @@ -5850,7 +5850,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_pid_t"; break; case 1: - p = "userland void *"; + p = "userland void * __capability"; break; case 2: p = "l_uint"; @@ -5869,13 +5869,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; break; case 3: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 4: p = "l_uint"; @@ -5894,7 +5894,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 2: - p = "userland const char *"; + p = "userland const char * __capability"; break; default: break; @@ -5904,7 +5904,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 278: switch (ndx) { case 0: - p = "userland char *"; + p = "userland char * __capability"; break; case 1: p = "l_size_t"; @@ -5920,7 +5920,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 279: switch (ndx) { case 0: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 1: p = "l_uint"; @@ -5936,7 +5936,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland void *"; + p = "userland void * __capability"; break; case 2: p = "l_uint"; @@ -5952,13 +5952,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: - p = "userland const char **"; + p = "userland const char * __capability * __capability"; break; case 3: - p = "userland const char **"; + p = "userland const char * __capability * __capability"; break; case 4: p = "l_int"; @@ -5994,7 +5994,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 284: switch (ndx) { case 0: - p = "l_ulong"; + p = "userland void * __capability"; break; case 1: p = "l_size_t"; @@ -6013,13 +6013,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland l_loff_t *"; + p = "userland l_loff_t * __capability"; break; case 2: p = "l_int"; break; case 3: - p = "userland l_loff_t *"; + p = "userland l_loff_t * __capability"; break; case 4: p = "l_size_t"; @@ -6038,7 +6038,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_ulong"; break; case 1: - p = "userland const struct iovec *"; + p = "userland const struct iovec * __capability"; break; case 2: p = "l_ulong"; @@ -6063,7 +6063,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_ulong"; break; case 1: - p = "userland const struct iovec *"; + p = "userland const struct iovec * __capability"; break; case 2: p = "l_ulong"; @@ -6130,7 +6130,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_uint"; @@ -6139,7 +6139,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_uint"; break; case 4: - p = "userland void *"; + p = "userland void * __capability"; break; default: break; @@ -6152,7 +6152,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 293: switch (ndx) { case 0: - p = "userland struct linux_rseq *"; + p = "userland struct linux_rseq * __capability"; break; case 1: p = "uint32_t"; @@ -6180,7 +6180,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 2: - p = "userland l_siginfo_t *"; + p = "userland l_siginfo_t * __capability"; break; case 3: p = "l_uint"; @@ -6223,7 +6223,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 435: switch (ndx) { case 0: - p = "userland struct l_user_clone_args *"; + p = "userland struct l_user_clone_args * __capability"; break; case 1: p = "l_size_t"; @@ -6261,7 +6261,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland const char *"; + p = "userland const char * __capability"; break; case 2: p = "l_int"; @@ -6283,16 +6283,16 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) p = "l_int"; break; case 1: - p = "userland struct epoll_event *"; + p = "userland struct epoll_event * __capability"; break; case 2: p = "l_int"; break; case 3: - p = "userland struct l_timespec *"; + p = "userland struct l_timespec * __capability"; break; case 4: - p = "userland l_sigset_t *"; + p = "userland l_sigset_t * __capability"; break; case 5: p = "l_size_t"; @@ -6553,7 +6553,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* chroot */ + /* linux_chroot */ case 51: if (ndx == 0 || ndx == 1) p = "int"; @@ -6605,7 +6605,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* read */ + /* linux_read */ case 63: if (ndx == 0 || ndx == 1) p = "int"; @@ -6615,7 +6615,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* readv */ + /* linux_readv */ case 65: if (ndx == 0 || ndx == 1) p = "int"; @@ -6721,7 +6721,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* acct */ + /* linux_acct */ case 89: if (ndx == 0 || ndx == 1) p = "int"; @@ -6993,7 +6993,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* getresuid */ + /* linux_getresuid */ case 148: if (ndx == 0 || ndx == 1) p = "int"; @@ -7003,7 +7003,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* getresgid */ + /* linux_getresgid */ case 150: if (ndx == 0 || ndx == 1) p = "int"; @@ -7075,7 +7075,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* getrusage */ + /* linux_getrusage */ case 165: if (ndx == 0 || ndx == 1) p = "int"; @@ -7095,12 +7095,12 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* gettimeofday */ + /* linux_gettimeofday */ case 169: if (ndx == 0 || ndx == 1) p = "int"; break; - /* settimeofday */ + /* linux_settimeofday */ case 170: if (ndx == 0 || ndx == 1) p = "int"; @@ -7191,7 +7191,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* semop */ + /* linux_semop */ case 193: if (ndx == 0 || ndx == 1) p = "int"; @@ -7296,7 +7296,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* munmap */ + /* linux_munmap */ case 215: if (ndx == 0 || ndx == 1) p = "int"; @@ -7332,7 +7332,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* swapon */ + /* linux_swapon */ case 224: if (ndx == 0 || ndx == 1) p = "int"; @@ -7349,12 +7349,12 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; - /* mlock */ + /* linux_mlock */ case 228: if (ndx == 0 || ndx == 1) p = "int"; break; - /* munlock */ + /* linux_munlock */ case 229: if (ndx == 0 || ndx == 1) p = "int"; diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c index 7377575a69eb..119e8e818cf1 100644 --- a/sys/arm64/linux/linux_sysvec.c +++ b/sys/arm64/linux/linux_sysvec.c @@ -27,6 +27,9 @@ */ #define __ELF_WORD_SIZE 64 +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) +#define __ELF_CHERI +#endif #include #include @@ -47,8 +50,15 @@ #include #include +#ifdef COMPAT_LINUX64 +#include +#include +#include +#else #include #include +#include +#endif #include #include #include @@ -59,15 +69,17 @@ #include #include -#include - #include #include #ifdef VFP #include #endif +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) +MODULE_VERSION(linux64celf, 1); +#else MODULE_VERSION(linux64elf, 1); +#endif #define LINUX_VDSOPAGE_SIZE PAGE_SIZE * 2 #define LINUX_VDSOPAGE (VM_MAXUSER_ADDRESS - \ @@ -82,12 +94,17 @@ MODULE_VERSION(linux64elf, 1); static int linux_szsigcode; static vm_object_t linux_vdso_obj; static char *linux_vdso_mapping; -extern char _binary_linux_vdso_so_o_start; -extern char _binary_linux_vdso_so_o_end; +extern char _binary_linux_vdso_so_o_start[]; +extern char _binary_linux_vdso_so_o_end[]; static vm_offset_t linux_vdso_base; +#ifdef COMPAT_LINUX64 +extern struct sysent linux64_sysent[LINUX64_SYS_MAXSYSCALL]; +extern const char *linux64_syscallnames[]; +#else extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; extern const char *linux_syscallnames[]; +#endif SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); @@ -97,7 +114,7 @@ static void linux_vdso_reloc(char *mapping, Elf_Addr offset); static void linux_set_syscall_retval(struct thread *td, int error); static int linux_fetch_syscall_args(struct thread *td); static void linux_exec_setregs(struct thread *td, struct image_params *imgp, - uintptr_t stack); + uintcap_t stack); static void linux_exec_sysvec_init(void *param); static int linux_on_exec_vmspace(struct proc *p, struct image_params *imgp); @@ -111,7 +128,7 @@ linux_fetch_syscall_args(struct thread *td) { struct proc *p; struct syscall_args *sa; - register_t *ap; + syscallarg_t *ap; p = td->td_proc; ap = td->td_frame->tf_x; @@ -128,7 +145,7 @@ linux_fetch_syscall_args(struct thread *td) if (sa->callp->sy_narg > nitems(sa->args)) panic("ARM64TODO: Could we have more than %zu args?", nitems(sa->args)); - memcpy(sa->args, ap, nitems(sa->args) * sizeof(register_t)); + memcpy(sa->args, ap, nitems(sa->args) * sizeof(syscallarg_t)); td->td_retval[0] = 0; return (0); @@ -150,11 +167,17 @@ linux_set_syscall_retval(struct thread *td, int error) void linux64_arch_copyout_auxargs(struct image_params *imgp, Elf_Auxinfo **pos) { - - AUXARGS_ENTRY((*pos), LINUX_AT_SYSINFO_EHDR, linux_vdso_base); + // vDSO not yet working for PCuABI, we disable it at the moment + // AUXARGS_ENTRY((*pos), LINUX_AT_SYSINFO_EHDR, linux_vdso_base); AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP, *imgp->sysent->sv_hwcap); AUXARGS_ENTRY((*pos), LINUX_AT_HWCAP2, *imgp->sysent->sv_hwcap2); + +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) && !defined(COMPAT_LINUX32) + // Use vdso bound capability because we do not have a good method to get string size yet. + AUXARGS_ENTRY_PTR((*pos), LINUX_AT_PLATFORM, cheri_capability_build_user_data(CHERI_CAP_USER_DATA_PERMS, linux_vdso_base, LINUX_VDSOPAGE_SIZE, (uintcap_t)linux_platform - linux_vdso_base)); +#else AUXARGS_ENTRY((*pos), LINUX_AT_PLATFORM, PTROUT(linux_platform)); +#endif } /* @@ -162,18 +185,51 @@ linux64_arch_copyout_auxargs(struct image_params *imgp, Elf_Auxinfo **pos) */ static void linux_exec_setregs(struct thread *td, struct image_params *imgp, - uintptr_t stack) + uintcap_t stack) { struct trapframe *regs = td->td_frame; struct pcb *pcb = td->td_pcb; memset(regs, 0, sizeof(*regs)); + + +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + regs->tf_x[0] = (uintcap_t)imgp->args->argc; + regs->tf_x[1] = (uintcap_t)imgp->argv; + regs->tf_x[2] = (uintcap_t)imgp->envv; + regs->tf_x[3] = (uintcap_t)imgp->auxv; + regs->tf_sp = stack; + trapframe_set_elr(regs, (uintcap_t)cheri_exec_pcc(td, imgp)); +#else regs->tf_sp = stack; +#if __has_feature(capabilities) + hybridabi_thread_setregs(td, imgp->entry_addr); +#else regs->tf_elr = imgp->entry_addr; +#endif +#endif + pcb->pcb_tpidr_el0 = 0; pcb->pcb_tpidrro_el0 = 0; + +#if __has_feature(capabilities) + WRITE_SPECIALREG_CAP(ctpidrro_el0, 0); + WRITE_SPECIALREG_CAP(ctpidr_el0, 0); +#else WRITE_SPECIALREG(tpidrro_el0, 0); WRITE_SPECIALREG(tpidr_el0, 0); +#endif + +#if __has_feature(capabilities) + td->td_pcb->pcb_cid_el0 = 0; + td->td_pcb->pcb_rcsp_el0 = 0; + td->td_pcb->pcb_rddc_el0 = 0; + td->td_pcb->pcb_rctpidr_el0 = 0; + WRITE_SPECIALREG_CAP(cid_el0, 0); + WRITE_SPECIALREG_CAP(rcsp_el0, 0); + WRITE_SPECIALREG_CAP(rddc_el0, 0); + WRITE_SPECIALREG_CAP(rctpidr_el0, 0); +#endif #ifdef VFP vfp_reset_state(td, pcb); @@ -190,6 +246,11 @@ linux_parse_sigreturn_ctx(struct thread *td, struct l_sigcontext *sc) { struct l_fpsimd_context *fpsimd; struct _l_aarch64_ctx *ctx; + struct trapframe *tf; +#if __has_feature(capabilities) + struct l_morello_context *morello; +#endif + tf = td->td_frame; int offset; offset = 0; @@ -236,11 +297,42 @@ linux_parse_sigreturn_ctx(struct thread *td, struct l_sigcontext *sc) break; #endif +#if __has_feature(capabilities) + // We merge the capability registers c0-c30 with the x0-x30 + // Because standard registers may get modified by the signal handler. + // To avoid untagging sealed capabilities unintentionally, + // compare the registers first before assigning the values + // This code assumes that addresses without cap have been restored to tf + +#define MORELLO_MERGE_C_X(target, addr_source, cap_source) do { \ + if ((uint64_t)(uintcap_t)addr_source != (uint64_t)(uintcap_t)cap_source) { \ + target = cheri_setaddress(cap_source, (uint64_t)(uintcap_t)addr_source); \ + } else { \ + target = cap_source; \ + } \ + } while (0) + + + case L_MORELLO_MAGIC: + morello = (struct l_morello_context *)ctx; + + for (int i = 0; i < 30; i++) { + MORELLO_MERGE_C_X(tf->tf_x[i], tf->tf_x[i], morello->cregs[i]); + } + + MORELLO_MERGE_C_X(tf->tf_lr, tf->tf_lr, morello->cregs[30]); + MORELLO_MERGE_C_X(tf->tf_sp, tf->tf_sp, morello->csp); + td->td_pcb->pcb_rcsp_el0 = morello->rcsp; + WRITE_SPECIALREG_CAP(rcsp_el0, morello->rcsp); + MORELLO_MERGE_C_X(tf->tf_elr, tf->tf_elr, morello->pcc); + + break; +#endif default: return (false); } - offset += ctx->size; + offset += roundup(ctx->size, 16); } } @@ -249,7 +341,7 @@ int linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) { struct l_rt_sigframe *sf; - struct l_sigframe *frame; + struct l_sigframe * __capability frame; struct trapframe *tf; sigset_t bmask; int error; @@ -257,14 +349,16 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) sf = malloc(sizeof(*sf), M_LINUX, M_WAITOK | M_ZERO); tf = td->td_frame; - frame = (struct l_sigframe *)tf->tf_sp; - error = copyin((void *)&frame->sf, sf, sizeof(*sf)); + frame = (struct l_sigframe * __capability)tf->tf_sp; + error = copyincap(LINUX_USER_CAP((uintcap_t)&frame->sf, sizeof(*sf)), sf, sizeof(*sf)); if (error != 0) { free(sf, M_LINUX); return (error); } - memcpy(tf->tf_x, sf->sf_uc.uc_sc.regs, sizeof(tf->tf_x)); + for (int i = 0; i < 30; i++) { + tf->tf_x[i] = sf->sf_uc.uc_sc.regs[i]; + } tf->tf_lr = sf->sf_uc.uc_sc.regs[30]; tf->tf_sp = sf->sf_uc.uc_sc.sp; tf->tf_elr = sf->sf_uc.uc_sc.pc; @@ -296,9 +390,12 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) struct thread *td; struct proc *p; struct trapframe *tf; - struct l_sigframe *fp, *frame; + struct l_sigframe * __capability fp, *frame; struct l_fpsimd_context *fpsimd; struct l_esr_context *esr; +#if __has_feature(capabilities) + struct l_morello_context *morello; +#endif l_stack_t uc_stack; ucontext_t uc; uint8_t *scr; @@ -323,23 +420,23 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) /* Allocate and validate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { - fp = (struct l_sigframe *)((uintptr_t)td->td_sigstk.ss_sp + + fp = (struct l_sigframe * __capability)((uintcap_t)td->td_sigstk.ss_sp + td->td_sigstk.ss_size); #if defined(COMPAT_43) td->td_sigstk.ss_flags |= SS_ONSTACK; #endif } else { - fp = (struct l_sigframe *)td->td_frame->tf_sp; + fp = (struct l_sigframe * __capability)td->td_frame->tf_sp; } /* Make room, keeping the stack aligned */ fp--; - fp = (struct l_sigframe *)STACKALIGN(fp); + fp = (struct l_sigframe * __capability)STACKALIGN(fp); get_mcontext(td, &uc.uc_mcontext, 0); uc.uc_sigmask = *mask; - uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); + uc_stack.ss_sp = (uintcap_t)(td->td_sigstk.ss_sp); uc_stack.ss_size = td->td_sigstk.ss_size; uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ? (onstack ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; @@ -349,12 +446,14 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) /* Fill in the frame to copy out */ frame = malloc(sizeof(*frame), M_LINUX, M_WAITOK | M_ZERO); - memcpy(&frame->sf.sf_uc.uc_sc.regs, tf->tf_x, sizeof(tf->tf_x)); + for (int i = 0; i < 30; i++) { + frame->sf.sf_uc.uc_sc.regs[i] = tf->tf_x[i]; + } frame->sf.sf_uc.uc_sc.regs[30] = tf->tf_lr; frame->sf.sf_uc.uc_sc.sp = tf->tf_sp; frame->sf.sf_uc.uc_sc.pc = tf->tf_elr; frame->sf.sf_uc.uc_sc.pstate = tf->tf_spsr; - frame->sf.sf_uc.uc_sc.fault_address = (register_t)ksi->ksi_addr; + frame->sf.sf_uc.uc_sc.fault_address = (uintcap_t)ksi->ksi_addr; /* Stack frame for unwinding */ frame->fp = tf->tf_x[29]; @@ -386,12 +485,30 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) esr->head.magic = L_ESR_MAGIC; esr->head.size = sizeof(struct l_esr_context); esr->esr = tf->tf_esr; + scr += roundup(sizeof(struct l_esr_context), 16); } +#if __has_feature(capabilities) + morello = (struct l_morello_context *) scr; + morello->head.magic = L_MORELLO_MAGIC; + morello->head.size = sizeof(struct l_morello_context); + morello->__pad = 0; + memcpy(morello->cregs, tf->tf_x, sizeof(tf->tf_x)); + morello->cregs[30] = tf->tf_lr; + morello->csp = tf->tf_sp; + morello->rcsp = td->td_pcb->pcb_rcsp_el0; + morello->pcc = tf->tf_elr; +#endif + memcpy(&frame->sf.sf_uc.uc_stack, &uc_stack, sizeof(uc_stack)); +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + KASSERT(cheri_gettag(fp), ("Expected valid fp capability")); + KASSERT(cheri_gettag(catcher), ("Expected valid handler capability")); +#endif + /* Copy the sigframe out to the user's stack. */ - if (copyout(frame, fp, sizeof(*fp)) != 0) { + if (copyoutcap(frame, LINUX_USER_CAP((uintcap_t)fp, sizeof(*fp)), sizeof(*fp)) != 0) { /* Process has trashed its stack. Kill it. */ free(frame, M_LINUX); CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp); @@ -400,18 +517,28 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) } free(frame, M_LINUX); + // Use offsetof (following freebsd64) to make sure no capability info is present in case fp has no capability info tf->tf_x[0]= sig; if (issiginfo) { - tf->tf_x[1] = (register_t)&fp->sf.sf_si; - tf->tf_x[2] = (register_t)&fp->sf.sf_uc; + tf->tf_x[1] = (uintcap_t)fp + offsetof(struct l_sigframe, sf) + offsetof(struct l_rt_sigframe, sf_si); + tf->tf_x[2] = (uintcap_t)fp + offsetof(struct l_sigframe, sf) + offsetof(struct l_rt_sigframe, sf_uc); } else { tf->tf_x[1] = 0; tf->tf_x[2] = 0; } - tf->tf_x[29] = (register_t)&fp->fp; - tf->tf_elr = (register_t)catcher; - tf->tf_sp = (register_t)fp; - tf->tf_lr = (register_t)__user_rt_sigreturn; + tf->tf_x[29] = (uintcap_t)fp + offsetof(struct l_sigframe, fp); + tf->tf_sp = (uintcap_t)fp; +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + tf->tf_lr = (uintcap_t)cheri_capability_build_user_code(td, CHERI_CAP_USER_CODE_PERMS, linux_vdso_base, LINUX_VDSOPAGE_SIZE, (uintcap_t)__user_rt_sigreturn - linux_vdso_base); +#else + tf->tf_lr = (uintcap_t)__user_rt_sigreturn; +#endif + +#if __has_feature(capabilities) + trapframe_set_elr(tf, (uintcap_t)catcher); +#else + tf->tf_elr = (uintcap_t)catcher; +#endif CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr, tf->tf_sp); @@ -421,14 +548,23 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) } struct sysentvec elf_linux_sysvec = { +#ifdef COMPAT_LINUX64 + .sv_size = LINUX64_SYS_MAXSYSCALL, + .sv_table = linux64_sysent, +#else .sv_size = LINUX_SYS_MAXSYSCALL, .sv_table = linux_sysent, +#endif .sv_fixup = __elfN(freebsd_fixup), .sv_sendsig = linux_rt_sendsig, - .sv_sigcode = &_binary_linux_vdso_so_o_start, + .sv_sigcode = _binary_linux_vdso_so_o_start, .sv_szsigcode = &linux_szsigcode, +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + .sv_name = "Linux ELF64C", +#else .sv_name = "Linux ELF64", - .sv_coredump = elf64_coredump, +#endif + .sv_coredump = __elfN(coredump), .sv_elf_core_osabi = ELFOSABI_NONE, .sv_elf_core_abi_vendor = LINUX_ABI_VENDOR, .sv_elf_core_prepare_notes = linux64_prepare_notes, @@ -437,17 +573,30 @@ struct sysentvec elf_linux_sysvec = { .sv_maxuser = VM_MAXUSER_ADDRESS, .sv_usrstack = LINUX_USRSTACK, .sv_psstringssz = sizeof(struct ps_strings), +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + .sv_stackprot = VM_PROT_RW_CAP, +#else .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE, +#endif .sv_copyout_auxargs = __linuxN(copyout_auxargs), .sv_copyout_strings = __linuxN(copyout_strings), .sv_setregs = linux_exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + .sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_DISCIGN | + SV_SIG_WAITNDQ | SV_TIMEKEEP | SV_CHERI, +#else .sv_flags = SV_ABI_LINUX | SV_LP64 | SV_SHP | SV_SIG_DISCIGN | SV_SIG_WAITNDQ | SV_TIMEKEEP, +#endif .sv_set_syscall_retval = linux_set_syscall_retval, .sv_fetch_syscall_args = linux_fetch_syscall_args, +#ifdef COMPAT_LINUX64 + .sv_syscallnames = linux64_syscallnames, +#else .sv_syscallnames = linux_syscallnames, +#endif .sv_shared_page_base = LINUX_SHAREDPAGE, .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = linux_schedtail, @@ -480,7 +629,7 @@ linux_on_exec_vmspace(struct proc *p, struct image_params *imgp) static void linux_exec_sysvec_init(void *param) { - l_uintptr_t *ktimekeep_base; + l_ulong *ktimekeep_base; struct sysentvec *sv; ptrdiff_t tkoff; @@ -489,7 +638,7 @@ linux_exec_sysvec_init(void *param) exec_sysvec_init(sv); tkoff = kern_timekeep_base - linux_vdso_base; - ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff); + ktimekeep_base = (l_ulong *)(linux_vdso_mapping + tkoff); *ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset; } SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY, @@ -498,8 +647,8 @@ SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY, static void linux_vdso_install(const void *param) { - char *vdso_start = &_binary_linux_vdso_so_o_start; - char *vdso_end = &_binary_linux_vdso_so_o_end; + char *vdso_start = _binary_linux_vdso_so_o_start; + char *vdso_end = _binary_linux_vdso_so_o_end; linux_szsigcode = vdso_end - vdso_start; MPASS(linux_szsigcode <= LINUX_VDSOPAGE_SIZE); @@ -577,7 +726,7 @@ linux_vdso_reloc(char *mapping, Elf_Addr offset) } } -static Elf_Brandnote linux64_brandnote = { +static Elf_Brandnote linux_brandnote = { .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), .hdr.n_descsz = 16, .hdr.n_type = 1, @@ -586,26 +735,26 @@ static Elf_Brandnote linux64_brandnote = { .trans_osrel = linux_trans_osrel }; -static Elf64_Brandinfo linux_glibc2brand = { +static Elf_Brandinfo linux_glibc2brand = { .brand = ELFOSABI_LINUX, .machine = EM_AARCH64, .compat_3_brand = "Linux", .interp_path = "/lib64/ld-linux-x86-64.so.2", .sysvec = &elf_linux_sysvec, .interp_newpath = NULL, - .brand_note = &linux64_brandnote, + .brand_note = &linux_brandnote, .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE }; -Elf64_Brandinfo *linux_brandlist[] = { +Elf_Brandinfo *linux_brandlist[] = { &linux_glibc2brand, NULL }; static int -linux64_elf_modevent(module_t mod, int type, void *data) +linux_elf_modevent(module_t mod, int type, void *data) { - Elf64_Brandinfo **brandinfo; + Elf_Brandinfo **brandinfo; struct linux_ioctl_handler**lihp; int error; @@ -614,7 +763,7 @@ linux64_elf_modevent(module_t mod, int type, void *data) case MOD_LOAD: for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; ++brandinfo) - if (elf64_insert_brand_entry(*brandinfo) < 0) + if (__elfN(insert_brand_entry)(*brandinfo) < 0) error = EINVAL; if (error == 0) { SET_FOREACH(lihp, linux_ioctl_handler_set) @@ -627,12 +776,12 @@ linux64_elf_modevent(module_t mod, int type, void *data) case MOD_UNLOAD: for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; ++brandinfo) - if (elf64_brand_inuse(*brandinfo)) + if (__elfN(brand_inuse)(*brandinfo)) error = EBUSY; if (error == 0) { for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; ++brandinfo) - if (elf64_remove_brand_entry(*brandinfo) < 0) + if (__elfN(remove_brand_entry)(*brandinfo) < 0) error = EINVAL; } if (error == 0) { @@ -649,12 +798,22 @@ linux64_elf_modevent(module_t mod, int type, void *data) return (error); } -static moduledata_t linux64_elf_mod = { +static moduledata_t linux_elf_mod = { +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + "linux64celf", +#else "linux64elf", - linux64_elf_modevent, +#endif + linux_elf_modevent, 0 }; -DECLARE_MODULE_TIED(linux64elf, linux64_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) +DECLARE_MODULE_TIED(linux64celf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); +MODULE_DEPEND(linux64celf, linux_common, 1, 1, 1); +FEATURE(linux64c, "AArch64 Linux 64bit CheriABI support"); +#else +DECLARE_MODULE_TIED(linux64elf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); MODULE_DEPEND(linux64elf, linux_common, 1, 1, 1); FEATURE(linux64, "AArch64 Linux 64bit support"); +#endif diff --git a/sys/arm64/linux/linux_vdso_gtod.c b/sys/arm64/linux/linux_vdso_gtod.c index f7def68d88c4..19d8de94fb1f 100644 --- a/sys/arm64/linux/linux_vdso_gtod.c +++ b/sys/arm64/linux/linux_vdso_gtod.c @@ -38,8 +38,13 @@ #include #include +#ifdef COMPAT_LINUX64 +#include +#include +#else #include -#include +#include +#endif #include #include @@ -83,7 +88,7 @@ __vdso_clock_gettime_fallback(clockid_t clock_id, struct l_timespec *lts) static int __vdso_gettimeofday_fallback(l_timeval *ltv, struct timezone *ltz) { - register long svc asm("x8") = LINUX_SYS_gettimeofday; + register long svc asm("x8") = LINUX_SYS_linux_gettimeofday; register l_timeval *tv asm("x0") = ltv; register struct timezone *tz asm("x1") = ltz; register long res asm ("x0"); diff --git a/sys/arm64/linux/syscalls.conf b/sys/arm64/linux/syscalls.conf index 2c6c1e45f8d9..4c6c3c694fae 100644 --- a/sys/arm64/linux/syscalls.conf +++ b/sys/arm64/linux/syscalls.conf @@ -8,3 +8,5 @@ switchname="linux_sysent" namesname="linux_syscallnames" systrace="linux_systrace_args.c" compat_set="" +ptr_qualified="* __capability " +abi_intptr_t="intcap_t" \ No newline at end of file diff --git a/sys/arm64/linux/syscalls.master b/sys/arm64/linux/syscalls.master index 79c04c398e00..aef7aca5556c 100644 --- a/sys/arm64/linux/syscalls.master +++ b/sys/arm64/linux/syscalls.master @@ -161,7 +161,7 @@ int linux_fcntl( l_uint fd, l_uint cmd, - l_ulong arg + l_uintptr_t arg ); } 26 AUE_NULL STD { @@ -179,7 +179,7 @@ int linux_ioctl( l_uint fd, l_uint cmd, - l_ulong arg + l_uintptr_t arg ); } 30 AUE_SETPRIORITY STD { @@ -310,8 +310,8 @@ int fd ); } -51 AUE_CHROOT NOPROTO { - int chroot( +51 AUE_CHROOT STD { + int linux_chroot( char *path ); } @@ -381,8 +381,8 @@ l_int whence ); } -63 AUE_NULL NOPROTO { - int read( +63 AUE_NULL STD { + int linux_read( int fd, char *buf, l_size_t nbyte @@ -395,8 +395,8 @@ l_size_t nbyte ); } -65 AUE_READV NOPROTO { - int readv( +65 AUE_READV STD { + int linux_readv( int fd, struct iovec *iovp, u_int iovcnt @@ -501,7 +501,7 @@ int linux_newfstatat( l_int dfd, char *pathname, - struct l_stat64 *statbuf, + struct l_newstat *statbuf, l_int flag ); } @@ -558,8 +558,8 @@ l_int flags ); } -89 AUE_ACCT NOPROTO { - int acct( +89 AUE_ACCT STD { + int linux_acct( char *path ); } @@ -726,8 +726,8 @@ int linux_ptrace( l_long req, l_long pid, - l_ulong addr, - l_ulong data + l_uintptr_t addr, + l_uintptr_t data ); } 118 AUE_SCHED_SETPARAM STD { @@ -909,11 +909,11 @@ uid_t suid ); } -148 AUE_GETRESUID NOPROTO { - int getresuid( - uid_t *ruid, - uid_t *euid, - uid_t *suid +148 AUE_GETRESUID STD { + int linux_getresuid( + l_uid_t *ruid, + l_uid_t *euid, + l_uid_t *suid ); } 149 AUE_SETRESGID NOPROTO { @@ -923,11 +923,11 @@ gid_t sgid ); } -150 AUE_GETRESGID NOPROTO { - int getresgid( - gid_t *rgid, - gid_t *egid, - gid_t *sgid +150 AUE_GETRESGID STD { + int linux_getresgid( + l_gid_t *rgid, + l_gid_t *egid, + l_gid_t *sgid ); } 151 AUE_SETFSUID STD { @@ -1005,9 +1005,9 @@ struct l_rlimit *rlim ); } -165 AUE_GETRUSAGE NOPROTO { - int getrusage( - int who, +165 AUE_GETRUSAGE STD { + int linux_getrusage( + l_int who, struct rusage *rusage ); } @@ -1032,15 +1032,15 @@ void *cache ); } -169 AUE_NULL NOPROTO { - int gettimeofday( - struct l_timeval *tp, +169 AUE_NULL STD { + int linux_gettimeofday( + l_timeval *tp, struct timezone *tzp ); } -170 AUE_SETTIMEOFDAY NOPROTO { - int settimeofday( - struct l_timeval *tv, +170 AUE_SETTIMEOFDAY STD { + int linux_settimeofday( + l_timeval *tv, struct timezone *tzp ); } @@ -1170,8 +1170,8 @@ struct l_timespec *timeout ); } -193 AUE_NULL NOPROTO { - int semop( +193 AUE_NULL STD { + int linux_semop( l_int semid, struct sembuf *sops, l_size_t nsops @@ -1323,19 +1323,19 @@ l_ulong dsend ); } -215 AUE_MUNMAP NOPROTO { - int munmap( +215 AUE_MUNMAP STD { + int linux_munmap( void *addr, l_size_t len ); } 216 AUE_NULL STD { int linux_mremap( - l_ulong addr, + void *addr, l_ulong old_len, l_ulong new_len, l_ulong flags, - l_ulong new_addr + void *new_addr ); } 217 AUE_NULL STD { @@ -1350,9 +1350,9 @@ 220 AUE_RFORK STD { int linux_clone( l_ulong flags, - l_ulong stack, + l_uintptr_t stack, l_int *parent_tidptr, - l_ulong tls, + l_uintptr_t tls, l_int *child_tidptr ); } @@ -1365,7 +1365,7 @@ } 222 AUE_MMAP STD { int linux_mmap2( - l_ulong addr, + void *addr, l_ulong len, l_ulong prot, l_ulong flags, @@ -1381,8 +1381,8 @@ l_int advice ); } -224 AUE_SWAPON NOPROTO { - int swapon( +224 AUE_SWAPON STD { + int linux_swapon( char *name ); } @@ -1391,28 +1391,28 @@ } 226 AUE_MPROTECT STD { int linux_mprotect( - l_ulong addr, + void *addr, l_size_t len, l_ulong prot ); } 227 AUE_MSYNC STD { int linux_msync( - l_ulong addr, + void *addr, l_size_t len, l_int fl ); } -228 AUE_MLOCK NOPROTO { - int mlock( +228 AUE_MLOCK STD { + int linux_mlock( const void *addr, - size_t len + l_size_t len ); } -229 AUE_MUNLOCK NOPROTO { - int munlock( +229 AUE_MUNLOCK STD { + int linux_munlock( const void *addr, - size_t len + l_size_t len ); } 230 AUE_MLOCKALL NOPROTO { @@ -1425,14 +1425,14 @@ } 232 AUE_MINCORE STD { int linux_mincore( - l_ulong start, + void *start, l_size_t len, u_char *vec ); } 233 AUE_MADVISE STD { int linux_madvise( - l_ulong addr, + void *addr, l_size_t len, l_int behav ); @@ -1653,7 +1653,7 @@ } 284 AUE_NULL STD { int linux_mlock2( - l_ulong start, + void *start, l_size_t len, l_int flags ); diff --git a/sys/arm64/linux64/Makefile b/sys/arm64/linux64/Makefile new file mode 100755 index 000000000000..9b475f9cfcbf --- /dev/null +++ b/sys/arm64/linux64/Makefile @@ -0,0 +1,7 @@ +# Makefile for syscall tables +# + +GENERATED_PREFIX= linux64_ + +.include "../../conf/sysent.mk" + diff --git a/sys/arm64/linux64/linux.h b/sys/arm64/linux64/linux.h new file mode 100755 index 000000000000..206de116c9ab --- /dev/null +++ b/sys/arm64/linux64/linux.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1994-1996 Søren Schmidt + * Copyright (c) 2013 Dmitry Chagin + * Copyright (c) 2018 Turing Robotic Industries Inc. + * + * 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. + */ + +#ifndef _ARM64_LINUX64_LINUX_H_ +#define _ARM64_LINUX64_LINUX_H_ + +#include "../linux/linux.h" + +struct iovec; +struct uio; +struct l_iovec64 { + l_uintptr_t iov_base; + l_size_t iov_len; +}; + +#ifdef _KERNEL +int linux64_copyiniov(struct l_iovec64 * __capability iovp64, + l_ulong iovcnt, struct iovec **iovp, int error); +int linux64_copyinuio(struct l_iovec64 * __capability iovp64, + l_ulong iovcnt, struct uio **uiop); +#endif /* _KERNEL */ + +#endif /* _ARM64_LINUX64_LINUX_H_ */ diff --git a/sys/arm64/linux64/linux64_dummy_machdep.c b/sys/arm64/linux64/linux64_dummy_machdep.c new file mode 100755 index 000000000000..af55466581ae --- /dev/null +++ b/sys/arm64/linux64/linux64_dummy_machdep.c @@ -0,0 +1 @@ +#include "../linux/linux_dummy_machdep.c" diff --git a/sys/arm64/linux64/linux64_genassym.c b/sys/arm64/linux64/linux64_genassym.c new file mode 100755 index 000000000000..ef2d1c6a0738 --- /dev/null +++ b/sys/arm64/linux64/linux64_genassym.c @@ -0,0 +1 @@ +#include "../linux/linux_genassym.c" diff --git a/sys/arm64/linux64/linux64_locore.asm b/sys/arm64/linux64/linux64_locore.asm new file mode 100755 index 000000000000..42e3cabe2b07 --- /dev/null +++ b/sys/arm64/linux64/linux64_locore.asm @@ -0,0 +1 @@ +#include "../linux/linux_locore.asm" diff --git a/sys/arm64/linux64/linux64_machdep.c b/sys/arm64/linux64/linux64_machdep.c new file mode 100755 index 000000000000..f5ca94953945 --- /dev/null +++ b/sys/arm64/linux64/linux64_machdep.c @@ -0,0 +1,96 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 Turing Robotic Industries Inc. + * Copyright (c) 2000 Marcel Moolenaar + * + * 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 "../linux/linux_machdep.c" + +CTASSERT(sizeof(struct l_iovec64) == 16); + +int +linux64_copyiniov(struct l_iovec64 * __capability iovp64, l_ulong iovcnt, + struct iovec **iovp, int error) +{ + struct l_iovec64 iov64; + struct iovec *iov; + uint64_t iovlen; + int i; + *iovp = NULL; + if (iovcnt > UIO_MAXIOV) + return (error); + iovlen = iovcnt * sizeof(struct iovec); + iov = malloc(iovlen, M_IOV, M_WAITOK); + for (i = 0; i < iovcnt; i++) { + error = copyin(&iovp64[i], &iov64, sizeof(struct l_iovec64)); + if (error) { + free(iov, M_IOV); + return (error); + } + IOVEC_INIT_C(&iov[i], __USER_CAP(iov64.iov_base, + iov64.iov_len), iov64.iov_len); + } + *iovp = iov; + return(0); +} + +int +linux64_copyinuio(struct l_iovec64 * __capability iovp, l_ulong iovcnt, + struct uio **uiop) +{ + struct l_iovec64 iov64; + struct iovec *iov; + struct uio *uio; + int error, i; + + *uiop = NULL; + if (iovcnt > UIO_MAXIOV) + return (EINVAL); + uio = allocuio(iovcnt); + iov = uio->uio_iov; + for (i = 0; i < iovcnt; i++) { + error = copyin(&iovp[i], &iov64, sizeof(struct l_iovec64)); + if (error) { + freeuio(uio); + return (error); + } + IOVEC_INIT_C(&iov[i], __USER_CAP(iov64.iov_base, + iov64.iov_len), iov64.iov_len); + } + uio->uio_iovcnt = iovcnt; + uio->uio_segflg = UIO_USERSPACE; + uio->uio_offset = -1; + uio->uio_resid = 0; + for (i = 0; i < iovcnt; i++) { + if (iov->iov_len > SIZE_MAX - uio->uio_resid) { + freeuio(uio); + return (EINVAL); + } + uio->uio_resid += iov->iov_len; + iov++; + } + *uiop = uio; + return (0); +} \ No newline at end of file diff --git a/sys/arm64/linux64/linux64_proto.h b/sys/arm64/linux64/linux64_proto.h new file mode 100755 index 000000000000..48dbcdf44afd --- /dev/null +++ b/sys/arm64/linux64/linux64_proto.h @@ -0,0 +1,1858 @@ +/* + * System call prototypes. + * + * DO NOT EDIT-- this file is automatically @generated. + */ + +#ifndef _LINUX64_SYSPROTO_H_ +#define _LINUX64_SYSPROTO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct proc; + +struct thread; + +#define PAD_(t) (sizeof(syscallarg_t) <= sizeof(t) ? \ + 0 : sizeof(syscallarg_t) - sizeof(t)) + +#if BYTE_ORDER == LITTLE_ENDIAN +#define PADL_(t) 0 +#define PADR_(t) PAD_(t) +#else +#define PADL_(t) PAD_(t) +#define PADR_(t) 0 +#endif + +struct linux_setxattr_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_lsetxattr_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_fsetxattr_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_getxattr_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; +}; +struct linux_lgetxattr_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; +}; +struct linux_fgetxattr_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char value_l_[PADL_(void *)]; void * value; char value_r_[PADR_(void *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; +}; +struct linux_listxattr_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char list_l_[PADL_(char *)]; char * list; char list_r_[PADR_(char *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; +}; +struct linux_llistxattr_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char list_l_[PADL_(char *)]; char * list; char list_r_[PADR_(char *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; +}; +struct linux_flistxattr_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char list_l_[PADL_(char *)]; char * list; char list_r_[PADR_(char *)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; +}; +struct linux_removexattr_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; +}; +struct linux_lremovexattr_args { + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; +}; +struct linux_fremovexattr_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; +}; +struct linux_getcwd_args { + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char bufsize_l_[PADL_(l_ulong)]; l_ulong bufsize; char bufsize_r_[PADR_(l_ulong)]; +}; +struct linux_lookup_dcookie_args { + syscallarg_t dummy; +}; +struct linux_eventfd2_args { + char initval_l_[PADL_(l_uint)]; l_uint initval; char initval_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_epoll_create1_args { + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_epoll_ctl_args { + char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; + char op_l_[PADL_(l_int)]; l_int op; char op_r_[PADR_(l_int)]; + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char event_l_[PADL_(struct epoll_event *)]; struct epoll_event * event; char event_r_[PADR_(struct epoll_event *)]; +}; +struct linux_epoll_pwait_args { + char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; + char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; + char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; + char timeout_l_[PADL_(l_int)]; l_int timeout; char timeout_r_[PADR_(l_int)]; + char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; + char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; +}; +struct linux_dup3_args { + char oldfd_l_[PADL_(l_int)]; l_int oldfd; char oldfd_r_[PADR_(l_int)]; + char newfd_l_[PADL_(l_int)]; l_int newfd; char newfd_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_fcntl_args { + char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; + char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; + char arg_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg; char arg_r_[PADR_(l_uintptr_t)]; +}; +struct linux_inotify_init1_args { + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_inotify_add_watch_args { + syscallarg_t dummy; +}; +struct linux_inotify_rm_watch_args { + syscallarg_t dummy; +}; +struct linux_ioctl_args { + char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; + char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; + char arg_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg; char arg_r_[PADR_(l_uintptr_t)]; +}; +struct linux_ioprio_set_args { + char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; + char who_l_[PADL_(l_int)]; l_int who; char who_r_[PADR_(l_int)]; + char ioprio_l_[PADL_(l_int)]; l_int ioprio; char ioprio_r_[PADR_(l_int)]; +}; +struct linux_ioprio_get_args { + char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; + char who_l_[PADL_(l_int)]; l_int who; char who_r_[PADR_(l_int)]; +}; +struct linux_mknodat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; + char dev_l_[PADL_(l_dev_t)]; l_dev_t dev; char dev_r_[PADR_(l_dev_t)]; +}; +struct linux_mkdirat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; +}; +struct linux_unlinkat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; +}; +struct linux_symlinkat_args { + char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; + char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; +}; +struct linux_linkat_args { + char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; + char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; + char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; +}; +struct linux_renameat_args { + char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; + char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; + char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; +}; +struct linux_mount_args { + char specialfile_l_[PADL_(char *)]; char * specialfile; char specialfile_r_[PADR_(char *)]; + char dir_l_[PADL_(char *)]; char * dir; char dir_r_[PADR_(char *)]; + char filesystemtype_l_[PADL_(char *)]; char * filesystemtype; char filesystemtype_r_[PADR_(char *)]; + char rwflag_l_[PADL_(l_ulong)]; l_ulong rwflag; char rwflag_r_[PADR_(l_ulong)]; + char data_l_[PADL_(void *)]; void * data; char data_r_[PADR_(void *)]; +}; +struct linux_pivot_root_args { + syscallarg_t dummy; +}; +struct linux_statfs_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; +}; +struct linux_fstatfs_args { + char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; + char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; +}; +struct linux_truncate_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char length_l_[PADL_(l_ulong)]; l_ulong length; char length_r_[PADR_(l_ulong)]; +}; +struct linux_ftruncate_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char length_l_[PADL_(l_long)]; l_long length; char length_r_[PADR_(l_long)]; +}; +struct linux_fallocate_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; + char len_l_[PADL_(l_loff_t)]; l_loff_t len; char len_r_[PADR_(l_loff_t)]; +}; +struct linux_faccessat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; +}; +struct linux_chdir_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; +}; +struct linux_chroot_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; +}; +struct linux_fchmodat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; +}; +struct linux_fchownat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; + char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; + char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; +}; +struct linux_openat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; +}; +struct linux_vhangup_args { + syscallarg_t dummy; +}; +struct linux_pipe2_args { + char pipefds_l_[PADL_(l_int *)]; l_int * pipefds; char pipefds_r_[PADR_(l_int *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_getdents64_args { + char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; + char dirent_l_[PADL_(void *)]; void * dirent; char dirent_r_[PADR_(void *)]; + char count_l_[PADL_(l_uint)]; l_uint count; char count_r_[PADR_(l_uint)]; +}; +struct linux_lseek_args { + char fdes_l_[PADL_(l_uint)]; l_uint fdes; char fdes_r_[PADR_(l_uint)]; + char off_l_[PADL_(l_off_t)]; l_off_t off; char off_r_[PADR_(l_off_t)]; + char whence_l_[PADL_(l_int)]; l_int whence; char whence_r_[PADR_(l_int)]; +}; +struct linux_read_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; +}; +struct linux_write_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; +}; +struct linux_readv_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char iovp_l_[PADL_(struct iovec *)]; struct iovec * iovp; char iovp_r_[PADR_(struct iovec *)]; + char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)]; +}; +struct linux_writev_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char iovp_l_[PADL_(struct iovec *)]; struct iovec * iovp; char iovp_r_[PADR_(struct iovec *)]; + char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)]; +}; +struct linux_pread_args { + char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; + char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; +}; +struct linux_pwrite_args { + char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char nbyte_l_[PADL_(l_size_t)]; l_size_t nbyte; char nbyte_r_[PADR_(l_size_t)]; + char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; +}; +struct linux_preadv_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; +}; +struct linux_pwritev_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(struct iovec *)]; struct iovec * vec; char vec_r_[PADR_(struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; +}; +struct linux_sendfile_args { + char out_l_[PADL_(l_int)]; l_int out; char out_r_[PADR_(l_int)]; + char in_l_[PADL_(l_int)]; l_int in; char in_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_off_t *)]; l_off_t * offset; char offset_r_[PADR_(l_off_t *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; +}; +struct linux_pselect6_args { + char nfds_l_[PADL_(l_int)]; l_int nfds; char nfds_r_[PADR_(l_int)]; + char readfds_l_[PADL_(l_fd_set *)]; l_fd_set * readfds; char readfds_r_[PADR_(l_fd_set *)]; + char writefds_l_[PADL_(l_fd_set *)]; l_fd_set * writefds; char writefds_r_[PADR_(l_fd_set *)]; + char exceptfds_l_[PADL_(l_fd_set *)]; l_fd_set * exceptfds; char exceptfds_r_[PADR_(l_fd_set *)]; + char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; + char sig_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * sig; char sig_r_[PADR_(l_uintptr_t *)]; +}; +struct linux_ppoll_args { + char fds_l_[PADL_(struct pollfd *)]; struct pollfd * fds; char fds_r_[PADR_(struct pollfd *)]; + char nfds_l_[PADL_(l_uint)]; l_uint nfds; char nfds_r_[PADR_(l_uint)]; + char tsp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tsp; char tsp_r_[PADR_(struct l_timespec *)]; + char sset_l_[PADL_(l_sigset_t *)]; l_sigset_t * sset; char sset_r_[PADR_(l_sigset_t *)]; + char ssize_l_[PADL_(l_size_t)]; l_size_t ssize; char ssize_r_[PADR_(l_size_t)]; +}; +struct linux_signalfd4_args { + syscallarg_t dummy; +}; +struct linux_vmsplice_args { + syscallarg_t dummy; +}; +struct linux_splice_args { + char fd_in_l_[PADL_(int)]; int fd_in; char fd_in_r_[PADR_(int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(int)]; int fd_out; char fd_out_r_[PADR_(int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_tee_args { + syscallarg_t dummy; +}; +struct linux_readlinkat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)]; +}; +struct linux_newfstatat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)]; + char statbuf_l_[PADL_(struct l_newstat *)]; struct l_newstat * statbuf; char statbuf_r_[PADR_(struct l_newstat *)]; + char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; +}; +struct linux_newfstat_args { + char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; + char buf_l_[PADL_(struct l_newstat *)]; struct l_newstat * buf; char buf_r_[PADR_(struct l_newstat *)]; +}; +struct linux_fdatasync_args { + char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)]; +}; +struct linux_sync_file_range_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; + char nbytes_l_[PADL_(l_loff_t)]; l_loff_t nbytes; char nbytes_r_[PADR_(l_loff_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_timerfd_create_args { + char clockid_l_[PADL_(l_int)]; l_int clockid; char clockid_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_timerfd_settime_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char new_value_l_[PADL_(const struct l_itimerspec *)]; const struct l_itimerspec * new_value; char new_value_r_[PADR_(const struct l_itimerspec *)]; + char old_value_l_[PADL_(struct l_itimerspec *)]; struct l_itimerspec * old_value; char old_value_r_[PADR_(struct l_itimerspec *)]; +}; +struct linux_timerfd_gettime_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char old_value_l_[PADL_(struct l_itimerspec *)]; struct l_itimerspec * old_value; char old_value_r_[PADR_(struct l_itimerspec *)]; +}; +struct linux_utimensat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char times_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * times; char times_r_[PADR_(const struct l_timespec *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_acct_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; +}; +struct linux_capget_args { + char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; + char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; +}; +struct linux_capset_args { + char hdrp_l_[PADL_(struct l_user_cap_header *)]; struct l_user_cap_header * hdrp; char hdrp_r_[PADR_(struct l_user_cap_header *)]; + char datap_l_[PADL_(struct l_user_cap_data *)]; struct l_user_cap_data * datap; char datap_r_[PADR_(struct l_user_cap_data *)]; +}; +struct linux_personality_args { + char per_l_[PADL_(l_uint)]; l_uint per; char per_r_[PADR_(l_uint)]; +}; +struct linux_exit_args { + char rval_l_[PADL_(u_int)]; u_int rval; char rval_r_[PADR_(u_int)]; +}; +struct linux_exit_group_args { + char error_code_l_[PADL_(l_int)]; l_int error_code; char error_code_r_[PADR_(l_int)]; +}; +struct linux_waitid_args { + char idtype_l_[PADL_(l_int)]; l_int idtype; char idtype_r_[PADR_(l_int)]; + char id_l_[PADL_(l_pid_t)]; l_pid_t id; char id_r_[PADR_(l_pid_t)]; + char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; + char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; + char rusage_l_[PADL_(struct rusage *)]; struct rusage * rusage; char rusage_r_[PADR_(struct rusage *)]; +}; +struct linux_set_tid_address_args { + char tidptr_l_[PADL_(l_int *)]; l_int * tidptr; char tidptr_r_[PADR_(l_int *)]; +}; +struct linux_unshare_args { + syscallarg_t dummy; +}; +struct linux_sys_futex_args { + char uaddr_l_[PADL_(uint32_t *)]; uint32_t * uaddr; char uaddr_r_[PADR_(uint32_t *)]; + char op_l_[PADL_(l_int)]; l_int op; char op_r_[PADR_(l_int)]; + char val_l_[PADL_(uint32_t)]; uint32_t val; char val_r_[PADR_(uint32_t)]; + char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; + char uaddr2_l_[PADL_(uint32_t *)]; uint32_t * uaddr2; char uaddr2_r_[PADR_(uint32_t *)]; + char val3_l_[PADL_(uint32_t)]; uint32_t val3; char val3_r_[PADR_(uint32_t)]; +}; +struct linux_set_robust_list_args { + char head_l_[PADL_(struct linux_robust_list_head *)]; struct linux_robust_list_head * head; char head_r_[PADR_(struct linux_robust_list_head *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; +}; +struct linux_get_robust_list_args { + char pid_l_[PADL_(l_int)]; l_int pid; char pid_r_[PADR_(l_int)]; + char head_l_[PADL_(struct linux_robust_list_head **)]; struct linux_robust_list_head ** head; char head_r_[PADR_(struct linux_robust_list_head **)]; + char len_l_[PADL_(l_size_t *)]; l_size_t * len; char len_r_[PADR_(l_size_t *)]; +}; +struct linux_nanosleep_args { + char rqtp_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * rqtp; char rqtp_r_[PADR_(const struct l_timespec *)]; + char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; +}; +struct linux_getitimer_args { + char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; + char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; +}; +struct linux_setitimer_args { + char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; + char itv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * itv; char itv_r_[PADR_(struct l_itimerval *)]; + char oitv_l_[PADL_(struct l_itimerval *)]; struct l_itimerval * oitv; char oitv_r_[PADR_(struct l_itimerval *)]; +}; +struct linux_kexec_load_args { + syscallarg_t dummy; +}; +struct linux_init_module_args { + syscallarg_t dummy; +}; +struct linux_delete_module_args { + syscallarg_t dummy; +}; +struct linux_timer_create_args { + char clock_id_l_[PADL_(clockid_t)]; clockid_t clock_id; char clock_id_r_[PADR_(clockid_t)]; + char evp_l_[PADL_(struct l_sigevent *)]; struct l_sigevent * evp; char evp_r_[PADR_(struct l_sigevent *)]; + char timerid_l_[PADL_(l_timer_t *)]; l_timer_t * timerid; char timerid_r_[PADR_(l_timer_t *)]; +}; +struct linux_timer_gettime_args { + char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; + char setting_l_[PADL_(struct itimerspec *)]; struct itimerspec * setting; char setting_r_[PADR_(struct itimerspec *)]; +}; +struct linux_timer_getoverrun_args { + char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; +}; +struct linux_timer_settime_args { + char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char new_l_[PADL_(const struct itimerspec *)]; const struct itimerspec * new; char new_r_[PADR_(const struct itimerspec *)]; + char old_l_[PADL_(struct itimerspec *)]; struct itimerspec * old; char old_r_[PADR_(struct itimerspec *)]; +}; +struct linux_timer_delete_args { + char timerid_l_[PADL_(l_timer_t)]; l_timer_t timerid; char timerid_r_[PADR_(l_timer_t)]; +}; +struct linux_clock_settime_args { + char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; + char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; +}; +struct linux_clock_gettime_args { + char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; + char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; +}; +struct linux_clock_getres_args { + char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; + char tp_l_[PADL_(struct l_timespec *)]; struct l_timespec * tp; char tp_r_[PADR_(struct l_timespec *)]; +}; +struct linux_clock_nanosleep_args { + char which_l_[PADL_(clockid_t)]; clockid_t which; char which_r_[PADR_(clockid_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char rqtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rqtp; char rqtp_r_[PADR_(struct l_timespec *)]; + char rmtp_l_[PADL_(struct l_timespec *)]; struct l_timespec * rmtp; char rmtp_r_[PADR_(struct l_timespec *)]; +}; +struct linux_syslog_args { + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; +}; +struct linux_ptrace_args { + char req_l_[PADL_(l_long)]; l_long req; char req_r_[PADR_(l_long)]; + char pid_l_[PADL_(l_long)]; l_long pid; char pid_r_[PADR_(l_long)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char data_l_[PADL_(l_uintptr_t)]; l_uintptr_t data; char data_r_[PADR_(l_uintptr_t)]; +}; +struct linux_sched_setparam_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; +}; +struct linux_sched_setscheduler_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; + char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; +}; +struct linux_sched_getscheduler_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; +}; +struct linux_sched_getparam_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char param_l_[PADL_(struct sched_param *)]; struct sched_param * param; char param_r_[PADR_(struct sched_param *)]; +}; +struct linux_sched_setaffinity_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; + char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; +}; +struct linux_sched_getaffinity_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; + char user_mask_ptr_l_[PADL_(l_ulong *)]; l_ulong * user_mask_ptr; char user_mask_ptr_r_[PADR_(l_ulong *)]; +}; +struct linux_sched_get_priority_max_args { + char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; +}; +struct linux_sched_get_priority_min_args { + char policy_l_[PADL_(l_int)]; l_int policy; char policy_r_[PADR_(l_int)]; +}; +struct linux_sched_rr_get_interval_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char interval_l_[PADL_(struct l_timespec *)]; struct l_timespec * interval; char interval_r_[PADR_(struct l_timespec *)]; +}; +struct linux_kill_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char signum_l_[PADL_(l_int)]; l_int signum; char signum_r_[PADR_(l_int)]; +}; +struct linux_tkill_args { + char tid_l_[PADL_(l_pid_t)]; l_pid_t tid; char tid_r_[PADR_(l_pid_t)]; + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; +}; +struct linux_tgkill_args { + char tgid_l_[PADL_(l_pid_t)]; l_pid_t tgid; char tgid_r_[PADR_(l_pid_t)]; + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; +}; +struct linux_sigaltstack_args { + char uss_l_[PADL_(l_stack_t *)]; l_stack_t * uss; char uss_r_[PADR_(l_stack_t *)]; + char uoss_l_[PADL_(l_stack_t *)]; l_stack_t * uoss; char uoss_r_[PADR_(l_stack_t *)]; +}; +struct linux_rt_sigsuspend_args { + char newset_l_[PADL_(l_sigset_t *)]; l_sigset_t * newset; char newset_r_[PADR_(l_sigset_t *)]; + char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; +}; +struct linux_rt_sigaction_args { + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; + char act_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * act; char act_r_[PADR_(l_sigaction_t *)]; + char oact_l_[PADL_(l_sigaction_t *)]; l_sigaction_t * oact; char oact_r_[PADR_(l_sigaction_t *)]; + char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; +}; +struct linux_rt_sigprocmask_args { + char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; + char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; + char omask_l_[PADL_(l_sigset_t *)]; l_sigset_t * omask; char omask_r_[PADR_(l_sigset_t *)]; + char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; +}; +struct linux_rt_sigpending_args { + char set_l_[PADL_(l_sigset_t *)]; l_sigset_t * set; char set_r_[PADR_(l_sigset_t *)]; + char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; +}; +struct linux_rt_sigtimedwait_args { + char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; + char ptr_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * ptr; char ptr_r_[PADR_(l_siginfo_t *)]; + char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; + char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; +}; +struct linux_rt_sigqueueinfo_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; + char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; +}; +struct linux_rt_sigreturn_args { + syscallarg_t dummy; +}; +struct linux_getpriority_args { + char which_l_[PADL_(l_int)]; l_int which; char which_r_[PADR_(l_int)]; + char who_l_[PADL_(l_int)]; l_int who; char who_r_[PADR_(l_int)]; +}; +struct linux_reboot_args { + char magic1_l_[PADL_(l_int)]; l_int magic1; char magic1_r_[PADR_(l_int)]; + char magic2_l_[PADL_(l_int)]; l_int magic2; char magic2_r_[PADR_(l_int)]; + char cmd_l_[PADL_(l_uint)]; l_uint cmd; char cmd_r_[PADR_(l_uint)]; + char arg_l_[PADL_(void *)]; void * arg; char arg_r_[PADR_(void *)]; +}; +struct linux_getresuid_args { + char ruid_l_[PADL_(l_uid_t *)]; l_uid_t * ruid; char ruid_r_[PADR_(l_uid_t *)]; + char euid_l_[PADL_(l_uid_t *)]; l_uid_t * euid; char euid_r_[PADR_(l_uid_t *)]; + char suid_l_[PADL_(l_uid_t *)]; l_uid_t * suid; char suid_r_[PADR_(l_uid_t *)]; +}; +struct linux_getresgid_args { + char rgid_l_[PADL_(l_gid_t *)]; l_gid_t * rgid; char rgid_r_[PADR_(l_gid_t *)]; + char egid_l_[PADL_(l_gid_t *)]; l_gid_t * egid; char egid_r_[PADR_(l_gid_t *)]; + char sgid_l_[PADL_(l_gid_t *)]; l_gid_t * sgid; char sgid_r_[PADR_(l_gid_t *)]; +}; +struct linux_setfsuid_args { + char uid_l_[PADL_(l_uid_t)]; l_uid_t uid; char uid_r_[PADR_(l_uid_t)]; +}; +struct linux_setfsgid_args { + char gid_l_[PADL_(l_gid_t)]; l_gid_t gid; char gid_r_[PADR_(l_gid_t)]; +}; +struct linux_times_args { + char buf_l_[PADL_(struct l_times_argv *)]; struct l_times_argv * buf; char buf_r_[PADR_(struct l_times_argv *)]; +}; +struct linux_getsid_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; +}; +struct linux_getgroups_args { + char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; + char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; +}; +struct linux_setgroups_args { + char gidsetsize_l_[PADL_(l_int)]; l_int gidsetsize; char gidsetsize_r_[PADR_(l_int)]; + char grouplist_l_[PADL_(l_gid_t *)]; l_gid_t * grouplist; char grouplist_r_[PADR_(l_gid_t *)]; +}; +struct linux_newuname_args { + char buf_l_[PADL_(struct l_new_utsname *)]; struct l_new_utsname * buf; char buf_r_[PADR_(struct l_new_utsname *)]; +}; +struct linux_sethostname_args { + char hostname_l_[PADL_(char *)]; char * hostname; char hostname_r_[PADR_(char *)]; + char len_l_[PADL_(l_uint)]; l_uint len; char len_r_[PADR_(l_uint)]; +}; +struct linux_setdomainname_args { + char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; + char len_l_[PADL_(l_int)]; l_int len; char len_r_[PADR_(l_int)]; +}; +struct linux_getrlimit_args { + char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; + char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; +}; +struct linux_setrlimit_args { + char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; + char rlim_l_[PADL_(struct l_rlimit *)]; struct l_rlimit * rlim; char rlim_r_[PADR_(struct l_rlimit *)]; +}; +struct linux_getrusage_args { + char who_l_[PADL_(l_int)]; l_int who; char who_r_[PADR_(l_int)]; + char rusage_l_[PADL_(struct rusage *)]; struct rusage * rusage; char rusage_r_[PADR_(struct rusage *)]; +}; +struct linux_prctl_args { + char option_l_[PADL_(l_int)]; l_int option; char option_r_[PADR_(l_int)]; + char arg2_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg2; char arg2_r_[PADR_(l_uintptr_t)]; + char arg3_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg3; char arg3_r_[PADR_(l_uintptr_t)]; + char arg4_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg4; char arg4_r_[PADR_(l_uintptr_t)]; + char arg5_l_[PADL_(l_uintptr_t)]; l_uintptr_t arg5; char arg5_r_[PADR_(l_uintptr_t)]; +}; +struct linux_getcpu_args { + char cpu_l_[PADL_(l_uint *)]; l_uint * cpu; char cpu_r_[PADR_(l_uint *)]; + char node_l_[PADL_(l_uint *)]; l_uint * node; char node_r_[PADR_(l_uint *)]; + char cache_l_[PADL_(void *)]; void * cache; char cache_r_[PADR_(void *)]; +}; +struct linux_gettimeofday_args { + char tp_l_[PADL_(l_timeval *)]; l_timeval * tp; char tp_r_[PADR_(l_timeval *)]; + char tzp_l_[PADL_(struct timezone *)]; struct timezone * tzp; char tzp_r_[PADR_(struct timezone *)]; +}; +struct linux_settimeofday_args { + char tv_l_[PADL_(l_timeval *)]; l_timeval * tv; char tv_r_[PADR_(l_timeval *)]; + char tzp_l_[PADL_(struct timezone *)]; struct timezone * tzp; char tzp_r_[PADR_(struct timezone *)]; +}; +struct linux_adjtimex_args { + syscallarg_t dummy; +}; +struct linux_getpid_args { + syscallarg_t dummy; +}; +struct linux_getppid_args { + syscallarg_t dummy; +}; +struct linux_getuid_args { + syscallarg_t dummy; +}; +struct linux_getgid_args { + syscallarg_t dummy; +}; +struct linux_gettid_args { + syscallarg_t dummy; +}; +struct linux_sysinfo_args { + char info_l_[PADL_(struct l_sysinfo *)]; struct l_sysinfo * info; char info_r_[PADR_(struct l_sysinfo *)]; +}; +struct linux_mq_open_args { + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char oflag_l_[PADL_(l_int)]; l_int oflag; char oflag_r_[PADR_(l_int)]; + char mode_l_[PADL_(l_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)]; + char attr_l_[PADL_(struct mq_attr *)]; struct mq_attr * attr; char attr_r_[PADR_(struct mq_attr *)]; +}; +struct linux_mq_unlink_args { + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; +}; +struct linux_mq_timedsend_args { + char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; + char msg_ptr_l_[PADL_(const char *)]; const char * msg_ptr; char msg_ptr_r_[PADR_(const char *)]; + char msg_len_l_[PADL_(l_size_t)]; l_size_t msg_len; char msg_len_r_[PADR_(l_size_t)]; + char msg_prio_l_[PADL_(l_uint)]; l_uint msg_prio; char msg_prio_r_[PADR_(l_uint)]; + char abs_timeout_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec *)]; +}; +struct linux_mq_timedreceive_args { + char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; + char msg_ptr_l_[PADL_(char *)]; char * msg_ptr; char msg_ptr_r_[PADR_(char *)]; + char msg_len_l_[PADL_(l_size_t)]; l_size_t msg_len; char msg_len_r_[PADR_(l_size_t)]; + char msg_prio_l_[PADL_(l_uint *)]; l_uint * msg_prio; char msg_prio_r_[PADR_(l_uint *)]; + char abs_timeout_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * abs_timeout; char abs_timeout_r_[PADR_(const struct l_timespec *)]; +}; +struct linux_mq_notify_args { + char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; + char sevp_l_[PADL_(const struct l_sigevent *)]; const struct l_sigevent * sevp; char sevp_r_[PADR_(const struct l_sigevent *)]; +}; +struct linux_mq_getsetattr_args { + char mqd_l_[PADL_(l_mqd_t)]; l_mqd_t mqd; char mqd_r_[PADR_(l_mqd_t)]; + char attr_l_[PADL_(const struct mq_attr *)]; const struct mq_attr * attr; char attr_r_[PADR_(const struct mq_attr *)]; + char oattr_l_[PADL_(struct mq_attr *)]; struct mq_attr * oattr; char oattr_r_[PADR_(struct mq_attr *)]; +}; +struct linux_msgget_args { + char key_l_[PADL_(l_key_t)]; l_key_t key; char key_r_[PADR_(l_key_t)]; + char msgflg_l_[PADL_(l_int)]; l_int msgflg; char msgflg_r_[PADR_(l_int)]; +}; +struct linux_msgctl_args { + char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char buf_l_[PADL_(struct l_msqid_ds *)]; struct l_msqid_ds * buf; char buf_r_[PADR_(struct l_msqid_ds *)]; +}; +struct linux_msgrcv_args { + char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; + char msgp_l_[PADL_(struct l_msgbuf *)]; struct l_msgbuf * msgp; char msgp_r_[PADR_(struct l_msgbuf *)]; + char msgsz_l_[PADL_(l_size_t)]; l_size_t msgsz; char msgsz_r_[PADR_(l_size_t)]; + char msgtyp_l_[PADL_(l_long)]; l_long msgtyp; char msgtyp_r_[PADR_(l_long)]; + char msgflg_l_[PADL_(l_int)]; l_int msgflg; char msgflg_r_[PADR_(l_int)]; +}; +struct linux_msgsnd_args { + char msqid_l_[PADL_(l_int)]; l_int msqid; char msqid_r_[PADR_(l_int)]; + char msgp_l_[PADL_(struct l_msgbuf *)]; struct l_msgbuf * msgp; char msgp_r_[PADR_(struct l_msgbuf *)]; + char msgsz_l_[PADL_(l_size_t)]; l_size_t msgsz; char msgsz_r_[PADR_(l_size_t)]; + char msgflg_l_[PADL_(l_int)]; l_int msgflg; char msgflg_r_[PADR_(l_int)]; +}; +struct linux_semget_args { + char key_l_[PADL_(l_key_t)]; l_key_t key; char key_r_[PADR_(l_key_t)]; + char nsems_l_[PADL_(l_int)]; l_int nsems; char nsems_r_[PADR_(l_int)]; + char semflg_l_[PADL_(l_int)]; l_int semflg; char semflg_r_[PADR_(l_int)]; +}; +struct linux_semctl_args { + char semid_l_[PADL_(l_int)]; l_int semid; char semid_r_[PADR_(l_int)]; + char semnum_l_[PADL_(l_int)]; l_int semnum; char semnum_r_[PADR_(l_int)]; + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char arg_l_[PADL_(union l_semun)]; union l_semun arg; char arg_r_[PADR_(union l_semun)]; +}; +struct linux_semtimedop_args { + char semid_l_[PADL_(l_int)]; l_int semid; char semid_r_[PADR_(l_int)]; + char tsops_l_[PADL_(struct sembuf *)]; struct sembuf * tsops; char tsops_r_[PADR_(struct sembuf *)]; + char nsops_l_[PADL_(l_size_t)]; l_size_t nsops; char nsops_r_[PADR_(l_size_t)]; + char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; +}; +struct linux_semop_args { + char semid_l_[PADL_(l_int)]; l_int semid; char semid_r_[PADR_(l_int)]; + char sops_l_[PADL_(struct sembuf *)]; struct sembuf * sops; char sops_r_[PADR_(struct sembuf *)]; + char nsops_l_[PADL_(l_size_t)]; l_size_t nsops; char nsops_r_[PADR_(l_size_t)]; +}; +struct linux_shmget_args { + char key_l_[PADL_(l_key_t)]; l_key_t key; char key_r_[PADR_(l_key_t)]; + char size_l_[PADL_(l_size_t)]; l_size_t size; char size_r_[PADR_(l_size_t)]; + char shmflg_l_[PADL_(l_int)]; l_int shmflg; char shmflg_r_[PADR_(l_int)]; +}; +struct linux_shmctl_args { + char shmid_l_[PADL_(l_int)]; l_int shmid; char shmid_r_[PADR_(l_int)]; + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char buf_l_[PADL_(struct l_shmid_ds *)]; struct l_shmid_ds * buf; char buf_r_[PADR_(struct l_shmid_ds *)]; +}; +struct linux_shmat_args { + char shmid_l_[PADL_(l_int)]; l_int shmid; char shmid_r_[PADR_(l_int)]; + char shmaddr_l_[PADL_(char *)]; char * shmaddr; char shmaddr_r_[PADR_(char *)]; + char shmflg_l_[PADL_(l_int)]; l_int shmflg; char shmflg_r_[PADR_(l_int)]; +}; +struct linux_shmdt_args { + char shmaddr_l_[PADL_(char *)]; char * shmaddr; char shmaddr_r_[PADR_(char *)]; +}; +struct linux_socket_args { + char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; +}; +struct linux_socketpair_args { + char domain_l_[PADL_(l_int)]; l_int domain; char domain_r_[PADR_(l_int)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char protocol_l_[PADL_(l_int)]; l_int protocol; char protocol_r_[PADR_(l_int)]; + char rsv_l_[PADL_(l_uintptr_t)]; l_uintptr_t rsv; char rsv_r_[PADR_(l_uintptr_t)]; +}; +struct linux_bind_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; +}; +struct linux_listen_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char backlog_l_[PADL_(l_int)]; l_int backlog; char backlog_r_[PADR_(l_int)]; +}; +struct linux_accept_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_connect_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char name_l_[PADL_(l_uintptr_t)]; l_uintptr_t name; char name_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_int)]; l_int namelen; char namelen_r_[PADR_(l_int)]; +}; +struct linux_getsockname_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_getpeername_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_sendto_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; + char to_l_[PADL_(l_uintptr_t)]; l_uintptr_t to; char to_r_[PADR_(l_uintptr_t)]; + char tolen_l_[PADL_(l_int)]; l_int tolen; char tolen_r_[PADR_(l_int)]; +}; +struct linux_recvfrom_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char buf_l_[PADL_(l_uintptr_t)]; l_uintptr_t buf; char buf_r_[PADR_(l_uintptr_t)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; + char from_l_[PADL_(l_uintptr_t)]; l_uintptr_t from; char from_r_[PADR_(l_uintptr_t)]; + char fromlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t fromlen; char fromlen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_setsockopt_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; + char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; + char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; + char optlen_l_[PADL_(l_int)]; l_int optlen; char optlen_r_[PADR_(l_int)]; +}; +struct linux_getsockopt_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char level_l_[PADL_(l_int)]; l_int level; char level_r_[PADR_(l_int)]; + char optname_l_[PADL_(l_int)]; l_int optname; char optname_r_[PADR_(l_int)]; + char optval_l_[PADL_(l_uintptr_t)]; l_uintptr_t optval; char optval_r_[PADR_(l_uintptr_t)]; + char optlen_l_[PADL_(l_uintptr_t)]; l_uintptr_t optlen; char optlen_r_[PADR_(l_uintptr_t)]; +}; +struct linux_shutdown_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char how_l_[PADL_(l_int)]; l_int how; char how_r_[PADR_(l_int)]; +}; +struct linux_sendmsg_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_recvmsg_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(l_uintptr_t)]; l_uintptr_t msg; char msg_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_brk_args { + char dsend_l_[PADL_(l_ulong)]; l_ulong dsend; char dsend_r_[PADR_(l_ulong)]; +}; +struct linux_munmap_args { + char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; +}; +struct linux_mremap_args { + char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char old_len_l_[PADL_(l_ulong)]; l_ulong old_len; char old_len_r_[PADR_(l_ulong)]; + char new_len_l_[PADL_(l_ulong)]; l_ulong new_len; char new_len_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; + char new_addr_l_[PADL_(l_ulong)]; l_ulong new_addr; char new_addr_r_[PADR_(l_ulong)]; +}; +struct linux_add_key_args { + syscallarg_t dummy; +}; +struct linux_request_key_args { + syscallarg_t dummy; +}; +struct linux_keyctl_args { + syscallarg_t dummy; +}; +struct linux_clone_args { + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; + char stack_l_[PADL_(l_ulong)]; l_ulong stack; char stack_r_[PADR_(l_ulong)]; + char parent_tidptr_l_[PADL_(l_int *)]; l_int * parent_tidptr; char parent_tidptr_r_[PADR_(l_int *)]; + char tls_l_[PADL_(l_ulong)]; l_ulong tls; char tls_r_[PADR_(l_ulong)]; + char child_tidptr_l_[PADL_(l_int *)]; l_int * child_tidptr; char child_tidptr_r_[PADR_(l_int *)]; +}; +struct linux_execve_args { + char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; + char argp_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * argp; char argp_r_[PADR_(l_uintptr_t *)]; + char envp_l_[PADL_(l_uintptr_t *)]; l_uintptr_t * envp; char envp_r_[PADR_(l_uintptr_t *)]; +}; +struct linux_mmap2_args { + char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_ulong)]; l_ulong len; char len_r_[PADR_(l_ulong)]; + char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char pgoff_l_[PADL_(l_ulong)]; l_ulong pgoff; char pgoff_r_[PADR_(l_ulong)]; +}; +struct linux_fadvise64_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char offset_l_[PADL_(l_loff_t)]; l_loff_t offset; char offset_r_[PADR_(l_loff_t)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char advice_l_[PADL_(l_int)]; l_int advice; char advice_r_[PADR_(l_int)]; +}; +struct linux_swapon_args { + char name_l_[PADL_(char *)]; char * name; char name_r_[PADR_(char *)]; +}; +struct linux_swapoff_args { + syscallarg_t dummy; +}; +struct linux_mprotect_args { + char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; +}; +struct linux_msync_args { + char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char fl_l_[PADL_(l_int)]; l_int fl; char fl_r_[PADR_(l_int)]; +}; +struct linux_mlock_args { + char addr_l_[PADL_(const void *)]; const void * addr; char addr_r_[PADR_(const void *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; +}; +struct linux_munlock_args { + char addr_l_[PADL_(const void *)]; const void * addr; char addr_r_[PADR_(const void *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; +}; +struct linux_mincore_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char vec_l_[PADL_(u_char *)]; u_char * vec; char vec_r_[PADR_(u_char *)]; +}; +struct linux_madvise_args { + char addr_l_[PADL_(l_ulong)]; l_ulong addr; char addr_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char behav_l_[PADL_(l_int)]; l_int behav; char behav_r_[PADR_(l_int)]; +}; +struct linux_remap_file_pages_args { + syscallarg_t dummy; +}; +struct linux_mbind_args { + syscallarg_t dummy; +}; +struct linux_get_mempolicy_args { + syscallarg_t dummy; +}; +struct linux_set_mempolicy_args { + syscallarg_t dummy; +}; +struct linux_migrate_pages_args { + syscallarg_t dummy; +}; +struct linux_move_pages_args { + syscallarg_t dummy; +}; +struct linux_rt_tgsigqueueinfo_args { + char tgid_l_[PADL_(l_pid_t)]; l_pid_t tgid; char tgid_r_[PADR_(l_pid_t)]; + char tid_l_[PADL_(l_pid_t)]; l_pid_t tid; char tid_r_[PADR_(l_pid_t)]; + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; + char uinfo_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * uinfo; char uinfo_r_[PADR_(l_siginfo_t *)]; +}; +struct linux_perf_event_open_args { + syscallarg_t dummy; +}; +struct linux_accept4_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char addr_l_[PADL_(l_uintptr_t)]; l_uintptr_t addr; char addr_r_[PADR_(l_uintptr_t)]; + char namelen_l_[PADL_(l_uintptr_t)]; l_uintptr_t namelen; char namelen_r_[PADR_(l_uintptr_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_recvmmsg_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; + char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; + char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; +}; +struct linux_wait4_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char status_l_[PADL_(l_int *)]; l_int * status; char status_r_[PADR_(l_int *)]; + char options_l_[PADL_(l_int)]; l_int options; char options_r_[PADR_(l_int)]; + char rusage_l_[PADL_(struct rusage *)]; struct rusage * rusage; char rusage_r_[PADR_(struct rusage *)]; +}; +struct linux_prlimit64_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char resource_l_[PADL_(l_uint)]; l_uint resource; char resource_r_[PADR_(l_uint)]; + char new_l_[PADL_(struct rlimit *)]; struct rlimit * new; char new_r_[PADR_(struct rlimit *)]; + char old_l_[PADL_(struct rlimit *)]; struct rlimit * old; char old_r_[PADR_(struct rlimit *)]; +}; +struct linux_fanotify_init_args { + syscallarg_t dummy; +}; +struct linux_fanotify_mark_args { + syscallarg_t dummy; +}; +struct linux_name_to_handle_at_args { + char dirfd_l_[PADL_(l_int)]; l_int dirfd; char dirfd_r_[PADR_(l_int)]; + char name_l_[PADL_(const char *)]; const char * name; char name_r_[PADR_(const char *)]; + char handle_l_[PADL_(struct l_file_handle *)]; struct l_file_handle * handle; char handle_r_[PADR_(struct l_file_handle *)]; + char mnt_id_l_[PADL_(l_int *)]; l_int * mnt_id; char mnt_id_r_[PADR_(l_int *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_open_by_handle_at_args { + char mountdirfd_l_[PADL_(l_int)]; l_int mountdirfd; char mountdirfd_r_[PADR_(l_int)]; + char handle_l_[PADL_(struct l_file_handle *)]; struct l_file_handle * handle; char handle_r_[PADR_(struct l_file_handle *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_clock_adjtime_args { + syscallarg_t dummy; +}; +struct linux_syncfs_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; +}; +struct linux_setns_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char nstype_l_[PADL_(l_int)]; l_int nstype; char nstype_r_[PADR_(l_int)]; +}; +struct linux_sendmmsg_args { + char s_l_[PADL_(l_int)]; l_int s; char s_r_[PADR_(l_int)]; + char msg_l_[PADL_(struct l_mmsghdr *)]; struct l_mmsghdr * msg; char msg_r_[PADR_(struct l_mmsghdr *)]; + char vlen_l_[PADL_(l_uint)]; l_uint vlen; char vlen_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_process_vm_readv_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; + char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; +}; +struct linux_process_vm_writev_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char lvec_l_[PADL_(const struct iovec *)]; const struct iovec * lvec; char lvec_r_[PADR_(const struct iovec *)]; + char liovcnt_l_[PADL_(l_ulong)]; l_ulong liovcnt; char liovcnt_r_[PADR_(l_ulong)]; + char rvec_l_[PADL_(const struct iovec *)]; const struct iovec * rvec; char rvec_r_[PADR_(const struct iovec *)]; + char riovcnt_l_[PADL_(l_ulong)]; l_ulong riovcnt; char riovcnt_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; +}; +struct linux_kcmp_args { + char pid1_l_[PADL_(l_pid_t)]; l_pid_t pid1; char pid1_r_[PADR_(l_pid_t)]; + char pid2_l_[PADL_(l_pid_t)]; l_pid_t pid2; char pid2_r_[PADR_(l_pid_t)]; + char type_l_[PADL_(l_int)]; l_int type; char type_r_[PADR_(l_int)]; + char idx1_l_[PADL_(l_ulong)]; l_ulong idx1; char idx1_r_[PADR_(l_ulong)]; + char idx_l_[PADL_(l_ulong)]; l_ulong idx; char idx_r_[PADR_(l_ulong)]; +}; +struct linux_finit_module_args { + char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; + char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_sched_setattr_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_sched_getattr_args { + char pid_l_[PADL_(l_pid_t)]; l_pid_t pid; char pid_r_[PADR_(l_pid_t)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_renameat2_args { + char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)]; + char oldname_l_[PADL_(const char *)]; const char * oldname; char oldname_r_[PADR_(const char *)]; + char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)]; + char newname_l_[PADL_(const char *)]; const char * newname; char newname_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_seccomp_args { + char op_l_[PADL_(l_uint)]; l_uint op; char op_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; + char uargs_l_[PADL_(const char *)]; const char * uargs; char uargs_r_[PADR_(const char *)]; +}; +struct linux_getrandom_args { + char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)]; + char count_l_[PADL_(l_size_t)]; l_size_t count; char count_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_memfd_create_args { + char uname_ptr_l_[PADL_(const char *)]; const char * uname_ptr; char uname_ptr_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_bpf_args { + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char attr_l_[PADL_(void *)]; void * attr; char attr_r_[PADR_(void *)]; + char size_l_[PADL_(l_uint)]; l_uint size; char size_r_[PADR_(l_uint)]; +}; +struct linux_execveat_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char argv_l_[PADL_(const char **)]; const char ** argv; char argv_r_[PADR_(const char **)]; + char envp_l_[PADL_(const char **)]; const char ** envp; char envp_r_[PADR_(const char **)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_userfaultfd_args { + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_membarrier_args { + char cmd_l_[PADL_(l_int)]; l_int cmd; char cmd_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_mlock2_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_copy_file_range_args { + char fd_in_l_[PADL_(l_int)]; l_int fd_in; char fd_in_r_[PADR_(l_int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(l_int)]; l_int fd_out; char fd_out_r_[PADR_(l_int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_preadv2_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_pwritev2_args { + char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)]; + char vec_l_[PADL_(const struct iovec *)]; const struct iovec * vec; char vec_r_[PADR_(const struct iovec *)]; + char vlen_l_[PADL_(l_ulong)]; l_ulong vlen; char vlen_r_[PADR_(l_ulong)]; + char pos_l_l_[PADL_(l_ulong)]; l_ulong pos_l; char pos_l_r_[PADR_(l_ulong)]; + char pos_h_l_[PADL_(l_ulong)]; l_ulong pos_h; char pos_h_r_[PADR_(l_ulong)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_pkey_mprotect_args { + char start_l_[PADL_(l_ulong)]; l_ulong start; char start_r_[PADR_(l_ulong)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char prot_l_[PADL_(l_ulong)]; l_ulong prot; char prot_r_[PADR_(l_ulong)]; + char pkey_l_[PADL_(l_int)]; l_int pkey; char pkey_r_[PADR_(l_int)]; +}; +struct linux_pkey_alloc_args { + char flags_l_[PADL_(l_ulong)]; l_ulong flags; char flags_r_[PADR_(l_ulong)]; + char init_val_l_[PADL_(l_ulong)]; l_ulong init_val; char init_val_r_[PADR_(l_ulong)]; +}; +struct linux_pkey_free_args { + char pkey_l_[PADL_(l_int)]; l_int pkey; char pkey_r_[PADR_(l_int)]; +}; +struct linux_statx_args { + char dirfd_l_[PADL_(l_int)]; l_int dirfd; char dirfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; + char mask_l_[PADL_(l_uint)]; l_uint mask; char mask_r_[PADR_(l_uint)]; + char statxbuf_l_[PADL_(void *)]; void * statxbuf; char statxbuf_r_[PADR_(void *)]; +}; +struct linux_io_pgetevents_args { + syscallarg_t dummy; +}; +struct linux_rseq_args { + char rseq_l_[PADL_(struct linux_rseq *)]; struct linux_rseq * rseq; char rseq_r_[PADR_(struct linux_rseq *)]; + char rseq_len_l_[PADL_(uint32_t)]; uint32_t rseq_len; char rseq_len_r_[PADR_(uint32_t)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; + char sig_l_[PADL_(uint32_t)]; uint32_t sig; char sig_r_[PADR_(uint32_t)]; +}; +struct linux_kexec_file_load_args { + syscallarg_t dummy; +}; +struct linux_pidfd_send_signal_args { + char pidfd_l_[PADL_(l_int)]; l_int pidfd; char pidfd_r_[PADR_(l_int)]; + char sig_l_[PADL_(l_int)]; l_int sig; char sig_r_[PADR_(l_int)]; + char info_l_[PADL_(l_siginfo_t *)]; l_siginfo_t * info; char info_r_[PADR_(l_siginfo_t *)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_io_uring_setup_args { + syscallarg_t dummy; +}; +struct linux_io_uring_enter_args { + syscallarg_t dummy; +}; +struct linux_io_uring_register_args { + syscallarg_t dummy; +}; +struct linux_open_tree_args { + syscallarg_t dummy; +}; +struct linux_move_mount_args { + syscallarg_t dummy; +}; +struct linux_fsopen_args { + syscallarg_t dummy; +}; +struct linux_fsconfig_args { + syscallarg_t dummy; +}; +struct linux_fsmount_args { + syscallarg_t dummy; +}; +struct linux_fspick_args { + syscallarg_t dummy; +}; +struct linux_pidfd_open_args { + syscallarg_t dummy; +}; +struct linux_clone3_args { + char uargs_l_[PADL_(struct l_user_clone_args *)]; struct l_user_clone_args * uargs; char uargs_r_[PADR_(struct l_user_clone_args *)]; + char usize_l_[PADL_(l_size_t)]; l_size_t usize; char usize_r_[PADR_(l_size_t)]; +}; +struct linux_close_range_args { + char first_l_[PADL_(l_uint)]; l_uint first; char first_r_[PADR_(l_uint)]; + char last_l_[PADL_(l_uint)]; l_uint last; char last_r_[PADR_(l_uint)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; +}; +struct linux_openat2_args { + syscallarg_t dummy; +}; +struct linux_pidfd_getfd_args { + syscallarg_t dummy; +}; +struct linux_faccessat2_args { + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char filename_l_[PADL_(const char *)]; const char * filename; char filename_r_[PADR_(const char *)]; + char amode_l_[PADL_(l_int)]; l_int amode; char amode_r_[PADR_(l_int)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; +}; +struct linux_process_madvise_args { + syscallarg_t dummy; +}; +struct linux_epoll_pwait2_args { + char epfd_l_[PADL_(l_int)]; l_int epfd; char epfd_r_[PADR_(l_int)]; + char events_l_[PADL_(struct epoll_event *)]; struct epoll_event * events; char events_r_[PADR_(struct epoll_event *)]; + char maxevents_l_[PADL_(l_int)]; l_int maxevents; char maxevents_r_[PADR_(l_int)]; + char timeout_l_[PADL_(struct l_timespec *)]; struct l_timespec * timeout; char timeout_r_[PADR_(struct l_timespec *)]; + char mask_l_[PADL_(l_sigset_t *)]; l_sigset_t * mask; char mask_r_[PADR_(l_sigset_t *)]; + char sigsetsize_l_[PADL_(l_size_t)]; l_size_t sigsetsize; char sigsetsize_r_[PADR_(l_size_t)]; +}; +struct linux_mount_setattr_args { + syscallarg_t dummy; +}; +struct linux_quotactl_fd_args { + syscallarg_t dummy; +}; +struct linux_landlock_create_ruleset_args { + syscallarg_t dummy; +}; +struct linux_landlock_add_rule_args { + syscallarg_t dummy; +}; +struct linux_landlock_restrict_self_args { + syscallarg_t dummy; +}; +struct linux_memfd_secret_args { + syscallarg_t dummy; +}; +struct linux_process_mrelease_args { + syscallarg_t dummy; +}; +struct linux_futex_waitv_args { + syscallarg_t dummy; +}; +struct linux_set_mempolicy_home_node_args { + syscallarg_t dummy; +}; +struct linux_cachestat_args { + syscallarg_t dummy; +}; +struct linux_fchmodat2_args { + syscallarg_t dummy; +}; +int linux_setxattr(struct thread *, struct linux_setxattr_args *); +int linux_lsetxattr(struct thread *, struct linux_lsetxattr_args *); +int linux_fsetxattr(struct thread *, struct linux_fsetxattr_args *); +int linux_getxattr(struct thread *, struct linux_getxattr_args *); +int linux_lgetxattr(struct thread *, struct linux_lgetxattr_args *); +int linux_fgetxattr(struct thread *, struct linux_fgetxattr_args *); +int linux_listxattr(struct thread *, struct linux_listxattr_args *); +int linux_llistxattr(struct thread *, struct linux_llistxattr_args *); +int linux_flistxattr(struct thread *, struct linux_flistxattr_args *); +int linux_removexattr(struct thread *, struct linux_removexattr_args *); +int linux_lremovexattr(struct thread *, struct linux_lremovexattr_args *); +int linux_fremovexattr(struct thread *, struct linux_fremovexattr_args *); +int linux_getcwd(struct thread *, struct linux_getcwd_args *); +int linux_lookup_dcookie(struct thread *, struct linux_lookup_dcookie_args *); +int linux_eventfd2(struct thread *, struct linux_eventfd2_args *); +int linux_epoll_create1(struct thread *, struct linux_epoll_create1_args *); +int linux_epoll_ctl(struct thread *, struct linux_epoll_ctl_args *); +int linux_epoll_pwait(struct thread *, struct linux_epoll_pwait_args *); +int linux_dup3(struct thread *, struct linux_dup3_args *); +int linux_fcntl(struct thread *, struct linux_fcntl_args *); +int linux_inotify_init1(struct thread *, struct linux_inotify_init1_args *); +int linux_inotify_add_watch(struct thread *, struct linux_inotify_add_watch_args *); +int linux_inotify_rm_watch(struct thread *, struct linux_inotify_rm_watch_args *); +int linux_ioctl(struct thread *, struct linux_ioctl_args *); +int linux_ioprio_set(struct thread *, struct linux_ioprio_set_args *); +int linux_ioprio_get(struct thread *, struct linux_ioprio_get_args *); +int linux_mknodat(struct thread *, struct linux_mknodat_args *); +int linux_mkdirat(struct thread *, struct linux_mkdirat_args *); +int linux_unlinkat(struct thread *, struct linux_unlinkat_args *); +int linux_symlinkat(struct thread *, struct linux_symlinkat_args *); +int linux_linkat(struct thread *, struct linux_linkat_args *); +int linux_renameat(struct thread *, struct linux_renameat_args *); +int linux_mount(struct thread *, struct linux_mount_args *); +int linux_pivot_root(struct thread *, struct linux_pivot_root_args *); +int linux_statfs(struct thread *, struct linux_statfs_args *); +int linux_fstatfs(struct thread *, struct linux_fstatfs_args *); +int linux_truncate(struct thread *, struct linux_truncate_args *); +int linux_ftruncate(struct thread *, struct linux_ftruncate_args *); +int linux_fallocate(struct thread *, struct linux_fallocate_args *); +int linux_faccessat(struct thread *, struct linux_faccessat_args *); +int linux_chdir(struct thread *, struct linux_chdir_args *); +int linux_chroot(struct thread *, struct linux_chroot_args *); +int linux_fchmodat(struct thread *, struct linux_fchmodat_args *); +int linux_fchownat(struct thread *, struct linux_fchownat_args *); +int linux_openat(struct thread *, struct linux_openat_args *); +int linux_vhangup(struct thread *, struct linux_vhangup_args *); +int linux_pipe2(struct thread *, struct linux_pipe2_args *); +int linux_getdents64(struct thread *, struct linux_getdents64_args *); +int linux_lseek(struct thread *, struct linux_lseek_args *); +int linux_read(struct thread *, struct linux_read_args *); +int linux_write(struct thread *, struct linux_write_args *); +int linux_readv(struct thread *, struct linux_readv_args *); +int linux_writev(struct thread *, struct linux_writev_args *); +int linux_pread(struct thread *, struct linux_pread_args *); +int linux_pwrite(struct thread *, struct linux_pwrite_args *); +int linux_preadv(struct thread *, struct linux_preadv_args *); +int linux_pwritev(struct thread *, struct linux_pwritev_args *); +int linux_sendfile(struct thread *, struct linux_sendfile_args *); +int linux_pselect6(struct thread *, struct linux_pselect6_args *); +int linux_ppoll(struct thread *, struct linux_ppoll_args *); +int linux_signalfd4(struct thread *, struct linux_signalfd4_args *); +int linux_vmsplice(struct thread *, struct linux_vmsplice_args *); +int linux_splice(struct thread *, struct linux_splice_args *); +int linux_tee(struct thread *, struct linux_tee_args *); +int linux_readlinkat(struct thread *, struct linux_readlinkat_args *); +int linux_newfstatat(struct thread *, struct linux_newfstatat_args *); +int linux_newfstat(struct thread *, struct linux_newfstat_args *); +int linux_fdatasync(struct thread *, struct linux_fdatasync_args *); +int linux_sync_file_range(struct thread *, struct linux_sync_file_range_args *); +int linux_timerfd_create(struct thread *, struct linux_timerfd_create_args *); +int linux_timerfd_settime(struct thread *, struct linux_timerfd_settime_args *); +int linux_timerfd_gettime(struct thread *, struct linux_timerfd_gettime_args *); +int linux_utimensat(struct thread *, struct linux_utimensat_args *); +int linux_acct(struct thread *, struct linux_acct_args *); +int linux_capget(struct thread *, struct linux_capget_args *); +int linux_capset(struct thread *, struct linux_capset_args *); +int linux_personality(struct thread *, struct linux_personality_args *); +int linux_exit(struct thread *, struct linux_exit_args *); +int linux_exit_group(struct thread *, struct linux_exit_group_args *); +int linux_waitid(struct thread *, struct linux_waitid_args *); +int linux_set_tid_address(struct thread *, struct linux_set_tid_address_args *); +int linux_unshare(struct thread *, struct linux_unshare_args *); +int linux_sys_futex(struct thread *, struct linux_sys_futex_args *); +int linux_set_robust_list(struct thread *, struct linux_set_robust_list_args *); +int linux_get_robust_list(struct thread *, struct linux_get_robust_list_args *); +int linux_nanosleep(struct thread *, struct linux_nanosleep_args *); +int linux_getitimer(struct thread *, struct linux_getitimer_args *); +int linux_setitimer(struct thread *, struct linux_setitimer_args *); +int linux_kexec_load(struct thread *, struct linux_kexec_load_args *); +int linux_init_module(struct thread *, struct linux_init_module_args *); +int linux_delete_module(struct thread *, struct linux_delete_module_args *); +int linux_timer_create(struct thread *, struct linux_timer_create_args *); +int linux_timer_gettime(struct thread *, struct linux_timer_gettime_args *); +int linux_timer_getoverrun(struct thread *, struct linux_timer_getoverrun_args *); +int linux_timer_settime(struct thread *, struct linux_timer_settime_args *); +int linux_timer_delete(struct thread *, struct linux_timer_delete_args *); +int linux_clock_settime(struct thread *, struct linux_clock_settime_args *); +int linux_clock_gettime(struct thread *, struct linux_clock_gettime_args *); +int linux_clock_getres(struct thread *, struct linux_clock_getres_args *); +int linux_clock_nanosleep(struct thread *, struct linux_clock_nanosleep_args *); +int linux_syslog(struct thread *, struct linux_syslog_args *); +int linux_ptrace(struct thread *, struct linux_ptrace_args *); +int linux_sched_setparam(struct thread *, struct linux_sched_setparam_args *); +int linux_sched_setscheduler(struct thread *, struct linux_sched_setscheduler_args *); +int linux_sched_getscheduler(struct thread *, struct linux_sched_getscheduler_args *); +int linux_sched_getparam(struct thread *, struct linux_sched_getparam_args *); +int linux_sched_setaffinity(struct thread *, struct linux_sched_setaffinity_args *); +int linux_sched_getaffinity(struct thread *, struct linux_sched_getaffinity_args *); +int linux_sched_get_priority_max(struct thread *, struct linux_sched_get_priority_max_args *); +int linux_sched_get_priority_min(struct thread *, struct linux_sched_get_priority_min_args *); +int linux_sched_rr_get_interval(struct thread *, struct linux_sched_rr_get_interval_args *); +int linux_kill(struct thread *, struct linux_kill_args *); +int linux_tkill(struct thread *, struct linux_tkill_args *); +int linux_tgkill(struct thread *, struct linux_tgkill_args *); +int linux_sigaltstack(struct thread *, struct linux_sigaltstack_args *); +int linux_rt_sigsuspend(struct thread *, struct linux_rt_sigsuspend_args *); +int linux_rt_sigaction(struct thread *, struct linux_rt_sigaction_args *); +int linux_rt_sigprocmask(struct thread *, struct linux_rt_sigprocmask_args *); +int linux_rt_sigpending(struct thread *, struct linux_rt_sigpending_args *); +int linux_rt_sigtimedwait(struct thread *, struct linux_rt_sigtimedwait_args *); +int linux_rt_sigqueueinfo(struct thread *, struct linux_rt_sigqueueinfo_args *); +int linux_rt_sigreturn(struct thread *, struct linux_rt_sigreturn_args *); +int linux_getpriority(struct thread *, struct linux_getpriority_args *); +int linux_reboot(struct thread *, struct linux_reboot_args *); +int linux_getresuid(struct thread *, struct linux_getresuid_args *); +int linux_getresgid(struct thread *, struct linux_getresgid_args *); +int linux_setfsuid(struct thread *, struct linux_setfsuid_args *); +int linux_setfsgid(struct thread *, struct linux_setfsgid_args *); +int linux_times(struct thread *, struct linux_times_args *); +int linux_getsid(struct thread *, struct linux_getsid_args *); +int linux_getgroups(struct thread *, struct linux_getgroups_args *); +int linux_setgroups(struct thread *, struct linux_setgroups_args *); +int linux_newuname(struct thread *, struct linux_newuname_args *); +int linux_sethostname(struct thread *, struct linux_sethostname_args *); +int linux_setdomainname(struct thread *, struct linux_setdomainname_args *); +int linux_getrlimit(struct thread *, struct linux_getrlimit_args *); +int linux_setrlimit(struct thread *, struct linux_setrlimit_args *); +int linux_getrusage(struct thread *, struct linux_getrusage_args *); +int linux_prctl(struct thread *, struct linux_prctl_args *); +int linux_getcpu(struct thread *, struct linux_getcpu_args *); +int linux_gettimeofday(struct thread *, struct linux_gettimeofday_args *); +int linux_settimeofday(struct thread *, struct linux_settimeofday_args *); +int linux_adjtimex(struct thread *, struct linux_adjtimex_args *); +int linux_getpid(struct thread *, struct linux_getpid_args *); +int linux_getppid(struct thread *, struct linux_getppid_args *); +int linux_getuid(struct thread *, struct linux_getuid_args *); +int linux_getgid(struct thread *, struct linux_getgid_args *); +int linux_gettid(struct thread *, struct linux_gettid_args *); +int linux_sysinfo(struct thread *, struct linux_sysinfo_args *); +int linux_mq_open(struct thread *, struct linux_mq_open_args *); +int linux_mq_unlink(struct thread *, struct linux_mq_unlink_args *); +int linux_mq_timedsend(struct thread *, struct linux_mq_timedsend_args *); +int linux_mq_timedreceive(struct thread *, struct linux_mq_timedreceive_args *); +int linux_mq_notify(struct thread *, struct linux_mq_notify_args *); +int linux_mq_getsetattr(struct thread *, struct linux_mq_getsetattr_args *); +int linux_msgget(struct thread *, struct linux_msgget_args *); +int linux_msgctl(struct thread *, struct linux_msgctl_args *); +int linux_msgrcv(struct thread *, struct linux_msgrcv_args *); +int linux_msgsnd(struct thread *, struct linux_msgsnd_args *); +int linux_semget(struct thread *, struct linux_semget_args *); +int linux_semctl(struct thread *, struct linux_semctl_args *); +int linux_semtimedop(struct thread *, struct linux_semtimedop_args *); +int linux_semop(struct thread *, struct linux_semop_args *); +int linux_shmget(struct thread *, struct linux_shmget_args *); +int linux_shmctl(struct thread *, struct linux_shmctl_args *); +int linux_shmat(struct thread *, struct linux_shmat_args *); +int linux_shmdt(struct thread *, struct linux_shmdt_args *); +int linux_socket(struct thread *, struct linux_socket_args *); +int linux_socketpair(struct thread *, struct linux_socketpair_args *); +int linux_bind(struct thread *, struct linux_bind_args *); +int linux_listen(struct thread *, struct linux_listen_args *); +int linux_accept(struct thread *, struct linux_accept_args *); +int linux_connect(struct thread *, struct linux_connect_args *); +int linux_getsockname(struct thread *, struct linux_getsockname_args *); +int linux_getpeername(struct thread *, struct linux_getpeername_args *); +int linux_sendto(struct thread *, struct linux_sendto_args *); +int linux_recvfrom(struct thread *, struct linux_recvfrom_args *); +int linux_setsockopt(struct thread *, struct linux_setsockopt_args *); +int linux_getsockopt(struct thread *, struct linux_getsockopt_args *); +int linux_shutdown(struct thread *, struct linux_shutdown_args *); +int linux_sendmsg(struct thread *, struct linux_sendmsg_args *); +int linux_recvmsg(struct thread *, struct linux_recvmsg_args *); +int linux_brk(struct thread *, struct linux_brk_args *); +int linux_munmap(struct thread *, struct linux_munmap_args *); +int linux_mremap(struct thread *, struct linux_mremap_args *); +int linux_add_key(struct thread *, struct linux_add_key_args *); +int linux_request_key(struct thread *, struct linux_request_key_args *); +int linux_keyctl(struct thread *, struct linux_keyctl_args *); +int linux_clone(struct thread *, struct linux_clone_args *); +int linux_execve(struct thread *, struct linux_execve_args *); +int linux_mmap2(struct thread *, struct linux_mmap2_args *); +int linux_fadvise64(struct thread *, struct linux_fadvise64_args *); +int linux_swapon(struct thread *, struct linux_swapon_args *); +int linux_swapoff(struct thread *, struct linux_swapoff_args *); +int linux_mprotect(struct thread *, struct linux_mprotect_args *); +int linux_msync(struct thread *, struct linux_msync_args *); +int linux_mlock(struct thread *, struct linux_mlock_args *); +int linux_munlock(struct thread *, struct linux_munlock_args *); +int linux_mincore(struct thread *, struct linux_mincore_args *); +int linux_madvise(struct thread *, struct linux_madvise_args *); +int linux_remap_file_pages(struct thread *, struct linux_remap_file_pages_args *); +int linux_mbind(struct thread *, struct linux_mbind_args *); +int linux_get_mempolicy(struct thread *, struct linux_get_mempolicy_args *); +int linux_set_mempolicy(struct thread *, struct linux_set_mempolicy_args *); +int linux_migrate_pages(struct thread *, struct linux_migrate_pages_args *); +int linux_move_pages(struct thread *, struct linux_move_pages_args *); +int linux_rt_tgsigqueueinfo(struct thread *, struct linux_rt_tgsigqueueinfo_args *); +int linux_perf_event_open(struct thread *, struct linux_perf_event_open_args *); +int linux_accept4(struct thread *, struct linux_accept4_args *); +int linux_recvmmsg(struct thread *, struct linux_recvmmsg_args *); +int linux_wait4(struct thread *, struct linux_wait4_args *); +int linux_prlimit64(struct thread *, struct linux_prlimit64_args *); +int linux_fanotify_init(struct thread *, struct linux_fanotify_init_args *); +int linux_fanotify_mark(struct thread *, struct linux_fanotify_mark_args *); +int linux_name_to_handle_at(struct thread *, struct linux_name_to_handle_at_args *); +int linux_open_by_handle_at(struct thread *, struct linux_open_by_handle_at_args *); +int linux_clock_adjtime(struct thread *, struct linux_clock_adjtime_args *); +int linux_syncfs(struct thread *, struct linux_syncfs_args *); +int linux_setns(struct thread *, struct linux_setns_args *); +int linux_sendmmsg(struct thread *, struct linux_sendmmsg_args *); +int linux_process_vm_readv(struct thread *, struct linux_process_vm_readv_args *); +int linux_process_vm_writev(struct thread *, struct linux_process_vm_writev_args *); +int linux_kcmp(struct thread *, struct linux_kcmp_args *); +int linux_finit_module(struct thread *, struct linux_finit_module_args *); +int linux_sched_setattr(struct thread *, struct linux_sched_setattr_args *); +int linux_sched_getattr(struct thread *, struct linux_sched_getattr_args *); +int linux_renameat2(struct thread *, struct linux_renameat2_args *); +int linux_seccomp(struct thread *, struct linux_seccomp_args *); +int linux_getrandom(struct thread *, struct linux_getrandom_args *); +int linux_memfd_create(struct thread *, struct linux_memfd_create_args *); +int linux_bpf(struct thread *, struct linux_bpf_args *); +int linux_execveat(struct thread *, struct linux_execveat_args *); +int linux_userfaultfd(struct thread *, struct linux_userfaultfd_args *); +int linux_membarrier(struct thread *, struct linux_membarrier_args *); +int linux_mlock2(struct thread *, struct linux_mlock2_args *); +int linux_copy_file_range(struct thread *, struct linux_copy_file_range_args *); +int linux_preadv2(struct thread *, struct linux_preadv2_args *); +int linux_pwritev2(struct thread *, struct linux_pwritev2_args *); +int linux_pkey_mprotect(struct thread *, struct linux_pkey_mprotect_args *); +int linux_pkey_alloc(struct thread *, struct linux_pkey_alloc_args *); +int linux_pkey_free(struct thread *, struct linux_pkey_free_args *); +int linux_statx(struct thread *, struct linux_statx_args *); +int linux_io_pgetevents(struct thread *, struct linux_io_pgetevents_args *); +int linux_rseq(struct thread *, struct linux_rseq_args *); +int linux_kexec_file_load(struct thread *, struct linux_kexec_file_load_args *); +int linux_pidfd_send_signal(struct thread *, struct linux_pidfd_send_signal_args *); +int linux_io_uring_setup(struct thread *, struct linux_io_uring_setup_args *); +int linux_io_uring_enter(struct thread *, struct linux_io_uring_enter_args *); +int linux_io_uring_register(struct thread *, struct linux_io_uring_register_args *); +int linux_open_tree(struct thread *, struct linux_open_tree_args *); +int linux_move_mount(struct thread *, struct linux_move_mount_args *); +int linux_fsopen(struct thread *, struct linux_fsopen_args *); +int linux_fsconfig(struct thread *, struct linux_fsconfig_args *); +int linux_fsmount(struct thread *, struct linux_fsmount_args *); +int linux_fspick(struct thread *, struct linux_fspick_args *); +int linux_pidfd_open(struct thread *, struct linux_pidfd_open_args *); +int linux_clone3(struct thread *, struct linux_clone3_args *); +int linux_close_range(struct thread *, struct linux_close_range_args *); +int linux_openat2(struct thread *, struct linux_openat2_args *); +int linux_pidfd_getfd(struct thread *, struct linux_pidfd_getfd_args *); +int linux_faccessat2(struct thread *, struct linux_faccessat2_args *); +int linux_process_madvise(struct thread *, struct linux_process_madvise_args *); +int linux_epoll_pwait2(struct thread *, struct linux_epoll_pwait2_args *); +int linux_mount_setattr(struct thread *, struct linux_mount_setattr_args *); +int linux_quotactl_fd(struct thread *, struct linux_quotactl_fd_args *); +int linux_landlock_create_ruleset(struct thread *, struct linux_landlock_create_ruleset_args *); +int linux_landlock_add_rule(struct thread *, struct linux_landlock_add_rule_args *); +int linux_landlock_restrict_self(struct thread *, struct linux_landlock_restrict_self_args *); +int linux_memfd_secret(struct thread *, struct linux_memfd_secret_args *); +int linux_process_mrelease(struct thread *, struct linux_process_mrelease_args *); +int linux_futex_waitv(struct thread *, struct linux_futex_waitv_args *); +int linux_set_mempolicy_home_node(struct thread *, struct linux_set_mempolicy_home_node_args *); +int linux_cachestat(struct thread *, struct linux_cachestat_args *); +int linux_fchmodat2(struct thread *, struct linux_fchmodat2_args *); +#define LINUX64_SYS_AUE_linux_setxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_lsetxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_fsetxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_getxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_lgetxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_fgetxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_listxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_llistxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_flistxattr AUE_NULL +#define LINUX64_SYS_AUE_linux_removexattr AUE_NULL +#define LINUX64_SYS_AUE_linux_lremovexattr AUE_NULL +#define LINUX64_SYS_AUE_linux_fremovexattr AUE_NULL +#define LINUX64_SYS_AUE_linux_getcwd AUE_GETCWD +#define LINUX64_SYS_AUE_linux_lookup_dcookie AUE_NULL +#define LINUX64_SYS_AUE_linux_eventfd2 AUE_NULL +#define LINUX64_SYS_AUE_linux_epoll_create1 AUE_NULL +#define LINUX64_SYS_AUE_linux_epoll_ctl AUE_NULL +#define LINUX64_SYS_AUE_linux_epoll_pwait AUE_NULL +#define LINUX64_SYS_AUE_linux_dup3 AUE_NULL +#define LINUX64_SYS_AUE_linux_fcntl AUE_FCNTL +#define LINUX64_SYS_AUE_linux_inotify_init1 AUE_NULL +#define LINUX64_SYS_AUE_linux_inotify_add_watch AUE_NULL +#define LINUX64_SYS_AUE_linux_inotify_rm_watch AUE_NULL +#define LINUX64_SYS_AUE_linux_ioctl AUE_IOCTL +#define LINUX64_SYS_AUE_linux_ioprio_set AUE_SETPRIORITY +#define LINUX64_SYS_AUE_linux_ioprio_get AUE_GETPRIORITY +#define LINUX64_SYS_AUE_linux_mknodat AUE_MKNODAT +#define LINUX64_SYS_AUE_linux_mkdirat AUE_MKDIRAT +#define LINUX64_SYS_AUE_linux_unlinkat AUE_UNLINKAT +#define LINUX64_SYS_AUE_linux_symlinkat AUE_SYMLINKAT +#define LINUX64_SYS_AUE_linux_linkat AUE_LINKAT +#define LINUX64_SYS_AUE_linux_renameat AUE_RENAMEAT +#define LINUX64_SYS_AUE_linux_mount AUE_MOUNT +#define LINUX64_SYS_AUE_linux_pivot_root AUE_PIVOT_ROOT +#define LINUX64_SYS_AUE_linux_statfs AUE_STATFS +#define LINUX64_SYS_AUE_linux_fstatfs AUE_FSTATFS +#define LINUX64_SYS_AUE_linux_truncate AUE_TRUNCATE +#define LINUX64_SYS_AUE_linux_ftruncate AUE_FTRUNCATE +#define LINUX64_SYS_AUE_linux_fallocate AUE_NULL +#define LINUX64_SYS_AUE_linux_faccessat AUE_FACCESSAT +#define LINUX64_SYS_AUE_linux_chdir AUE_CHDIR +#define LINUX64_SYS_AUE_linux_chroot AUE_CHROOT +#define LINUX64_SYS_AUE_linux_fchmodat AUE_FCHMODAT +#define LINUX64_SYS_AUE_linux_fchownat AUE_FCHOWNAT +#define LINUX64_SYS_AUE_linux_openat AUE_OPEN_RWTC +#define LINUX64_SYS_AUE_linux_vhangup AUE_NULL +#define LINUX64_SYS_AUE_linux_pipe2 AUE_NULL +#define LINUX64_SYS_AUE_linux_getdents64 AUE_GETDIRENTRIES +#define LINUX64_SYS_AUE_linux_lseek AUE_LSEEK +#define LINUX64_SYS_AUE_linux_read AUE_NULL +#define LINUX64_SYS_AUE_linux_write AUE_NULL +#define LINUX64_SYS_AUE_linux_readv AUE_READV +#define LINUX64_SYS_AUE_linux_writev AUE_WRITEV +#define LINUX64_SYS_AUE_linux_pread AUE_PREAD +#define LINUX64_SYS_AUE_linux_pwrite AUE_PWRITE +#define LINUX64_SYS_AUE_linux_preadv AUE_NULL +#define LINUX64_SYS_AUE_linux_pwritev AUE_NULL +#define LINUX64_SYS_AUE_linux_sendfile AUE_SENDFILE +#define LINUX64_SYS_AUE_linux_pselect6 AUE_SELECT +#define LINUX64_SYS_AUE_linux_ppoll AUE_POLL +#define LINUX64_SYS_AUE_linux_signalfd4 AUE_NULL +#define LINUX64_SYS_AUE_linux_vmsplice AUE_NULL +#define LINUX64_SYS_AUE_linux_splice AUE_NULL +#define LINUX64_SYS_AUE_linux_tee AUE_NULL +#define LINUX64_SYS_AUE_linux_readlinkat AUE_READLINKAT +#define LINUX64_SYS_AUE_linux_newfstatat AUE_FSTATAT +#define LINUX64_SYS_AUE_linux_newfstat AUE_FSTAT +#define LINUX64_SYS_AUE_linux_fdatasync AUE_NULL +#define LINUX64_SYS_AUE_linux_sync_file_range AUE_NULL +#define LINUX64_SYS_AUE_linux_timerfd_create AUE_NULL +#define LINUX64_SYS_AUE_linux_timerfd_settime AUE_NULL +#define LINUX64_SYS_AUE_linux_timerfd_gettime AUE_NULL +#define LINUX64_SYS_AUE_linux_utimensat AUE_FUTIMESAT +#define LINUX64_SYS_AUE_linux_acct AUE_ACCT +#define LINUX64_SYS_AUE_linux_capget AUE_CAPGET +#define LINUX64_SYS_AUE_linux_capset AUE_CAPSET +#define LINUX64_SYS_AUE_linux_personality AUE_PERSONALITY +#define LINUX64_SYS_AUE_linux_exit AUE_EXIT +#define LINUX64_SYS_AUE_linux_exit_group AUE_EXIT +#define LINUX64_SYS_AUE_linux_waitid AUE_WAIT6 +#define LINUX64_SYS_AUE_linux_set_tid_address AUE_NULL +#define LINUX64_SYS_AUE_linux_unshare AUE_NULL +#define LINUX64_SYS_AUE_linux_sys_futex AUE_NULL +#define LINUX64_SYS_AUE_linux_set_robust_list AUE_NULL +#define LINUX64_SYS_AUE_linux_get_robust_list AUE_NULL +#define LINUX64_SYS_AUE_linux_nanosleep AUE_NULL +#define LINUX64_SYS_AUE_linux_getitimer AUE_GETITIMER +#define LINUX64_SYS_AUE_linux_setitimer AUE_SETITIMER +#define LINUX64_SYS_AUE_linux_kexec_load AUE_NULL +#define LINUX64_SYS_AUE_linux_init_module AUE_NULL +#define LINUX64_SYS_AUE_linux_delete_module AUE_NULL +#define LINUX64_SYS_AUE_linux_timer_create AUE_NULL +#define LINUX64_SYS_AUE_linux_timer_gettime AUE_NULL +#define LINUX64_SYS_AUE_linux_timer_getoverrun AUE_NULL +#define LINUX64_SYS_AUE_linux_timer_settime AUE_NULL +#define LINUX64_SYS_AUE_linux_timer_delete AUE_NULL +#define LINUX64_SYS_AUE_linux_clock_settime AUE_CLOCK_SETTIME +#define LINUX64_SYS_AUE_linux_clock_gettime AUE_NULL +#define LINUX64_SYS_AUE_linux_clock_getres AUE_NULL +#define LINUX64_SYS_AUE_linux_clock_nanosleep AUE_NULL +#define LINUX64_SYS_AUE_linux_syslog AUE_NULL +#define LINUX64_SYS_AUE_linux_ptrace AUE_PTRACE +#define LINUX64_SYS_AUE_linux_sched_setparam AUE_SCHED_SETPARAM +#define LINUX64_SYS_AUE_linux_sched_setscheduler AUE_SCHED_SETSCHEDULER +#define LINUX64_SYS_AUE_linux_sched_getscheduler AUE_SCHED_GETSCHEDULER +#define LINUX64_SYS_AUE_linux_sched_getparam AUE_SCHED_GETPARAM +#define LINUX64_SYS_AUE_linux_sched_setaffinity AUE_NULL +#define LINUX64_SYS_AUE_linux_sched_getaffinity AUE_NULL +#define LINUX64_SYS_AUE_linux_sched_get_priority_max AUE_SCHED_GET_PRIORITY_MAX +#define LINUX64_SYS_AUE_linux_sched_get_priority_min AUE_SCHED_GET_PRIORITY_MIN +#define LINUX64_SYS_AUE_linux_sched_rr_get_interval AUE_SCHED_RR_GET_INTERVAL +#define LINUX64_SYS_AUE_linux_kill AUE_KILL +#define LINUX64_SYS_AUE_linux_tkill AUE_NULL +#define LINUX64_SYS_AUE_linux_tgkill AUE_NULL +#define LINUX64_SYS_AUE_linux_sigaltstack AUE_NULL +#define LINUX64_SYS_AUE_linux_rt_sigsuspend AUE_NULL +#define LINUX64_SYS_AUE_linux_rt_sigaction AUE_NULL +#define LINUX64_SYS_AUE_linux_rt_sigprocmask AUE_NULL +#define LINUX64_SYS_AUE_linux_rt_sigpending AUE_NULL +#define LINUX64_SYS_AUE_linux_rt_sigtimedwait AUE_NULL +#define LINUX64_SYS_AUE_linux_rt_sigqueueinfo AUE_NULL +#define LINUX64_SYS_AUE_linux_rt_sigreturn AUE_NULL +#define LINUX64_SYS_AUE_linux_getpriority AUE_GETPRIORITY +#define LINUX64_SYS_AUE_linux_reboot AUE_REBOOT +#define LINUX64_SYS_AUE_linux_getresuid AUE_GETRESUID +#define LINUX64_SYS_AUE_linux_getresgid AUE_GETRESGID +#define LINUX64_SYS_AUE_linux_setfsuid AUE_SETFSUID +#define LINUX64_SYS_AUE_linux_setfsgid AUE_SETFSGID +#define LINUX64_SYS_AUE_linux_times AUE_NULL +#define LINUX64_SYS_AUE_linux_getsid AUE_GETSID +#define LINUX64_SYS_AUE_linux_getgroups AUE_GETGROUPS +#define LINUX64_SYS_AUE_linux_setgroups AUE_SETGROUPS +#define LINUX64_SYS_AUE_linux_newuname AUE_NULL +#define LINUX64_SYS_AUE_linux_sethostname AUE_SYSCTL +#define LINUX64_SYS_AUE_linux_setdomainname AUE_SYSCTL +#define LINUX64_SYS_AUE_linux_getrlimit AUE_GETRLIMIT +#define LINUX64_SYS_AUE_linux_setrlimit AUE_SETRLIMIT +#define LINUX64_SYS_AUE_linux_getrusage AUE_GETRUSAGE +#define LINUX64_SYS_AUE_linux_prctl AUE_PRCTL +#define LINUX64_SYS_AUE_linux_getcpu AUE_NULL +#define LINUX64_SYS_AUE_linux_gettimeofday AUE_NULL +#define LINUX64_SYS_AUE_linux_settimeofday AUE_SETTIMEOFDAY +#define LINUX64_SYS_AUE_linux_adjtimex AUE_ADJTIME +#define LINUX64_SYS_AUE_linux_getpid AUE_GETPID +#define LINUX64_SYS_AUE_linux_getppid AUE_GETPPID +#define LINUX64_SYS_AUE_linux_getuid AUE_GETUID +#define LINUX64_SYS_AUE_linux_getgid AUE_GETGID +#define LINUX64_SYS_AUE_linux_gettid AUE_NULL +#define LINUX64_SYS_AUE_linux_sysinfo AUE_NULL +#define LINUX64_SYS_AUE_linux_mq_open AUE_NULL +#define LINUX64_SYS_AUE_linux_mq_unlink AUE_NULL +#define LINUX64_SYS_AUE_linux_mq_timedsend AUE_NULL +#define LINUX64_SYS_AUE_linux_mq_timedreceive AUE_NULL +#define LINUX64_SYS_AUE_linux_mq_notify AUE_NULL +#define LINUX64_SYS_AUE_linux_mq_getsetattr AUE_NULL +#define LINUX64_SYS_AUE_linux_msgget AUE_NULL +#define LINUX64_SYS_AUE_linux_msgctl AUE_NULL +#define LINUX64_SYS_AUE_linux_msgrcv AUE_NULL +#define LINUX64_SYS_AUE_linux_msgsnd AUE_NULL +#define LINUX64_SYS_AUE_linux_semget AUE_NULL +#define LINUX64_SYS_AUE_linux_semctl AUE_NULL +#define LINUX64_SYS_AUE_linux_semtimedop AUE_NULL +#define LINUX64_SYS_AUE_linux_semop AUE_NULL +#define LINUX64_SYS_AUE_linux_shmget AUE_NULL +#define LINUX64_SYS_AUE_linux_shmctl AUE_NULL +#define LINUX64_SYS_AUE_linux_shmat AUE_NULL +#define LINUX64_SYS_AUE_linux_shmdt AUE_NULL +#define LINUX64_SYS_AUE_linux_socket AUE_SOCKET +#define LINUX64_SYS_AUE_linux_socketpair AUE_SOCKETPAIR +#define LINUX64_SYS_AUE_linux_bind AUE_BIND +#define LINUX64_SYS_AUE_linux_listen AUE_LISTEN +#define LINUX64_SYS_AUE_linux_accept AUE_ACCEPT +#define LINUX64_SYS_AUE_linux_connect AUE_CONNECT +#define LINUX64_SYS_AUE_linux_getsockname AUE_GETSOCKNAME +#define LINUX64_SYS_AUE_linux_getpeername AUE_GETPEERNAME +#define LINUX64_SYS_AUE_linux_sendto AUE_SENDTO +#define LINUX64_SYS_AUE_linux_recvfrom AUE_RECVFROM +#define LINUX64_SYS_AUE_linux_setsockopt AUE_SETSOCKOPT +#define LINUX64_SYS_AUE_linux_getsockopt AUE_GETSOCKOPT +#define LINUX64_SYS_AUE_linux_shutdown AUE_NULL +#define LINUX64_SYS_AUE_linux_sendmsg AUE_SENDMSG +#define LINUX64_SYS_AUE_linux_recvmsg AUE_RECVMSG +#define LINUX64_SYS_AUE_linux_brk AUE_NULL +#define LINUX64_SYS_AUE_linux_munmap AUE_MUNMAP +#define LINUX64_SYS_AUE_linux_mremap AUE_NULL +#define LINUX64_SYS_AUE_linux_add_key AUE_NULL +#define LINUX64_SYS_AUE_linux_request_key AUE_NULL +#define LINUX64_SYS_AUE_linux_keyctl AUE_NULL +#define LINUX64_SYS_AUE_linux_clone AUE_RFORK +#define LINUX64_SYS_AUE_linux_execve AUE_EXECVE +#define LINUX64_SYS_AUE_linux_mmap2 AUE_MMAP +#define LINUX64_SYS_AUE_linux_fadvise64 AUE_NULL +#define LINUX64_SYS_AUE_linux_swapon AUE_SWAPON +#define LINUX64_SYS_AUE_linux_swapoff AUE_SWAPOFF +#define LINUX64_SYS_AUE_linux_mprotect AUE_MPROTECT +#define LINUX64_SYS_AUE_linux_msync AUE_MSYNC +#define LINUX64_SYS_AUE_linux_mlock AUE_MLOCK +#define LINUX64_SYS_AUE_linux_munlock AUE_MUNLOCK +#define LINUX64_SYS_AUE_linux_mincore AUE_MINCORE +#define LINUX64_SYS_AUE_linux_madvise AUE_MADVISE +#define LINUX64_SYS_AUE_linux_remap_file_pages AUE_NULL +#define LINUX64_SYS_AUE_linux_mbind AUE_NULL +#define LINUX64_SYS_AUE_linux_get_mempolicy AUE_NULL +#define LINUX64_SYS_AUE_linux_set_mempolicy AUE_NULL +#define LINUX64_SYS_AUE_linux_migrate_pages AUE_NULL +#define LINUX64_SYS_AUE_linux_move_pages AUE_NULL +#define LINUX64_SYS_AUE_linux_rt_tgsigqueueinfo AUE_NULL +#define LINUX64_SYS_AUE_linux_perf_event_open AUE_NULL +#define LINUX64_SYS_AUE_linux_accept4 AUE_ACCEPT +#define LINUX64_SYS_AUE_linux_recvmmsg AUE_NULL +#define LINUX64_SYS_AUE_linux_wait4 AUE_WAIT4 +#define LINUX64_SYS_AUE_linux_prlimit64 AUE_NULL +#define LINUX64_SYS_AUE_linux_fanotify_init AUE_NULL +#define LINUX64_SYS_AUE_linux_fanotify_mark AUE_NULL +#define LINUX64_SYS_AUE_linux_name_to_handle_at AUE_NULL +#define LINUX64_SYS_AUE_linux_open_by_handle_at AUE_NULL +#define LINUX64_SYS_AUE_linux_clock_adjtime AUE_NULL +#define LINUX64_SYS_AUE_linux_syncfs AUE_SYNC +#define LINUX64_SYS_AUE_linux_setns AUE_NULL +#define LINUX64_SYS_AUE_linux_sendmmsg AUE_NULL +#define LINUX64_SYS_AUE_linux_process_vm_readv AUE_NULL +#define LINUX64_SYS_AUE_linux_process_vm_writev AUE_NULL +#define LINUX64_SYS_AUE_linux_kcmp AUE_NULL +#define LINUX64_SYS_AUE_linux_finit_module AUE_NULL +#define LINUX64_SYS_AUE_linux_sched_setattr AUE_NULL +#define LINUX64_SYS_AUE_linux_sched_getattr AUE_NULL +#define LINUX64_SYS_AUE_linux_renameat2 AUE_NULL +#define LINUX64_SYS_AUE_linux_seccomp AUE_NULL +#define LINUX64_SYS_AUE_linux_getrandom AUE_NULL +#define LINUX64_SYS_AUE_linux_memfd_create AUE_NULL +#define LINUX64_SYS_AUE_linux_bpf AUE_NULL +#define LINUX64_SYS_AUE_linux_execveat AUE_NULL +#define LINUX64_SYS_AUE_linux_userfaultfd AUE_NULL +#define LINUX64_SYS_AUE_linux_membarrier AUE_NULL +#define LINUX64_SYS_AUE_linux_mlock2 AUE_NULL +#define LINUX64_SYS_AUE_linux_copy_file_range AUE_NULL +#define LINUX64_SYS_AUE_linux_preadv2 AUE_NULL +#define LINUX64_SYS_AUE_linux_pwritev2 AUE_NULL +#define LINUX64_SYS_AUE_linux_pkey_mprotect AUE_NULL +#define LINUX64_SYS_AUE_linux_pkey_alloc AUE_NULL +#define LINUX64_SYS_AUE_linux_pkey_free AUE_NULL +#define LINUX64_SYS_AUE_linux_statx AUE_NULL +#define LINUX64_SYS_AUE_linux_io_pgetevents AUE_NULL +#define LINUX64_SYS_AUE_linux_rseq AUE_NULL +#define LINUX64_SYS_AUE_linux_kexec_file_load AUE_NULL +#define LINUX64_SYS_AUE_linux_pidfd_send_signal AUE_NULL +#define LINUX64_SYS_AUE_linux_io_uring_setup AUE_NULL +#define LINUX64_SYS_AUE_linux_io_uring_enter AUE_NULL +#define LINUX64_SYS_AUE_linux_io_uring_register AUE_NULL +#define LINUX64_SYS_AUE_linux_open_tree AUE_NULL +#define LINUX64_SYS_AUE_linux_move_mount AUE_NULL +#define LINUX64_SYS_AUE_linux_fsopen AUE_NULL +#define LINUX64_SYS_AUE_linux_fsconfig AUE_NULL +#define LINUX64_SYS_AUE_linux_fsmount AUE_NULL +#define LINUX64_SYS_AUE_linux_fspick AUE_NULL +#define LINUX64_SYS_AUE_linux_pidfd_open AUE_NULL +#define LINUX64_SYS_AUE_linux_clone3 AUE_NULL +#define LINUX64_SYS_AUE_linux_close_range AUE_CLOSERANGE +#define LINUX64_SYS_AUE_linux_openat2 AUE_NULL +#define LINUX64_SYS_AUE_linux_pidfd_getfd AUE_NULL +#define LINUX64_SYS_AUE_linux_faccessat2 AUE_NULL +#define LINUX64_SYS_AUE_linux_process_madvise AUE_NULL +#define LINUX64_SYS_AUE_linux_epoll_pwait2 AUE_NULL +#define LINUX64_SYS_AUE_linux_mount_setattr AUE_NULL +#define LINUX64_SYS_AUE_linux_quotactl_fd AUE_NULL +#define LINUX64_SYS_AUE_linux_landlock_create_ruleset AUE_NULL +#define LINUX64_SYS_AUE_linux_landlock_add_rule AUE_NULL +#define LINUX64_SYS_AUE_linux_landlock_restrict_self AUE_NULL +#define LINUX64_SYS_AUE_linux_memfd_secret AUE_NULL +#define LINUX64_SYS_AUE_linux_process_mrelease AUE_NULL +#define LINUX64_SYS_AUE_linux_futex_waitv AUE_NULL +#define LINUX64_SYS_AUE_linux_set_mempolicy_home_node AUE_NULL +#define LINUX64_SYS_AUE_linux_cachestat AUE_NULL +#define LINUX64_SYS_AUE_linux_fchmodat2 AUE_NULL + +#undef PAD_ +#undef PADL_ +#undef PADR_ + +#endif /* !_LINUX64_SYSPROTO_H_ */ diff --git a/sys/arm64/linux64/linux64_sigframe.h b/sys/arm64/linux64/linux64_sigframe.h new file mode 100755 index 000000000000..578d9ca57bfd --- /dev/null +++ b/sys/arm64/linux64/linux64_sigframe.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 1994-1996 Søren Schmidt + * Copyright (c) 2018 Turing Robotic Industries Inc. + * Copyright (c) 2022 Dmitry Chagin + * + * 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. + */ + +#ifndef _ARM64_LINUX64_SIGFRAME_H_ +#define _ARM64_LINUX64_SIGFRAME_H_ + +#include "../linux/linux_sigframe.h" + +#endif /* _ARM64_LINUX64_SIGFRAME_H_ */ diff --git a/sys/arm64/linux64/linux64_support.S b/sys/arm64/linux64/linux64_support.S new file mode 100755 index 000000000000..d5834cc2baa8 --- /dev/null +++ b/sys/arm64/linux64/linux64_support.S @@ -0,0 +1 @@ +#include "../linux/linux_support.S" \ No newline at end of file diff --git a/sys/arm64/linux64/linux64_syscall.h b/sys/arm64/linux64/linux64_syscall.h new file mode 100755 index 000000000000..404f5797fdc4 --- /dev/null +++ b/sys/arm64/linux64/linux64_syscall.h @@ -0,0 +1,304 @@ +/* + * System call numbers. + * + * DO NOT EDIT-- this file is automatically @generated. + */ + +#define LINUX64_SYS_linux_setxattr 5 +#define LINUX64_SYS_linux_lsetxattr 6 +#define LINUX64_SYS_linux_fsetxattr 7 +#define LINUX64_SYS_linux_getxattr 8 +#define LINUX64_SYS_linux_lgetxattr 9 +#define LINUX64_SYS_linux_fgetxattr 10 +#define LINUX64_SYS_linux_listxattr 11 +#define LINUX64_SYS_linux_llistxattr 12 +#define LINUX64_SYS_linux_flistxattr 13 +#define LINUX64_SYS_linux_removexattr 14 +#define LINUX64_SYS_linux_lremovexattr 15 +#define LINUX64_SYS_linux_fremovexattr 16 +#define LINUX64_SYS_linux_getcwd 17 +#define LINUX64_SYS_linux_lookup_dcookie 18 +#define LINUX64_SYS_linux_eventfd2 19 +#define LINUX64_SYS_linux_epoll_create1 20 +#define LINUX64_SYS_linux_epoll_ctl 21 +#define LINUX64_SYS_linux_epoll_pwait 22 +#define LINUX64_SYS_dup 23 +#define LINUX64_SYS_linux_dup3 24 +#define LINUX64_SYS_linux_fcntl 25 +#define LINUX64_SYS_linux_inotify_init1 26 +#define LINUX64_SYS_linux_inotify_add_watch 27 +#define LINUX64_SYS_linux_inotify_rm_watch 28 +#define LINUX64_SYS_linux_ioctl 29 +#define LINUX64_SYS_linux_ioprio_set 30 +#define LINUX64_SYS_linux_ioprio_get 31 +#define LINUX64_SYS_flock 32 +#define LINUX64_SYS_linux_mknodat 33 +#define LINUX64_SYS_linux_mkdirat 34 +#define LINUX64_SYS_linux_unlinkat 35 +#define LINUX64_SYS_linux_symlinkat 36 +#define LINUX64_SYS_linux_linkat 37 +#define LINUX64_SYS_linux_renameat 38 +#define LINUX64_SYS_linux_mount 40 +#define LINUX64_SYS_linux_pivot_root 41 +#define LINUX64_SYS_linux_statfs 43 +#define LINUX64_SYS_linux_fstatfs 44 +#define LINUX64_SYS_linux_truncate 45 +#define LINUX64_SYS_linux_ftruncate 46 +#define LINUX64_SYS_linux_fallocate 47 +#define LINUX64_SYS_linux_faccessat 48 +#define LINUX64_SYS_linux_chdir 49 +#define LINUX64_SYS_fchdir 50 +#define LINUX64_SYS_linux_chroot 51 +#define LINUX64_SYS_fchmod 52 +#define LINUX64_SYS_linux_fchmodat 53 +#define LINUX64_SYS_linux_fchownat 54 +#define LINUX64_SYS_fchown 55 +#define LINUX64_SYS_linux_openat 56 +#define LINUX64_SYS_close 57 +#define LINUX64_SYS_linux_vhangup 58 +#define LINUX64_SYS_linux_pipe2 59 +#define LINUX64_SYS_linux_getdents64 61 +#define LINUX64_SYS_linux_lseek 62 +#define LINUX64_SYS_linux_read 63 +#define LINUX64_SYS_linux_write 64 +#define LINUX64_SYS_linux_readv 65 +#define LINUX64_SYS_linux_writev 66 +#define LINUX64_SYS_linux_pread 67 +#define LINUX64_SYS_linux_pwrite 68 +#define LINUX64_SYS_linux_preadv 69 +#define LINUX64_SYS_linux_pwritev 70 +#define LINUX64_SYS_linux_sendfile 71 +#define LINUX64_SYS_linux_pselect6 72 +#define LINUX64_SYS_linux_ppoll 73 +#define LINUX64_SYS_linux_signalfd4 74 +#define LINUX64_SYS_linux_vmsplice 75 +#define LINUX64_SYS_linux_splice 76 +#define LINUX64_SYS_linux_tee 77 +#define LINUX64_SYS_linux_readlinkat 78 +#define LINUX64_SYS_linux_newfstatat 79 +#define LINUX64_SYS_linux_newfstat 80 +#define LINUX64_SYS_fsync 82 +#define LINUX64_SYS_linux_fdatasync 83 +#define LINUX64_SYS_linux_sync_file_range 84 +#define LINUX64_SYS_linux_timerfd_create 85 +#define LINUX64_SYS_linux_timerfd_settime 86 +#define LINUX64_SYS_linux_timerfd_gettime 87 +#define LINUX64_SYS_linux_utimensat 88 +#define LINUX64_SYS_linux_acct 89 +#define LINUX64_SYS_linux_capget 90 +#define LINUX64_SYS_linux_capset 91 +#define LINUX64_SYS_linux_personality 92 +#define LINUX64_SYS_linux_exit 93 +#define LINUX64_SYS_linux_exit_group 94 +#define LINUX64_SYS_linux_waitid 95 +#define LINUX64_SYS_linux_set_tid_address 96 +#define LINUX64_SYS_linux_unshare 97 +#define LINUX64_SYS_linux_sys_futex 98 +#define LINUX64_SYS_linux_set_robust_list 99 +#define LINUX64_SYS_linux_get_robust_list 100 +#define LINUX64_SYS_linux_nanosleep 101 +#define LINUX64_SYS_linux_getitimer 102 +#define LINUX64_SYS_linux_setitimer 103 +#define LINUX64_SYS_linux_kexec_load 104 +#define LINUX64_SYS_linux_init_module 105 +#define LINUX64_SYS_linux_delete_module 106 +#define LINUX64_SYS_linux_timer_create 107 +#define LINUX64_SYS_linux_timer_gettime 108 +#define LINUX64_SYS_linux_timer_getoverrun 109 +#define LINUX64_SYS_linux_timer_settime 110 +#define LINUX64_SYS_linux_timer_delete 111 +#define LINUX64_SYS_linux_clock_settime 112 +#define LINUX64_SYS_linux_clock_gettime 113 +#define LINUX64_SYS_linux_clock_getres 114 +#define LINUX64_SYS_linux_clock_nanosleep 115 +#define LINUX64_SYS_linux_syslog 116 +#define LINUX64_SYS_linux_ptrace 117 +#define LINUX64_SYS_linux_sched_setparam 118 +#define LINUX64_SYS_linux_sched_setscheduler 119 +#define LINUX64_SYS_linux_sched_getscheduler 120 +#define LINUX64_SYS_linux_sched_getparam 121 +#define LINUX64_SYS_linux_sched_setaffinity 122 +#define LINUX64_SYS_linux_sched_getaffinity 123 +#define LINUX64_SYS_sched_yield 124 +#define LINUX64_SYS_linux_sched_get_priority_max 125 +#define LINUX64_SYS_linux_sched_get_priority_min 126 +#define LINUX64_SYS_linux_sched_rr_get_interval 127 +#define LINUX64_SYS_linux_kill 129 +#define LINUX64_SYS_linux_tkill 130 +#define LINUX64_SYS_linux_tgkill 131 +#define LINUX64_SYS_linux_sigaltstack 132 +#define LINUX64_SYS_linux_rt_sigsuspend 133 +#define LINUX64_SYS_linux_rt_sigaction 134 +#define LINUX64_SYS_linux_rt_sigprocmask 135 +#define LINUX64_SYS_linux_rt_sigpending 136 +#define LINUX64_SYS_linux_rt_sigtimedwait 137 +#define LINUX64_SYS_linux_rt_sigqueueinfo 138 +#define LINUX64_SYS_linux_rt_sigreturn 139 +#define LINUX64_SYS_setpriority 140 +#define LINUX64_SYS_linux_getpriority 141 +#define LINUX64_SYS_linux_reboot 142 +#define LINUX64_SYS_setregid 143 +#define LINUX64_SYS_setgid 144 +#define LINUX64_SYS_setreuid 145 +#define LINUX64_SYS_setuid 146 +#define LINUX64_SYS_setresuid 147 +#define LINUX64_SYS_linux_getresuid 148 +#define LINUX64_SYS_setresgid 149 +#define LINUX64_SYS_linux_getresgid 150 +#define LINUX64_SYS_linux_setfsuid 151 +#define LINUX64_SYS_linux_setfsgid 152 +#define LINUX64_SYS_linux_times 153 +#define LINUX64_SYS_setpgid 154 +#define LINUX64_SYS_getpgid 155 +#define LINUX64_SYS_linux_getsid 156 +#define LINUX64_SYS_setsid 157 +#define LINUX64_SYS_linux_getgroups 158 +#define LINUX64_SYS_linux_setgroups 159 +#define LINUX64_SYS_linux_newuname 160 +#define LINUX64_SYS_linux_sethostname 161 +#define LINUX64_SYS_linux_setdomainname 162 +#define LINUX64_SYS_linux_getrlimit 163 +#define LINUX64_SYS_linux_setrlimit 164 +#define LINUX64_SYS_linux_getrusage 165 +#define LINUX64_SYS_umask 166 +#define LINUX64_SYS_linux_prctl 167 +#define LINUX64_SYS_linux_getcpu 168 +#define LINUX64_SYS_linux_gettimeofday 169 +#define LINUX64_SYS_linux_settimeofday 170 +#define LINUX64_SYS_linux_adjtimex 171 +#define LINUX64_SYS_linux_getpid 172 +#define LINUX64_SYS_linux_getppid 173 +#define LINUX64_SYS_linux_getuid 174 +#define LINUX64_SYS_geteuid 175 +#define LINUX64_SYS_linux_getgid 176 +#define LINUX64_SYS_getegid 177 +#define LINUX64_SYS_linux_gettid 178 +#define LINUX64_SYS_linux_sysinfo 179 +#define LINUX64_SYS_linux_mq_open 180 +#define LINUX64_SYS_linux_mq_unlink 181 +#define LINUX64_SYS_linux_mq_timedsend 182 +#define LINUX64_SYS_linux_mq_timedreceive 183 +#define LINUX64_SYS_linux_mq_notify 184 +#define LINUX64_SYS_linux_mq_getsetattr 185 +#define LINUX64_SYS_linux_msgget 186 +#define LINUX64_SYS_linux_msgctl 187 +#define LINUX64_SYS_linux_msgrcv 188 +#define LINUX64_SYS_linux_msgsnd 189 +#define LINUX64_SYS_linux_semget 190 +#define LINUX64_SYS_linux_semctl 191 +#define LINUX64_SYS_linux_semtimedop 192 +#define LINUX64_SYS_linux_semop 193 +#define LINUX64_SYS_linux_shmget 194 +#define LINUX64_SYS_linux_shmctl 195 +#define LINUX64_SYS_linux_shmat 196 +#define LINUX64_SYS_linux_shmdt 197 +#define LINUX64_SYS_linux_socket 198 +#define LINUX64_SYS_linux_socketpair 199 +#define LINUX64_SYS_linux_bind 200 +#define LINUX64_SYS_linux_listen 201 +#define LINUX64_SYS_linux_accept 202 +#define LINUX64_SYS_linux_connect 203 +#define LINUX64_SYS_linux_getsockname 204 +#define LINUX64_SYS_linux_getpeername 205 +#define LINUX64_SYS_linux_sendto 206 +#define LINUX64_SYS_linux_recvfrom 207 +#define LINUX64_SYS_linux_setsockopt 208 +#define LINUX64_SYS_linux_getsockopt 209 +#define LINUX64_SYS_linux_shutdown 210 +#define LINUX64_SYS_linux_sendmsg 211 +#define LINUX64_SYS_linux_recvmsg 212 +#define LINUX64_SYS_linux_brk 214 +#define LINUX64_SYS_linux_munmap 215 +#define LINUX64_SYS_linux_mremap 216 +#define LINUX64_SYS_linux_add_key 217 +#define LINUX64_SYS_linux_request_key 218 +#define LINUX64_SYS_linux_keyctl 219 +#define LINUX64_SYS_linux_clone 220 +#define LINUX64_SYS_linux_execve 221 +#define LINUX64_SYS_linux_mmap2 222 +#define LINUX64_SYS_linux_fadvise64 223 +#define LINUX64_SYS_linux_swapon 224 +#define LINUX64_SYS_linux_swapoff 225 +#define LINUX64_SYS_linux_mprotect 226 +#define LINUX64_SYS_linux_msync 227 +#define LINUX64_SYS_linux_mlock 228 +#define LINUX64_SYS_linux_munlock 229 +#define LINUX64_SYS_mlockall 230 +#define LINUX64_SYS_munlockall 231 +#define LINUX64_SYS_linux_mincore 232 +#define LINUX64_SYS_linux_madvise 233 +#define LINUX64_SYS_linux_remap_file_pages 234 +#define LINUX64_SYS_linux_mbind 235 +#define LINUX64_SYS_linux_get_mempolicy 236 +#define LINUX64_SYS_linux_set_mempolicy 237 +#define LINUX64_SYS_linux_migrate_pages 238 +#define LINUX64_SYS_linux_move_pages 239 +#define LINUX64_SYS_linux_rt_tgsigqueueinfo 240 +#define LINUX64_SYS_linux_perf_event_open 241 +#define LINUX64_SYS_linux_accept4 242 +#define LINUX64_SYS_linux_recvmmsg 243 +#define LINUX64_SYS_linux_wait4 260 +#define LINUX64_SYS_linux_prlimit64 261 +#define LINUX64_SYS_linux_fanotify_init 262 +#define LINUX64_SYS_linux_fanotify_mark 263 +#define LINUX64_SYS_linux_name_to_handle_at 264 +#define LINUX64_SYS_linux_open_by_handle_at 265 +#define LINUX64_SYS_linux_clock_adjtime 266 +#define LINUX64_SYS_linux_syncfs 267 +#define LINUX64_SYS_linux_setns 268 +#define LINUX64_SYS_linux_sendmmsg 269 +#define LINUX64_SYS_linux_process_vm_readv 270 +#define LINUX64_SYS_linux_process_vm_writev 271 +#define LINUX64_SYS_linux_kcmp 272 +#define LINUX64_SYS_linux_finit_module 273 +#define LINUX64_SYS_linux_sched_setattr 274 +#define LINUX64_SYS_linux_sched_getattr 275 +#define LINUX64_SYS_linux_renameat2 276 +#define LINUX64_SYS_linux_seccomp 277 +#define LINUX64_SYS_linux_getrandom 278 +#define LINUX64_SYS_linux_memfd_create 279 +#define LINUX64_SYS_linux_bpf 280 +#define LINUX64_SYS_linux_execveat 281 +#define LINUX64_SYS_linux_userfaultfd 282 +#define LINUX64_SYS_linux_membarrier 283 +#define LINUX64_SYS_linux_mlock2 284 +#define LINUX64_SYS_linux_copy_file_range 285 +#define LINUX64_SYS_linux_preadv2 286 +#define LINUX64_SYS_linux_pwritev2 287 +#define LINUX64_SYS_linux_pkey_mprotect 288 +#define LINUX64_SYS_linux_pkey_alloc 289 +#define LINUX64_SYS_linux_pkey_free 290 +#define LINUX64_SYS_linux_statx 291 +#define LINUX64_SYS_linux_io_pgetevents 292 +#define LINUX64_SYS_linux_rseq 293 +#define LINUX64_SYS_linux_kexec_file_load 294 +#define LINUX64_SYS_linux_pidfd_send_signal 424 +#define LINUX64_SYS_linux_io_uring_setup 425 +#define LINUX64_SYS_linux_io_uring_enter 426 +#define LINUX64_SYS_linux_io_uring_register 427 +#define LINUX64_SYS_linux_open_tree 428 +#define LINUX64_SYS_linux_move_mount 429 +#define LINUX64_SYS_linux_fsopen 430 +#define LINUX64_SYS_linux_fsconfig 431 +#define LINUX64_SYS_linux_fsmount 432 +#define LINUX64_SYS_linux_fspick 433 +#define LINUX64_SYS_linux_pidfd_open 434 +#define LINUX64_SYS_linux_clone3 435 +#define LINUX64_SYS_linux_close_range 436 +#define LINUX64_SYS_linux_openat2 437 +#define LINUX64_SYS_linux_pidfd_getfd 438 +#define LINUX64_SYS_linux_faccessat2 439 +#define LINUX64_SYS_linux_process_madvise 440 +#define LINUX64_SYS_linux_epoll_pwait2 441 +#define LINUX64_SYS_linux_mount_setattr 442 +#define LINUX64_SYS_linux_quotactl_fd 443 +#define LINUX64_SYS_linux_landlock_create_ruleset 444 +#define LINUX64_SYS_linux_landlock_add_rule 445 +#define LINUX64_SYS_linux_landlock_restrict_self 446 +#define LINUX64_SYS_linux_memfd_secret 447 +#define LINUX64_SYS_linux_process_mrelease 448 +#define LINUX64_SYS_linux_futex_waitv 449 +#define LINUX64_SYS_linux_set_mempolicy_home_node 450 +#define LINUX64_SYS_linux_cachestat 451 +#define LINUX64_SYS_linux_fchmodat2 452 +#define LINUX64_SYS_MAXSYSCALL 453 diff --git a/sys/arm64/linux64/linux64_syscalls.c b/sys/arm64/linux64/linux64_syscalls.c new file mode 100755 index 000000000000..b4dbae3914f0 --- /dev/null +++ b/sys/arm64/linux64/linux64_syscalls.c @@ -0,0 +1,461 @@ +/* + * System call names. + * + * DO NOT EDIT-- this file is automatically @generated. + */ + +const char *linux64_syscallnames[] = { + "#0", /* 0 = linux_io_setup */ + "#1", /* 1 = linux_io_destroy */ + "#2", /* 2 = linux_io_submit */ + "#3", /* 3 = linux_io_cancel */ + "#4", /* 4 = linux_io_getevents */ + "linux_setxattr", /* 5 = linux_setxattr */ + "linux_lsetxattr", /* 6 = linux_lsetxattr */ + "linux_fsetxattr", /* 7 = linux_fsetxattr */ + "linux_getxattr", /* 8 = linux_getxattr */ + "linux_lgetxattr", /* 9 = linux_lgetxattr */ + "linux_fgetxattr", /* 10 = linux_fgetxattr */ + "linux_listxattr", /* 11 = linux_listxattr */ + "linux_llistxattr", /* 12 = linux_llistxattr */ + "linux_flistxattr", /* 13 = linux_flistxattr */ + "linux_removexattr", /* 14 = linux_removexattr */ + "linux_lremovexattr", /* 15 = linux_lremovexattr */ + "linux_fremovexattr", /* 16 = linux_fremovexattr */ + "linux_getcwd", /* 17 = linux_getcwd */ + "linux_lookup_dcookie", /* 18 = linux_lookup_dcookie */ + "linux_eventfd2", /* 19 = linux_eventfd2 */ + "linux_epoll_create1", /* 20 = linux_epoll_create1 */ + "linux_epoll_ctl", /* 21 = linux_epoll_ctl */ + "linux_epoll_pwait", /* 22 = linux_epoll_pwait */ + "dup", /* 23 = dup */ + "linux_dup3", /* 24 = linux_dup3 */ + "linux_fcntl", /* 25 = linux_fcntl */ + "linux_inotify_init1", /* 26 = linux_inotify_init1 */ + "linux_inotify_add_watch", /* 27 = linux_inotify_add_watch */ + "linux_inotify_rm_watch", /* 28 = linux_inotify_rm_watch */ + "linux_ioctl", /* 29 = linux_ioctl */ + "linux_ioprio_set", /* 30 = linux_ioprio_set */ + "linux_ioprio_get", /* 31 = linux_ioprio_get */ + "flock", /* 32 = flock */ + "linux_mknodat", /* 33 = linux_mknodat */ + "linux_mkdirat", /* 34 = linux_mkdirat */ + "linux_unlinkat", /* 35 = linux_unlinkat */ + "linux_symlinkat", /* 36 = linux_symlinkat */ + "linux_linkat", /* 37 = linux_linkat */ + "linux_renameat", /* 38 = linux_renameat */ + "#39", /* 39 = linux_umount2 */ + "linux_mount", /* 40 = linux_mount */ + "linux_pivot_root", /* 41 = linux_pivot_root */ + "#42", /* 42 = nfsservctl */ + "linux_statfs", /* 43 = linux_statfs */ + "linux_fstatfs", /* 44 = linux_fstatfs */ + "linux_truncate", /* 45 = linux_truncate */ + "linux_ftruncate", /* 46 = linux_ftruncate */ + "linux_fallocate", /* 47 = linux_fallocate */ + "linux_faccessat", /* 48 = linux_faccessat */ + "linux_chdir", /* 49 = linux_chdir */ + "fchdir", /* 50 = fchdir */ + "linux_chroot", /* 51 = linux_chroot */ + "fchmod", /* 52 = fchmod */ + "linux_fchmodat", /* 53 = linux_fchmodat */ + "linux_fchownat", /* 54 = linux_fchownat */ + "fchown", /* 55 = fchown */ + "linux_openat", /* 56 = linux_openat */ + "close", /* 57 = close */ + "linux_vhangup", /* 58 = linux_vhangup */ + "linux_pipe2", /* 59 = linux_pipe2 */ + "#60", /* 60 = linux_quotactl */ + "linux_getdents64", /* 61 = linux_getdents64 */ + "linux_lseek", /* 62 = linux_lseek */ + "linux_read", /* 63 = linux_read */ + "linux_write", /* 64 = linux_write */ + "linux_readv", /* 65 = linux_readv */ + "linux_writev", /* 66 = linux_writev */ + "linux_pread", /* 67 = linux_pread */ + "linux_pwrite", /* 68 = linux_pwrite */ + "linux_preadv", /* 69 = linux_preadv */ + "linux_pwritev", /* 70 = linux_pwritev */ + "linux_sendfile", /* 71 = linux_sendfile */ + "linux_pselect6", /* 72 = linux_pselect6 */ + "linux_ppoll", /* 73 = linux_ppoll */ + "linux_signalfd4", /* 74 = linux_signalfd4 */ + "linux_vmsplice", /* 75 = linux_vmsplice */ + "linux_splice", /* 76 = linux_splice */ + "linux_tee", /* 77 = linux_tee */ + "linux_readlinkat", /* 78 = linux_readlinkat */ + "linux_newfstatat", /* 79 = linux_newfstatat */ + "linux_newfstat", /* 80 = linux_newfstat */ + "#81", /* 81 = linux_sync */ + "fsync", /* 82 = fsync */ + "linux_fdatasync", /* 83 = linux_fdatasync */ + "linux_sync_file_range", /* 84 = linux_sync_file_range */ + "linux_timerfd_create", /* 85 = linux_timerfd_create */ + "linux_timerfd_settime", /* 86 = linux_timerfd_settime */ + "linux_timerfd_gettime", /* 87 = linux_timerfd_gettime */ + "linux_utimensat", /* 88 = linux_utimensat */ + "linux_acct", /* 89 = linux_acct */ + "linux_capget", /* 90 = linux_capget */ + "linux_capset", /* 91 = linux_capset */ + "linux_personality", /* 92 = linux_personality */ + "linux_exit", /* 93 = linux_exit */ + "linux_exit_group", /* 94 = linux_exit_group */ + "linux_waitid", /* 95 = linux_waitid */ + "linux_set_tid_address", /* 96 = linux_set_tid_address */ + "linux_unshare", /* 97 = linux_unshare */ + "linux_sys_futex", /* 98 = linux_sys_futex */ + "linux_set_robust_list", /* 99 = linux_set_robust_list */ + "linux_get_robust_list", /* 100 = linux_get_robust_list */ + "linux_nanosleep", /* 101 = linux_nanosleep */ + "linux_getitimer", /* 102 = linux_getitimer */ + "linux_setitimer", /* 103 = linux_setitimer */ + "linux_kexec_load", /* 104 = linux_kexec_load */ + "linux_init_module", /* 105 = linux_init_module */ + "linux_delete_module", /* 106 = linux_delete_module */ + "linux_timer_create", /* 107 = linux_timer_create */ + "linux_timer_gettime", /* 108 = linux_timer_gettime */ + "linux_timer_getoverrun", /* 109 = linux_timer_getoverrun */ + "linux_timer_settime", /* 110 = linux_timer_settime */ + "linux_timer_delete", /* 111 = linux_timer_delete */ + "linux_clock_settime", /* 112 = linux_clock_settime */ + "linux_clock_gettime", /* 113 = linux_clock_gettime */ + "linux_clock_getres", /* 114 = linux_clock_getres */ + "linux_clock_nanosleep", /* 115 = linux_clock_nanosleep */ + "linux_syslog", /* 116 = linux_syslog */ + "linux_ptrace", /* 117 = linux_ptrace */ + "linux_sched_setparam", /* 118 = linux_sched_setparam */ + "linux_sched_setscheduler", /* 119 = linux_sched_setscheduler */ + "linux_sched_getscheduler", /* 120 = linux_sched_getscheduler */ + "linux_sched_getparam", /* 121 = linux_sched_getparam */ + "linux_sched_setaffinity", /* 122 = linux_sched_setaffinity */ + "linux_sched_getaffinity", /* 123 = linux_sched_getaffinity */ + "sched_yield", /* 124 = sched_yield */ + "linux_sched_get_priority_max", /* 125 = linux_sched_get_priority_max */ + "linux_sched_get_priority_min", /* 126 = linux_sched_get_priority_min */ + "linux_sched_rr_get_interval", /* 127 = linux_sched_rr_get_interval */ + "#128", /* 128 = restart_syscall */ + "linux_kill", /* 129 = linux_kill */ + "linux_tkill", /* 130 = linux_tkill */ + "linux_tgkill", /* 131 = linux_tgkill */ + "linux_sigaltstack", /* 132 = linux_sigaltstack */ + "linux_rt_sigsuspend", /* 133 = linux_rt_sigsuspend */ + "linux_rt_sigaction", /* 134 = linux_rt_sigaction */ + "linux_rt_sigprocmask", /* 135 = linux_rt_sigprocmask */ + "linux_rt_sigpending", /* 136 = linux_rt_sigpending */ + "linux_rt_sigtimedwait", /* 137 = linux_rt_sigtimedwait */ + "linux_rt_sigqueueinfo", /* 138 = linux_rt_sigqueueinfo */ + "linux_rt_sigreturn", /* 139 = linux_rt_sigreturn */ + "setpriority", /* 140 = setpriority */ + "linux_getpriority", /* 141 = linux_getpriority */ + "linux_reboot", /* 142 = linux_reboot */ + "setregid", /* 143 = setregid */ + "setgid", /* 144 = setgid */ + "setreuid", /* 145 = setreuid */ + "setuid", /* 146 = setuid */ + "setresuid", /* 147 = setresuid */ + "linux_getresuid", /* 148 = linux_getresuid */ + "setresgid", /* 149 = setresgid */ + "linux_getresgid", /* 150 = linux_getresgid */ + "linux_setfsuid", /* 151 = linux_setfsuid */ + "linux_setfsgid", /* 152 = linux_setfsgid */ + "linux_times", /* 153 = linux_times */ + "setpgid", /* 154 = setpgid */ + "getpgid", /* 155 = getpgid */ + "linux_getsid", /* 156 = linux_getsid */ + "setsid", /* 157 = setsid */ + "linux_getgroups", /* 158 = linux_getgroups */ + "linux_setgroups", /* 159 = linux_setgroups */ + "linux_newuname", /* 160 = linux_newuname */ + "linux_sethostname", /* 161 = linux_sethostname */ + "linux_setdomainname", /* 162 = linux_setdomainname */ + "linux_getrlimit", /* 163 = linux_getrlimit */ + "linux_setrlimit", /* 164 = linux_setrlimit */ + "linux_getrusage", /* 165 = linux_getrusage */ + "umask", /* 166 = umask */ + "linux_prctl", /* 167 = linux_prctl */ + "linux_getcpu", /* 168 = linux_getcpu */ + "linux_gettimeofday", /* 169 = linux_gettimeofday */ + "linux_settimeofday", /* 170 = linux_settimeofday */ + "linux_adjtimex", /* 171 = linux_adjtimex */ + "linux_getpid", /* 172 = linux_getpid */ + "linux_getppid", /* 173 = linux_getppid */ + "linux_getuid", /* 174 = linux_getuid */ + "geteuid", /* 175 = geteuid */ + "linux_getgid", /* 176 = linux_getgid */ + "getegid", /* 177 = getegid */ + "linux_gettid", /* 178 = linux_gettid */ + "linux_sysinfo", /* 179 = linux_sysinfo */ + "linux_mq_open", /* 180 = linux_mq_open */ + "linux_mq_unlink", /* 181 = linux_mq_unlink */ + "linux_mq_timedsend", /* 182 = linux_mq_timedsend */ + "linux_mq_timedreceive", /* 183 = linux_mq_timedreceive */ + "linux_mq_notify", /* 184 = linux_mq_notify */ + "linux_mq_getsetattr", /* 185 = linux_mq_getsetattr */ + "linux_msgget", /* 186 = linux_msgget */ + "linux_msgctl", /* 187 = linux_msgctl */ + "linux_msgrcv", /* 188 = linux_msgrcv */ + "linux_msgsnd", /* 189 = linux_msgsnd */ + "linux_semget", /* 190 = linux_semget */ + "linux_semctl", /* 191 = linux_semctl */ + "linux_semtimedop", /* 192 = linux_semtimedop */ + "linux_semop", /* 193 = linux_semop */ + "linux_shmget", /* 194 = linux_shmget */ + "linux_shmctl", /* 195 = linux_shmctl */ + "linux_shmat", /* 196 = linux_shmat */ + "linux_shmdt", /* 197 = linux_shmdt */ + "linux_socket", /* 198 = linux_socket */ + "linux_socketpair", /* 199 = linux_socketpair */ + "linux_bind", /* 200 = linux_bind */ + "linux_listen", /* 201 = linux_listen */ + "linux_accept", /* 202 = linux_accept */ + "linux_connect", /* 203 = linux_connect */ + "linux_getsockname", /* 204 = linux_getsockname */ + "linux_getpeername", /* 205 = linux_getpeername */ + "linux_sendto", /* 206 = linux_sendto */ + "linux_recvfrom", /* 207 = linux_recvfrom */ + "linux_setsockopt", /* 208 = linux_setsockopt */ + "linux_getsockopt", /* 209 = linux_getsockopt */ + "linux_shutdown", /* 210 = linux_shutdown */ + "linux_sendmsg", /* 211 = linux_sendmsg */ + "linux_recvmsg", /* 212 = linux_recvmsg */ + "#213", /* 213 = linux_readahead */ + "linux_brk", /* 214 = linux_brk */ + "linux_munmap", /* 215 = linux_munmap */ + "linux_mremap", /* 216 = linux_mremap */ + "linux_add_key", /* 217 = linux_add_key */ + "linux_request_key", /* 218 = linux_request_key */ + "linux_keyctl", /* 219 = linux_keyctl */ + "linux_clone", /* 220 = linux_clone */ + "linux_execve", /* 221 = linux_execve */ + "linux_mmap2", /* 222 = linux_mmap2 */ + "linux_fadvise64", /* 223 = linux_fadvise64 */ + "linux_swapon", /* 224 = linux_swapon */ + "linux_swapoff", /* 225 = linux_swapoff */ + "linux_mprotect", /* 226 = linux_mprotect */ + "linux_msync", /* 227 = linux_msync */ + "linux_mlock", /* 228 = linux_mlock */ + "linux_munlock", /* 229 = linux_munlock */ + "mlockall", /* 230 = mlockall */ + "munlockall", /* 231 = munlockall */ + "linux_mincore", /* 232 = linux_mincore */ + "linux_madvise", /* 233 = linux_madvise */ + "linux_remap_file_pages", /* 234 = linux_remap_file_pages */ + "linux_mbind", /* 235 = linux_mbind */ + "linux_get_mempolicy", /* 236 = linux_get_mempolicy */ + "linux_set_mempolicy", /* 237 = linux_set_mempolicy */ + "linux_migrate_pages", /* 238 = linux_migrate_pages */ + "linux_move_pages", /* 239 = linux_move_pages */ + "linux_rt_tgsigqueueinfo", /* 240 = linux_rt_tgsigqueueinfo */ + "linux_perf_event_open", /* 241 = linux_perf_event_open */ + "linux_accept4", /* 242 = linux_accept4 */ + "linux_recvmmsg", /* 243 = linux_recvmmsg */ + "#244", /* 244 = unimpl_md_syscall */ + "#245", /* 245 = unimpl_md_syscall */ + "#246", /* 246 = unimpl_md_syscall */ + "#247", /* 247 = unimpl_md_syscall */ + "#248", /* 248 = unimpl_md_syscall */ + "#249", /* 249 = unimpl_md_syscall */ + "#250", /* 250 = unimpl_md_syscall */ + "#251", /* 251 = unimpl_md_syscall */ + "#252", /* 252 = unimpl_md_syscall */ + "#253", /* 253 = unimpl_md_syscall */ + "#254", /* 254 = unimpl_md_syscall */ + "#255", /* 255 = unimpl_md_syscall */ + "#256", /* 256 = unimpl_md_syscall */ + "#257", /* 257 = unimpl_md_syscall */ + "#258", /* 258 = unimpl_md_syscall */ + "#259", /* 259 = unimpl_md_syscall */ + "linux_wait4", /* 260 = linux_wait4 */ + "linux_prlimit64", /* 261 = linux_prlimit64 */ + "linux_fanotify_init", /* 262 = linux_fanotify_init */ + "linux_fanotify_mark", /* 263 = linux_fanotify_mark */ + "linux_name_to_handle_at", /* 264 = linux_name_to_handle_at */ + "linux_open_by_handle_at", /* 265 = linux_open_by_handle_at */ + "linux_clock_adjtime", /* 266 = linux_clock_adjtime */ + "linux_syncfs", /* 267 = linux_syncfs */ + "linux_setns", /* 268 = linux_setns */ + "linux_sendmmsg", /* 269 = linux_sendmmsg */ + "linux_process_vm_readv", /* 270 = linux_process_vm_readv */ + "linux_process_vm_writev", /* 271 = linux_process_vm_writev */ + "linux_kcmp", /* 272 = linux_kcmp */ + "linux_finit_module", /* 273 = linux_finit_module */ + "linux_sched_setattr", /* 274 = linux_sched_setattr */ + "linux_sched_getattr", /* 275 = linux_sched_getattr */ + "linux_renameat2", /* 276 = linux_renameat2 */ + "linux_seccomp", /* 277 = linux_seccomp */ + "linux_getrandom", /* 278 = linux_getrandom */ + "linux_memfd_create", /* 279 = linux_memfd_create */ + "linux_bpf", /* 280 = linux_bpf */ + "linux_execveat", /* 281 = linux_execveat */ + "linux_userfaultfd", /* 282 = linux_userfaultfd */ + "linux_membarrier", /* 283 = linux_membarrier */ + "linux_mlock2", /* 284 = linux_mlock2 */ + "linux_copy_file_range", /* 285 = linux_copy_file_range */ + "linux_preadv2", /* 286 = linux_preadv2 */ + "linux_pwritev2", /* 287 = linux_pwritev2 */ + "linux_pkey_mprotect", /* 288 = linux_pkey_mprotect */ + "linux_pkey_alloc", /* 289 = linux_pkey_alloc */ + "linux_pkey_free", /* 290 = linux_pkey_free */ + "linux_statx", /* 291 = linux_statx */ + "linux_io_pgetevents", /* 292 = linux_io_pgetevents */ + "linux_rseq", /* 293 = linux_rseq */ + "linux_kexec_file_load", /* 294 = linux_kexec_file_load */ + "#295", /* 295 = unimpl_md_syscall */ + "#296", /* 296 = unimpl_md_syscall */ + "#297", /* 297 = unimpl_md_syscall */ + "#298", /* 298 = unimpl_md_syscall */ + "#299", /* 299 = unimpl_md_syscall */ + "#300", /* 300 = unimpl_md_syscall */ + "#301", /* 301 = unimpl_md_syscall */ + "#302", /* 302 = unimpl_md_syscall */ + "#303", /* 303 = unimpl_md_syscall */ + "#304", /* 304 = unimpl_md_syscall */ + "#305", /* 305 = unimpl_md_syscall */ + "#306", /* 306 = unimpl_md_syscall */ + "#307", /* 307 = unimpl_md_syscall */ + "#308", /* 308 = unimpl_md_syscall */ + "#309", /* 309 = unimpl_md_syscall */ + "#310", /* 310 = unimpl_md_syscall */ + "#311", /* 311 = unimpl_md_syscall */ + "#312", /* 312 = unimpl_md_syscall */ + "#313", /* 313 = unimpl_md_syscall */ + "#314", /* 314 = unimpl_md_syscall */ + "#315", /* 315 = unimpl_md_syscall */ + "#316", /* 316 = unimpl_md_syscall */ + "#317", /* 317 = unimpl_md_syscall */ + "#318", /* 318 = unimpl_md_syscall */ + "#319", /* 319 = unimpl_md_syscall */ + "#320", /* 320 = unimpl_md_syscall */ + "#321", /* 321 = unimpl_md_syscall */ + "#322", /* 322 = unimpl_md_syscall */ + "#323", /* 323 = unimpl_md_syscall */ + "#324", /* 324 = unimpl_md_syscall */ + "#325", /* 325 = unimpl_md_syscall */ + "#326", /* 326 = unimpl_md_syscall */ + "#327", /* 327 = unimpl_md_syscall */ + "#328", /* 328 = unimpl_md_syscall */ + "#329", /* 329 = unimpl_md_syscall */ + "#330", /* 330 = unimpl_md_syscall */ + "#331", /* 331 = unimpl_md_syscall */ + "#332", /* 332 = unimpl_md_syscall */ + "#333", /* 333 = unimpl_md_syscall */ + "#334", /* 334 = unimpl_md_syscall */ + "#335", /* 335 = unimpl_md_syscall */ + "#336", /* 336 = unimpl_md_syscall */ + "#337", /* 337 = unimpl_md_syscall */ + "#338", /* 338 = unimpl_md_syscall */ + "#339", /* 339 = unimpl_md_syscall */ + "#340", /* 340 = unimpl_md_syscall */ + "#341", /* 341 = unimpl_md_syscall */ + "#342", /* 342 = unimpl_md_syscall */ + "#343", /* 343 = unimpl_md_syscall */ + "#344", /* 344 = unimpl_md_syscall */ + "#345", /* 345 = unimpl_md_syscall */ + "#346", /* 346 = unimpl_md_syscall */ + "#347", /* 347 = unimpl_md_syscall */ + "#348", /* 348 = unimpl_md_syscall */ + "#349", /* 349 = unimpl_md_syscall */ + "#350", /* 350 = unimpl_md_syscall */ + "#351", /* 351 = unimpl_md_syscall */ + "#352", /* 352 = unimpl_md_syscall */ + "#353", /* 353 = unimpl_md_syscall */ + "#354", /* 354 = unimpl_md_syscall */ + "#355", /* 355 = unimpl_md_syscall */ + "#356", /* 356 = unimpl_md_syscall */ + "#357", /* 357 = unimpl_md_syscall */ + "#358", /* 358 = unimpl_md_syscall */ + "#359", /* 359 = unimpl_md_syscall */ + "#360", /* 360 = unimpl_md_syscall */ + "#361", /* 361 = unimpl_md_syscall */ + "#362", /* 362 = unimpl_md_syscall */ + "#363", /* 363 = unimpl_md_syscall */ + "#364", /* 364 = unimpl_md_syscall */ + "#365", /* 365 = unimpl_md_syscall */ + "#366", /* 366 = unimpl_md_syscall */ + "#367", /* 367 = unimpl_md_syscall */ + "#368", /* 368 = unimpl_md_syscall */ + "#369", /* 369 = unimpl_md_syscall */ + "#370", /* 370 = unimpl_md_syscall */ + "#371", /* 371 = unimpl_md_syscall */ + "#372", /* 372 = unimpl_md_syscall */ + "#373", /* 373 = unimpl_md_syscall */ + "#374", /* 374 = unimpl_md_syscall */ + "#375", /* 375 = unimpl_md_syscall */ + "#376", /* 376 = unimpl_md_syscall */ + "#377", /* 377 = unimpl_md_syscall */ + "#378", /* 378 = unimpl_md_syscall */ + "#379", /* 379 = unimpl_md_syscall */ + "#380", /* 380 = unimpl_md_syscall */ + "#381", /* 381 = unimpl_md_syscall */ + "#382", /* 382 = unimpl_md_syscall */ + "#383", /* 383 = unimpl_md_syscall */ + "#384", /* 384 = unimpl_md_syscall */ + "#385", /* 385 = unimpl_md_syscall */ + "#386", /* 386 = unimpl_md_syscall */ + "#387", /* 387 = unimpl_md_syscall */ + "#388", /* 388 = unimpl_md_syscall */ + "#389", /* 389 = unimpl_md_syscall */ + "#390", /* 390 = unimpl_md_syscall */ + "#391", /* 391 = unimpl_md_syscall */ + "#392", /* 392 = unimpl_md_syscall */ + "#393", /* 393 = unimpl_md_syscall */ + "#394", /* 394 = unimpl_md_syscall */ + "#395", /* 395 = unimpl_md_syscall */ + "#396", /* 396 = unimpl_md_syscall */ + "#397", /* 397 = unimpl_md_syscall */ + "#398", /* 398 = unimpl_md_syscall */ + "#399", /* 399 = unimpl_md_syscall */ + "#400", /* 400 = unimpl_md_syscall */ + "#401", /* 401 = unimpl_md_syscall */ + "#402", /* 402 = unimpl_md_syscall */ + "#403", /* 403 = unimpl_md_syscall */ + "#404", /* 404 = unimpl_md_syscall */ + "#405", /* 405 = unimpl_md_syscall */ + "#406", /* 406 = unimpl_md_syscall */ + "#407", /* 407 = unimpl_md_syscall */ + "#408", /* 408 = unimpl_md_syscall */ + "#409", /* 409 = unimpl_md_syscall */ + "#410", /* 410 = unimpl_md_syscall */ + "#411", /* 411 = unimpl_md_syscall */ + "#412", /* 412 = unimpl_md_syscall */ + "#413", /* 413 = unimpl_md_syscall */ + "#414", /* 414 = unimpl_md_syscall */ + "#415", /* 415 = unimpl_md_syscall */ + "#416", /* 416 = unimpl_md_syscall */ + "#417", /* 417 = unimpl_md_syscall */ + "#418", /* 418 = unimpl_md_syscall */ + "#419", /* 419 = unimpl_md_syscall */ + "#420", /* 420 = unimpl_md_syscall */ + "#421", /* 421 = unimpl_md_syscall */ + "#422", /* 422 = unimpl_md_syscall */ + "#423", /* 423 = unimpl_md_syscall */ + "linux_pidfd_send_signal", /* 424 = linux_pidfd_send_signal */ + "linux_io_uring_setup", /* 425 = linux_io_uring_setup */ + "linux_io_uring_enter", /* 426 = linux_io_uring_enter */ + "linux_io_uring_register", /* 427 = linux_io_uring_register */ + "linux_open_tree", /* 428 = linux_open_tree */ + "linux_move_mount", /* 429 = linux_move_mount */ + "linux_fsopen", /* 430 = linux_fsopen */ + "linux_fsconfig", /* 431 = linux_fsconfig */ + "linux_fsmount", /* 432 = linux_fsmount */ + "linux_fspick", /* 433 = linux_fspick */ + "linux_pidfd_open", /* 434 = linux_pidfd_open */ + "linux_clone3", /* 435 = linux_clone3 */ + "linux_close_range", /* 436 = linux_close_range */ + "linux_openat2", /* 437 = linux_openat2 */ + "linux_pidfd_getfd", /* 438 = linux_pidfd_getfd */ + "linux_faccessat2", /* 439 = linux_faccessat2 */ + "linux_process_madvise", /* 440 = linux_process_madvise */ + "linux_epoll_pwait2", /* 441 = linux_epoll_pwait2 */ + "linux_mount_setattr", /* 442 = linux_mount_setattr */ + "linux_quotactl_fd", /* 443 = linux_quotactl_fd */ + "linux_landlock_create_ruleset", /* 444 = linux_landlock_create_ruleset */ + "linux_landlock_add_rule", /* 445 = linux_landlock_add_rule */ + "linux_landlock_restrict_self", /* 446 = linux_landlock_restrict_self */ + "linux_memfd_secret", /* 447 = linux_memfd_secret */ + "linux_process_mrelease", /* 448 = linux_process_mrelease */ + "linux_futex_waitv", /* 449 = linux_futex_waitv */ + "linux_set_mempolicy_home_node", /* 450 = linux_set_mempolicy_home_node */ + "linux_cachestat", /* 451 = linux_cachestat */ + "linux_fchmodat2", /* 452 = linux_fchmodat2 */ +}; diff --git a/sys/arm64/linux64/linux64_sysent.c b/sys/arm64/linux64/linux64_sysent.c new file mode 100755 index 000000000000..4b571c6529af --- /dev/null +++ b/sys/arm64/linux64/linux64_sysent.c @@ -0,0 +1,470 @@ +/* + * System call switch table. + * + * DO NOT EDIT-- this file is automatically @generated. + */ + +#include +#include +#include +#include +#include + +#define AS(name) (sizeof(struct name) / sizeof(syscallarg_t)) + +/* The casts are bogus but will do for now. */ +struct sysent linux64_sysent[] = { + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 0 = linux_io_setup */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 1 = linux_io_destroy */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 2 = linux_io_submit */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 3 = linux_io_cancel */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 4 = linux_io_getevents */ + { .sy_narg = AS(linux_setxattr_args), .sy_call = (sy_call_t *)linux_setxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 5 = linux_setxattr */ + { .sy_narg = AS(linux_lsetxattr_args), .sy_call = (sy_call_t *)linux_lsetxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 6 = linux_lsetxattr */ + { .sy_narg = AS(linux_fsetxattr_args), .sy_call = (sy_call_t *)linux_fsetxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 7 = linux_fsetxattr */ + { .sy_narg = AS(linux_getxattr_args), .sy_call = (sy_call_t *)linux_getxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 8 = linux_getxattr */ + { .sy_narg = AS(linux_lgetxattr_args), .sy_call = (sy_call_t *)linux_lgetxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 9 = linux_lgetxattr */ + { .sy_narg = AS(linux_fgetxattr_args), .sy_call = (sy_call_t *)linux_fgetxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 10 = linux_fgetxattr */ + { .sy_narg = AS(linux_listxattr_args), .sy_call = (sy_call_t *)linux_listxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 11 = linux_listxattr */ + { .sy_narg = AS(linux_llistxattr_args), .sy_call = (sy_call_t *)linux_llistxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 12 = linux_llistxattr */ + { .sy_narg = AS(linux_flistxattr_args), .sy_call = (sy_call_t *)linux_flistxattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 13 = linux_flistxattr */ + { .sy_narg = AS(linux_removexattr_args), .sy_call = (sy_call_t *)linux_removexattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 14 = linux_removexattr */ + { .sy_narg = AS(linux_lremovexattr_args), .sy_call = (sy_call_t *)linux_lremovexattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 15 = linux_lremovexattr */ + { .sy_narg = AS(linux_fremovexattr_args), .sy_call = (sy_call_t *)linux_fremovexattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 16 = linux_fremovexattr */ + { .sy_narg = AS(linux_getcwd_args), .sy_call = (sy_call_t *)linux_getcwd, .sy_auevent = AUE_GETCWD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 17 = linux_getcwd */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_lookup_dcookie, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 18 = linux_lookup_dcookie */ + { .sy_narg = AS(linux_eventfd2_args), .sy_call = (sy_call_t *)linux_eventfd2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 19 = linux_eventfd2 */ + { .sy_narg = AS(linux_epoll_create1_args), .sy_call = (sy_call_t *)linux_epoll_create1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 20 = linux_epoll_create1 */ + { .sy_narg = AS(linux_epoll_ctl_args), .sy_call = (sy_call_t *)linux_epoll_ctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 21 = linux_epoll_ctl */ + { .sy_narg = AS(linux_epoll_pwait_args), .sy_call = (sy_call_t *)linux_epoll_pwait, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 22 = linux_epoll_pwait */ + { .sy_narg = AS(dup_args), .sy_call = (sy_call_t *)sys_dup, .sy_auevent = AUE_DUP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 23 = dup */ + { .sy_narg = AS(linux_dup3_args), .sy_call = (sy_call_t *)linux_dup3, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 24 = linux_dup3 */ + { .sy_narg = AS(linux_fcntl_args), .sy_call = (sy_call_t *)linux_fcntl, .sy_auevent = AUE_FCNTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 25 = linux_fcntl */ + { .sy_narg = AS(linux_inotify_init1_args), .sy_call = (sy_call_t *)linux_inotify_init1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 26 = linux_inotify_init1 */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 27 = linux_inotify_add_watch */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 28 = linux_inotify_rm_watch */ + { .sy_narg = AS(linux_ioctl_args), .sy_call = (sy_call_t *)linux_ioctl, .sy_auevent = AUE_IOCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 29 = linux_ioctl */ + { .sy_narg = AS(linux_ioprio_set_args), .sy_call = (sy_call_t *)linux_ioprio_set, .sy_auevent = AUE_SETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 30 = linux_ioprio_set */ + { .sy_narg = AS(linux_ioprio_get_args), .sy_call = (sy_call_t *)linux_ioprio_get, .sy_auevent = AUE_GETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 31 = linux_ioprio_get */ + { .sy_narg = AS(flock_args), .sy_call = (sy_call_t *)sys_flock, .sy_auevent = AUE_FLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 32 = flock */ + { .sy_narg = AS(linux_mknodat_args), .sy_call = (sy_call_t *)linux_mknodat, .sy_auevent = AUE_MKNODAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 33 = linux_mknodat */ + { .sy_narg = AS(linux_mkdirat_args), .sy_call = (sy_call_t *)linux_mkdirat, .sy_auevent = AUE_MKDIRAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 34 = linux_mkdirat */ + { .sy_narg = AS(linux_unlinkat_args), .sy_call = (sy_call_t *)linux_unlinkat, .sy_auevent = AUE_UNLINKAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 35 = linux_unlinkat */ + { .sy_narg = AS(linux_symlinkat_args), .sy_call = (sy_call_t *)linux_symlinkat, .sy_auevent = AUE_SYMLINKAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 36 = linux_symlinkat */ + { .sy_narg = AS(linux_linkat_args), .sy_call = (sy_call_t *)linux_linkat, .sy_auevent = AUE_LINKAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 37 = linux_linkat */ + { .sy_narg = AS(linux_renameat_args), .sy_call = (sy_call_t *)linux_renameat, .sy_auevent = AUE_RENAMEAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 38 = linux_renameat */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 39 = linux_umount2 */ + { .sy_narg = AS(linux_mount_args), .sy_call = (sy_call_t *)linux_mount, .sy_auevent = AUE_MOUNT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 40 = linux_mount */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_pivot_root, .sy_auevent = AUE_PIVOT_ROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 41 = linux_pivot_root */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 42 = nfsservctl */ + { .sy_narg = AS(linux_statfs_args), .sy_call = (sy_call_t *)linux_statfs, .sy_auevent = AUE_STATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 43 = linux_statfs */ + { .sy_narg = AS(linux_fstatfs_args), .sy_call = (sy_call_t *)linux_fstatfs, .sy_auevent = AUE_FSTATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 44 = linux_fstatfs */ + { .sy_narg = AS(linux_truncate_args), .sy_call = (sy_call_t *)linux_truncate, .sy_auevent = AUE_TRUNCATE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 45 = linux_truncate */ + { .sy_narg = AS(linux_ftruncate_args), .sy_call = (sy_call_t *)linux_ftruncate, .sy_auevent = AUE_FTRUNCATE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 46 = linux_ftruncate */ + { .sy_narg = AS(linux_fallocate_args), .sy_call = (sy_call_t *)linux_fallocate, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 47 = linux_fallocate */ + { .sy_narg = AS(linux_faccessat_args), .sy_call = (sy_call_t *)linux_faccessat, .sy_auevent = AUE_FACCESSAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 48 = linux_faccessat */ + { .sy_narg = AS(linux_chdir_args), .sy_call = (sy_call_t *)linux_chdir, .sy_auevent = AUE_CHDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 49 = linux_chdir */ + { .sy_narg = AS(fchdir_args), .sy_call = (sy_call_t *)sys_fchdir, .sy_auevent = AUE_FCHDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 50 = fchdir */ + { .sy_narg = AS(linux_chroot_args), .sy_call = (sy_call_t *)linux_chroot, .sy_auevent = AUE_CHROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 51 = linux_chroot */ + { .sy_narg = AS(fchmod_args), .sy_call = (sy_call_t *)sys_fchmod, .sy_auevent = AUE_FCHMOD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 52 = fchmod */ + { .sy_narg = AS(linux_fchmodat_args), .sy_call = (sy_call_t *)linux_fchmodat, .sy_auevent = AUE_FCHMODAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 53 = linux_fchmodat */ + { .sy_narg = AS(linux_fchownat_args), .sy_call = (sy_call_t *)linux_fchownat, .sy_auevent = AUE_FCHOWNAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 54 = linux_fchownat */ + { .sy_narg = AS(fchown_args), .sy_call = (sy_call_t *)sys_fchown, .sy_auevent = AUE_FCHOWN, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 55 = fchown */ + { .sy_narg = AS(linux_openat_args), .sy_call = (sy_call_t *)linux_openat, .sy_auevent = AUE_OPEN_RWTC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 56 = linux_openat */ + { .sy_narg = AS(close_args), .sy_call = (sy_call_t *)sys_close, .sy_auevent = AUE_CLOSE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 57 = close */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_vhangup, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 58 = linux_vhangup */ + { .sy_narg = AS(linux_pipe2_args), .sy_call = (sy_call_t *)linux_pipe2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 59 = linux_pipe2 */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 60 = linux_quotactl */ + { .sy_narg = AS(linux_getdents64_args), .sy_call = (sy_call_t *)linux_getdents64, .sy_auevent = AUE_GETDIRENTRIES, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 61 = linux_getdents64 */ + { .sy_narg = AS(linux_lseek_args), .sy_call = (sy_call_t *)linux_lseek, .sy_auevent = AUE_LSEEK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 62 = linux_lseek */ + { .sy_narg = AS(linux_read_args), .sy_call = (sy_call_t *)linux_read, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 63 = linux_read */ + { .sy_narg = AS(linux_write_args), .sy_call = (sy_call_t *)linux_write, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 64 = linux_write */ + { .sy_narg = AS(linux_readv_args), .sy_call = (sy_call_t *)linux_readv, .sy_auevent = AUE_READV, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 65 = linux_readv */ + { .sy_narg = AS(linux_writev_args), .sy_call = (sy_call_t *)linux_writev, .sy_auevent = AUE_WRITEV, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 66 = linux_writev */ + { .sy_narg = AS(linux_pread_args), .sy_call = (sy_call_t *)linux_pread, .sy_auevent = AUE_PREAD, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 67 = linux_pread */ + { .sy_narg = AS(linux_pwrite_args), .sy_call = (sy_call_t *)linux_pwrite, .sy_auevent = AUE_PWRITE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 68 = linux_pwrite */ + { .sy_narg = AS(linux_preadv_args), .sy_call = (sy_call_t *)linux_preadv, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 69 = linux_preadv */ + { .sy_narg = AS(linux_pwritev_args), .sy_call = (sy_call_t *)linux_pwritev, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 70 = linux_pwritev */ + { .sy_narg = AS(linux_sendfile_args), .sy_call = (sy_call_t *)linux_sendfile, .sy_auevent = AUE_SENDFILE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 71 = linux_sendfile */ + { .sy_narg = AS(linux_pselect6_args), .sy_call = (sy_call_t *)linux_pselect6, .sy_auevent = AUE_SELECT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 72 = linux_pselect6 */ + { .sy_narg = AS(linux_ppoll_args), .sy_call = (sy_call_t *)linux_ppoll, .sy_auevent = AUE_POLL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 73 = linux_ppoll */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_signalfd4, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 74 = linux_signalfd4 */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_vmsplice, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 75 = linux_vmsplice */ + { .sy_narg = AS(linux_splice_args), .sy_call = (sy_call_t *)linux_splice, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 76 = linux_splice */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_tee, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 77 = linux_tee */ + { .sy_narg = AS(linux_readlinkat_args), .sy_call = (sy_call_t *)linux_readlinkat, .sy_auevent = AUE_READLINKAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 78 = linux_readlinkat */ + { .sy_narg = AS(linux_newfstatat_args), .sy_call = (sy_call_t *)linux_newfstatat, .sy_auevent = AUE_FSTATAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 79 = linux_newfstatat */ + { .sy_narg = AS(linux_newfstat_args), .sy_call = (sy_call_t *)linux_newfstat, .sy_auevent = AUE_FSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 80 = linux_newfstat */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 81 = linux_sync */ + { .sy_narg = AS(fsync_args), .sy_call = (sy_call_t *)sys_fsync, .sy_auevent = AUE_FSYNC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 82 = fsync */ + { .sy_narg = AS(linux_fdatasync_args), .sy_call = (sy_call_t *)linux_fdatasync, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 83 = linux_fdatasync */ + { .sy_narg = AS(linux_sync_file_range_args), .sy_call = (sy_call_t *)linux_sync_file_range, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 84 = linux_sync_file_range */ + { .sy_narg = AS(linux_timerfd_create_args), .sy_call = (sy_call_t *)linux_timerfd_create, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 85 = linux_timerfd_create */ + { .sy_narg = AS(linux_timerfd_settime_args), .sy_call = (sy_call_t *)linux_timerfd_settime, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 86 = linux_timerfd_settime */ + { .sy_narg = AS(linux_timerfd_gettime_args), .sy_call = (sy_call_t *)linux_timerfd_gettime, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 87 = linux_timerfd_gettime */ + { .sy_narg = AS(linux_utimensat_args), .sy_call = (sy_call_t *)linux_utimensat, .sy_auevent = AUE_FUTIMESAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 88 = linux_utimensat */ + { .sy_narg = AS(linux_acct_args), .sy_call = (sy_call_t *)linux_acct, .sy_auevent = AUE_ACCT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 89 = linux_acct */ + { .sy_narg = AS(linux_capget_args), .sy_call = (sy_call_t *)linux_capget, .sy_auevent = AUE_CAPGET, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 90 = linux_capget */ + { .sy_narg = AS(linux_capset_args), .sy_call = (sy_call_t *)linux_capset, .sy_auevent = AUE_CAPSET, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 91 = linux_capset */ + { .sy_narg = AS(linux_personality_args), .sy_call = (sy_call_t *)linux_personality, .sy_auevent = AUE_PERSONALITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 92 = linux_personality */ + { .sy_narg = AS(linux_exit_args), .sy_call = (sy_call_t *)linux_exit, .sy_auevent = AUE_EXIT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 93 = linux_exit */ + { .sy_narg = AS(linux_exit_group_args), .sy_call = (sy_call_t *)linux_exit_group, .sy_auevent = AUE_EXIT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 94 = linux_exit_group */ + { .sy_narg = AS(linux_waitid_args), .sy_call = (sy_call_t *)linux_waitid, .sy_auevent = AUE_WAIT6, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 95 = linux_waitid */ + { .sy_narg = AS(linux_set_tid_address_args), .sy_call = (sy_call_t *)linux_set_tid_address, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 96 = linux_set_tid_address */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_unshare, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 97 = linux_unshare */ + { .sy_narg = AS(linux_sys_futex_args), .sy_call = (sy_call_t *)linux_sys_futex, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 98 = linux_sys_futex */ + { .sy_narg = AS(linux_set_robust_list_args), .sy_call = (sy_call_t *)linux_set_robust_list, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 99 = linux_set_robust_list */ + { .sy_narg = AS(linux_get_robust_list_args), .sy_call = (sy_call_t *)linux_get_robust_list, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 100 = linux_get_robust_list */ + { .sy_narg = AS(linux_nanosleep_args), .sy_call = (sy_call_t *)linux_nanosleep, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 101 = linux_nanosleep */ + { .sy_narg = AS(linux_getitimer_args), .sy_call = (sy_call_t *)linux_getitimer, .sy_auevent = AUE_GETITIMER, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 102 = linux_getitimer */ + { .sy_narg = AS(linux_setitimer_args), .sy_call = (sy_call_t *)linux_setitimer, .sy_auevent = AUE_SETITIMER, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 103 = linux_setitimer */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_kexec_load, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 104 = linux_kexec_load */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_init_module, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 105 = linux_init_module */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_delete_module, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 106 = linux_delete_module */ + { .sy_narg = AS(linux_timer_create_args), .sy_call = (sy_call_t *)linux_timer_create, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 107 = linux_timer_create */ + { .sy_narg = AS(linux_timer_gettime_args), .sy_call = (sy_call_t *)linux_timer_gettime, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 108 = linux_timer_gettime */ + { .sy_narg = AS(linux_timer_getoverrun_args), .sy_call = (sy_call_t *)linux_timer_getoverrun, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 109 = linux_timer_getoverrun */ + { .sy_narg = AS(linux_timer_settime_args), .sy_call = (sy_call_t *)linux_timer_settime, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 110 = linux_timer_settime */ + { .sy_narg = AS(linux_timer_delete_args), .sy_call = (sy_call_t *)linux_timer_delete, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 111 = linux_timer_delete */ + { .sy_narg = AS(linux_clock_settime_args), .sy_call = (sy_call_t *)linux_clock_settime, .sy_auevent = AUE_CLOCK_SETTIME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 112 = linux_clock_settime */ + { .sy_narg = AS(linux_clock_gettime_args), .sy_call = (sy_call_t *)linux_clock_gettime, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 113 = linux_clock_gettime */ + { .sy_narg = AS(linux_clock_getres_args), .sy_call = (sy_call_t *)linux_clock_getres, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 114 = linux_clock_getres */ + { .sy_narg = AS(linux_clock_nanosleep_args), .sy_call = (sy_call_t *)linux_clock_nanosleep, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 115 = linux_clock_nanosleep */ + { .sy_narg = AS(linux_syslog_args), .sy_call = (sy_call_t *)linux_syslog, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 116 = linux_syslog */ + { .sy_narg = AS(linux_ptrace_args), .sy_call = (sy_call_t *)linux_ptrace, .sy_auevent = AUE_PTRACE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 117 = linux_ptrace */ + { .sy_narg = AS(linux_sched_setparam_args), .sy_call = (sy_call_t *)linux_sched_setparam, .sy_auevent = AUE_SCHED_SETPARAM, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 118 = linux_sched_setparam */ + { .sy_narg = AS(linux_sched_setscheduler_args), .sy_call = (sy_call_t *)linux_sched_setscheduler, .sy_auevent = AUE_SCHED_SETSCHEDULER, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 119 = linux_sched_setscheduler */ + { .sy_narg = AS(linux_sched_getscheduler_args), .sy_call = (sy_call_t *)linux_sched_getscheduler, .sy_auevent = AUE_SCHED_GETSCHEDULER, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 120 = linux_sched_getscheduler */ + { .sy_narg = AS(linux_sched_getparam_args), .sy_call = (sy_call_t *)linux_sched_getparam, .sy_auevent = AUE_SCHED_GETPARAM, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 121 = linux_sched_getparam */ + { .sy_narg = AS(linux_sched_setaffinity_args), .sy_call = (sy_call_t *)linux_sched_setaffinity, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 122 = linux_sched_setaffinity */ + { .sy_narg = AS(linux_sched_getaffinity_args), .sy_call = (sy_call_t *)linux_sched_getaffinity, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 123 = linux_sched_getaffinity */ + { .sy_narg = 0, .sy_call = (sy_call_t *)sys_sched_yield, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 124 = sched_yield */ + { .sy_narg = AS(linux_sched_get_priority_max_args), .sy_call = (sy_call_t *)linux_sched_get_priority_max, .sy_auevent = AUE_SCHED_GET_PRIORITY_MAX, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 125 = linux_sched_get_priority_max */ + { .sy_narg = AS(linux_sched_get_priority_min_args), .sy_call = (sy_call_t *)linux_sched_get_priority_min, .sy_auevent = AUE_SCHED_GET_PRIORITY_MIN, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 126 = linux_sched_get_priority_min */ + { .sy_narg = AS(linux_sched_rr_get_interval_args), .sy_call = (sy_call_t *)linux_sched_rr_get_interval, .sy_auevent = AUE_SCHED_RR_GET_INTERVAL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 127 = linux_sched_rr_get_interval */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 128 = restart_syscall */ + { .sy_narg = AS(linux_kill_args), .sy_call = (sy_call_t *)linux_kill, .sy_auevent = AUE_KILL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 129 = linux_kill */ + { .sy_narg = AS(linux_tkill_args), .sy_call = (sy_call_t *)linux_tkill, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 130 = linux_tkill */ + { .sy_narg = AS(linux_tgkill_args), .sy_call = (sy_call_t *)linux_tgkill, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 131 = linux_tgkill */ + { .sy_narg = AS(linux_sigaltstack_args), .sy_call = (sy_call_t *)linux_sigaltstack, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 132 = linux_sigaltstack */ + { .sy_narg = AS(linux_rt_sigsuspend_args), .sy_call = (sy_call_t *)linux_rt_sigsuspend, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 133 = linux_rt_sigsuspend */ + { .sy_narg = AS(linux_rt_sigaction_args), .sy_call = (sy_call_t *)linux_rt_sigaction, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 134 = linux_rt_sigaction */ + { .sy_narg = AS(linux_rt_sigprocmask_args), .sy_call = (sy_call_t *)linux_rt_sigprocmask, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 135 = linux_rt_sigprocmask */ + { .sy_narg = AS(linux_rt_sigpending_args), .sy_call = (sy_call_t *)linux_rt_sigpending, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 136 = linux_rt_sigpending */ + { .sy_narg = AS(linux_rt_sigtimedwait_args), .sy_call = (sy_call_t *)linux_rt_sigtimedwait, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 137 = linux_rt_sigtimedwait */ + { .sy_narg = AS(linux_rt_sigqueueinfo_args), .sy_call = (sy_call_t *)linux_rt_sigqueueinfo, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 138 = linux_rt_sigqueueinfo */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_rt_sigreturn, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 139 = linux_rt_sigreturn */ + { .sy_narg = AS(setpriority_args), .sy_call = (sy_call_t *)sys_setpriority, .sy_auevent = AUE_SETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 140 = setpriority */ + { .sy_narg = AS(linux_getpriority_args), .sy_call = (sy_call_t *)linux_getpriority, .sy_auevent = AUE_GETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 141 = linux_getpriority */ + { .sy_narg = AS(linux_reboot_args), .sy_call = (sy_call_t *)linux_reboot, .sy_auevent = AUE_REBOOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 142 = linux_reboot */ + { .sy_narg = AS(setregid_args), .sy_call = (sy_call_t *)sys_setregid, .sy_auevent = AUE_SETREGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 143 = setregid */ + { .sy_narg = AS(setgid_args), .sy_call = (sy_call_t *)sys_setgid, .sy_auevent = AUE_SETGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 144 = setgid */ + { .sy_narg = AS(setreuid_args), .sy_call = (sy_call_t *)sys_setreuid, .sy_auevent = AUE_SETREUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 145 = setreuid */ + { .sy_narg = AS(setuid_args), .sy_call = (sy_call_t *)sys_setuid, .sy_auevent = AUE_SETUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 146 = setuid */ + { .sy_narg = AS(setresuid_args), .sy_call = (sy_call_t *)sys_setresuid, .sy_auevent = AUE_SETRESUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 147 = setresuid */ + { .sy_narg = AS(linux_getresuid_args), .sy_call = (sy_call_t *)linux_getresuid, .sy_auevent = AUE_GETRESUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 148 = linux_getresuid */ + { .sy_narg = AS(setresgid_args), .sy_call = (sy_call_t *)sys_setresgid, .sy_auevent = AUE_SETRESGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 149 = setresgid */ + { .sy_narg = AS(linux_getresgid_args), .sy_call = (sy_call_t *)linux_getresgid, .sy_auevent = AUE_GETRESGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 150 = linux_getresgid */ + { .sy_narg = AS(linux_setfsuid_args), .sy_call = (sy_call_t *)linux_setfsuid, .sy_auevent = AUE_SETFSUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 151 = linux_setfsuid */ + { .sy_narg = AS(linux_setfsgid_args), .sy_call = (sy_call_t *)linux_setfsgid, .sy_auevent = AUE_SETFSGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 152 = linux_setfsgid */ + { .sy_narg = AS(linux_times_args), .sy_call = (sy_call_t *)linux_times, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 153 = linux_times */ + { .sy_narg = AS(setpgid_args), .sy_call = (sy_call_t *)sys_setpgid, .sy_auevent = AUE_SETPGRP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 154 = setpgid */ + { .sy_narg = AS(getpgid_args), .sy_call = (sy_call_t *)sys_getpgid, .sy_auevent = AUE_GETPGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 155 = getpgid */ + { .sy_narg = AS(linux_getsid_args), .sy_call = (sy_call_t *)linux_getsid, .sy_auevent = AUE_GETSID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 156 = linux_getsid */ + { .sy_narg = 0, .sy_call = (sy_call_t *)sys_setsid, .sy_auevent = AUE_SETSID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 157 = setsid */ + { .sy_narg = AS(linux_getgroups_args), .sy_call = (sy_call_t *)linux_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 158 = linux_getgroups */ + { .sy_narg = AS(linux_setgroups_args), .sy_call = (sy_call_t *)linux_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 159 = linux_setgroups */ + { .sy_narg = AS(linux_newuname_args), .sy_call = (sy_call_t *)linux_newuname, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 160 = linux_newuname */ + { .sy_narg = AS(linux_sethostname_args), .sy_call = (sy_call_t *)linux_sethostname, .sy_auevent = AUE_SYSCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 161 = linux_sethostname */ + { .sy_narg = AS(linux_setdomainname_args), .sy_call = (sy_call_t *)linux_setdomainname, .sy_auevent = AUE_SYSCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 162 = linux_setdomainname */ + { .sy_narg = AS(linux_getrlimit_args), .sy_call = (sy_call_t *)linux_getrlimit, .sy_auevent = AUE_GETRLIMIT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 163 = linux_getrlimit */ + { .sy_narg = AS(linux_setrlimit_args), .sy_call = (sy_call_t *)linux_setrlimit, .sy_auevent = AUE_SETRLIMIT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 164 = linux_setrlimit */ + { .sy_narg = AS(linux_getrusage_args), .sy_call = (sy_call_t *)linux_getrusage, .sy_auevent = AUE_GETRUSAGE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 165 = linux_getrusage */ + { .sy_narg = AS(umask_args), .sy_call = (sy_call_t *)sys_umask, .sy_auevent = AUE_UMASK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 166 = umask */ + { .sy_narg = AS(linux_prctl_args), .sy_call = (sy_call_t *)linux_prctl, .sy_auevent = AUE_PRCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 167 = linux_prctl */ + { .sy_narg = AS(linux_getcpu_args), .sy_call = (sy_call_t *)linux_getcpu, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 168 = linux_getcpu */ + { .sy_narg = AS(linux_gettimeofday_args), .sy_call = (sy_call_t *)linux_gettimeofday, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 169 = linux_gettimeofday */ + { .sy_narg = AS(linux_settimeofday_args), .sy_call = (sy_call_t *)linux_settimeofday, .sy_auevent = AUE_SETTIMEOFDAY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 170 = linux_settimeofday */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_adjtimex, .sy_auevent = AUE_ADJTIME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 171 = linux_adjtimex */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_getpid, .sy_auevent = AUE_GETPID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 172 = linux_getpid */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_getppid, .sy_auevent = AUE_GETPPID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 173 = linux_getppid */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_getuid, .sy_auevent = AUE_GETUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 174 = linux_getuid */ + { .sy_narg = 0, .sy_call = (sy_call_t *)sys_geteuid, .sy_auevent = AUE_GETEUID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 175 = geteuid */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_getgid, .sy_auevent = AUE_GETGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 176 = linux_getgid */ + { .sy_narg = 0, .sy_call = (sy_call_t *)sys_getegid, .sy_auevent = AUE_GETEGID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 177 = getegid */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_gettid, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 178 = linux_gettid */ + { .sy_narg = AS(linux_sysinfo_args), .sy_call = (sy_call_t *)linux_sysinfo, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 179 = linux_sysinfo */ + { .sy_narg = AS(linux_mq_open_args), .sy_call = (sy_call_t *)linux_mq_open, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 180 = linux_mq_open */ + { .sy_narg = AS(linux_mq_unlink_args), .sy_call = (sy_call_t *)linux_mq_unlink, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 181 = linux_mq_unlink */ + { .sy_narg = AS(linux_mq_timedsend_args), .sy_call = (sy_call_t *)linux_mq_timedsend, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 182 = linux_mq_timedsend */ + { .sy_narg = AS(linux_mq_timedreceive_args), .sy_call = (sy_call_t *)linux_mq_timedreceive, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 183 = linux_mq_timedreceive */ + { .sy_narg = AS(linux_mq_notify_args), .sy_call = (sy_call_t *)linux_mq_notify, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 184 = linux_mq_notify */ + { .sy_narg = AS(linux_mq_getsetattr_args), .sy_call = (sy_call_t *)linux_mq_getsetattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 185 = linux_mq_getsetattr */ + { .sy_narg = AS(linux_msgget_args), .sy_call = (sy_call_t *)linux_msgget, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 186 = linux_msgget */ + { .sy_narg = AS(linux_msgctl_args), .sy_call = (sy_call_t *)linux_msgctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 187 = linux_msgctl */ + { .sy_narg = AS(linux_msgrcv_args), .sy_call = (sy_call_t *)linux_msgrcv, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 188 = linux_msgrcv */ + { .sy_narg = AS(linux_msgsnd_args), .sy_call = (sy_call_t *)linux_msgsnd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 189 = linux_msgsnd */ + { .sy_narg = AS(linux_semget_args), .sy_call = (sy_call_t *)linux_semget, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 190 = linux_semget */ + { .sy_narg = AS(linux_semctl_args), .sy_call = (sy_call_t *)linux_semctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 191 = linux_semctl */ + { .sy_narg = AS(linux_semtimedop_args), .sy_call = (sy_call_t *)linux_semtimedop, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 192 = linux_semtimedop */ + { .sy_narg = AS(linux_semop_args), .sy_call = (sy_call_t *)linux_semop, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 193 = linux_semop */ + { .sy_narg = AS(linux_shmget_args), .sy_call = (sy_call_t *)linux_shmget, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 194 = linux_shmget */ + { .sy_narg = AS(linux_shmctl_args), .sy_call = (sy_call_t *)linux_shmctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 195 = linux_shmctl */ + { .sy_narg = AS(linux_shmat_args), .sy_call = (sy_call_t *)linux_shmat, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 196 = linux_shmat */ + { .sy_narg = AS(linux_shmdt_args), .sy_call = (sy_call_t *)linux_shmdt, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 197 = linux_shmdt */ + { .sy_narg = AS(linux_socket_args), .sy_call = (sy_call_t *)linux_socket, .sy_auevent = AUE_SOCKET, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 198 = linux_socket */ + { .sy_narg = AS(linux_socketpair_args), .sy_call = (sy_call_t *)linux_socketpair, .sy_auevent = AUE_SOCKETPAIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 199 = linux_socketpair */ + { .sy_narg = AS(linux_bind_args), .sy_call = (sy_call_t *)linux_bind, .sy_auevent = AUE_BIND, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 200 = linux_bind */ + { .sy_narg = AS(linux_listen_args), .sy_call = (sy_call_t *)linux_listen, .sy_auevent = AUE_LISTEN, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 201 = linux_listen */ + { .sy_narg = AS(linux_accept_args), .sy_call = (sy_call_t *)linux_accept, .sy_auevent = AUE_ACCEPT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 202 = linux_accept */ + { .sy_narg = AS(linux_connect_args), .sy_call = (sy_call_t *)linux_connect, .sy_auevent = AUE_CONNECT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 203 = linux_connect */ + { .sy_narg = AS(linux_getsockname_args), .sy_call = (sy_call_t *)linux_getsockname, .sy_auevent = AUE_GETSOCKNAME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 204 = linux_getsockname */ + { .sy_narg = AS(linux_getpeername_args), .sy_call = (sy_call_t *)linux_getpeername, .sy_auevent = AUE_GETPEERNAME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 205 = linux_getpeername */ + { .sy_narg = AS(linux_sendto_args), .sy_call = (sy_call_t *)linux_sendto, .sy_auevent = AUE_SENDTO, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 206 = linux_sendto */ + { .sy_narg = AS(linux_recvfrom_args), .sy_call = (sy_call_t *)linux_recvfrom, .sy_auevent = AUE_RECVFROM, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 207 = linux_recvfrom */ + { .sy_narg = AS(linux_setsockopt_args), .sy_call = (sy_call_t *)linux_setsockopt, .sy_auevent = AUE_SETSOCKOPT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 208 = linux_setsockopt */ + { .sy_narg = AS(linux_getsockopt_args), .sy_call = (sy_call_t *)linux_getsockopt, .sy_auevent = AUE_GETSOCKOPT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 209 = linux_getsockopt */ + { .sy_narg = AS(linux_shutdown_args), .sy_call = (sy_call_t *)linux_shutdown, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 210 = linux_shutdown */ + { .sy_narg = AS(linux_sendmsg_args), .sy_call = (sy_call_t *)linux_sendmsg, .sy_auevent = AUE_SENDMSG, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 211 = linux_sendmsg */ + { .sy_narg = AS(linux_recvmsg_args), .sy_call = (sy_call_t *)linux_recvmsg, .sy_auevent = AUE_RECVMSG, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 212 = linux_recvmsg */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 213 = linux_readahead */ + { .sy_narg = AS(linux_brk_args), .sy_call = (sy_call_t *)linux_brk, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 214 = linux_brk */ + { .sy_narg = AS(linux_munmap_args), .sy_call = (sy_call_t *)linux_munmap, .sy_auevent = AUE_MUNMAP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 215 = linux_munmap */ + { .sy_narg = AS(linux_mremap_args), .sy_call = (sy_call_t *)linux_mremap, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 216 = linux_mremap */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_add_key, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 217 = linux_add_key */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_request_key, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 218 = linux_request_key */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_keyctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 219 = linux_keyctl */ + { .sy_narg = AS(linux_clone_args), .sy_call = (sy_call_t *)linux_clone, .sy_auevent = AUE_RFORK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 220 = linux_clone */ + { .sy_narg = AS(linux_execve_args), .sy_call = (sy_call_t *)linux_execve, .sy_auevent = AUE_EXECVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 221 = linux_execve */ + { .sy_narg = AS(linux_mmap2_args), .sy_call = (sy_call_t *)linux_mmap2, .sy_auevent = AUE_MMAP, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 222 = linux_mmap2 */ + { .sy_narg = AS(linux_fadvise64_args), .sy_call = (sy_call_t *)linux_fadvise64, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 223 = linux_fadvise64 */ + { .sy_narg = AS(linux_swapon_args), .sy_call = (sy_call_t *)linux_swapon, .sy_auevent = AUE_SWAPON, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 224 = linux_swapon */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_swapoff, .sy_auevent = AUE_SWAPOFF, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 225 = linux_swapoff */ + { .sy_narg = AS(linux_mprotect_args), .sy_call = (sy_call_t *)linux_mprotect, .sy_auevent = AUE_MPROTECT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 226 = linux_mprotect */ + { .sy_narg = AS(linux_msync_args), .sy_call = (sy_call_t *)linux_msync, .sy_auevent = AUE_MSYNC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 227 = linux_msync */ + { .sy_narg = AS(linux_mlock_args), .sy_call = (sy_call_t *)linux_mlock, .sy_auevent = AUE_MLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 228 = linux_mlock */ + { .sy_narg = AS(linux_munlock_args), .sy_call = (sy_call_t *)linux_munlock, .sy_auevent = AUE_MUNLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 229 = linux_munlock */ + { .sy_narg = AS(mlockall_args), .sy_call = (sy_call_t *)sys_mlockall, .sy_auevent = AUE_MLOCKALL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 230 = mlockall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)sys_munlockall, .sy_auevent = AUE_MUNLOCKALL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 231 = munlockall */ + { .sy_narg = AS(linux_mincore_args), .sy_call = (sy_call_t *)linux_mincore, .sy_auevent = AUE_MINCORE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 232 = linux_mincore */ + { .sy_narg = AS(linux_madvise_args), .sy_call = (sy_call_t *)linux_madvise, .sy_auevent = AUE_MADVISE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 233 = linux_madvise */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_remap_file_pages, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 234 = linux_remap_file_pages */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_mbind, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 235 = linux_mbind */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_get_mempolicy, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 236 = linux_get_mempolicy */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_set_mempolicy, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 237 = linux_set_mempolicy */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_migrate_pages, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 238 = linux_migrate_pages */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_move_pages, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 239 = linux_move_pages */ + { .sy_narg = AS(linux_rt_tgsigqueueinfo_args), .sy_call = (sy_call_t *)linux_rt_tgsigqueueinfo, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 240 = linux_rt_tgsigqueueinfo */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_perf_event_open, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 241 = linux_perf_event_open */ + { .sy_narg = AS(linux_accept4_args), .sy_call = (sy_call_t *)linux_accept4, .sy_auevent = AUE_ACCEPT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 242 = linux_accept4 */ + { .sy_narg = AS(linux_recvmmsg_args), .sy_call = (sy_call_t *)linux_recvmmsg, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 243 = linux_recvmmsg */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 244 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 245 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 246 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 247 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 248 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 249 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 250 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 251 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 252 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 253 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 254 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 255 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 256 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 257 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 258 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 259 = unimpl_md_syscall */ + { .sy_narg = AS(linux_wait4_args), .sy_call = (sy_call_t *)linux_wait4, .sy_auevent = AUE_WAIT4, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 260 = linux_wait4 */ + { .sy_narg = AS(linux_prlimit64_args), .sy_call = (sy_call_t *)linux_prlimit64, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 261 = linux_prlimit64 */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_fanotify_init, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 262 = linux_fanotify_init */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_fanotify_mark, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 263 = linux_fanotify_mark */ + { .sy_narg = AS(linux_name_to_handle_at_args), .sy_call = (sy_call_t *)linux_name_to_handle_at, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 264 = linux_name_to_handle_at */ + { .sy_narg = AS(linux_open_by_handle_at_args), .sy_call = (sy_call_t *)linux_open_by_handle_at, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 265 = linux_open_by_handle_at */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_clock_adjtime, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 266 = linux_clock_adjtime */ + { .sy_narg = AS(linux_syncfs_args), .sy_call = (sy_call_t *)linux_syncfs, .sy_auevent = AUE_SYNC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 267 = linux_syncfs */ + { .sy_narg = AS(linux_setns_args), .sy_call = (sy_call_t *)linux_setns, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 268 = linux_setns */ + { .sy_narg = AS(linux_sendmmsg_args), .sy_call = (sy_call_t *)linux_sendmmsg, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 269 = linux_sendmmsg */ + { .sy_narg = AS(linux_process_vm_readv_args), .sy_call = (sy_call_t *)linux_process_vm_readv, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 270 = linux_process_vm_readv */ + { .sy_narg = AS(linux_process_vm_writev_args), .sy_call = (sy_call_t *)linux_process_vm_writev, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 271 = linux_process_vm_writev */ + { .sy_narg = AS(linux_kcmp_args), .sy_call = (sy_call_t *)linux_kcmp, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 272 = linux_kcmp */ + { .sy_narg = AS(linux_finit_module_args), .sy_call = (sy_call_t *)linux_finit_module, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 273 = linux_finit_module */ + { .sy_narg = AS(linux_sched_setattr_args), .sy_call = (sy_call_t *)linux_sched_setattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 274 = linux_sched_setattr */ + { .sy_narg = AS(linux_sched_getattr_args), .sy_call = (sy_call_t *)linux_sched_getattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 275 = linux_sched_getattr */ + { .sy_narg = AS(linux_renameat2_args), .sy_call = (sy_call_t *)linux_renameat2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 276 = linux_renameat2 */ + { .sy_narg = AS(linux_seccomp_args), .sy_call = (sy_call_t *)linux_seccomp, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 277 = linux_seccomp */ + { .sy_narg = AS(linux_getrandom_args), .sy_call = (sy_call_t *)linux_getrandom, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 278 = linux_getrandom */ + { .sy_narg = AS(linux_memfd_create_args), .sy_call = (sy_call_t *)linux_memfd_create, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 279 = linux_memfd_create */ + { .sy_narg = AS(linux_bpf_args), .sy_call = (sy_call_t *)linux_bpf, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 280 = linux_bpf */ + { .sy_narg = AS(linux_execveat_args), .sy_call = (sy_call_t *)linux_execveat, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 281 = linux_execveat */ + { .sy_narg = AS(linux_userfaultfd_args), .sy_call = (sy_call_t *)linux_userfaultfd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 282 = linux_userfaultfd */ + { .sy_narg = AS(linux_membarrier_args), .sy_call = (sy_call_t *)linux_membarrier, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 283 = linux_membarrier */ + { .sy_narg = AS(linux_mlock2_args), .sy_call = (sy_call_t *)linux_mlock2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 284 = linux_mlock2 */ + { .sy_narg = AS(linux_copy_file_range_args), .sy_call = (sy_call_t *)linux_copy_file_range, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 285 = linux_copy_file_range */ + { .sy_narg = AS(linux_preadv2_args), .sy_call = (sy_call_t *)linux_preadv2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 286 = linux_preadv2 */ + { .sy_narg = AS(linux_pwritev2_args), .sy_call = (sy_call_t *)linux_pwritev2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 287 = linux_pwritev2 */ + { .sy_narg = AS(linux_pkey_mprotect_args), .sy_call = (sy_call_t *)linux_pkey_mprotect, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 288 = linux_pkey_mprotect */ + { .sy_narg = AS(linux_pkey_alloc_args), .sy_call = (sy_call_t *)linux_pkey_alloc, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 289 = linux_pkey_alloc */ + { .sy_narg = AS(linux_pkey_free_args), .sy_call = (sy_call_t *)linux_pkey_free, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 290 = linux_pkey_free */ + { .sy_narg = AS(linux_statx_args), .sy_call = (sy_call_t *)linux_statx, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 291 = linux_statx */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_io_pgetevents, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 292 = linux_io_pgetevents */ + { .sy_narg = AS(linux_rseq_args), .sy_call = (sy_call_t *)linux_rseq, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 293 = linux_rseq */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_kexec_file_load, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 294 = linux_kexec_file_load */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 295 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 296 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 297 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 298 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 299 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 300 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 301 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 302 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 303 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 304 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 305 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 306 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 307 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 308 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 309 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 310 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 311 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 312 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 313 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 314 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 315 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 316 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 317 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 318 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 319 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 320 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 321 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 322 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 323 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 324 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 325 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 326 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 327 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 328 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 329 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 330 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 331 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 332 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 333 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 334 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 335 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 336 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 337 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 338 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 339 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 340 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 341 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 342 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 343 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 344 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 345 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 346 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 347 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 348 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 349 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 350 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 351 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 352 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 353 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 354 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 355 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 356 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 357 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 358 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 359 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 360 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 361 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 362 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 363 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 364 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 365 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 366 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 367 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 368 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 369 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 370 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 371 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 372 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 373 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 374 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 375 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 376 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 377 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 378 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 379 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 380 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 381 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 382 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 383 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 384 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 385 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 386 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 387 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 388 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 389 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 390 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 391 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 392 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 393 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 394 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 395 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 396 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 397 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 398 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 399 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 400 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 401 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 402 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 403 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 404 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 405 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 406 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 407 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 408 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 409 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 410 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 411 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 412 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 413 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 414 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 415 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 416 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 417 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 418 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 419 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 420 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 421 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 422 = unimpl_md_syscall */ + { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 423 = unimpl_md_syscall */ + { .sy_narg = AS(linux_pidfd_send_signal_args), .sy_call = (sy_call_t *)linux_pidfd_send_signal, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 424 = linux_pidfd_send_signal */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_io_uring_setup, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 425 = linux_io_uring_setup */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_io_uring_enter, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 426 = linux_io_uring_enter */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_io_uring_register, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 427 = linux_io_uring_register */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_open_tree, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 428 = linux_open_tree */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_move_mount, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 429 = linux_move_mount */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_fsopen, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 430 = linux_fsopen */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_fsconfig, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 431 = linux_fsconfig */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_fsmount, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 432 = linux_fsmount */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_fspick, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 433 = linux_fspick */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_pidfd_open, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 434 = linux_pidfd_open */ + { .sy_narg = AS(linux_clone3_args), .sy_call = (sy_call_t *)linux_clone3, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 435 = linux_clone3 */ + { .sy_narg = AS(linux_close_range_args), .sy_call = (sy_call_t *)linux_close_range, .sy_auevent = AUE_CLOSERANGE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 436 = linux_close_range */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_openat2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 437 = linux_openat2 */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_pidfd_getfd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 438 = linux_pidfd_getfd */ + { .sy_narg = AS(linux_faccessat2_args), .sy_call = (sy_call_t *)linux_faccessat2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 439 = linux_faccessat2 */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_process_madvise, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 440 = linux_process_madvise */ + { .sy_narg = AS(linux_epoll_pwait2_args), .sy_call = (sy_call_t *)linux_epoll_pwait2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 441 = linux_epoll_pwait2 */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_mount_setattr, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 442 = linux_mount_setattr */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_quotactl_fd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 443 = linux_quotactl_fd */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_landlock_create_ruleset, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 444 = linux_landlock_create_ruleset */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_landlock_add_rule, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 445 = linux_landlock_add_rule */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_landlock_restrict_self, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 446 = linux_landlock_restrict_self */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_memfd_secret, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 447 = linux_memfd_secret */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_process_mrelease, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 448 = linux_process_mrelease */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_futex_waitv, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 449 = linux_futex_waitv */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_set_mempolicy_home_node, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 450 = linux_set_mempolicy_home_node */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_cachestat, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 451 = linux_cachestat */ + { .sy_narg = 0, .sy_call = (sy_call_t *)linux_fchmodat2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 452 = linux_fchmodat2 */ +}; diff --git a/sys/arm64/linux64/linux64_systrace_args.c b/sys/arm64/linux64/linux64_systrace_args.c new file mode 100755 index 000000000000..61948c08c5ba --- /dev/null +++ b/sys/arm64/linux64/linux64_systrace_args.c @@ -0,0 +1,7646 @@ +/* + * System call argument to DTrace register array converstion. + * + * DO NOT EDIT-- this file is automatically @generated. + * This file is part of the DTrace syscall provider. + */ + +static void +systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) +{ + int64_t *iarg = (int64_t *)uarg; + int a = 0; + switch (sysnum) { + /* linux_setxattr */ + case 5: { + struct linux_setxattr_args *p = params; + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->value; /* void * */ + iarg[a++] = p->size; /* l_size_t */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 5; + break; + } + /* linux_lsetxattr */ + case 6: { + struct linux_lsetxattr_args *p = params; + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->value; /* void * */ + iarg[a++] = p->size; /* l_size_t */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 5; + break; + } + /* linux_fsetxattr */ + case 7: { + struct linux_fsetxattr_args *p = params; + iarg[a++] = p->fd; /* l_int */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->value; /* void * */ + iarg[a++] = p->size; /* l_size_t */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 5; + break; + } + /* linux_getxattr */ + case 8: { + struct linux_getxattr_args *p = params; + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->value; /* void * */ + iarg[a++] = p->size; /* l_size_t */ + *n_args = 4; + break; + } + /* linux_lgetxattr */ + case 9: { + struct linux_lgetxattr_args *p = params; + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->value; /* void * */ + iarg[a++] = p->size; /* l_size_t */ + *n_args = 4; + break; + } + /* linux_fgetxattr */ + case 10: { + struct linux_fgetxattr_args *p = params; + iarg[a++] = p->fd; /* l_int */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->value; /* void * */ + iarg[a++] = p->size; /* l_size_t */ + *n_args = 4; + break; + } + /* linux_listxattr */ + case 11: { + struct linux_listxattr_args *p = params; + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->list; /* char * */ + iarg[a++] = p->size; /* l_size_t */ + *n_args = 3; + break; + } + /* linux_llistxattr */ + case 12: { + struct linux_llistxattr_args *p = params; + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->list; /* char * */ + iarg[a++] = p->size; /* l_size_t */ + *n_args = 3; + break; + } + /* linux_flistxattr */ + case 13: { + struct linux_flistxattr_args *p = params; + iarg[a++] = p->fd; /* l_int */ + uarg[a++] = (intptr_t)p->list; /* char * */ + iarg[a++] = p->size; /* l_size_t */ + *n_args = 3; + break; + } + /* linux_removexattr */ + case 14: { + struct linux_removexattr_args *p = params; + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + *n_args = 2; + break; + } + /* linux_lremovexattr */ + case 15: { + struct linux_lremovexattr_args *p = params; + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + *n_args = 2; + break; + } + /* linux_fremovexattr */ + case 16: { + struct linux_fremovexattr_args *p = params; + iarg[a++] = p->fd; /* l_int */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + *n_args = 2; + break; + } + /* linux_getcwd */ + case 17: { + struct linux_getcwd_args *p = params; + uarg[a++] = (intptr_t)p->buf; /* char * */ + iarg[a++] = p->bufsize; /* l_ulong */ + *n_args = 2; + break; + } + /* linux_lookup_dcookie */ + case 18: { + *n_args = 0; + break; + } + /* linux_eventfd2 */ + case 19: { + struct linux_eventfd2_args *p = params; + iarg[a++] = p->initval; /* l_uint */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 2; + break; + } + /* linux_epoll_create1 */ + case 20: { + struct linux_epoll_create1_args *p = params; + iarg[a++] = p->flags; /* l_int */ + *n_args = 1; + break; + } + /* linux_epoll_ctl */ + case 21: { + struct linux_epoll_ctl_args *p = params; + iarg[a++] = p->epfd; /* l_int */ + iarg[a++] = p->op; /* l_int */ + iarg[a++] = p->fd; /* l_int */ + uarg[a++] = (intptr_t)p->event; /* struct epoll_event * */ + *n_args = 4; + break; + } + /* linux_epoll_pwait */ + case 22: { + struct linux_epoll_pwait_args *p = params; + iarg[a++] = p->epfd; /* l_int */ + uarg[a++] = (intptr_t)p->events; /* struct epoll_event * */ + iarg[a++] = p->maxevents; /* l_int */ + iarg[a++] = p->timeout; /* l_int */ + uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * */ + iarg[a++] = p->sigsetsize; /* l_size_t */ + *n_args = 6; + break; + } + /* dup */ + case 23: { + struct dup_args *p = params; + uarg[a++] = p->fd; /* u_int */ + *n_args = 1; + break; + } + /* linux_dup3 */ + case 24: { + struct linux_dup3_args *p = params; + iarg[a++] = p->oldfd; /* l_int */ + iarg[a++] = p->newfd; /* l_int */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_fcntl */ + case 25: { + struct linux_fcntl_args *p = params; + iarg[a++] = p->fd; /* l_uint */ + iarg[a++] = p->cmd; /* l_uint */ + uarg[a++] = (intptr_t)p->arg; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_inotify_init1 */ + case 26: { + struct linux_inotify_init1_args *p = params; + iarg[a++] = p->flags; /* l_int */ + *n_args = 1; + break; + } + /* linux_inotify_add_watch */ + case 27: { + *n_args = 0; + break; + } + /* linux_inotify_rm_watch */ + case 28: { + *n_args = 0; + break; + } + /* linux_ioctl */ + case 29: { + struct linux_ioctl_args *p = params; + iarg[a++] = p->fd; /* l_uint */ + iarg[a++] = p->cmd; /* l_uint */ + uarg[a++] = (intptr_t)p->arg; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_ioprio_set */ + case 30: { + struct linux_ioprio_set_args *p = params; + iarg[a++] = p->which; /* l_int */ + iarg[a++] = p->who; /* l_int */ + iarg[a++] = p->ioprio; /* l_int */ + *n_args = 3; + break; + } + /* linux_ioprio_get */ + case 31: { + struct linux_ioprio_get_args *p = params; + iarg[a++] = p->which; /* l_int */ + iarg[a++] = p->who; /* l_int */ + *n_args = 2; + break; + } + /* flock */ + case 32: { + struct flock_args *p = params; + iarg[a++] = p->fd; /* int */ + iarg[a++] = p->how; /* int */ + *n_args = 2; + break; + } + /* linux_mknodat */ + case 33: { + struct linux_mknodat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->filename; /* const char * */ + iarg[a++] = p->mode; /* l_int */ + iarg[a++] = p->dev; /* l_dev_t */ + *n_args = 4; + break; + } + /* linux_mkdirat */ + case 34: { + struct linux_mkdirat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->pathname; /* const char * */ + iarg[a++] = p->mode; /* l_mode_t */ + *n_args = 3; + break; + } + /* linux_unlinkat */ + case 35: { + struct linux_unlinkat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->pathname; /* const char * */ + iarg[a++] = p->flag; /* l_int */ + *n_args = 3; + break; + } + /* linux_symlinkat */ + case 36: { + struct linux_symlinkat_args *p = params; + uarg[a++] = (intptr_t)p->oldname; /* const char * */ + iarg[a++] = p->newdfd; /* l_int */ + uarg[a++] = (intptr_t)p->newname; /* const char * */ + *n_args = 3; + break; + } + /* linux_linkat */ + case 37: { + struct linux_linkat_args *p = params; + iarg[a++] = p->olddfd; /* l_int */ + uarg[a++] = (intptr_t)p->oldname; /* const char * */ + iarg[a++] = p->newdfd; /* l_int */ + uarg[a++] = (intptr_t)p->newname; /* const char * */ + iarg[a++] = p->flag; /* l_int */ + *n_args = 5; + break; + } + /* linux_renameat */ + case 38: { + struct linux_renameat_args *p = params; + iarg[a++] = p->olddfd; /* l_int */ + uarg[a++] = (intptr_t)p->oldname; /* const char * */ + iarg[a++] = p->newdfd; /* l_int */ + uarg[a++] = (intptr_t)p->newname; /* const char * */ + *n_args = 4; + break; + } + /* linux_mount */ + case 40: { + struct linux_mount_args *p = params; + uarg[a++] = (intptr_t)p->specialfile; /* char * */ + uarg[a++] = (intptr_t)p->dir; /* char * */ + uarg[a++] = (intptr_t)p->filesystemtype; /* char * */ + iarg[a++] = p->rwflag; /* l_ulong */ + uarg[a++] = (intptr_t)p->data; /* void * */ + *n_args = 5; + break; + } + /* linux_pivot_root */ + case 41: { + *n_args = 0; + break; + } + /* linux_statfs */ + case 43: { + struct linux_statfs_args *p = params; + uarg[a++] = (intptr_t)p->path; /* char * */ + uarg[a++] = (intptr_t)p->buf; /* struct l_statfs_buf * */ + *n_args = 2; + break; + } + /* linux_fstatfs */ + case 44: { + struct linux_fstatfs_args *p = params; + iarg[a++] = p->fd; /* l_uint */ + uarg[a++] = (intptr_t)p->buf; /* struct l_statfs_buf * */ + *n_args = 2; + break; + } + /* linux_truncate */ + case 45: { + struct linux_truncate_args *p = params; + uarg[a++] = (intptr_t)p->path; /* char * */ + iarg[a++] = p->length; /* l_ulong */ + *n_args = 2; + break; + } + /* linux_ftruncate */ + case 46: { + struct linux_ftruncate_args *p = params; + iarg[a++] = p->fd; /* l_int */ + iarg[a++] = p->length; /* l_long */ + *n_args = 2; + break; + } + /* linux_fallocate */ + case 47: { + struct linux_fallocate_args *p = params; + iarg[a++] = p->fd; /* l_int */ + iarg[a++] = p->mode; /* l_int */ + iarg[a++] = p->offset; /* l_loff_t */ + iarg[a++] = p->len; /* l_loff_t */ + *n_args = 4; + break; + } + /* linux_faccessat */ + case 48: { + struct linux_faccessat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->filename; /* const char * */ + iarg[a++] = p->amode; /* l_int */ + *n_args = 3; + break; + } + /* linux_chdir */ + case 49: { + struct linux_chdir_args *p = params; + uarg[a++] = (intptr_t)p->path; /* char * */ + *n_args = 1; + break; + } + /* fchdir */ + case 50: { + struct fchdir_args *p = params; + iarg[a++] = p->fd; /* int */ + *n_args = 1; + break; + } + /* linux_chroot */ + case 51: { + struct linux_chroot_args *p = params; + uarg[a++] = (intptr_t)p->path; /* char * */ + *n_args = 1; + break; + } + /* fchmod */ + case 52: { + struct fchmod_args *p = params; + iarg[a++] = p->fd; /* int */ + iarg[a++] = p->mode; /* int */ + *n_args = 2; + break; + } + /* linux_fchmodat */ + case 53: { + struct linux_fchmodat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->filename; /* const char * */ + iarg[a++] = p->mode; /* l_mode_t */ + *n_args = 3; + break; + } + /* linux_fchownat */ + case 54: { + struct linux_fchownat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->filename; /* const char * */ + iarg[a++] = p->uid; /* l_uid_t */ + iarg[a++] = p->gid; /* l_gid_t */ + iarg[a++] = p->flag; /* l_int */ + *n_args = 5; + break; + } + /* fchown */ + case 55: { + struct fchown_args *p = params; + iarg[a++] = p->fd; /* int */ + iarg[a++] = p->uid; /* int */ + iarg[a++] = p->gid; /* int */ + *n_args = 3; + break; + } + /* linux_openat */ + case 56: { + struct linux_openat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->filename; /* const char * */ + iarg[a++] = p->flags; /* l_int */ + iarg[a++] = p->mode; /* l_mode_t */ + *n_args = 4; + break; + } + /* close */ + case 57: { + struct close_args *p = params; + iarg[a++] = p->fd; /* int */ + *n_args = 1; + break; + } + /* linux_vhangup */ + case 58: { + *n_args = 0; + break; + } + /* linux_pipe2 */ + case 59: { + struct linux_pipe2_args *p = params; + uarg[a++] = (intptr_t)p->pipefds; /* l_int * */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 2; + break; + } + /* linux_getdents64 */ + case 61: { + struct linux_getdents64_args *p = params; + iarg[a++] = p->fd; /* l_uint */ + uarg[a++] = (intptr_t)p->dirent; /* void * */ + iarg[a++] = p->count; /* l_uint */ + *n_args = 3; + break; + } + /* linux_lseek */ + case 62: { + struct linux_lseek_args *p = params; + iarg[a++] = p->fdes; /* l_uint */ + iarg[a++] = p->off; /* l_off_t */ + iarg[a++] = p->whence; /* l_int */ + *n_args = 3; + break; + } + /* linux_read */ + case 63: { + struct linux_read_args *p = params; + iarg[a++] = p->fd; /* int */ + uarg[a++] = (intptr_t)p->buf; /* char * */ + iarg[a++] = p->nbyte; /* l_size_t */ + *n_args = 3; + break; + } + /* linux_write */ + case 64: { + struct linux_write_args *p = params; + iarg[a++] = p->fd; /* int */ + uarg[a++] = (intptr_t)p->buf; /* char * */ + iarg[a++] = p->nbyte; /* l_size_t */ + *n_args = 3; + break; + } + /* linux_readv */ + case 65: { + struct linux_readv_args *p = params; + iarg[a++] = p->fd; /* int */ + uarg[a++] = (intptr_t)p->iovp; /* struct iovec * */ + uarg[a++] = p->iovcnt; /* u_int */ + *n_args = 3; + break; + } + /* linux_writev */ + case 66: { + struct linux_writev_args *p = params; + iarg[a++] = p->fd; /* int */ + uarg[a++] = (intptr_t)p->iovp; /* struct iovec * */ + uarg[a++] = p->iovcnt; /* u_int */ + *n_args = 3; + break; + } + /* linux_pread */ + case 67: { + struct linux_pread_args *p = params; + iarg[a++] = p->fd; /* l_uint */ + uarg[a++] = (intptr_t)p->buf; /* char * */ + iarg[a++] = p->nbyte; /* l_size_t */ + iarg[a++] = p->offset; /* l_loff_t */ + *n_args = 4; + break; + } + /* linux_pwrite */ + case 68: { + struct linux_pwrite_args *p = params; + iarg[a++] = p->fd; /* l_uint */ + uarg[a++] = (intptr_t)p->buf; /* char * */ + iarg[a++] = p->nbyte; /* l_size_t */ + iarg[a++] = p->offset; /* l_loff_t */ + *n_args = 4; + break; + } + /* linux_preadv */ + case 69: { + struct linux_preadv_args *p = params; + iarg[a++] = p->fd; /* l_ulong */ + uarg[a++] = (intptr_t)p->vec; /* struct iovec * */ + iarg[a++] = p->vlen; /* l_ulong */ + iarg[a++] = p->pos_l; /* l_ulong */ + iarg[a++] = p->pos_h; /* l_ulong */ + *n_args = 5; + break; + } + /* linux_pwritev */ + case 70: { + struct linux_pwritev_args *p = params; + iarg[a++] = p->fd; /* l_ulong */ + uarg[a++] = (intptr_t)p->vec; /* struct iovec * */ + iarg[a++] = p->vlen; /* l_ulong */ + iarg[a++] = p->pos_l; /* l_ulong */ + iarg[a++] = p->pos_h; /* l_ulong */ + *n_args = 5; + break; + } + /* linux_sendfile */ + case 71: { + struct linux_sendfile_args *p = params; + iarg[a++] = p->out; /* l_int */ + iarg[a++] = p->in; /* l_int */ + uarg[a++] = (intptr_t)p->offset; /* l_off_t * */ + iarg[a++] = p->count; /* l_size_t */ + *n_args = 4; + break; + } + /* linux_pselect6 */ + case 72: { + struct linux_pselect6_args *p = params; + iarg[a++] = p->nfds; /* l_int */ + uarg[a++] = (intptr_t)p->readfds; /* l_fd_set * */ + uarg[a++] = (intptr_t)p->writefds; /* l_fd_set * */ + uarg[a++] = (intptr_t)p->exceptfds; /* l_fd_set * */ + uarg[a++] = (intptr_t)p->tsp; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->sig; /* l_uintptr_t * */ + *n_args = 6; + break; + } + /* linux_ppoll */ + case 73: { + struct linux_ppoll_args *p = params; + uarg[a++] = (intptr_t)p->fds; /* struct pollfd * */ + iarg[a++] = p->nfds; /* l_uint */ + uarg[a++] = (intptr_t)p->tsp; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->sset; /* l_sigset_t * */ + iarg[a++] = p->ssize; /* l_size_t */ + *n_args = 5; + break; + } + /* linux_signalfd4 */ + case 74: { + *n_args = 0; + break; + } + /* linux_vmsplice */ + case 75: { + *n_args = 0; + break; + } + /* linux_splice */ + case 76: { + struct linux_splice_args *p = params; + iarg[a++] = p->fd_in; /* int */ + uarg[a++] = (intptr_t)p->off_in; /* l_loff_t * */ + iarg[a++] = p->fd_out; /* int */ + uarg[a++] = (intptr_t)p->off_out; /* l_loff_t * */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 6; + break; + } + /* linux_tee */ + case 77: { + *n_args = 0; + break; + } + /* linux_readlinkat */ + case 78: { + struct linux_readlinkat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->path; /* const char * */ + uarg[a++] = (intptr_t)p->buf; /* char * */ + iarg[a++] = p->bufsiz; /* l_int */ + *n_args = 4; + break; + } + /* linux_newfstatat */ + case 79: { + struct linux_newfstatat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->pathname; /* char * */ + uarg[a++] = (intptr_t)p->statbuf; /* struct l_newstat * */ + iarg[a++] = p->flag; /* l_int */ + *n_args = 4; + break; + } + /* linux_newfstat */ + case 80: { + struct linux_newfstat_args *p = params; + iarg[a++] = p->fd; /* l_uint */ + uarg[a++] = (intptr_t)p->buf; /* struct l_newstat * */ + *n_args = 2; + break; + } + /* fsync */ + case 82: { + struct fsync_args *p = params; + iarg[a++] = p->fd; /* int */ + *n_args = 1; + break; + } + /* linux_fdatasync */ + case 83: { + struct linux_fdatasync_args *p = params; + iarg[a++] = p->fd; /* l_uint */ + *n_args = 1; + break; + } + /* linux_sync_file_range */ + case 84: { + struct linux_sync_file_range_args *p = params; + iarg[a++] = p->fd; /* l_int */ + iarg[a++] = p->offset; /* l_loff_t */ + iarg[a++] = p->nbytes; /* l_loff_t */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 4; + break; + } + /* linux_timerfd_create */ + case 85: { + struct linux_timerfd_create_args *p = params; + iarg[a++] = p->clockid; /* l_int */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 2; + break; + } + /* linux_timerfd_settime */ + case 86: { + struct linux_timerfd_settime_args *p = params; + iarg[a++] = p->fd; /* l_int */ + iarg[a++] = p->flags; /* l_int */ + uarg[a++] = (intptr_t)p->new_value; /* const struct l_itimerspec * */ + uarg[a++] = (intptr_t)p->old_value; /* struct l_itimerspec * */ + *n_args = 4; + break; + } + /* linux_timerfd_gettime */ + case 87: { + struct linux_timerfd_gettime_args *p = params; + iarg[a++] = p->fd; /* l_int */ + uarg[a++] = (intptr_t)p->old_value; /* struct l_itimerspec * */ + *n_args = 2; + break; + } + /* linux_utimensat */ + case 88: { + struct linux_utimensat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->pathname; /* const char * */ + uarg[a++] = (intptr_t)p->times; /* const struct l_timespec * */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 4; + break; + } + /* linux_acct */ + case 89: { + struct linux_acct_args *p = params; + uarg[a++] = (intptr_t)p->path; /* char * */ + *n_args = 1; + break; + } + /* linux_capget */ + case 90: { + struct linux_capget_args *p = params; + uarg[a++] = (intptr_t)p->hdrp; /* struct l_user_cap_header * */ + uarg[a++] = (intptr_t)p->datap; /* struct l_user_cap_data * */ + *n_args = 2; + break; + } + /* linux_capset */ + case 91: { + struct linux_capset_args *p = params; + uarg[a++] = (intptr_t)p->hdrp; /* struct l_user_cap_header * */ + uarg[a++] = (intptr_t)p->datap; /* struct l_user_cap_data * */ + *n_args = 2; + break; + } + /* linux_personality */ + case 92: { + struct linux_personality_args *p = params; + iarg[a++] = p->per; /* l_uint */ + *n_args = 1; + break; + } + /* linux_exit */ + case 93: { + struct linux_exit_args *p = params; + uarg[a++] = p->rval; /* u_int */ + *n_args = 1; + break; + } + /* linux_exit_group */ + case 94: { + struct linux_exit_group_args *p = params; + iarg[a++] = p->error_code; /* l_int */ + *n_args = 1; + break; + } + /* linux_waitid */ + case 95: { + struct linux_waitid_args *p = params; + iarg[a++] = p->idtype; /* l_int */ + iarg[a++] = p->id; /* l_pid_t */ + uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * */ + iarg[a++] = p->options; /* l_int */ + uarg[a++] = (intptr_t)p->rusage; /* struct rusage * */ + *n_args = 5; + break; + } + /* linux_set_tid_address */ + case 96: { + struct linux_set_tid_address_args *p = params; + uarg[a++] = (intptr_t)p->tidptr; /* l_int * */ + *n_args = 1; + break; + } + /* linux_unshare */ + case 97: { + *n_args = 0; + break; + } + /* linux_sys_futex */ + case 98: { + struct linux_sys_futex_args *p = params; + uarg[a++] = (intptr_t)p->uaddr; /* uint32_t * */ + iarg[a++] = p->op; /* l_int */ + uarg[a++] = p->val; /* uint32_t */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->uaddr2; /* uint32_t * */ + uarg[a++] = p->val3; /* uint32_t */ + *n_args = 6; + break; + } + /* linux_set_robust_list */ + case 99: { + struct linux_set_robust_list_args *p = params; + uarg[a++] = (intptr_t)p->head; /* struct linux_robust_list_head * */ + iarg[a++] = p->len; /* l_size_t */ + *n_args = 2; + break; + } + /* linux_get_robust_list */ + case 100: { + struct linux_get_robust_list_args *p = params; + iarg[a++] = p->pid; /* l_int */ + uarg[a++] = (intptr_t)p->head; /* struct linux_robust_list_head ** */ + uarg[a++] = (intptr_t)p->len; /* l_size_t * */ + *n_args = 3; + break; + } + /* linux_nanosleep */ + case 101: { + struct linux_nanosleep_args *p = params; + uarg[a++] = (intptr_t)p->rqtp; /* const struct l_timespec * */ + uarg[a++] = (intptr_t)p->rmtp; /* struct l_timespec * */ + *n_args = 2; + break; + } + /* linux_getitimer */ + case 102: { + struct linux_getitimer_args *p = params; + iarg[a++] = p->which; /* l_int */ + uarg[a++] = (intptr_t)p->itv; /* struct l_itimerval * */ + *n_args = 2; + break; + } + /* linux_setitimer */ + case 103: { + struct linux_setitimer_args *p = params; + iarg[a++] = p->which; /* l_int */ + uarg[a++] = (intptr_t)p->itv; /* struct l_itimerval * */ + uarg[a++] = (intptr_t)p->oitv; /* struct l_itimerval * */ + *n_args = 3; + break; + } + /* linux_kexec_load */ + case 104: { + *n_args = 0; + break; + } + /* linux_init_module */ + case 105: { + *n_args = 0; + break; + } + /* linux_delete_module */ + case 106: { + *n_args = 0; + break; + } + /* linux_timer_create */ + case 107: { + struct linux_timer_create_args *p = params; + iarg[a++] = p->clock_id; /* clockid_t */ + uarg[a++] = (intptr_t)p->evp; /* struct l_sigevent * */ + uarg[a++] = (intptr_t)p->timerid; /* l_timer_t * */ + *n_args = 3; + break; + } + /* linux_timer_gettime */ + case 108: { + struct linux_timer_gettime_args *p = params; + iarg[a++] = p->timerid; /* l_timer_t */ + uarg[a++] = (intptr_t)p->setting; /* struct itimerspec * */ + *n_args = 2; + break; + } + /* linux_timer_getoverrun */ + case 109: { + struct linux_timer_getoverrun_args *p = params; + iarg[a++] = p->timerid; /* l_timer_t */ + *n_args = 1; + break; + } + /* linux_timer_settime */ + case 110: { + struct linux_timer_settime_args *p = params; + iarg[a++] = p->timerid; /* l_timer_t */ + iarg[a++] = p->flags; /* l_int */ + uarg[a++] = (intptr_t)p->new; /* const struct itimerspec * */ + uarg[a++] = (intptr_t)p->old; /* struct itimerspec * */ + *n_args = 4; + break; + } + /* linux_timer_delete */ + case 111: { + struct linux_timer_delete_args *p = params; + iarg[a++] = p->timerid; /* l_timer_t */ + *n_args = 1; + break; + } + /* linux_clock_settime */ + case 112: { + struct linux_clock_settime_args *p = params; + iarg[a++] = p->which; /* clockid_t */ + uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * */ + *n_args = 2; + break; + } + /* linux_clock_gettime */ + case 113: { + struct linux_clock_gettime_args *p = params; + iarg[a++] = p->which; /* clockid_t */ + uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * */ + *n_args = 2; + break; + } + /* linux_clock_getres */ + case 114: { + struct linux_clock_getres_args *p = params; + iarg[a++] = p->which; /* clockid_t */ + uarg[a++] = (intptr_t)p->tp; /* struct l_timespec * */ + *n_args = 2; + break; + } + /* linux_clock_nanosleep */ + case 115: { + struct linux_clock_nanosleep_args *p = params; + iarg[a++] = p->which; /* clockid_t */ + iarg[a++] = p->flags; /* l_int */ + uarg[a++] = (intptr_t)p->rqtp; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->rmtp; /* struct l_timespec * */ + *n_args = 4; + break; + } + /* linux_syslog */ + case 116: { + struct linux_syslog_args *p = params; + iarg[a++] = p->type; /* l_int */ + uarg[a++] = (intptr_t)p->buf; /* char * */ + iarg[a++] = p->len; /* l_int */ + *n_args = 3; + break; + } + /* linux_ptrace */ + case 117: { + struct linux_ptrace_args *p = params; + iarg[a++] = p->req; /* l_long */ + iarg[a++] = p->pid; /* l_long */ + uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->data; /* l_uintptr_t */ + *n_args = 4; + break; + } + /* linux_sched_setparam */ + case 118: { + struct linux_sched_setparam_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + uarg[a++] = (intptr_t)p->param; /* struct sched_param * */ + *n_args = 2; + break; + } + /* linux_sched_setscheduler */ + case 119: { + struct linux_sched_setscheduler_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + iarg[a++] = p->policy; /* l_int */ + uarg[a++] = (intptr_t)p->param; /* struct sched_param * */ + *n_args = 3; + break; + } + /* linux_sched_getscheduler */ + case 120: { + struct linux_sched_getscheduler_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + *n_args = 1; + break; + } + /* linux_sched_getparam */ + case 121: { + struct linux_sched_getparam_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + uarg[a++] = (intptr_t)p->param; /* struct sched_param * */ + *n_args = 2; + break; + } + /* linux_sched_setaffinity */ + case 122: { + struct linux_sched_setaffinity_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + iarg[a++] = p->len; /* l_uint */ + uarg[a++] = (intptr_t)p->user_mask_ptr; /* l_ulong * */ + *n_args = 3; + break; + } + /* linux_sched_getaffinity */ + case 123: { + struct linux_sched_getaffinity_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + iarg[a++] = p->len; /* l_uint */ + uarg[a++] = (intptr_t)p->user_mask_ptr; /* l_ulong * */ + *n_args = 3; + break; + } + /* sched_yield */ + case 124: { + *n_args = 0; + break; + } + /* linux_sched_get_priority_max */ + case 125: { + struct linux_sched_get_priority_max_args *p = params; + iarg[a++] = p->policy; /* l_int */ + *n_args = 1; + break; + } + /* linux_sched_get_priority_min */ + case 126: { + struct linux_sched_get_priority_min_args *p = params; + iarg[a++] = p->policy; /* l_int */ + *n_args = 1; + break; + } + /* linux_sched_rr_get_interval */ + case 127: { + struct linux_sched_rr_get_interval_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + uarg[a++] = (intptr_t)p->interval; /* struct l_timespec * */ + *n_args = 2; + break; + } + /* linux_kill */ + case 129: { + struct linux_kill_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + iarg[a++] = p->signum; /* l_int */ + *n_args = 2; + break; + } + /* linux_tkill */ + case 130: { + struct linux_tkill_args *p = params; + iarg[a++] = p->tid; /* l_pid_t */ + iarg[a++] = p->sig; /* l_int */ + *n_args = 2; + break; + } + /* linux_tgkill */ + case 131: { + struct linux_tgkill_args *p = params; + iarg[a++] = p->tgid; /* l_pid_t */ + iarg[a++] = p->pid; /* l_pid_t */ + iarg[a++] = p->sig; /* l_int */ + *n_args = 3; + break; + } + /* linux_sigaltstack */ + case 132: { + struct linux_sigaltstack_args *p = params; + uarg[a++] = (intptr_t)p->uss; /* l_stack_t * */ + uarg[a++] = (intptr_t)p->uoss; /* l_stack_t * */ + *n_args = 2; + break; + } + /* linux_rt_sigsuspend */ + case 133: { + struct linux_rt_sigsuspend_args *p = params; + uarg[a++] = (intptr_t)p->newset; /* l_sigset_t * */ + iarg[a++] = p->sigsetsize; /* l_size_t */ + *n_args = 2; + break; + } + /* linux_rt_sigaction */ + case 134: { + struct linux_rt_sigaction_args *p = params; + iarg[a++] = p->sig; /* l_int */ + uarg[a++] = (intptr_t)p->act; /* l_sigaction_t * */ + uarg[a++] = (intptr_t)p->oact; /* l_sigaction_t * */ + iarg[a++] = p->sigsetsize; /* l_size_t */ + *n_args = 4; + break; + } + /* linux_rt_sigprocmask */ + case 135: { + struct linux_rt_sigprocmask_args *p = params; + iarg[a++] = p->how; /* l_int */ + uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * */ + uarg[a++] = (intptr_t)p->omask; /* l_sigset_t * */ + iarg[a++] = p->sigsetsize; /* l_size_t */ + *n_args = 4; + break; + } + /* linux_rt_sigpending */ + case 136: { + struct linux_rt_sigpending_args *p = params; + uarg[a++] = (intptr_t)p->set; /* l_sigset_t * */ + iarg[a++] = p->sigsetsize; /* l_size_t */ + *n_args = 2; + break; + } + /* linux_rt_sigtimedwait */ + case 137: { + struct linux_rt_sigtimedwait_args *p = params; + uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * */ + uarg[a++] = (intptr_t)p->ptr; /* l_siginfo_t * */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ + iarg[a++] = p->sigsetsize; /* l_size_t */ + *n_args = 4; + break; + } + /* linux_rt_sigqueueinfo */ + case 138: { + struct linux_rt_sigqueueinfo_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + iarg[a++] = p->sig; /* l_int */ + uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * */ + *n_args = 3; + break; + } + /* linux_rt_sigreturn */ + case 139: { + *n_args = 0; + break; + } + /* setpriority */ + case 140: { + struct setpriority_args *p = params; + iarg[a++] = p->which; /* int */ + iarg[a++] = p->who; /* int */ + iarg[a++] = p->prio; /* int */ + *n_args = 3; + break; + } + /* linux_getpriority */ + case 141: { + struct linux_getpriority_args *p = params; + iarg[a++] = p->which; /* l_int */ + iarg[a++] = p->who; /* l_int */ + *n_args = 2; + break; + } + /* linux_reboot */ + case 142: { + struct linux_reboot_args *p = params; + iarg[a++] = p->magic1; /* l_int */ + iarg[a++] = p->magic2; /* l_int */ + iarg[a++] = p->cmd; /* l_uint */ + uarg[a++] = (intptr_t)p->arg; /* void * */ + *n_args = 4; + break; + } + /* setregid */ + case 143: { + struct setregid_args *p = params; + iarg[a++] = p->rgid; /* gid_t */ + iarg[a++] = p->egid; /* gid_t */ + *n_args = 2; + break; + } + /* setgid */ + case 144: { + struct setgid_args *p = params; + iarg[a++] = p->gid; /* gid_t */ + *n_args = 1; + break; + } + /* setreuid */ + case 145: { + struct setreuid_args *p = params; + uarg[a++] = p->ruid; /* uid_t */ + uarg[a++] = p->euid; /* uid_t */ + *n_args = 2; + break; + } + /* setuid */ + case 146: { + struct setuid_args *p = params; + uarg[a++] = p->uid; /* uid_t */ + *n_args = 1; + break; + } + /* setresuid */ + case 147: { + struct setresuid_args *p = params; + uarg[a++] = p->ruid; /* uid_t */ + uarg[a++] = p->euid; /* uid_t */ + uarg[a++] = p->suid; /* uid_t */ + *n_args = 3; + break; + } + /* linux_getresuid */ + case 148: { + struct linux_getresuid_args *p = params; + uarg[a++] = (intptr_t)p->ruid; /* l_uid_t * */ + uarg[a++] = (intptr_t)p->euid; /* l_uid_t * */ + uarg[a++] = (intptr_t)p->suid; /* l_uid_t * */ + *n_args = 3; + break; + } + /* setresgid */ + case 149: { + struct setresgid_args *p = params; + iarg[a++] = p->rgid; /* gid_t */ + iarg[a++] = p->egid; /* gid_t */ + iarg[a++] = p->sgid; /* gid_t */ + *n_args = 3; + break; + } + /* linux_getresgid */ + case 150: { + struct linux_getresgid_args *p = params; + uarg[a++] = (intptr_t)p->rgid; /* l_gid_t * */ + uarg[a++] = (intptr_t)p->egid; /* l_gid_t * */ + uarg[a++] = (intptr_t)p->sgid; /* l_gid_t * */ + *n_args = 3; + break; + } + /* linux_setfsuid */ + case 151: { + struct linux_setfsuid_args *p = params; + iarg[a++] = p->uid; /* l_uid_t */ + *n_args = 1; + break; + } + /* linux_setfsgid */ + case 152: { + struct linux_setfsgid_args *p = params; + iarg[a++] = p->gid; /* l_gid_t */ + *n_args = 1; + break; + } + /* linux_times */ + case 153: { + struct linux_times_args *p = params; + uarg[a++] = (intptr_t)p->buf; /* struct l_times_argv * */ + *n_args = 1; + break; + } + /* setpgid */ + case 154: { + struct setpgid_args *p = params; + iarg[a++] = p->pid; /* int */ + iarg[a++] = p->pgid; /* int */ + *n_args = 2; + break; + } + /* getpgid */ + case 155: { + struct getpgid_args *p = params; + iarg[a++] = p->pid; /* int */ + *n_args = 1; + break; + } + /* linux_getsid */ + case 156: { + struct linux_getsid_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + *n_args = 1; + break; + } + /* setsid */ + case 157: { + *n_args = 0; + break; + } + /* linux_getgroups */ + case 158: { + struct linux_getgroups_args *p = params; + iarg[a++] = p->gidsetsize; /* l_int */ + uarg[a++] = (intptr_t)p->grouplist; /* l_gid_t * */ + *n_args = 2; + break; + } + /* linux_setgroups */ + case 159: { + struct linux_setgroups_args *p = params; + iarg[a++] = p->gidsetsize; /* l_int */ + uarg[a++] = (intptr_t)p->grouplist; /* l_gid_t * */ + *n_args = 2; + break; + } + /* linux_newuname */ + case 160: { + struct linux_newuname_args *p = params; + uarg[a++] = (intptr_t)p->buf; /* struct l_new_utsname * */ + *n_args = 1; + break; + } + /* linux_sethostname */ + case 161: { + struct linux_sethostname_args *p = params; + uarg[a++] = (intptr_t)p->hostname; /* char * */ + iarg[a++] = p->len; /* l_uint */ + *n_args = 2; + break; + } + /* linux_setdomainname */ + case 162: { + struct linux_setdomainname_args *p = params; + uarg[a++] = (intptr_t)p->name; /* char * */ + iarg[a++] = p->len; /* l_int */ + *n_args = 2; + break; + } + /* linux_getrlimit */ + case 163: { + struct linux_getrlimit_args *p = params; + iarg[a++] = p->resource; /* l_uint */ + uarg[a++] = (intptr_t)p->rlim; /* struct l_rlimit * */ + *n_args = 2; + break; + } + /* linux_setrlimit */ + case 164: { + struct linux_setrlimit_args *p = params; + iarg[a++] = p->resource; /* l_uint */ + uarg[a++] = (intptr_t)p->rlim; /* struct l_rlimit * */ + *n_args = 2; + break; + } + /* linux_getrusage */ + case 165: { + struct linux_getrusage_args *p = params; + iarg[a++] = p->who; /* l_int */ + uarg[a++] = (intptr_t)p->rusage; /* struct rusage * */ + *n_args = 2; + break; + } + /* umask */ + case 166: { + struct umask_args *p = params; + iarg[a++] = p->newmask; /* int */ + *n_args = 1; + break; + } + /* linux_prctl */ + case 167: { + struct linux_prctl_args *p = params; + iarg[a++] = p->option; /* l_int */ + uarg[a++] = (intptr_t)p->arg2; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->arg3; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->arg4; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->arg5; /* l_uintptr_t */ + *n_args = 5; + break; + } + /* linux_getcpu */ + case 168: { + struct linux_getcpu_args *p = params; + uarg[a++] = (intptr_t)p->cpu; /* l_uint * */ + uarg[a++] = (intptr_t)p->node; /* l_uint * */ + uarg[a++] = (intptr_t)p->cache; /* void * */ + *n_args = 3; + break; + } + /* linux_gettimeofday */ + case 169: { + struct linux_gettimeofday_args *p = params; + uarg[a++] = (intptr_t)p->tp; /* l_timeval * */ + uarg[a++] = (intptr_t)p->tzp; /* struct timezone * */ + *n_args = 2; + break; + } + /* linux_settimeofday */ + case 170: { + struct linux_settimeofday_args *p = params; + uarg[a++] = (intptr_t)p->tv; /* l_timeval * */ + uarg[a++] = (intptr_t)p->tzp; /* struct timezone * */ + *n_args = 2; + break; + } + /* linux_adjtimex */ + case 171: { + *n_args = 0; + break; + } + /* linux_getpid */ + case 172: { + *n_args = 0; + break; + } + /* linux_getppid */ + case 173: { + *n_args = 0; + break; + } + /* linux_getuid */ + case 174: { + *n_args = 0; + break; + } + /* geteuid */ + case 175: { + *n_args = 0; + break; + } + /* linux_getgid */ + case 176: { + *n_args = 0; + break; + } + /* getegid */ + case 177: { + *n_args = 0; + break; + } + /* linux_gettid */ + case 178: { + *n_args = 0; + break; + } + /* linux_sysinfo */ + case 179: { + struct linux_sysinfo_args *p = params; + uarg[a++] = (intptr_t)p->info; /* struct l_sysinfo * */ + *n_args = 1; + break; + } + /* linux_mq_open */ + case 180: { + struct linux_mq_open_args *p = params; + uarg[a++] = (intptr_t)p->name; /* const char * */ + iarg[a++] = p->oflag; /* l_int */ + iarg[a++] = p->mode; /* l_mode_t */ + uarg[a++] = (intptr_t)p->attr; /* struct mq_attr * */ + *n_args = 4; + break; + } + /* linux_mq_unlink */ + case 181: { + struct linux_mq_unlink_args *p = params; + uarg[a++] = (intptr_t)p->name; /* const char * */ + *n_args = 1; + break; + } + /* linux_mq_timedsend */ + case 182: { + struct linux_mq_timedsend_args *p = params; + iarg[a++] = p->mqd; /* l_mqd_t */ + uarg[a++] = (intptr_t)p->msg_ptr; /* const char * */ + iarg[a++] = p->msg_len; /* l_size_t */ + iarg[a++] = p->msg_prio; /* l_uint */ + uarg[a++] = (intptr_t)p->abs_timeout; /* const struct l_timespec * */ + *n_args = 5; + break; + } + /* linux_mq_timedreceive */ + case 183: { + struct linux_mq_timedreceive_args *p = params; + iarg[a++] = p->mqd; /* l_mqd_t */ + uarg[a++] = (intptr_t)p->msg_ptr; /* char * */ + iarg[a++] = p->msg_len; /* l_size_t */ + uarg[a++] = (intptr_t)p->msg_prio; /* l_uint * */ + uarg[a++] = (intptr_t)p->abs_timeout; /* const struct l_timespec * */ + *n_args = 5; + break; + } + /* linux_mq_notify */ + case 184: { + struct linux_mq_notify_args *p = params; + iarg[a++] = p->mqd; /* l_mqd_t */ + uarg[a++] = (intptr_t)p->sevp; /* const struct l_sigevent * */ + *n_args = 2; + break; + } + /* linux_mq_getsetattr */ + case 185: { + struct linux_mq_getsetattr_args *p = params; + iarg[a++] = p->mqd; /* l_mqd_t */ + uarg[a++] = (intptr_t)p->attr; /* const struct mq_attr * */ + uarg[a++] = (intptr_t)p->oattr; /* struct mq_attr * */ + *n_args = 3; + break; + } + /* linux_msgget */ + case 186: { + struct linux_msgget_args *p = params; + iarg[a++] = p->key; /* l_key_t */ + iarg[a++] = p->msgflg; /* l_int */ + *n_args = 2; + break; + } + /* linux_msgctl */ + case 187: { + struct linux_msgctl_args *p = params; + iarg[a++] = p->msqid; /* l_int */ + iarg[a++] = p->cmd; /* l_int */ + uarg[a++] = (intptr_t)p->buf; /* struct l_msqid_ds * */ + *n_args = 3; + break; + } + /* linux_msgrcv */ + case 188: { + struct linux_msgrcv_args *p = params; + iarg[a++] = p->msqid; /* l_int */ + uarg[a++] = (intptr_t)p->msgp; /* struct l_msgbuf * */ + iarg[a++] = p->msgsz; /* l_size_t */ + iarg[a++] = p->msgtyp; /* l_long */ + iarg[a++] = p->msgflg; /* l_int */ + *n_args = 5; + break; + } + /* linux_msgsnd */ + case 189: { + struct linux_msgsnd_args *p = params; + iarg[a++] = p->msqid; /* l_int */ + uarg[a++] = (intptr_t)p->msgp; /* struct l_msgbuf * */ + iarg[a++] = p->msgsz; /* l_size_t */ + iarg[a++] = p->msgflg; /* l_int */ + *n_args = 4; + break; + } + /* linux_semget */ + case 190: { + struct linux_semget_args *p = params; + iarg[a++] = p->key; /* l_key_t */ + iarg[a++] = p->nsems; /* l_int */ + iarg[a++] = p->semflg; /* l_int */ + *n_args = 3; + break; + } + /* linux_semctl */ + case 191: { + struct linux_semctl_args *p = params; + iarg[a++] = p->semid; /* l_int */ + iarg[a++] = p->semnum; /* l_int */ + iarg[a++] = p->cmd; /* l_int */ + uarg[a++] = p->arg.buf; /* union l_semun */ + *n_args = 4; + break; + } + /* linux_semtimedop */ + case 192: { + struct linux_semtimedop_args *p = params; + iarg[a++] = p->semid; /* l_int */ + uarg[a++] = (intptr_t)p->tsops; /* struct sembuf * */ + iarg[a++] = p->nsops; /* l_size_t */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ + *n_args = 4; + break; + } + /* linux_semop */ + case 193: { + struct linux_semop_args *p = params; + iarg[a++] = p->semid; /* l_int */ + uarg[a++] = (intptr_t)p->sops; /* struct sembuf * */ + iarg[a++] = p->nsops; /* l_size_t */ + *n_args = 3; + break; + } + /* linux_shmget */ + case 194: { + struct linux_shmget_args *p = params; + iarg[a++] = p->key; /* l_key_t */ + iarg[a++] = p->size; /* l_size_t */ + iarg[a++] = p->shmflg; /* l_int */ + *n_args = 3; + break; + } + /* linux_shmctl */ + case 195: { + struct linux_shmctl_args *p = params; + iarg[a++] = p->shmid; /* l_int */ + iarg[a++] = p->cmd; /* l_int */ + uarg[a++] = (intptr_t)p->buf; /* struct l_shmid_ds * */ + *n_args = 3; + break; + } + /* linux_shmat */ + case 196: { + struct linux_shmat_args *p = params; + iarg[a++] = p->shmid; /* l_int */ + uarg[a++] = (intptr_t)p->shmaddr; /* char * */ + iarg[a++] = p->shmflg; /* l_int */ + *n_args = 3; + break; + } + /* linux_shmdt */ + case 197: { + struct linux_shmdt_args *p = params; + uarg[a++] = (intptr_t)p->shmaddr; /* char * */ + *n_args = 1; + break; + } + /* linux_socket */ + case 198: { + struct linux_socket_args *p = params; + iarg[a++] = p->domain; /* l_int */ + iarg[a++] = p->type; /* l_int */ + iarg[a++] = p->protocol; /* l_int */ + *n_args = 3; + break; + } + /* linux_socketpair */ + case 199: { + struct linux_socketpair_args *p = params; + iarg[a++] = p->domain; /* l_int */ + iarg[a++] = p->type; /* l_int */ + iarg[a++] = p->protocol; /* l_int */ + uarg[a++] = (intptr_t)p->rsv; /* l_uintptr_t */ + *n_args = 4; + break; + } + /* linux_bind */ + case 200: { + struct linux_bind_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->name; /* l_uintptr_t */ + iarg[a++] = p->namelen; /* l_int */ + *n_args = 3; + break; + } + /* linux_listen */ + case 201: { + struct linux_listen_args *p = params; + iarg[a++] = p->s; /* l_int */ + iarg[a++] = p->backlog; /* l_int */ + *n_args = 2; + break; + } + /* linux_accept */ + case 202: { + struct linux_accept_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->namelen; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_connect */ + case 203: { + struct linux_connect_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->name; /* l_uintptr_t */ + iarg[a++] = p->namelen; /* l_int */ + *n_args = 3; + break; + } + /* linux_getsockname */ + case 204: { + struct linux_getsockname_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->namelen; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_getpeername */ + case 205: { + struct linux_getpeername_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->namelen; /* l_uintptr_t */ + *n_args = 3; + break; + } + /* linux_sendto */ + case 206: { + struct linux_sendto_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->msg; /* l_uintptr_t */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->flags; /* l_uint */ + uarg[a++] = (intptr_t)p->to; /* l_uintptr_t */ + iarg[a++] = p->tolen; /* l_int */ + *n_args = 6; + break; + } + /* linux_recvfrom */ + case 207: { + struct linux_recvfrom_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->buf; /* l_uintptr_t */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->flags; /* l_uint */ + uarg[a++] = (intptr_t)p->from; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->fromlen; /* l_uintptr_t */ + *n_args = 6; + break; + } + /* linux_setsockopt */ + case 208: { + struct linux_setsockopt_args *p = params; + iarg[a++] = p->s; /* l_int */ + iarg[a++] = p->level; /* l_int */ + iarg[a++] = p->optname; /* l_int */ + uarg[a++] = (intptr_t)p->optval; /* l_uintptr_t */ + iarg[a++] = p->optlen; /* l_int */ + *n_args = 5; + break; + } + /* linux_getsockopt */ + case 209: { + struct linux_getsockopt_args *p = params; + iarg[a++] = p->s; /* l_int */ + iarg[a++] = p->level; /* l_int */ + iarg[a++] = p->optname; /* l_int */ + uarg[a++] = (intptr_t)p->optval; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->optlen; /* l_uintptr_t */ + *n_args = 5; + break; + } + /* linux_shutdown */ + case 210: { + struct linux_shutdown_args *p = params; + iarg[a++] = p->s; /* l_int */ + iarg[a++] = p->how; /* l_int */ + *n_args = 2; + break; + } + /* linux_sendmsg */ + case 211: { + struct linux_sendmsg_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->msg; /* l_uintptr_t */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_recvmsg */ + case 212: { + struct linux_recvmsg_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->msg; /* l_uintptr_t */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_brk */ + case 214: { + struct linux_brk_args *p = params; + iarg[a++] = p->dsend; /* l_ulong */ + *n_args = 1; + break; + } + /* linux_munmap */ + case 215: { + struct linux_munmap_args *p = params; + uarg[a++] = (intptr_t)p->addr; /* void * */ + iarg[a++] = p->len; /* l_size_t */ + *n_args = 2; + break; + } + /* linux_mremap */ + case 216: { + struct linux_mremap_args *p = params; + iarg[a++] = p->addr; /* l_ulong */ + iarg[a++] = p->old_len; /* l_ulong */ + iarg[a++] = p->new_len; /* l_ulong */ + iarg[a++] = p->flags; /* l_ulong */ + iarg[a++] = p->new_addr; /* l_ulong */ + *n_args = 5; + break; + } + /* linux_add_key */ + case 217: { + *n_args = 0; + break; + } + /* linux_request_key */ + case 218: { + *n_args = 0; + break; + } + /* linux_keyctl */ + case 219: { + *n_args = 0; + break; + } + /* linux_clone */ + case 220: { + struct linux_clone_args *p = params; + iarg[a++] = p->flags; /* l_ulong */ + iarg[a++] = p->stack; /* l_ulong */ + uarg[a++] = (intptr_t)p->parent_tidptr; /* l_int * */ + iarg[a++] = p->tls; /* l_ulong */ + uarg[a++] = (intptr_t)p->child_tidptr; /* l_int * */ + *n_args = 5; + break; + } + /* linux_execve */ + case 221: { + struct linux_execve_args *p = params; + uarg[a++] = (intptr_t)p->path; /* char * */ + uarg[a++] = (intptr_t)p->argp; /* l_uintptr_t * */ + uarg[a++] = (intptr_t)p->envp; /* l_uintptr_t * */ + *n_args = 3; + break; + } + /* linux_mmap2 */ + case 222: { + struct linux_mmap2_args *p = params; + iarg[a++] = p->addr; /* l_ulong */ + iarg[a++] = p->len; /* l_ulong */ + iarg[a++] = p->prot; /* l_ulong */ + iarg[a++] = p->flags; /* l_ulong */ + iarg[a++] = p->fd; /* l_ulong */ + iarg[a++] = p->pgoff; /* l_ulong */ + *n_args = 6; + break; + } + /* linux_fadvise64 */ + case 223: { + struct linux_fadvise64_args *p = params; + iarg[a++] = p->fd; /* l_int */ + iarg[a++] = p->offset; /* l_loff_t */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->advice; /* l_int */ + *n_args = 4; + break; + } + /* linux_swapon */ + case 224: { + struct linux_swapon_args *p = params; + uarg[a++] = (intptr_t)p->name; /* char * */ + *n_args = 1; + break; + } + /* linux_swapoff */ + case 225: { + *n_args = 0; + break; + } + /* linux_mprotect */ + case 226: { + struct linux_mprotect_args *p = params; + iarg[a++] = p->addr; /* l_ulong */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->prot; /* l_ulong */ + *n_args = 3; + break; + } + /* linux_msync */ + case 227: { + struct linux_msync_args *p = params; + iarg[a++] = p->addr; /* l_ulong */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->fl; /* l_int */ + *n_args = 3; + break; + } + /* linux_mlock */ + case 228: { + struct linux_mlock_args *p = params; + uarg[a++] = (intptr_t)p->addr; /* const void * */ + iarg[a++] = p->len; /* l_size_t */ + *n_args = 2; + break; + } + /* linux_munlock */ + case 229: { + struct linux_munlock_args *p = params; + uarg[a++] = (intptr_t)p->addr; /* const void * */ + iarg[a++] = p->len; /* l_size_t */ + *n_args = 2; + break; + } + /* mlockall */ + case 230: { + struct mlockall_args *p = params; + iarg[a++] = p->how; /* int */ + *n_args = 1; + break; + } + /* munlockall */ + case 231: { + *n_args = 0; + break; + } + /* linux_mincore */ + case 232: { + struct linux_mincore_args *p = params; + iarg[a++] = p->start; /* l_ulong */ + iarg[a++] = p->len; /* l_size_t */ + uarg[a++] = (intptr_t)p->vec; /* u_char * */ + *n_args = 3; + break; + } + /* linux_madvise */ + case 233: { + struct linux_madvise_args *p = params; + iarg[a++] = p->addr; /* l_ulong */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->behav; /* l_int */ + *n_args = 3; + break; + } + /* linux_remap_file_pages */ + case 234: { + *n_args = 0; + break; + } + /* linux_mbind */ + case 235: { + *n_args = 0; + break; + } + /* linux_get_mempolicy */ + case 236: { + *n_args = 0; + break; + } + /* linux_set_mempolicy */ + case 237: { + *n_args = 0; + break; + } + /* linux_migrate_pages */ + case 238: { + *n_args = 0; + break; + } + /* linux_move_pages */ + case 239: { + *n_args = 0; + break; + } + /* linux_rt_tgsigqueueinfo */ + case 240: { + struct linux_rt_tgsigqueueinfo_args *p = params; + iarg[a++] = p->tgid; /* l_pid_t */ + iarg[a++] = p->tid; /* l_pid_t */ + iarg[a++] = p->sig; /* l_int */ + uarg[a++] = (intptr_t)p->uinfo; /* l_siginfo_t * */ + *n_args = 4; + break; + } + /* linux_perf_event_open */ + case 241: { + *n_args = 0; + break; + } + /* linux_accept4 */ + case 242: { + struct linux_accept4_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->addr; /* l_uintptr_t */ + uarg[a++] = (intptr_t)p->namelen; /* l_uintptr_t */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 4; + break; + } + /* linux_recvmmsg */ + case 243: { + struct linux_recvmmsg_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->msg; /* struct l_mmsghdr * */ + iarg[a++] = p->vlen; /* l_uint */ + iarg[a++] = p->flags; /* l_uint */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ + *n_args = 5; + break; + } + /* linux_wait4 */ + case 260: { + struct linux_wait4_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + uarg[a++] = (intptr_t)p->status; /* l_int * */ + iarg[a++] = p->options; /* l_int */ + uarg[a++] = (intptr_t)p->rusage; /* struct rusage * */ + *n_args = 4; + break; + } + /* linux_prlimit64 */ + case 261: { + struct linux_prlimit64_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + iarg[a++] = p->resource; /* l_uint */ + uarg[a++] = (intptr_t)p->new; /* struct rlimit * */ + uarg[a++] = (intptr_t)p->old; /* struct rlimit * */ + *n_args = 4; + break; + } + /* linux_fanotify_init */ + case 262: { + *n_args = 0; + break; + } + /* linux_fanotify_mark */ + case 263: { + *n_args = 0; + break; + } + /* linux_name_to_handle_at */ + case 264: { + struct linux_name_to_handle_at_args *p = params; + iarg[a++] = p->dirfd; /* l_int */ + uarg[a++] = (intptr_t)p->name; /* const char * */ + uarg[a++] = (intptr_t)p->handle; /* struct l_file_handle * */ + uarg[a++] = (intptr_t)p->mnt_id; /* l_int * */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 5; + break; + } + /* linux_open_by_handle_at */ + case 265: { + struct linux_open_by_handle_at_args *p = params; + iarg[a++] = p->mountdirfd; /* l_int */ + uarg[a++] = (intptr_t)p->handle; /* struct l_file_handle * */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_clock_adjtime */ + case 266: { + *n_args = 0; + break; + } + /* linux_syncfs */ + case 267: { + struct linux_syncfs_args *p = params; + iarg[a++] = p->fd; /* l_int */ + *n_args = 1; + break; + } + /* linux_setns */ + case 268: { + struct linux_setns_args *p = params; + iarg[a++] = p->fd; /* l_int */ + iarg[a++] = p->nstype; /* l_int */ + *n_args = 2; + break; + } + /* linux_sendmmsg */ + case 269: { + struct linux_sendmmsg_args *p = params; + iarg[a++] = p->s; /* l_int */ + uarg[a++] = (intptr_t)p->msg; /* struct l_mmsghdr * */ + iarg[a++] = p->vlen; /* l_uint */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 4; + break; + } + /* linux_process_vm_readv */ + case 270: { + struct linux_process_vm_readv_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + uarg[a++] = (intptr_t)p->lvec; /* const struct iovec * */ + iarg[a++] = p->liovcnt; /* l_ulong */ + uarg[a++] = (intptr_t)p->rvec; /* const struct iovec * */ + iarg[a++] = p->riovcnt; /* l_ulong */ + iarg[a++] = p->flags; /* l_ulong */ + *n_args = 6; + break; + } + /* linux_process_vm_writev */ + case 271: { + struct linux_process_vm_writev_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + uarg[a++] = (intptr_t)p->lvec; /* const struct iovec * */ + iarg[a++] = p->liovcnt; /* l_ulong */ + uarg[a++] = (intptr_t)p->rvec; /* const struct iovec * */ + iarg[a++] = p->riovcnt; /* l_ulong */ + iarg[a++] = p->flags; /* l_ulong */ + *n_args = 6; + break; + } + /* linux_kcmp */ + case 272: { + struct linux_kcmp_args *p = params; + iarg[a++] = p->pid1; /* l_pid_t */ + iarg[a++] = p->pid2; /* l_pid_t */ + iarg[a++] = p->type; /* l_int */ + iarg[a++] = p->idx1; /* l_ulong */ + iarg[a++] = p->idx; /* l_ulong */ + *n_args = 5; + break; + } + /* linux_finit_module */ + case 273: { + struct linux_finit_module_args *p = params; + iarg[a++] = p->fd; /* l_int */ + uarg[a++] = (intptr_t)p->uargs; /* const char * */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_sched_setattr */ + case 274: { + struct linux_sched_setattr_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + uarg[a++] = (intptr_t)p->attr; /* void * */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_sched_getattr */ + case 275: { + struct linux_sched_getattr_args *p = params; + iarg[a++] = p->pid; /* l_pid_t */ + uarg[a++] = (intptr_t)p->attr; /* void * */ + iarg[a++] = p->size; /* l_uint */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 4; + break; + } + /* linux_renameat2 */ + case 276: { + struct linux_renameat2_args *p = params; + iarg[a++] = p->olddfd; /* l_int */ + uarg[a++] = (intptr_t)p->oldname; /* const char * */ + iarg[a++] = p->newdfd; /* l_int */ + uarg[a++] = (intptr_t)p->newname; /* const char * */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 5; + break; + } + /* linux_seccomp */ + case 277: { + struct linux_seccomp_args *p = params; + iarg[a++] = p->op; /* l_uint */ + iarg[a++] = p->flags; /* l_uint */ + uarg[a++] = (intptr_t)p->uargs; /* const char * */ + *n_args = 3; + break; + } + /* linux_getrandom */ + case 278: { + struct linux_getrandom_args *p = params; + uarg[a++] = (intptr_t)p->buf; /* char * */ + iarg[a++] = p->count; /* l_size_t */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_memfd_create */ + case 279: { + struct linux_memfd_create_args *p = params; + uarg[a++] = (intptr_t)p->uname_ptr; /* const char * */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 2; + break; + } + /* linux_bpf */ + case 280: { + struct linux_bpf_args *p = params; + iarg[a++] = p->cmd; /* l_int */ + uarg[a++] = (intptr_t)p->attr; /* void * */ + iarg[a++] = p->size; /* l_uint */ + *n_args = 3; + break; + } + /* linux_execveat */ + case 281: { + struct linux_execveat_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->filename; /* const char * */ + uarg[a++] = (intptr_t)p->argv; /* const char ** */ + uarg[a++] = (intptr_t)p->envp; /* const char ** */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 5; + break; + } + /* linux_userfaultfd */ + case 282: { + struct linux_userfaultfd_args *p = params; + iarg[a++] = p->flags; /* l_int */ + *n_args = 1; + break; + } + /* linux_membarrier */ + case 283: { + struct linux_membarrier_args *p = params; + iarg[a++] = p->cmd; /* l_int */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 2; + break; + } + /* linux_mlock2 */ + case 284: { + struct linux_mlock2_args *p = params; + iarg[a++] = p->start; /* l_ulong */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 3; + break; + } + /* linux_copy_file_range */ + case 285: { + struct linux_copy_file_range_args *p = params; + iarg[a++] = p->fd_in; /* l_int */ + uarg[a++] = (intptr_t)p->off_in; /* l_loff_t * */ + iarg[a++] = p->fd_out; /* l_int */ + uarg[a++] = (intptr_t)p->off_out; /* l_loff_t * */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 6; + break; + } + /* linux_preadv2 */ + case 286: { + struct linux_preadv2_args *p = params; + iarg[a++] = p->fd; /* l_ulong */ + uarg[a++] = (intptr_t)p->vec; /* const struct iovec * */ + iarg[a++] = p->vlen; /* l_ulong */ + iarg[a++] = p->pos_l; /* l_ulong */ + iarg[a++] = p->pos_h; /* l_ulong */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 6; + break; + } + /* linux_pwritev2 */ + case 287: { + struct linux_pwritev2_args *p = params; + iarg[a++] = p->fd; /* l_ulong */ + uarg[a++] = (intptr_t)p->vec; /* const struct iovec * */ + iarg[a++] = p->vlen; /* l_ulong */ + iarg[a++] = p->pos_l; /* l_ulong */ + iarg[a++] = p->pos_h; /* l_ulong */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 6; + break; + } + /* linux_pkey_mprotect */ + case 288: { + struct linux_pkey_mprotect_args *p = params; + iarg[a++] = p->start; /* l_ulong */ + iarg[a++] = p->len; /* l_size_t */ + iarg[a++] = p->prot; /* l_ulong */ + iarg[a++] = p->pkey; /* l_int */ + *n_args = 4; + break; + } + /* linux_pkey_alloc */ + case 289: { + struct linux_pkey_alloc_args *p = params; + iarg[a++] = p->flags; /* l_ulong */ + iarg[a++] = p->init_val; /* l_ulong */ + *n_args = 2; + break; + } + /* linux_pkey_free */ + case 290: { + struct linux_pkey_free_args *p = params; + iarg[a++] = p->pkey; /* l_int */ + *n_args = 1; + break; + } + /* linux_statx */ + case 291: { + struct linux_statx_args *p = params; + iarg[a++] = p->dirfd; /* l_int */ + uarg[a++] = (intptr_t)p->pathname; /* const char * */ + iarg[a++] = p->flags; /* l_uint */ + iarg[a++] = p->mask; /* l_uint */ + uarg[a++] = (intptr_t)p->statxbuf; /* void * */ + *n_args = 5; + break; + } + /* linux_io_pgetevents */ + case 292: { + *n_args = 0; + break; + } + /* linux_rseq */ + case 293: { + struct linux_rseq_args *p = params; + uarg[a++] = (intptr_t)p->rseq; /* struct linux_rseq * */ + uarg[a++] = p->rseq_len; /* uint32_t */ + iarg[a++] = p->flags; /* l_int */ + uarg[a++] = p->sig; /* uint32_t */ + *n_args = 4; + break; + } + /* linux_kexec_file_load */ + case 294: { + *n_args = 0; + break; + } + /* linux_pidfd_send_signal */ + case 424: { + struct linux_pidfd_send_signal_args *p = params; + iarg[a++] = p->pidfd; /* l_int */ + iarg[a++] = p->sig; /* l_int */ + uarg[a++] = (intptr_t)p->info; /* l_siginfo_t * */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 4; + break; + } + /* linux_io_uring_setup */ + case 425: { + *n_args = 0; + break; + } + /* linux_io_uring_enter */ + case 426: { + *n_args = 0; + break; + } + /* linux_io_uring_register */ + case 427: { + *n_args = 0; + break; + } + /* linux_open_tree */ + case 428: { + *n_args = 0; + break; + } + /* linux_move_mount */ + case 429: { + *n_args = 0; + break; + } + /* linux_fsopen */ + case 430: { + *n_args = 0; + break; + } + /* linux_fsconfig */ + case 431: { + *n_args = 0; + break; + } + /* linux_fsmount */ + case 432: { + *n_args = 0; + break; + } + /* linux_fspick */ + case 433: { + *n_args = 0; + break; + } + /* linux_pidfd_open */ + case 434: { + *n_args = 0; + break; + } + /* linux_clone3 */ + case 435: { + struct linux_clone3_args *p = params; + uarg[a++] = (intptr_t)p->uargs; /* struct l_user_clone_args * */ + iarg[a++] = p->usize; /* l_size_t */ + *n_args = 2; + break; + } + /* linux_close_range */ + case 436: { + struct linux_close_range_args *p = params; + iarg[a++] = p->first; /* l_uint */ + iarg[a++] = p->last; /* l_uint */ + iarg[a++] = p->flags; /* l_uint */ + *n_args = 3; + break; + } + /* linux_openat2 */ + case 437: { + *n_args = 0; + break; + } + /* linux_pidfd_getfd */ + case 438: { + *n_args = 0; + break; + } + /* linux_faccessat2 */ + case 439: { + struct linux_faccessat2_args *p = params; + iarg[a++] = p->dfd; /* l_int */ + uarg[a++] = (intptr_t)p->filename; /* const char * */ + iarg[a++] = p->amode; /* l_int */ + iarg[a++] = p->flags; /* l_int */ + *n_args = 4; + break; + } + /* linux_process_madvise */ + case 440: { + *n_args = 0; + break; + } + /* linux_epoll_pwait2 */ + case 441: { + struct linux_epoll_pwait2_args *p = params; + iarg[a++] = p->epfd; /* l_int */ + uarg[a++] = (intptr_t)p->events; /* struct epoll_event * */ + iarg[a++] = p->maxevents; /* l_int */ + uarg[a++] = (intptr_t)p->timeout; /* struct l_timespec * */ + uarg[a++] = (intptr_t)p->mask; /* l_sigset_t * */ + iarg[a++] = p->sigsetsize; /* l_size_t */ + *n_args = 6; + break; + } + /* linux_mount_setattr */ + case 442: { + *n_args = 0; + break; + } + /* linux_quotactl_fd */ + case 443: { + *n_args = 0; + break; + } + /* linux_landlock_create_ruleset */ + case 444: { + *n_args = 0; + break; + } + /* linux_landlock_add_rule */ + case 445: { + *n_args = 0; + break; + } + /* linux_landlock_restrict_self */ + case 446: { + *n_args = 0; + break; + } + /* linux_memfd_secret */ + case 447: { + *n_args = 0; + break; + } + /* linux_process_mrelease */ + case 448: { + *n_args = 0; + break; + } + /* linux_futex_waitv */ + case 449: { + *n_args = 0; + break; + } + /* linux_set_mempolicy_home_node */ + case 450: { + *n_args = 0; + break; + } + /* linux_cachestat */ + case 451: { + *n_args = 0; + break; + } + /* linux_fchmodat2 */ + case 452: { + *n_args = 0; + break; + } + default: + *n_args = 0; + break; + }; +} +static void +systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) +{ + const char *p = NULL; + switch (sysnum) { + /* linux_setxattr */ + case 5: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland void *"; + break; + case 3: + p = "l_size_t"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_lsetxattr */ + case 6: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland void *"; + break; + case 3: + p = "l_size_t"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_fsetxattr */ + case 7: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland void *"; + break; + case 3: + p = "l_size_t"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getxattr */ + case 8: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland void *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_lgetxattr */ + case 9: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland void *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_fgetxattr */ + case 10: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland void *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_listxattr */ + case 11: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_llistxattr */ + case 12: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_flistxattr */ + case 13: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_removexattr */ + case 14: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_lremovexattr */ + case 15: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_fremovexattr */ + case 16: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_getcwd */ + case 17: + switch (ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_lookup_dcookie */ + case 18: + break; + /* linux_eventfd2 */ + case 19: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_epoll_create1 */ + case 20: + switch (ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_epoll_ctl */ + case 21: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland struct epoll_event *"; + break; + default: + break; + }; + break; + /* linux_epoll_pwait */ + case 22: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct epoll_event *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_int"; + break; + case 4: + p = "userland l_sigset_t *"; + break; + case 5: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* dup */ + case 23: + switch (ndx) { + case 0: + p = "u_int"; + break; + default: + break; + }; + break; + /* linux_dup3 */ + case 24: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_fcntl */ + case 25: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_inotify_init1 */ + case 26: + switch (ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_inotify_add_watch */ + case 27: + break; + /* linux_inotify_rm_watch */ + case 28: + break; + /* linux_ioctl */ + case 29: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_ioprio_set */ + case 30: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_ioprio_get */ + case 31: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* flock */ + case 32: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* linux_mknodat */ + case 33: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_dev_t"; + break; + default: + break; + }; + break; + /* linux_mkdirat */ + case 34: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_mode_t"; + break; + default: + break; + }; + break; + /* linux_unlinkat */ + case 35: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_symlinkat */ + case 36: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_linkat */ + case 37: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland const char *"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_renameat */ + case 38: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_mount */ + case 40: + switch (ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "userland char *"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "userland void *"; + break; + default: + break; + }; + break; + /* linux_pivot_root */ + case 41: + break; + /* linux_statfs */ + case 43: + switch (ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "userland struct l_statfs_buf *"; + break; + default: + break; + }; + break; + /* linux_fstatfs */ + case 44: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "userland struct l_statfs_buf *"; + break; + default: + break; + }; + break; + /* linux_truncate */ + case 45: + switch (ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_ftruncate */ + case 46: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_long"; + break; + default: + break; + }; + break; + /* linux_fallocate */ + case 47: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_loff_t"; + break; + case 3: + p = "l_loff_t"; + break; + default: + break; + }; + break; + /* linux_faccessat */ + case 48: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_chdir */ + case 49: + switch (ndx) { + case 0: + p = "userland char *"; + break; + default: + break; + }; + break; + /* fchdir */ + case 50: + switch (ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* linux_chroot */ + case 51: + switch (ndx) { + case 0: + p = "userland char *"; + break; + default: + break; + }; + break; + /* fchmod */ + case 52: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* linux_fchmodat */ + case 53: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_mode_t"; + break; + default: + break; + }; + break; + /* linux_fchownat */ + case 54: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_uid_t"; + break; + case 3: + p = "l_gid_t"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* fchown */ + case 55: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* linux_openat */ + case 56: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_mode_t"; + break; + default: + break; + }; + break; + /* close */ + case 57: + switch (ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* linux_vhangup */ + case 58: + break; + /* linux_pipe2 */ + case 59: + switch (ndx) { + case 0: + p = "userland l_int *"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getdents64 */ + case 61: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_lseek */ + case 62: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_off_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_read */ + case 63: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_write */ + case 64: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_readv */ + case 65: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "u_int"; + break; + default: + break; + }; + break; + /* linux_writev */ + case 66: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "u_int"; + break; + default: + break; + }; + break; + /* linux_pread */ + case 67: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_loff_t"; + break; + default: + break; + }; + break; + /* linux_pwrite */ + case 68: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_loff_t"; + break; + default: + break; + }; + break; + /* linux_preadv */ + case 69: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_pwritev */ + case 70: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_sendfile */ + case 71: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_off_t *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_pselect6 */ + case 72: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_fd_set *"; + break; + case 2: + p = "userland l_fd_set *"; + break; + case 3: + p = "userland l_fd_set *"; + break; + case 4: + p = "userland struct l_timespec *"; + break; + case 5: + p = "userland l_uintptr_t *"; + break; + default: + break; + }; + break; + /* linux_ppoll */ + case 73: + switch (ndx) { + case 0: + p = "userland struct pollfd *"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "userland struct l_timespec *"; + break; + case 3: + p = "userland l_sigset_t *"; + break; + case 4: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_signalfd4 */ + case 74: + break; + /* linux_vmsplice */ + case 75: + break; + /* linux_splice */ + case 76: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_tee */ + case 77: + break; + /* linux_readlinkat */ + case 78: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland char *"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_newfstatat */ + case 79: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "userland struct l_newstat *"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_newfstat */ + case 80: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "userland struct l_newstat *"; + break; + default: + break; + }; + break; + /* fsync */ + case 82: + switch (ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* linux_fdatasync */ + case 83: + switch (ndx) { + case 0: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_sync_file_range */ + case 84: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_loff_t"; + break; + case 2: + p = "l_loff_t"; + break; + case 3: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_timerfd_create */ + case 85: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_timerfd_settime */ + case 86: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland const struct l_itimerspec *"; + break; + case 3: + p = "userland struct l_itimerspec *"; + break; + default: + break; + }; + break; + /* linux_timerfd_gettime */ + case 87: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct l_itimerspec *"; + break; + default: + break; + }; + break; + /* linux_utimensat */ + case 88: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland const struct l_timespec *"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_acct */ + case 89: + switch (ndx) { + case 0: + p = "userland char *"; + break; + default: + break; + }; + break; + /* linux_capget */ + case 90: + switch (ndx) { + case 0: + p = "userland struct l_user_cap_header *"; + break; + case 1: + p = "userland struct l_user_cap_data *"; + break; + default: + break; + }; + break; + /* linux_capset */ + case 91: + switch (ndx) { + case 0: + p = "userland struct l_user_cap_header *"; + break; + case 1: + p = "userland struct l_user_cap_data *"; + break; + default: + break; + }; + break; + /* linux_personality */ + case 92: + switch (ndx) { + case 0: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_exit */ + case 93: + switch (ndx) { + case 0: + p = "u_int"; + break; + default: + break; + }; + break; + /* linux_exit_group */ + case 94: + switch (ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_waitid */ + case 95: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "userland l_siginfo_t *"; + break; + case 3: + p = "l_int"; + break; + case 4: + p = "userland struct rusage *"; + break; + default: + break; + }; + break; + /* linux_set_tid_address */ + case 96: + switch (ndx) { + case 0: + p = "userland l_int *"; + break; + default: + break; + }; + break; + /* linux_unshare */ + case 97: + break; + /* linux_sys_futex */ + case 98: + switch (ndx) { + case 0: + p = "userland uint32_t *"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "uint32_t"; + break; + case 3: + p = "userland struct l_timespec *"; + break; + case 4: + p = "userland uint32_t *"; + break; + case 5: + p = "uint32_t"; + break; + default: + break; + }; + break; + /* linux_set_robust_list */ + case 99: + switch (ndx) { + case 0: + p = "userland struct linux_robust_list_head *"; + break; + case 1: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_get_robust_list */ + case 100: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct linux_robust_list_head **"; + break; + case 2: + p = "userland l_size_t *"; + break; + default: + break; + }; + break; + /* linux_nanosleep */ + case 101: + switch (ndx) { + case 0: + p = "userland const struct l_timespec *"; + break; + case 1: + p = "userland struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_getitimer */ + case 102: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct l_itimerval *"; + break; + default: + break; + }; + break; + /* linux_setitimer */ + case 103: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct l_itimerval *"; + break; + case 2: + p = "userland struct l_itimerval *"; + break; + default: + break; + }; + break; + /* linux_kexec_load */ + case 104: + break; + /* linux_init_module */ + case 105: + break; + /* linux_delete_module */ + case 106: + break; + /* linux_timer_create */ + case 107: + switch (ndx) { + case 0: + p = "clockid_t"; + break; + case 1: + p = "userland struct l_sigevent *"; + break; + case 2: + p = "userland l_timer_t *"; + break; + default: + break; + }; + break; + /* linux_timer_gettime */ + case 108: + switch (ndx) { + case 0: + p = "l_timer_t"; + break; + case 1: + p = "userland struct itimerspec *"; + break; + default: + break; + }; + break; + /* linux_timer_getoverrun */ + case 109: + switch (ndx) { + case 0: + p = "l_timer_t"; + break; + default: + break; + }; + break; + /* linux_timer_settime */ + case 110: + switch (ndx) { + case 0: + p = "l_timer_t"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland const struct itimerspec *"; + break; + case 3: + p = "userland struct itimerspec *"; + break; + default: + break; + }; + break; + /* linux_timer_delete */ + case 111: + switch (ndx) { + case 0: + p = "l_timer_t"; + break; + default: + break; + }; + break; + /* linux_clock_settime */ + case 112: + switch (ndx) { + case 0: + p = "clockid_t"; + break; + case 1: + p = "userland struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_clock_gettime */ + case 113: + switch (ndx) { + case 0: + p = "clockid_t"; + break; + case 1: + p = "userland struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_clock_getres */ + case 114: + switch (ndx) { + case 0: + p = "clockid_t"; + break; + case 1: + p = "userland struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_clock_nanosleep */ + case 115: + switch (ndx) { + case 0: + p = "clockid_t"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland struct l_timespec *"; + break; + case 3: + p = "userland struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_syslog */ + case 116: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_ptrace */ + case 117: + switch (ndx) { + case 0: + p = "l_long"; + break; + case 1: + p = "l_long"; + break; + case 2: + p = "l_uintptr_t"; + break; + case 3: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_sched_setparam */ + case 118: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland struct sched_param *"; + break; + default: + break; + }; + break; + /* linux_sched_setscheduler */ + case 119: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland struct sched_param *"; + break; + default: + break; + }; + break; + /* linux_sched_getscheduler */ + case 120: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + default: + break; + }; + break; + /* linux_sched_getparam */ + case 121: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland struct sched_param *"; + break; + default: + break; + }; + break; + /* linux_sched_setaffinity */ + case 122: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "userland l_ulong *"; + break; + default: + break; + }; + break; + /* linux_sched_getaffinity */ + case 123: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "userland l_ulong *"; + break; + default: + break; + }; + break; + /* sched_yield */ + case 124: + break; + /* linux_sched_get_priority_max */ + case 125: + switch (ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sched_get_priority_min */ + case 126: + switch (ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sched_rr_get_interval */ + case 127: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_kill */ + case 129: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_tkill */ + case 130: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_tgkill */ + case 131: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sigaltstack */ + case 132: + switch (ndx) { + case 0: + p = "userland l_stack_t *"; + break; + case 1: + p = "userland l_stack_t *"; + break; + default: + break; + }; + break; + /* linux_rt_sigsuspend */ + case 133: + switch (ndx) { + case 0: + p = "userland l_sigset_t *"; + break; + case 1: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_rt_sigaction */ + case 134: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_sigaction_t *"; + break; + case 2: + p = "userland l_sigaction_t *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_rt_sigprocmask */ + case 135: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_sigset_t *"; + break; + case 2: + p = "userland l_sigset_t *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_rt_sigpending */ + case 136: + switch (ndx) { + case 0: + p = "userland l_sigset_t *"; + break; + case 1: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_rt_sigtimedwait */ + case 137: + switch (ndx) { + case 0: + p = "userland l_sigset_t *"; + break; + case 1: + p = "userland l_siginfo_t *"; + break; + case 2: + p = "userland struct l_timespec *"; + break; + case 3: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_rt_sigqueueinfo */ + case 138: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_siginfo_t *"; + break; + default: + break; + }; + break; + /* linux_rt_sigreturn */ + case 139: + break; + /* setpriority */ + case 140: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* linux_getpriority */ + case 141: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_reboot */ + case 142: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_uint"; + break; + case 3: + p = "userland void *"; + break; + default: + break; + }; + break; + /* setregid */ + case 143: + switch (ndx) { + case 0: + p = "gid_t"; + break; + case 1: + p = "gid_t"; + break; + default: + break; + }; + break; + /* setgid */ + case 144: + switch (ndx) { + case 0: + p = "gid_t"; + break; + default: + break; + }; + break; + /* setreuid */ + case 145: + switch (ndx) { + case 0: + p = "uid_t"; + break; + case 1: + p = "uid_t"; + break; + default: + break; + }; + break; + /* setuid */ + case 146: + switch (ndx) { + case 0: + p = "uid_t"; + break; + default: + break; + }; + break; + /* setresuid */ + case 147: + switch (ndx) { + case 0: + p = "uid_t"; + break; + case 1: + p = "uid_t"; + break; + case 2: + p = "uid_t"; + break; + default: + break; + }; + break; + /* linux_getresuid */ + case 148: + switch (ndx) { + case 0: + p = "userland l_uid_t *"; + break; + case 1: + p = "userland l_uid_t *"; + break; + case 2: + p = "userland l_uid_t *"; + break; + default: + break; + }; + break; + /* setresgid */ + case 149: + switch (ndx) { + case 0: + p = "gid_t"; + break; + case 1: + p = "gid_t"; + break; + case 2: + p = "gid_t"; + break; + default: + break; + }; + break; + /* linux_getresgid */ + case 150: + switch (ndx) { + case 0: + p = "userland l_gid_t *"; + break; + case 1: + p = "userland l_gid_t *"; + break; + case 2: + p = "userland l_gid_t *"; + break; + default: + break; + }; + break; + /* linux_setfsuid */ + case 151: + switch (ndx) { + case 0: + p = "l_uid_t"; + break; + default: + break; + }; + break; + /* linux_setfsgid */ + case 152: + switch (ndx) { + case 0: + p = "l_gid_t"; + break; + default: + break; + }; + break; + /* linux_times */ + case 153: + switch (ndx) { + case 0: + p = "userland struct l_times_argv *"; + break; + default: + break; + }; + break; + /* setpgid */ + case 154: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* getpgid */ + case 155: + switch (ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* linux_getsid */ + case 156: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + default: + break; + }; + break; + /* setsid */ + case 157: + break; + /* linux_getgroups */ + case 158: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_gid_t *"; + break; + default: + break; + }; + break; + /* linux_setgroups */ + case 159: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_gid_t *"; + break; + default: + break; + }; + break; + /* linux_newuname */ + case 160: + switch (ndx) { + case 0: + p = "userland struct l_new_utsname *"; + break; + default: + break; + }; + break; + /* linux_sethostname */ + case 161: + switch (ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_setdomainname */ + case 162: + switch (ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getrlimit */ + case 163: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "userland struct l_rlimit *"; + break; + default: + break; + }; + break; + /* linux_setrlimit */ + case 164: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "userland struct l_rlimit *"; + break; + default: + break; + }; + break; + /* linux_getrusage */ + case 165: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct rusage *"; + break; + default: + break; + }; + break; + /* umask */ + case 166: + switch (ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* linux_prctl */ + case 167: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + case 3: + p = "l_uintptr_t"; + break; + case 4: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_getcpu */ + case 168: + switch (ndx) { + case 0: + p = "userland l_uint *"; + break; + case 1: + p = "userland l_uint *"; + break; + case 2: + p = "userland void *"; + break; + default: + break; + }; + break; + /* linux_gettimeofday */ + case 169: + switch (ndx) { + case 0: + p = "userland l_timeval *"; + break; + case 1: + p = "userland struct timezone *"; + break; + default: + break; + }; + break; + /* linux_settimeofday */ + case 170: + switch (ndx) { + case 0: + p = "userland l_timeval *"; + break; + case 1: + p = "userland struct timezone *"; + break; + default: + break; + }; + break; + /* linux_adjtimex */ + case 171: + break; + /* linux_getpid */ + case 172: + break; + /* linux_getppid */ + case 173: + break; + /* linux_getuid */ + case 174: + break; + /* geteuid */ + case 175: + break; + /* linux_getgid */ + case 176: + break; + /* getegid */ + case 177: + break; + /* linux_gettid */ + case 178: + break; + /* linux_sysinfo */ + case 179: + switch (ndx) { + case 0: + p = "userland struct l_sysinfo *"; + break; + default: + break; + }; + break; + /* linux_mq_open */ + case 180: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_mode_t"; + break; + case 3: + p = "userland struct mq_attr *"; + break; + default: + break; + }; + break; + /* linux_mq_unlink */ + case 181: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_mq_timedsend */ + case 182: + switch (ndx) { + case 0: + p = "l_mqd_t"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_uint"; + break; + case 4: + p = "userland const struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_mq_timedreceive */ + case 183: + switch (ndx) { + case 0: + p = "l_mqd_t"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "userland l_uint *"; + break; + case 4: + p = "userland const struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_mq_notify */ + case 184: + switch (ndx) { + case 0: + p = "l_mqd_t"; + break; + case 1: + p = "userland const struct l_sigevent *"; + break; + default: + break; + }; + break; + /* linux_mq_getsetattr */ + case 185: + switch (ndx) { + case 0: + p = "l_mqd_t"; + break; + case 1: + p = "userland const struct mq_attr *"; + break; + case 2: + p = "userland struct mq_attr *"; + break; + default: + break; + }; + break; + /* linux_msgget */ + case 186: + switch (ndx) { + case 0: + p = "l_key_t"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_msgctl */ + case 187: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland struct l_msqid_ds *"; + break; + default: + break; + }; + break; + /* linux_msgrcv */ + case 188: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct l_msgbuf *"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_long"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_msgsnd */ + case 189: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct l_msgbuf *"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_semget */ + case 190: + switch (ndx) { + case 0: + p = "l_key_t"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_semctl */ + case 191: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "union l_semun"; + break; + default: + break; + }; + break; + /* linux_semtimedop */ + case 192: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct sembuf *"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "userland struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_semop */ + case 193: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct sembuf *"; + break; + case 2: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_shmget */ + case 194: + switch (ndx) { + case 0: + p = "l_key_t"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_shmctl */ + case 195: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland struct l_shmid_ds *"; + break; + default: + break; + }; + break; + /* linux_shmat */ + case 196: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland char *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_shmdt */ + case 197: + switch (ndx) { + case 0: + p = "userland char *"; + break; + default: + break; + }; + break; + /* linux_socket */ + case 198: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_socketpair */ + case 199: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_bind */ + case 200: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_listen */ + case 201: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_accept */ + case 202: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_connect */ + case 203: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getsockname */ + case 204: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_getpeername */ + case 205: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_sendto */ + case 206: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_uint"; + break; + case 4: + p = "l_uintptr_t"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_recvfrom */ + case 207: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_uint"; + break; + case 4: + p = "l_uintptr_t"; + break; + case 5: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_setsockopt */ + case 208: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_getsockopt */ + case 209: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_uintptr_t"; + break; + case 4: + p = "l_uintptr_t"; + break; + default: + break; + }; + break; + /* linux_shutdown */ + case 210: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sendmsg */ + case 211: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_recvmsg */ + case 212: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_brk */ + case 214: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_munmap */ + case 215: + switch (ndx) { + case 0: + p = "userland void *"; + break; + case 1: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_mremap */ + case 216: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_ulong"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_add_key */ + case 217: + break; + /* linux_request_key */ + case 218: + break; + /* linux_keyctl */ + case 219: + break; + /* linux_clone */ + case 220: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_ulong"; + break; + case 2: + p = "userland l_int *"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "userland l_int *"; + break; + default: + break; + }; + break; + /* linux_execve */ + case 221: + switch (ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "userland l_uintptr_t *"; + break; + case 2: + p = "userland l_uintptr_t *"; + break; + default: + break; + }; + break; + /* linux_mmap2 */ + case 222: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_ulong"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_fadvise64 */ + case 223: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_loff_t"; + break; + case 2: + p = "l_size_t"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_swapon */ + case 224: + switch (ndx) { + case 0: + p = "userland char *"; + break; + default: + break; + }; + break; + /* linux_swapoff */ + case 225: + break; + /* linux_mprotect */ + case 226: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_msync */ + case 227: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_mlock */ + case 228: + switch (ndx) { + case 0: + p = "userland const void *"; + break; + case 1: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_munlock */ + case 229: + switch (ndx) { + case 0: + p = "userland const void *"; + break; + case 1: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* mlockall */ + case 230: + switch (ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* munlockall */ + case 231: + break; + /* linux_mincore */ + case 232: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "userland u_char *"; + break; + default: + break; + }; + break; + /* linux_madvise */ + case 233: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_remap_file_pages */ + case 234: + break; + /* linux_mbind */ + case 235: + break; + /* linux_get_mempolicy */ + case 236: + break; + /* linux_set_mempolicy */ + case 237: + break; + /* linux_migrate_pages */ + case 238: + break; + /* linux_move_pages */ + case 239: + break; + /* linux_rt_tgsigqueueinfo */ + case 240: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland l_siginfo_t *"; + break; + default: + break; + }; + break; + /* linux_perf_event_open */ + case 241: + break; + /* linux_accept4 */ + case 242: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_uintptr_t"; + break; + case 2: + p = "l_uintptr_t"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_recvmmsg */ + case 243: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct l_mmsghdr *"; + break; + case 2: + p = "l_uint"; + break; + case 3: + p = "l_uint"; + break; + case 4: + p = "userland struct l_timespec *"; + break; + default: + break; + }; + break; + /* linux_wait4 */ + case 260: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland l_int *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland struct rusage *"; + break; + default: + break; + }; + break; + /* linux_prlimit64 */ + case 261: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "userland struct rlimit *"; + break; + case 3: + p = "userland struct rlimit *"; + break; + default: + break; + }; + break; + /* linux_fanotify_init */ + case 262: + break; + /* linux_fanotify_mark */ + case 263: + break; + /* linux_name_to_handle_at */ + case 264: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland struct l_file_handle *"; + break; + case 3: + p = "userland l_int *"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_open_by_handle_at */ + case 265: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct l_file_handle *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_clock_adjtime */ + case 266: + break; + /* linux_syncfs */ + case 267: + switch (ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_setns */ + case 268: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sendmmsg */ + case 269: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct l_mmsghdr *"; + break; + case 2: + p = "l_uint"; + break; + case 3: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_process_vm_readv */ + case 270: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const struct iovec *"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_process_vm_writev */ + case 271: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "userland const struct iovec *"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_kcmp */ + case 272: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "l_pid_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_finit_module */ + case 273: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_sched_setattr */ + case 274: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_sched_getattr */ + case 275: + switch (ndx) { + case 0: + p = "l_pid_t"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + case 3: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_renameat2 */ + case 276: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland const char *"; + break; + case 4: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_seccomp */ + case 277: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "userland const char *"; + break; + default: + break; + }; + break; + /* linux_getrandom */ + case 278: + switch (ndx) { + case 0: + p = "userland char *"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_memfd_create */ + case 279: + switch (ndx) { + case 0: + p = "userland const char *"; + break; + case 1: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_bpf */ + case 280: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland void *"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_execveat */ + case 281: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "userland const char **"; + break; + case 3: + p = "userland const char **"; + break; + case 4: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_userfaultfd */ + case 282: + switch (ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_membarrier */ + case 283: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_mlock2 */ + case 284: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_copy_file_range */ + case 285: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_preadv2 */ + case 286: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pwritev2 */ + case 287: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "userland const struct iovec *"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_ulong"; + break; + case 4: + p = "l_ulong"; + break; + case 5: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pkey_mprotect */ + case 288: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_size_t"; + break; + case 2: + p = "l_ulong"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_pkey_alloc */ + case 289: + switch (ndx) { + case 0: + p = "l_ulong"; + break; + case 1: + p = "l_ulong"; + break; + default: + break; + }; + break; + /* linux_pkey_free */ + case 290: + switch (ndx) { + case 0: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_statx */ + case 291: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_uint"; + break; + case 3: + p = "l_uint"; + break; + case 4: + p = "userland void *"; + break; + default: + break; + }; + break; + /* linux_io_pgetevents */ + case 292: + break; + /* linux_rseq */ + case 293: + switch (ndx) { + case 0: + p = "userland struct linux_rseq *"; + break; + case 1: + p = "uint32_t"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "uint32_t"; + break; + default: + break; + }; + break; + /* linux_kexec_file_load */ + case 294: + break; + /* linux_pidfd_send_signal */ + case 424: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "l_int"; + break; + case 2: + p = "userland l_siginfo_t *"; + break; + case 3: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_io_uring_setup */ + case 425: + break; + /* linux_io_uring_enter */ + case 426: + break; + /* linux_io_uring_register */ + case 427: + break; + /* linux_open_tree */ + case 428: + break; + /* linux_move_mount */ + case 429: + break; + /* linux_fsopen */ + case 430: + break; + /* linux_fsconfig */ + case 431: + break; + /* linux_fsmount */ + case 432: + break; + /* linux_fspick */ + case 433: + break; + /* linux_pidfd_open */ + case 434: + break; + /* linux_clone3 */ + case 435: + switch (ndx) { + case 0: + p = "userland struct l_user_clone_args *"; + break; + case 1: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_close_range */ + case 436: + switch (ndx) { + case 0: + p = "l_uint"; + break; + case 1: + p = "l_uint"; + break; + case 2: + p = "l_uint"; + break; + default: + break; + }; + break; + /* linux_openat2 */ + case 437: + break; + /* linux_pidfd_getfd */ + case 438: + break; + /* linux_faccessat2 */ + case 439: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland const char *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; + break; + /* linux_process_madvise */ + case 440: + break; + /* linux_epoll_pwait2 */ + case 441: + switch (ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "userland struct epoll_event *"; + break; + case 2: + p = "l_int"; + break; + case 3: + p = "userland struct l_timespec *"; + break; + case 4: + p = "userland l_sigset_t *"; + break; + case 5: + p = "l_size_t"; + break; + default: + break; + }; + break; + /* linux_mount_setattr */ + case 442: + break; + /* linux_quotactl_fd */ + case 443: + break; + /* linux_landlock_create_ruleset */ + case 444: + break; + /* linux_landlock_add_rule */ + case 445: + break; + /* linux_landlock_restrict_self */ + case 446: + break; + /* linux_memfd_secret */ + case 447: + break; + /* linux_process_mrelease */ + case 448: + break; + /* linux_futex_waitv */ + case 449: + break; + /* linux_set_mempolicy_home_node */ + case 450: + break; + /* linux_cachestat */ + case 451: + break; + /* linux_fchmodat2 */ + case 452: + break; + default: + break; + }; + if (p != NULL) + strlcpy(desc, p, descsz); +} +static void +systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) +{ + const char *p = NULL; + switch (sysnum) { + /* linux_setxattr */ + case 5: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_lsetxattr */ + case 6: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fsetxattr */ + case 7: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getxattr */ + case 8: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_lgetxattr */ + case 9: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fgetxattr */ + case 10: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_listxattr */ + case 11: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_llistxattr */ + case 12: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_flistxattr */ + case 13: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_removexattr */ + case 14: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_lremovexattr */ + case 15: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fremovexattr */ + case 16: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getcwd */ + case 17: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_lookup_dcookie */ + case 18: + /* linux_eventfd2 */ + case 19: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_epoll_create1 */ + case 20: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_epoll_ctl */ + case 21: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_epoll_pwait */ + case 22: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* dup */ + case 23: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_dup3 */ + case 24: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fcntl */ + case 25: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_inotify_init1 */ + case 26: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_inotify_add_watch */ + case 27: + /* linux_inotify_rm_watch */ + case 28: + /* linux_ioctl */ + case 29: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_ioprio_set */ + case 30: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_ioprio_get */ + case 31: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* flock */ + case 32: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mknodat */ + case 33: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mkdirat */ + case 34: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_unlinkat */ + case 35: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_symlinkat */ + case 36: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_linkat */ + case 37: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_renameat */ + case 38: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mount */ + case 40: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pivot_root */ + case 41: + /* linux_statfs */ + case 43: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fstatfs */ + case 44: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_truncate */ + case 45: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_ftruncate */ + case 46: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fallocate */ + case 47: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_faccessat */ + case 48: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_chdir */ + case 49: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* fchdir */ + case 50: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_chroot */ + case 51: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* fchmod */ + case 52: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fchmodat */ + case 53: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fchownat */ + case 54: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* fchown */ + case 55: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_openat */ + case 56: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* close */ + case 57: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_vhangup */ + case 58: + /* linux_pipe2 */ + case 59: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getdents64 */ + case 61: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_lseek */ + case 62: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_read */ + case 63: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_write */ + case 64: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_readv */ + case 65: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_writev */ + case 66: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pread */ + case 67: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pwrite */ + case 68: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_preadv */ + case 69: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pwritev */ + case 70: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sendfile */ + case 71: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pselect6 */ + case 72: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_ppoll */ + case 73: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_signalfd4 */ + case 74: + /* linux_vmsplice */ + case 75: + /* linux_splice */ + case 76: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_tee */ + case 77: + /* linux_readlinkat */ + case 78: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_newfstatat */ + case 79: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_newfstat */ + case 80: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* fsync */ + case 82: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fdatasync */ + case 83: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sync_file_range */ + case 84: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_timerfd_create */ + case 85: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_timerfd_settime */ + case 86: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_timerfd_gettime */ + case 87: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_utimensat */ + case 88: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_acct */ + case 89: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_capget */ + case 90: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_capset */ + case 91: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_personality */ + case 92: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_exit */ + case 93: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_exit_group */ + case 94: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_waitid */ + case 95: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_set_tid_address */ + case 96: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_unshare */ + case 97: + /* linux_sys_futex */ + case 98: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_set_robust_list */ + case 99: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_get_robust_list */ + case 100: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_nanosleep */ + case 101: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getitimer */ + case 102: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setitimer */ + case 103: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_kexec_load */ + case 104: + /* linux_init_module */ + case 105: + /* linux_delete_module */ + case 106: + /* linux_timer_create */ + case 107: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_timer_gettime */ + case 108: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_timer_getoverrun */ + case 109: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_timer_settime */ + case 110: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_timer_delete */ + case 111: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_clock_settime */ + case 112: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_clock_gettime */ + case 113: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_clock_getres */ + case 114: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_clock_nanosleep */ + case 115: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_syslog */ + case 116: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_ptrace */ + case 117: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_setparam */ + case 118: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_setscheduler */ + case 119: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_getscheduler */ + case 120: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_getparam */ + case 121: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_setaffinity */ + case 122: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_getaffinity */ + case 123: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* sched_yield */ + case 124: + /* linux_sched_get_priority_max */ + case 125: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_get_priority_min */ + case 126: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_rr_get_interval */ + case 127: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_kill */ + case 129: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_tkill */ + case 130: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_tgkill */ + case 131: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sigaltstack */ + case 132: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_sigsuspend */ + case 133: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_sigaction */ + case 134: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_sigprocmask */ + case 135: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_sigpending */ + case 136: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_sigtimedwait */ + case 137: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_sigqueueinfo */ + case 138: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_rt_sigreturn */ + case 139: + /* setpriority */ + case 140: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getpriority */ + case 141: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_reboot */ + case 142: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setregid */ + case 143: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setgid */ + case 144: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setreuid */ + case 145: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setuid */ + case 146: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setresuid */ + case 147: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getresuid */ + case 148: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setresgid */ + case 149: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getresgid */ + case 150: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setfsuid */ + case 151: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setfsgid */ + case 152: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_times */ + case 153: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setpgid */ + case 154: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* getpgid */ + case 155: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getsid */ + case 156: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* setsid */ + case 157: + /* linux_getgroups */ + case 158: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setgroups */ + case 159: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_newuname */ + case 160: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sethostname */ + case 161: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setdomainname */ + case 162: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getrlimit */ + case 163: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setrlimit */ + case 164: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getrusage */ + case 165: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* umask */ + case 166: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_prctl */ + case 167: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getcpu */ + case 168: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_gettimeofday */ + case 169: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_settimeofday */ + case 170: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_adjtimex */ + case 171: + /* linux_getpid */ + case 172: + /* linux_getppid */ + case 173: + /* linux_getuid */ + case 174: + /* geteuid */ + case 175: + /* linux_getgid */ + case 176: + /* getegid */ + case 177: + /* linux_gettid */ + case 178: + /* linux_sysinfo */ + case 179: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mq_open */ + case 180: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mq_unlink */ + case 181: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mq_timedsend */ + case 182: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mq_timedreceive */ + case 183: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mq_notify */ + case 184: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mq_getsetattr */ + case 185: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_msgget */ + case 186: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_msgctl */ + case 187: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_msgrcv */ + case 188: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_msgsnd */ + case 189: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_semget */ + case 190: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_semctl */ + case 191: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_semtimedop */ + case 192: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_semop */ + case 193: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_shmget */ + case 194: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_shmctl */ + case 195: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_shmat */ + case 196: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_shmdt */ + case 197: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_socket */ + case 198: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_socketpair */ + case 199: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_bind */ + case 200: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_listen */ + case 201: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_accept */ + case 202: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_connect */ + case 203: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getsockname */ + case 204: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getpeername */ + case 205: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sendto */ + case 206: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_recvfrom */ + case 207: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setsockopt */ + case 208: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getsockopt */ + case 209: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_shutdown */ + case 210: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sendmsg */ + case 211: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_recvmsg */ + case 212: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_brk */ + case 214: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_munmap */ + case 215: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mremap */ + case 216: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_add_key */ + case 217: + /* linux_request_key */ + case 218: + /* linux_keyctl */ + case 219: + /* linux_clone */ + case 220: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_execve */ + case 221: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mmap2 */ + case 222: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fadvise64 */ + case 223: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_swapon */ + case 224: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_swapoff */ + case 225: + /* linux_mprotect */ + case 226: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_msync */ + case 227: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mlock */ + case 228: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_munlock */ + case 229: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* mlockall */ + case 230: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* munlockall */ + case 231: + /* linux_mincore */ + case 232: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_madvise */ + case 233: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_remap_file_pages */ + case 234: + /* linux_mbind */ + case 235: + /* linux_get_mempolicy */ + case 236: + /* linux_set_mempolicy */ + case 237: + /* linux_migrate_pages */ + case 238: + /* linux_move_pages */ + case 239: + /* linux_rt_tgsigqueueinfo */ + case 240: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_perf_event_open */ + case 241: + /* linux_accept4 */ + case 242: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_recvmmsg */ + case 243: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_wait4 */ + case 260: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_prlimit64 */ + case 261: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_fanotify_init */ + case 262: + /* linux_fanotify_mark */ + case 263: + /* linux_name_to_handle_at */ + case 264: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_open_by_handle_at */ + case 265: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_clock_adjtime */ + case 266: + /* linux_syncfs */ + case 267: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_setns */ + case 268: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sendmmsg */ + case 269: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_process_vm_readv */ + case 270: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_process_vm_writev */ + case 271: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_kcmp */ + case 272: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_finit_module */ + case 273: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_setattr */ + case 274: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_sched_getattr */ + case 275: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_renameat2 */ + case 276: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_seccomp */ + case 277: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_getrandom */ + case 278: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_memfd_create */ + case 279: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_bpf */ + case 280: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_execveat */ + case 281: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_userfaultfd */ + case 282: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_membarrier */ + case 283: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mlock2 */ + case 284: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_copy_file_range */ + case 285: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_preadv2 */ + case 286: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pwritev2 */ + case 287: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_mprotect */ + case 288: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_alloc */ + case 289: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_pkey_free */ + case 290: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_statx */ + case 291: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_io_pgetevents */ + case 292: + /* linux_rseq */ + case 293: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_kexec_file_load */ + case 294: + /* linux_pidfd_send_signal */ + case 424: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_io_uring_setup */ + case 425: + /* linux_io_uring_enter */ + case 426: + /* linux_io_uring_register */ + case 427: + /* linux_open_tree */ + case 428: + /* linux_move_mount */ + case 429: + /* linux_fsopen */ + case 430: + /* linux_fsconfig */ + case 431: + /* linux_fsmount */ + case 432: + /* linux_fspick */ + case 433: + /* linux_pidfd_open */ + case 434: + /* linux_clone3 */ + case 435: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_close_range */ + case 436: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_openat2 */ + case 437: + /* linux_pidfd_getfd */ + case 438: + /* linux_faccessat2 */ + case 439: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_process_madvise */ + case 440: + /* linux_epoll_pwait2 */ + case 441: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* linux_mount_setattr */ + case 442: + /* linux_quotactl_fd */ + case 443: + /* linux_landlock_create_ruleset */ + case 444: + /* linux_landlock_add_rule */ + case 445: + /* linux_landlock_restrict_self */ + case 446: + /* linux_memfd_secret */ + case 447: + /* linux_process_mrelease */ + case 448: + /* linux_futex_waitv */ + case 449: + /* linux_set_mempolicy_home_node */ + case 450: + /* linux_cachestat */ + case 451: + /* linux_fchmodat2 */ + case 452: + default: + break; + }; + if (p != NULL) + strlcpy(desc, p, descsz); +} diff --git a/sys/arm64/linux64/linux64_sysvec.c b/sys/arm64/linux64/linux64_sysvec.c new file mode 100755 index 000000000000..0b8ce1649fd8 --- /dev/null +++ b/sys/arm64/linux64/linux64_sysvec.c @@ -0,0 +1 @@ +#include "../linux/linux_sysvec.c" \ No newline at end of file diff --git a/sys/arm64/linux64/linux64_vdso.lds.s b/sys/arm64/linux64/linux64_vdso.lds.s new file mode 100755 index 000000000000..dd5475bb81f2 --- /dev/null +++ b/sys/arm64/linux64/linux64_vdso.lds.s @@ -0,0 +1,74 @@ +/* + * Linker script for 64-bit vDSO. + * Copied from Linux kernel arch/arm64/kernel/vdso/vdso.lds.S + */ + +SECTIONS +{ + . = . + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + /DISCARD/ : { + *(.note.GNU-stack .note.gnu.property) + } + + .note : { *(.note.*) } :text :note + + . = ALIGN(0x100); + + .text : { *(.text*) } :text =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + .dynamic : { *(.dynamic) } :text :dynamic + + .rodata : { *(.rodata*) } :text + .data : { + *(.data*) + } + + _end = .; + PROVIDE(end = .); + + /DISCARD/ : { + *(.eh_frame .eh_frame_hdr) + } +} + +PHDRS +{ + text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + note PT_NOTE FLAGS(4); /* PF_R */ +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + LINUX_2.6.39 { + global: + __kernel_rt_sigreturn; + __kernel_gettimeofday; + __kernel_clock_gettime; + __kernel_clock_getres; + local: *; + }; + + LINUX_0.0 { + global: + linux_platform; + kern_timekeep_base; + __user_rt_sigreturn; + local: *; + }; +} diff --git a/sys/arm64/linux64/linux64_vdso_gtod.c b/sys/arm64/linux64/linux64_vdso_gtod.c new file mode 100755 index 000000000000..95aa4aaf22fb --- /dev/null +++ b/sys/arm64/linux64/linux64_vdso_gtod.c @@ -0,0 +1,29 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2012 Konstantin Belousov + * Copyright (c) 2021 Dmitry Chagin + * + * 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 "../linux/linux_vdso_gtod.c" diff --git a/sys/arm64/linux64/syscalls.conf b/sys/arm64/linux64/syscalls.conf new file mode 100755 index 000000000000..bbc90260970c --- /dev/null +++ b/sys/arm64/linux64/syscalls.conf @@ -0,0 +1,10 @@ +sysnames="linux64_syscalls.c" +sysproto="linux64_proto.h" +sysproto_h=_LINUX64_SYSPROTO_H_ +syshdr="linux64_syscall.h" +syssw="linux64_sysent.c" +syscallprefix="LINUX64_SYS_" +switchname="linux64_sysent" +namesname="linux64_syscallnames" +systrace="linux64_systrace_args.c" +compat_set="" diff --git a/sys/arm64/linux64/syscalls.master b/sys/arm64/linux64/syscalls.master new file mode 100755 index 000000000000..68997cccbba1 --- /dev/null +++ b/sys/arm64/linux64/syscalls.master @@ -0,0 +1,1865 @@ + +; Linux ABI system call generic name/number map, based on Linux file +; include/uapi/asm-generic/unistd.h + +; #include's, #defines's, etc. may be included, and are copied to the output +; files. However, #ifdef, etc will be copied, but any lines that don't start +; with # will not. Caveat Emptor. + +#include +#include +#include +#include +#include + +0 AUE_NULL UNIMPL linux_io_setup +1 AUE_NULL UNIMPL linux_io_destroy +2 AUE_NULL UNIMPL linux_io_submit +3 AUE_NULL UNIMPL linux_io_cancel +4 AUE_NULL UNIMPL linux_io_getevents +5 AUE_NULL STD { + int linux_setxattr( + const char *path, + const char *name, + void *value, + l_size_t size, + l_int flags + ); + } +6 AUE_NULL STD { + int linux_lsetxattr( + const char *path, + const char *name, + void *value, + l_size_t size, + l_int flags + ); + } +7 AUE_NULL STD { + int linux_fsetxattr( + l_int fd, + const char *name, + void *value, + l_size_t size, + l_int flags + ); + } +8 AUE_NULL STD { + int linux_getxattr( + const char *path, + const char *name, + void *value, + l_size_t size + ); + } +9 AUE_NULL STD { + int linux_lgetxattr( + const char *path, + const char *name, + void *value, + l_size_t size + ); + } +10 AUE_NULL STD { + int linux_fgetxattr( + l_int fd, + const char *name, + void *value, + l_size_t size + ); + } +11 AUE_NULL STD { + int linux_listxattr( + const char *path, + char *list, + l_size_t size + ); + } +12 AUE_NULL STD { + int linux_llistxattr( + const char *path, + char *list, + l_size_t size + ); + } +13 AUE_NULL STD { + int linux_flistxattr( + l_int fd, + char *list, + l_size_t size + ); + } +14 AUE_NULL STD { + int linux_removexattr( + const char *path, + const char *name + ); + } +15 AUE_NULL STD { + int linux_lremovexattr( + const char *path, + const char *name + ); + } +16 AUE_NULL STD { + int linux_fremovexattr( + l_int fd, + const char *name + ); + } +17 AUE_GETCWD STD { + int linux_getcwd( + char *buf, + l_ulong bufsize + ); + } +18 AUE_NULL STD { + int linux_lookup_dcookie(void); + } +19 AUE_NULL STD { + int linux_eventfd2( + l_uint initval, + l_int flags + ); + } +20 AUE_NULL STD { + int linux_epoll_create1( + l_int flags + ); + } +21 AUE_NULL STD { + int linux_epoll_ctl( + l_int epfd, + l_int op, + l_int fd, + struct epoll_event *event + ); + } +22 AUE_NULL STD { + int linux_epoll_pwait( + l_int epfd, + struct epoll_event *events, + l_int maxevents, + l_int timeout, + l_sigset_t *mask, + l_size_t sigsetsize + ); + } +23 AUE_DUP NOPROTO { + int dup( + u_int fd + ); + } +24 AUE_NULL STD { + int linux_dup3( + l_int oldfd, + l_int newfd, + l_int flags + ); + } +25 AUE_FCNTL STD { + int linux_fcntl( + l_uint fd, + l_uint cmd, + l_uintptr_t arg + ); + } +26 AUE_NULL STD { + int linux_inotify_init1( + l_int flags + ); + } +27 AUE_NULL STD { + int linux_inotify_add_watch(void); + } +28 AUE_NULL STD { + int linux_inotify_rm_watch(void); + } +29 AUE_IOCTL STD { + int linux_ioctl( + l_uint fd, + l_uint cmd, + l_uintptr_t arg + ); + } +30 AUE_SETPRIORITY STD { + int linux_ioprio_set( + l_int which, + l_int who, + l_int ioprio + ); + } +31 AUE_GETPRIORITY STD { + int linux_ioprio_get( + l_int which, + l_int who + ); + } +32 AUE_FLOCK NOPROTO { + int flock( + int fd, + int how + ); + } +33 AUE_MKNODAT STD { + int linux_mknodat( + l_int dfd, + const char *filename, + l_int mode, + l_dev_t dev + ); + } +34 AUE_MKDIRAT STD { + int linux_mkdirat( + l_int dfd, + const char *pathname, + l_mode_t mode + ); + } +35 AUE_UNLINKAT STD { + int linux_unlinkat( + l_int dfd, + const char *pathname, + l_int flag + ); + } +36 AUE_SYMLINKAT STD { + int linux_symlinkat( + const char *oldname, + l_int newdfd, + const char *newname + ); + } +37 AUE_LINKAT STD { + int linux_linkat( + l_int olddfd, + const char *oldname, + l_int newdfd, + const char *newname, + l_int flag + ); + } +38 AUE_RENAMEAT STD { + int linux_renameat( + l_int olddfd, + const char *oldname, + l_int newdfd, + const char *newname + ); + } +39 AUE_NULL UNIMPL linux_umount2 +40 AUE_MOUNT STD { + int linux_mount( + char *specialfile, + char *dir, + char *filesystemtype, + l_ulong rwflag, + void *data + ); + } +41 AUE_PIVOT_ROOT STD { + int linux_pivot_root(void); + } +42 AUE_NULL UNIMPL nfsservctl +43 AUE_STATFS STD { + int linux_statfs( + char *path, + struct l_statfs_buf *buf + ); + } +44 AUE_FSTATFS STD { + int linux_fstatfs( + l_uint fd, + struct l_statfs_buf *buf + ); + } +45 AUE_TRUNCATE STD { + int linux_truncate( + char *path, + l_ulong length + ); + } +46 AUE_FTRUNCATE STD { + int linux_ftruncate( + l_int fd, + l_long length + ); + } +47 AUE_NULL STD { + int linux_fallocate( + l_int fd, + l_int mode, + l_loff_t offset, + l_loff_t len + ); + } +48 AUE_FACCESSAT STD { + int linux_faccessat( + l_int dfd, + const char *filename, + l_int amode + ); + } +49 AUE_CHDIR STD { + int linux_chdir( + char *path + ); + } +50 AUE_FCHDIR NOPROTO { + int fchdir( + int fd + ); + } +51 AUE_CHROOT STD { + int linux_chroot( + char *path + ); + } +52 AUE_FCHMOD NOPROTO { + int fchmod( + int fd, + int mode + ); + } +53 AUE_FCHMODAT STD { + int linux_fchmodat( + l_int dfd, + const char *filename, + l_mode_t mode + ); + } +54 AUE_FCHOWNAT STD { + int linux_fchownat( + l_int dfd, + const char *filename, + l_uid_t uid, + l_gid_t gid, + l_int flag + ); + } +55 AUE_FCHOWN NOPROTO { + int fchown( + int fd, + int uid, + int gid + ); + } +56 AUE_OPEN_RWTC STD { + int linux_openat( + l_int dfd, + const char *filename, + l_int flags, + l_mode_t mode + ); + } +57 AUE_CLOSE NOPROTO { + int close( + int fd + ); + } +58 AUE_NULL STD { + int linux_vhangup(void); + } +59 AUE_NULL STD { + int linux_pipe2( + l_int *pipefds, + l_int flags + ); + } +60 AUE_NULL UNIMPL linux_quotactl +61 AUE_GETDIRENTRIES STD { + int linux_getdents64( + l_uint fd, + void *dirent, + l_uint count + ); + } +62 AUE_LSEEK STD { + int linux_lseek( + l_uint fdes, + l_off_t off, + l_int whence + ); + } +63 AUE_NULL STD { + int linux_read( + int fd, + char *buf, + l_size_t nbyte + ); + } +64 AUE_NULL STD { + int linux_write( + int fd, + char *buf, + l_size_t nbyte + ); + } +65 AUE_READV STD { + int linux_readv( + int fd, + struct iovec *iovp, + u_int iovcnt + ); + } +66 AUE_WRITEV STD { + int linux_writev( + int fd, + struct iovec *iovp, + u_int iovcnt + ); + } +67 AUE_PREAD STD { + int linux_pread( + l_uint fd, + char *buf, + l_size_t nbyte, + l_loff_t offset + ); + } +68 AUE_PWRITE STD { + int linux_pwrite( + l_uint fd, + char *buf, + l_size_t nbyte, + l_loff_t offset + ); + } +69 AUE_NULL STD { + int linux_preadv( + l_ulong fd, + struct iovec *vec, + l_ulong vlen, + l_ulong pos_l, + l_ulong pos_h + ); + } +70 AUE_NULL STD { + int linux_pwritev( + l_ulong fd, + struct iovec *vec, + l_ulong vlen, + l_ulong pos_l, + l_ulong pos_h + ); + } +71 AUE_SENDFILE STD { + int linux_sendfile( + l_int out, + l_int in, + l_off_t *offset, + l_size_t count + ); + } +72 AUE_SELECT STD { + int linux_pselect6( + l_int nfds, + l_fd_set *readfds, + l_fd_set *writefds, + l_fd_set *exceptfds, + struct l_timespec *tsp, + l_uintptr_t *sig + ); + } +73 AUE_POLL STD { + int linux_ppoll( + struct pollfd *fds, + l_uint nfds, + struct l_timespec *tsp, + l_sigset_t *sset, + l_size_t ssize + ); + } +74 AUE_NULL STD { + int linux_signalfd4(void); + } +75 AUE_NULL STD { + int linux_vmsplice(void); + } +76 AUE_NULL STD { + int linux_splice( + int fd_in, + l_loff_t *off_in, + int fd_out, + l_loff_t *off_out, + l_size_t len, + l_uint flags + ); + } +77 AUE_NULL STD { + int linux_tee(void); + } +78 AUE_READLINKAT STD { + int linux_readlinkat( + l_int dfd, + const char *path, + char *buf, + l_int bufsiz + ); + } +79 AUE_FSTATAT STD { + int linux_newfstatat( + l_int dfd, + char *pathname, + struct l_newstat *statbuf, + l_int flag + ); + } +80 AUE_FSTAT STD { + int linux_newfstat( + l_uint fd, + struct l_newstat *buf + ); + } +81 AUE_NULL UNIMPL linux_sync +82 AUE_FSYNC NOPROTO { + int fsync( + int fd + ); + } +83 AUE_NULL STD { + int linux_fdatasync( + l_uint fd + ); + } +84 AUE_NULL STD { + int linux_sync_file_range( + l_int fd, + l_loff_t offset, + l_loff_t nbytes, + l_uint flags + ); + } +85 AUE_NULL STD { + int linux_timerfd_create( + l_int clockid, + l_int flags + ); + } +86 AUE_NULL STD { + int linux_timerfd_settime( + l_int fd, + l_int flags, + const struct l_itimerspec *new_value, + struct l_itimerspec *old_value + ); + } +87 AUE_NULL STD { + int linux_timerfd_gettime( + l_int fd, + struct l_itimerspec *old_value + ); + } +88 AUE_FUTIMESAT STD { + int linux_utimensat( + l_int dfd, + const char *pathname, + const struct l_timespec *times, + l_int flags + ); + } +89 AUE_ACCT STD { + int linux_acct( + char *path + ); + } +90 AUE_CAPGET STD { + int linux_capget( + struct l_user_cap_header *hdrp, + struct l_user_cap_data *datap + ); + } +91 AUE_CAPSET STD { + int linux_capset( + struct l_user_cap_header *hdrp, + struct l_user_cap_data *datap + ); + } +92 AUE_PERSONALITY STD { + int linux_personality( + l_uint per + ); + } +93 AUE_EXIT STD { + int linux_exit( + u_int rval + ); + } +94 AUE_EXIT STD { + int linux_exit_group( + l_int error_code + ); + } +95 AUE_WAIT6 STD { + int linux_waitid( + l_int idtype, + l_pid_t id, + l_siginfo_t *info, + l_int options, + struct rusage *rusage + ); + } +96 AUE_NULL STD { + int linux_set_tid_address( + l_int *tidptr + ); + } +97 AUE_NULL STD { + int linux_unshare(void); + } +98 AUE_NULL STD { + int linux_sys_futex( + uint32_t *uaddr, + l_int op, + uint32_t val, + struct l_timespec *timeout, + uint32_t *uaddr2, + uint32_t val3 + ); + } +99 AUE_NULL STD { + int linux_set_robust_list( + struct linux_robust_list_head *head, + l_size_t len + ); + } +100 AUE_NULL STD { + int linux_get_robust_list( + l_int pid, + struct linux_robust_list_head **head, + l_size_t *len + ); + } +101 AUE_NULL STD { + int linux_nanosleep( + const struct l_timespec *rqtp, + struct l_timespec *rmtp + ); + } +102 AUE_GETITIMER STD { + int linux_getitimer( + l_int which, + struct l_itimerval *itv + ); + } +103 AUE_SETITIMER STD { + int linux_setitimer( + l_int which, + struct l_itimerval *itv, + struct l_itimerval *oitv + ); + } +104 AUE_NULL STD { + int linux_kexec_load(void); + } +105 AUE_NULL STD { + int linux_init_module(void); + } +106 AUE_NULL STD { + int linux_delete_module(void); + } +107 AUE_NULL STD { + int linux_timer_create( + clockid_t clock_id, + struct l_sigevent *evp, + l_timer_t *timerid + ); + } +108 AUE_NULL STD { + int linux_timer_gettime( + l_timer_t timerid, + struct itimerspec *setting + ); + } +109 AUE_NULL STD { + int linux_timer_getoverrun( + l_timer_t timerid + ); + } +110 AUE_NULL STD { + int linux_timer_settime( + l_timer_t timerid, + l_int flags, + const struct itimerspec *new, + struct itimerspec *old + ); + } +111 AUE_NULL STD { + int linux_timer_delete( + l_timer_t timerid + ); + } +112 AUE_CLOCK_SETTIME STD { + int linux_clock_settime( + clockid_t which, + struct l_timespec *tp + ); + } +113 AUE_NULL STD { + int linux_clock_gettime( + clockid_t which, + struct l_timespec *tp + ); + } +114 AUE_NULL STD { + int linux_clock_getres( + clockid_t which, + struct l_timespec *tp + ); + } +115 AUE_NULL STD { + int linux_clock_nanosleep( + clockid_t which, + l_int flags, + struct l_timespec *rqtp, + struct l_timespec *rmtp + ); + } +116 AUE_NULL STD { + int linux_syslog( + l_int type, + char *buf, + l_int len + ); + } +117 AUE_PTRACE STD { + int linux_ptrace( + l_long req, + l_long pid, + l_uintptr_t addr, + l_uintptr_t data + ); + } +118 AUE_SCHED_SETPARAM STD { + int linux_sched_setparam( + l_pid_t pid, + struct sched_param *param + ); + } +119 AUE_SCHED_SETSCHEDULER STD { + int linux_sched_setscheduler( + l_pid_t pid, + l_int policy, + struct sched_param *param + ); + } +120 AUE_SCHED_GETSCHEDULER STD { + int linux_sched_getscheduler( + l_pid_t pid + ); + } +121 AUE_SCHED_GETPARAM STD { + int linux_sched_getparam( + l_pid_t pid, + struct sched_param *param + ); + } +122 AUE_NULL STD { + int linux_sched_setaffinity( + l_pid_t pid, + l_uint len, + l_ulong *user_mask_ptr + ); + } +123 AUE_NULL STD { + int linux_sched_getaffinity( + l_pid_t pid, + l_uint len, + l_ulong *user_mask_ptr + ); + } +124 AUE_NULL NOPROTO { + int sched_yield(void); + } +125 AUE_SCHED_GET_PRIORITY_MAX STD { + int linux_sched_get_priority_max( + l_int policy + ); + } +126 AUE_SCHED_GET_PRIORITY_MIN STD { + int linux_sched_get_priority_min( + l_int policy + ); + } +127 AUE_SCHED_RR_GET_INTERVAL STD { + int linux_sched_rr_get_interval( + l_pid_t pid, + struct l_timespec *interval + ); + } +128 AUE_NULL UNIMPL restart_syscall +129 AUE_KILL STD { + int linux_kill( + l_pid_t pid, + l_int signum + ); + } +130 AUE_NULL STD { + int linux_tkill( + l_pid_t tid, + l_int sig + ); + } +131 AUE_NULL STD { + int linux_tgkill( + l_pid_t tgid, + l_pid_t pid, + l_int sig + ); + } +132 AUE_NULL STD { + int linux_sigaltstack( + l_stack_t *uss, + l_stack_t *uoss + ); + } +133 AUE_NULL STD { + int linux_rt_sigsuspend( + l_sigset_t *newset, + l_size_t sigsetsize + ); + } +134 AUE_NULL STD { + int linux_rt_sigaction( + l_int sig, + l_sigaction_t *act, + l_sigaction_t *oact, + l_size_t sigsetsize + ); + } +135 AUE_NULL STD { + int linux_rt_sigprocmask( + l_int how, + l_sigset_t *mask, + l_sigset_t *omask, + l_size_t sigsetsize + ); + } +136 AUE_NULL STD { + int linux_rt_sigpending( + l_sigset_t *set, + l_size_t sigsetsize + ); + } +137 AUE_NULL STD { + int linux_rt_sigtimedwait( + l_sigset_t *mask, + l_siginfo_t *ptr, + struct l_timespec *timeout, + l_size_t sigsetsize + ); + } +138 AUE_NULL STD { + int linux_rt_sigqueueinfo( + l_pid_t pid, + l_int sig, + l_siginfo_t *info + ); + } +139 AUE_NULL STD { + int linux_rt_sigreturn(void); + } +140 AUE_SETPRIORITY NOPROTO { + int setpriority( + int which, + int who, + int prio + ); + } +141 AUE_GETPRIORITY STD { + int linux_getpriority( + l_int which, + l_int who + ); + } +142 AUE_REBOOT STD { + int linux_reboot( + l_int magic1, + l_int magic2, + l_uint cmd, + void *arg + ); + } +143 AUE_SETREGID NOPROTO { + int setregid( + gid_t rgid, + gid_t egid + ); + } +144 AUE_SETGID NOPROTO { + int setgid( + gid_t gid + ); + } +145 AUE_SETREUID NOPROTO { + int setreuid( + uid_t ruid, + uid_t euid + ); + } +146 AUE_SETUID NOPROTO { + int setuid( + uid_t uid + ); + } +147 AUE_SETRESUID NOPROTO { + int setresuid( + uid_t ruid, + uid_t euid, + uid_t suid + ); + } +148 AUE_GETRESUID STD { + int linux_getresuid( + l_uid_t *ruid, + l_uid_t *euid, + l_uid_t *suid + ); + } +149 AUE_SETRESGID NOPROTO { + int setresgid( + gid_t rgid, + gid_t egid, + gid_t sgid + ); + } +150 AUE_GETRESGID STD { + int linux_getresgid( + l_gid_t *rgid, + l_gid_t *egid, + l_gid_t *sgid + ); + } +151 AUE_SETFSUID STD { + int linux_setfsuid( + l_uid_t uid + ); + } +152 AUE_SETFSGID STD { + int linux_setfsgid( + l_gid_t gid + ); + } +153 AUE_NULL STD { + int linux_times( + struct l_times_argv *buf + ); + } +154 AUE_SETPGRP NOPROTO { + int setpgid( + int pid, + int pgid + ); + } +155 AUE_GETPGID NOPROTO { + int getpgid( + int pid + ); + } +156 AUE_GETSID STD { + int linux_getsid( + l_pid_t pid + ); + } +157 AUE_SETSID NOPROTO { + int setsid(void); + } +158 AUE_GETGROUPS STD { + int linux_getgroups( + l_int gidsetsize, + l_gid_t *grouplist + ); + } +159 AUE_SETGROUPS STD { + int linux_setgroups( + l_int gidsetsize, + l_gid_t *grouplist + ); + } +160 AUE_NULL STD { + int linux_newuname( + struct l_new_utsname *buf + ); + } +161 AUE_SYSCTL STD { + int linux_sethostname( + char *hostname, + l_uint len + ); + } +162 AUE_SYSCTL STD { + int linux_setdomainname( + char *name, + l_int len + ); + } +163 AUE_GETRLIMIT STD { + int linux_getrlimit( + l_uint resource, + struct l_rlimit *rlim + ); + } +164 AUE_SETRLIMIT STD { + int linux_setrlimit( + l_uint resource, + struct l_rlimit *rlim + ); + } +165 AUE_GETRUSAGE STD { + int linux_getrusage( + l_int who, + struct rusage *rusage + ); + } +166 AUE_UMASK NOPROTO { + int umask( + int newmask + ); + } +167 AUE_PRCTL STD { + int linux_prctl( + l_int option, + l_uintptr_t arg2, + l_uintptr_t arg3, + l_uintptr_t arg4, + l_uintptr_t arg5 + ); + } +168 AUE_NULL STD { + int linux_getcpu( + l_uint *cpu, + l_uint *node, + void *cache + ); + } +169 AUE_NULL STD { + int linux_gettimeofday( + l_timeval *tp, + struct timezone *tzp + ); + } +170 AUE_SETTIMEOFDAY STD { + int linux_settimeofday( + l_timeval *tv, + struct timezone *tzp + ); + } +171 AUE_ADJTIME STD { + int linux_adjtimex(void); + } +172 AUE_GETPID STD { + int linux_getpid(void); + } +173 AUE_GETPPID STD { + int linux_getppid(void); + } +174 AUE_GETUID STD { + int linux_getuid(void); + } +175 AUE_GETEUID NOPROTO { + int geteuid(void); + } +176 AUE_GETGID STD { + int linux_getgid(void); + } +177 AUE_GETEGID NOPROTO { + int getegid(void); + } +178 AUE_NULL STD { + int linux_gettid(void); + } +179 AUE_NULL STD { + int linux_sysinfo( + struct l_sysinfo *info + ); + } +180 AUE_NULL STD { + int linux_mq_open( + const char *name, + l_int oflag, + l_mode_t mode, + struct mq_attr *attr + ); + } +181 AUE_NULL STD { + int linux_mq_unlink( + const char *name + ); + } +182 AUE_NULL STD { + int linux_mq_timedsend( + l_mqd_t mqd, + const char *msg_ptr, + l_size_t msg_len, + l_uint msg_prio, + const struct l_timespec *abs_timeout + ); + } +183 AUE_NULL STD { + int linux_mq_timedreceive( + l_mqd_t mqd, + char *msg_ptr, + l_size_t msg_len, + l_uint *msg_prio, + const struct l_timespec *abs_timeout + ); + } +184 AUE_NULL STD { + int linux_mq_notify( + l_mqd_t mqd, + const struct l_sigevent *sevp + ); + } +185 AUE_NULL STD { + int linux_mq_getsetattr( + l_mqd_t mqd, + const struct mq_attr *attr, + struct mq_attr *oattr + ); + } +186 AUE_NULL STD { + int linux_msgget( + l_key_t key, + l_int msgflg + ); + } +187 AUE_NULL STD { + int linux_msgctl( + l_int msqid, + l_int cmd, + struct l_msqid_ds *buf + ); + } +188 AUE_NULL STD { + int linux_msgrcv( + l_int msqid, + struct l_msgbuf *msgp, + l_size_t msgsz, + l_long msgtyp, + l_int msgflg + ); + } +189 AUE_NULL STD { + int linux_msgsnd( + l_int msqid, + struct l_msgbuf *msgp, + l_size_t msgsz, + l_int msgflg + ); + } +190 AUE_NULL STD { + int linux_semget( + l_key_t key, + l_int nsems, + l_int semflg + ); + } +191 AUE_NULL STD { + int linux_semctl( + l_int semid, + l_int semnum, + l_int cmd, + union l_semun arg + ); + } +192 AUE_NULL STD { + int linux_semtimedop( + l_int semid, + struct sembuf *tsops, + l_size_t nsops, + struct l_timespec *timeout + ); + } +193 AUE_NULL STD { + int linux_semop( + l_int semid, + struct sembuf *sops, + l_size_t nsops + ); + } +194 AUE_NULL STD { + int linux_shmget( + l_key_t key, + l_size_t size, + l_int shmflg + ); + } +195 AUE_NULL STD { + int linux_shmctl( + l_int shmid, + l_int cmd, + struct l_shmid_ds *buf + ); + } +196 AUE_NULL STD { + int linux_shmat( + l_int shmid, + char *shmaddr, + l_int shmflg + ); + } +197 AUE_NULL STD { + int linux_shmdt( + char *shmaddr + ); + } +198 AUE_SOCKET STD { + int linux_socket( + l_int domain, + l_int type, + l_int protocol + ); + } +199 AUE_SOCKETPAIR STD { + int linux_socketpair( + l_int domain, + l_int type, + l_int protocol, + l_uintptr_t rsv + ); + } +200 AUE_BIND STD { + int linux_bind( + l_int s, + l_uintptr_t name, + l_int namelen + ); + } +201 AUE_LISTEN STD { + int linux_listen( + l_int s, + l_int backlog + ); + } +202 AUE_ACCEPT STD { + int linux_accept( + l_int s, + l_uintptr_t addr, + l_uintptr_t namelen + ); + } +203 AUE_CONNECT STD { + int linux_connect( + l_int s, + l_uintptr_t name, + l_int namelen + ); + } +204 AUE_GETSOCKNAME STD { + int linux_getsockname( + l_int s, + l_uintptr_t addr, + l_uintptr_t namelen + ); + } +205 AUE_GETPEERNAME STD { + int linux_getpeername( + l_int s, + l_uintptr_t addr, + l_uintptr_t namelen + ); + } +206 AUE_SENDTO STD { + int linux_sendto( + l_int s, + l_uintptr_t msg, + l_size_t len, + l_uint flags, + l_uintptr_t to, + l_int tolen + ); + } +207 AUE_RECVFROM STD { + int linux_recvfrom( + l_int s, + l_uintptr_t buf, + l_size_t len, + l_uint flags, + l_uintptr_t from, + l_uintptr_t fromlen + ); + } +208 AUE_SETSOCKOPT STD { + int linux_setsockopt( + l_int s, + l_int level, + l_int optname, + l_uintptr_t optval, + l_int optlen + ); + } +209 AUE_GETSOCKOPT STD { + int linux_getsockopt( + l_int s, + l_int level, + l_int optname, + l_uintptr_t optval, + l_uintptr_t optlen + ); + } +210 AUE_NULL STD { + int linux_shutdown( + l_int s, + l_int how + ); + } +211 AUE_SENDMSG STD { + int linux_sendmsg( + l_int s, + l_uintptr_t msg, + l_uint flags + ); + } +212 AUE_RECVMSG STD { + int linux_recvmsg( + l_int s, + l_uintptr_t msg, + l_uint flags + ); + } +213 AUE_NULL UNIMPL linux_readahead +214 AUE_NULL STD { + int linux_brk( + l_ulong dsend + ); + } +215 AUE_MUNMAP STD { + int linux_munmap( + void *addr, + l_size_t len + ); + } +216 AUE_NULL STD { + int linux_mremap( + l_ulong addr, + l_ulong old_len, + l_ulong new_len, + l_ulong flags, + l_ulong new_addr + ); + } +217 AUE_NULL STD { + int linux_add_key(void); + } +218 AUE_NULL STD { + int linux_request_key(void); + } +219 AUE_NULL STD { + int linux_keyctl(void); + } +220 AUE_RFORK STD { + int linux_clone( + l_ulong flags, + l_ulong stack, + l_int *parent_tidptr, + l_ulong tls, + l_int *child_tidptr + ); + } +221 AUE_EXECVE STD { + int linux_execve( + char *path, + l_uintptr_t *argp, + l_uintptr_t *envp + ); + } +222 AUE_MMAP STD { + int linux_mmap2( + l_ulong addr, + l_ulong len, + l_ulong prot, + l_ulong flags, + l_ulong fd, + l_ulong pgoff + ); + } +223 AUE_NULL STD { + int linux_fadvise64( + l_int fd, + l_loff_t offset, + l_size_t len, + l_int advice + ); + } +224 AUE_SWAPON STD { + int linux_swapon( + char *name + ); + } +225 AUE_SWAPOFF STD { + int linux_swapoff(void); + } +226 AUE_MPROTECT STD { + int linux_mprotect( + l_ulong addr, + l_size_t len, + l_ulong prot + ); + } +227 AUE_MSYNC STD { + int linux_msync( + l_ulong addr, + l_size_t len, + l_int fl + ); + } +228 AUE_MLOCK STD { + int linux_mlock( + const void *addr, + l_size_t len + ); + } +229 AUE_MUNLOCK STD { + int linux_munlock( + const void *addr, + l_size_t len + ); + } +230 AUE_MLOCKALL NOPROTO { + int mlockall( + int how + ); + } +231 AUE_MUNLOCKALL NOPROTO { + int munlockall(void); + } +232 AUE_MINCORE STD { + int linux_mincore( + l_ulong start, + l_size_t len, + u_char *vec + ); + } +233 AUE_MADVISE STD { + int linux_madvise( + l_ulong addr, + l_size_t len, + l_int behav + ); + } +234 AUE_NULL STD { + int linux_remap_file_pages(void); + } +235 AUE_NULL STD { + int linux_mbind(void); + } +236 AUE_NULL STD { + int linux_get_mempolicy(void); + } +237 AUE_NULL STD { + int linux_set_mempolicy(void); + } +238 AUE_NULL STD { + int linux_migrate_pages(void); + } +239 AUE_NULL STD { + int linux_move_pages(void); + } +240 AUE_NULL STD { + int linux_rt_tgsigqueueinfo( + l_pid_t tgid, + l_pid_t tid, + l_int sig, + l_siginfo_t *uinfo + ); + } +241 AUE_NULL STD { + int linux_perf_event_open(void); + } +242 AUE_ACCEPT STD { + int linux_accept4( + l_int s, + l_uintptr_t addr, + l_uintptr_t namelen, + l_int flags + ); + } +243 AUE_NULL STD { + int linux_recvmmsg( + l_int s, + struct l_mmsghdr *msg, + l_uint vlen, + l_uint flags, + struct l_timespec *timeout + ); + } +244-259 AUE_NULL UNIMPL unimpl_md_syscall +260 AUE_WAIT4 STD { + int linux_wait4( + l_pid_t pid, + l_int *status, + l_int options, + struct rusage *rusage + ); + } +261 AUE_NULL STD { + int linux_prlimit64( + l_pid_t pid, + l_uint resource, + struct rlimit *new, + struct rlimit *old + ); + } +262 AUE_NULL STD { + int linux_fanotify_init(void); + } +263 AUE_NULL STD { + int linux_fanotify_mark(void); + } +264 AUE_NULL STD { + int linux_name_to_handle_at( + l_int dirfd, + const char *name, + struct l_file_handle *handle, + l_int *mnt_id, + l_int flags + ); + } +265 AUE_NULL STD { + int linux_open_by_handle_at( + l_int mountdirfd, + struct l_file_handle *handle, + l_int flags + ); + } +266 AUE_NULL STD { + int linux_clock_adjtime(void); + } +267 AUE_SYNC STD { + int linux_syncfs( + l_int fd + ); + } +268 AUE_NULL STD { + int linux_setns( + l_int fd, + l_int nstype + ); + } +269 AUE_NULL STD { + int linux_sendmmsg( + l_int s, + struct l_mmsghdr *msg, + l_uint vlen, + l_uint flags + ); + } +270 AUE_NULL STD { + int linux_process_vm_readv( + l_pid_t pid, + const struct iovec *lvec, + l_ulong liovcnt, + const struct iovec *rvec, + l_ulong riovcnt, + l_ulong flags + ); + } +271 AUE_NULL STD { + int linux_process_vm_writev( + l_pid_t pid, + const struct iovec *lvec, + l_ulong liovcnt, + const struct iovec *rvec, + l_ulong riovcnt, + l_ulong flags + ); + } +272 AUE_NULL STD { + int linux_kcmp( + l_pid_t pid1, + l_pid_t pid2, + l_int type, + l_ulong idx1, + l_ulong idx + ); + } +273 AUE_NULL STD { + int linux_finit_module( + l_int fd, + const char *uargs, + l_int flags + ); + } +274 AUE_NULL STD { + int linux_sched_setattr( + l_pid_t pid, + void *attr, + l_uint flags + ); + } +275 AUE_NULL STD { + int linux_sched_getattr( + l_pid_t pid, + void *attr, + l_uint size, + l_uint flags + ); + } +276 AUE_NULL STD { + int linux_renameat2( + l_int olddfd, + const char *oldname, + l_int newdfd, + const char *newname, + l_uint flags + ); + } +277 AUE_NULL STD { + int linux_seccomp( + l_uint op, + l_uint flags, + const char *uargs + ); + } +278 AUE_NULL STD { + int linux_getrandom( + char *buf, + l_size_t count, + l_uint flags + ); + } +279 AUE_NULL STD { + int linux_memfd_create( + const char *uname_ptr, + l_uint flags + ); + } +280 AUE_NULL STD { + int linux_bpf( + l_int cmd, + void *attr, + l_uint size + ); + } +281 AUE_NULL STD { + int linux_execveat( + l_int dfd, + const char *filename, + const char **argv, + const char **envp, + l_int flags + ); + } +282 AUE_NULL STD { + int linux_userfaultfd( + l_int flags + ); + } +283 AUE_NULL STD { + int linux_membarrier( + l_int cmd, + l_int flags + ); + } +284 AUE_NULL STD { + int linux_mlock2( + l_ulong start, + l_size_t len, + l_int flags + ); + } +285 AUE_NULL STD { + int linux_copy_file_range( + l_int fd_in, + l_loff_t *off_in, + l_int fd_out, + l_loff_t *off_out, + l_size_t len, + l_uint flags + ); + } +286 AUE_NULL STD { + int linux_preadv2( + l_ulong fd, + const struct iovec *vec, + l_ulong vlen, + l_ulong pos_l, + l_ulong pos_h, + l_int flags + ); + } +287 AUE_NULL STD { + int linux_pwritev2( + l_ulong fd, + const struct iovec *vec, + l_ulong vlen, + l_ulong pos_l, + l_ulong pos_h, + l_int flags + ); + } +288 AUE_NULL STD { + int linux_pkey_mprotect( + l_ulong start, + l_size_t len, + l_ulong prot, + l_int pkey + ); + } +289 AUE_NULL STD { + int linux_pkey_alloc( + l_ulong flags, + l_ulong init_val + ); + } +290 AUE_NULL STD { + int linux_pkey_free( + l_int pkey + ); + } +; Linux 4.11: +291 AUE_NULL STD { + int linux_statx( + l_int dirfd, + const char *pathname, + l_uint flags, + l_uint mask, + void *statxbuf + ); + } +; Linux 4.18: +292 AUE_NULL STD { + int linux_io_pgetevents(void); + } +293 AUE_NULL STD { + int linux_rseq( + struct linux_rseq *rseq, + uint32_t rseq_len, + l_int flags, + uint32_t sig + ); + } +294 AUE_NULL STD { + int linux_kexec_file_load(void); + } +; Linux 5.1: +295-423 AUE_NULL UNIMPL unimpl_md_syscall +424 AUE_NULL STD { + int linux_pidfd_send_signal( + l_int pidfd, + l_int sig, + l_siginfo_t *info, + l_uint flags + ); + } +425 AUE_NULL STD { + int linux_io_uring_setup(void); + } +426 AUE_NULL STD { + int linux_io_uring_enter(void); + } +427 AUE_NULL STD { + int linux_io_uring_register(void); + } +; Linux 5.2: +428 AUE_NULL STD { + int linux_open_tree(void); + } +429 AUE_NULL STD { + int linux_move_mount(void); + } +430 AUE_NULL STD { + int linux_fsopen(void); + } +431 AUE_NULL STD { + int linux_fsconfig(void); + } +432 AUE_NULL STD { + int linux_fsmount(void); + } +433 AUE_NULL STD { + int linux_fspick(void); + } +; Linux 5.3: +434 AUE_NULL STD { + int linux_pidfd_open(void); + } +435 AUE_NULL STD { + int linux_clone3( + struct l_user_clone_args *uargs, + l_size_t usize + ); + } +; Linux 5.9: +436 AUE_CLOSERANGE STD { + int linux_close_range( + l_uint first, + l_uint last, + l_uint flags + ); + } +; Linux 5.6: +437 AUE_NULL STD { + int linux_openat2(void); + } +438 AUE_NULL STD { + int linux_pidfd_getfd(void); + } +; Linux 5.8: +439 AUE_NULL STD { + int linux_faccessat2( + l_int dfd, + const char *filename, + l_int amode, + l_int flags + ); + } +; Linux 5.10: +440 AUE_NULL STD { + int linux_process_madvise(void); + } +; Linux 5.11: +441 AUE_NULL STD { + int linux_epoll_pwait2( + l_int epfd, + struct epoll_event *events, + l_int maxevents, + struct l_timespec *timeout, + l_sigset_t *mask, + l_size_t sigsetsize + ); + } +; Linux 5.12: +442 AUE_NULL STD { + int linux_mount_setattr(void); + } +; Linux 5.14: +443 AUE_NULL STD { + int linux_quotactl_fd(void); + } +; Linux 5.13: +444 AUE_NULL STD { + int linux_landlock_create_ruleset(void); + } +445 AUE_NULL STD { + int linux_landlock_add_rule(void); + } +446 AUE_NULL STD { + int linux_landlock_restrict_self(void); + } +; Linux 5.14: +447 AUE_NULL STD { + int linux_memfd_secret(void); + } +; Linux 5.15: +448 AUE_NULL STD { + int linux_process_mrelease(void); + } +; Linux 5.16: +449 AUE_NULL STD { + int linux_futex_waitv(void); + } +; Linux 5.17: +450 AUE_NULL STD { + int linux_set_mempolicy_home_node(void); + } +; Linux 6.5: +451 AUE_NULL STD { + int linux_cachestat(void); + } +; Linux 6.6: +452 AUE_NULL STD { + int linux_fchmodat2(void); + } + + ; vim: syntax=off diff --git a/sys/cheri/cheri_syscall.c b/sys/cheri/cheri_syscall.c index 2aa99029cb20..67d5cd98a030 100644 --- a/sys/cheri/cheri_syscall.c +++ b/sys/cheri/cheri_syscall.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,13 @@ int cheri_syscall_authorize(struct thread *td, u_int code, int nargs, syscallarg_t *args) { + /* + * PCuABI Binaries does not have this permission. We just skip the check. + */ + if (SV_PROC_ABI(td->td_proc) == SV_ABI_LINUX) { + return (0); + } + uintmax_t c_perms; /* diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index fcd8a2be7232..ece3e38d031c 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -571,7 +571,7 @@ linprocfs_doprocmountinfo(PFS_FILL_ARGS) { const char *mntfrom, *mntto, *fstype; char *dlep, *flep; - struct statfs *buf, *sp; + struct statfs * __capability buf, *sp; size_t count, lep_len; struct vnode *vp; struct pwd *pwd; @@ -595,7 +595,7 @@ linprocfs_doprocmountinfo(PFS_FILL_ARGS) if (error != 0) goto out; - for (sp = buf; count > 0; sp++, count--) { + for (sp = (__cheri_fromcap struct statfs *)buf; count > 0; sp++, count--) { error = _mtab_helper(pn, sp, &mntfrom, &mntto, &fstype); if (error != 0) { MPASS(error == ECANCELED); @@ -648,7 +648,7 @@ linprocfs_doprocmountinfo(PFS_FILL_ARGS) error = 0; out: - free(buf, M_TEMP); + free_c(buf, M_TEMP); free(flep, M_TEMP); return (error); } diff --git a/sys/compat/linux/check_error.d b/sys/compat/linux/check_error.d index 6d922454b1f0..0a5b6a3fe7c3 100644 --- a/sys/compat/linux/check_error.d +++ b/sys/compat/linux/check_error.d @@ -1,117 +1,117 @@ -#!/usr/sbin/dtrace -qs - -/*- - * Copyright (c) 2008-2012 Alexander Leidinger - * 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 - * in this position and unchanged. - * 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 ``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 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. - */ - -/* - * Report error conditions: - * - emulation errors (unsupportet stuff, unknown stuff, ...) - * - kernel errors (resource shortage, ...) - * - programming errors (errors which can happen, but should not happen) - */ - -linuxulator*:dummy::not_implemented, -linuxulator*:emul:linux_thread_detach:child_clear_tid_error, -linuxulator*:emul:linux_thread_detach:futex_failed, -linuxulator*:emul:linux_schedtail:copyout_error, -linuxulator*:time:linux_clock_gettime:conversion_error, -linuxulator*:time:linux_clock_gettime:gettime_error, -linuxulator*:time:linux_clock_gettime:copyout_error, -linuxulator*:time:linux_clock_settime:conversion_error, -linuxulator*:time:linux_clock_settime:settime_error, -linuxulator*:time:linux_clock_settime:copyin_error, -linuxulator*:time:linux_clock_getres:conversion_error, -linuxulator*:time:linux_clock_getres:getres_error, -linuxulator*:time:linux_clock_getres:copyout_error, -linuxulator*:time:linux_nanosleep:conversion_error, -linuxulator*:time:linux_nanosleep:nanosleep_error, -linuxulator*:time:linux_nanosleep:copyout_error, -linuxulator*:time:linux_nanosleep:copyin_error, -linuxulator*:time:linux_clock_nanosleep:copyin_error, -linuxulator*:time:linux_clock_nanosleep:conversion_error, -linuxulator*:time:linux_clock_nanosleep:copyout_error, -linuxulator*:time:linux_clock_nanosleep:nanosleep_error, -linuxulator*:sysctl:handle_string:copyout_error, -linuxulator*:sysctl:linux_sysctl:copyin_error, -linuxulator*:mib:linux_sysctl_osname:sysctl_string_error, -linuxulator*:mib:linux_sysctl_osrelease:sysctl_string_error, -linuxulator*:mib:linux_sysctl_oss_version:sysctl_string_error, -linuxulator*:mib:linux_prison_create:vfs_copyopt_error, -linuxulator*:mib:linux_prison_check:vfs_copyopt_error, -linuxulator*:mib:linux_prison_check:vfs_getopt_error, -linuxulator*:mib:linux_prison_set:vfs_copyopt_error, -linuxulator*:mib:linux_prison_set:vfs_getopt_error, -linuxulator*:mib:linux_prison_get:vfs_setopt_error, -linuxulator*:mib:linux_prison_get:vfs_setopts_error -{ - printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod, probefunc); - stack(); - ustack(); -} - -linuxulator*:util:linux_driver_get_name_dev:nullcall, -linuxulator*:util:linux_driver_get_major_minor:nullcall, -linuxulator*:time:linux_clock_getres:nullcall -{ - printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n", probename, probeprov, probemod, probefunc, execname); - stack(); - ustack(); -} - -linuxulator*:util:linux_driver_get_major_minor:notfound -{ - printf("WARNING: Application %s failed to find %s in %s:%s:%s, this may or may not be a problem.\n", execname, stringof(args[0]), probename, probeprov, probemod); - stack(); - ustack(); -} - -linuxulator*:time:linux_to_native_clockid:unknown_clockid -{ - printf("INFO: Application %s tried to use unknown clockid %d. Please report this to freebsd-emulation@FreeBSD.org.\n", execname, arg0); -} - -linuxulator*:time:linux_to_native_clockid:unsupported_clockid, -linuxulator*:time:linux_clock_nanosleep:unsupported_clockid -{ - printf("WARNING: Application %s tried to use unsupported clockid (%d), this may or may not be a problem for the application.\nPatches to support this clockid are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0); -} - -linuxulator*:time:linux_clock_nanosleep:unsupported_flags -{ - printf("WARNING: Application %s tried to use unsupported flags (%d), this may or may not be a problem for the application.\nPatches to support those flags are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0); -} - -linuxulator*:sysctl:linux_sysctl:wrong_length -{ - printf("ERROR: Application %s issued a sysctl which failed the length restrictions.\nThe length passed is %d, the min length supported is 1 and the max length supported is %d.\n", execname, arg0, arg1); - stack(); - ustack(); -} - -linuxulator*:sysctl:linux_sysctl:unsupported_sysctl -{ - printf("ERROR: Application %s issued an unsupported sysctl (%s).\nPatches to support this sysctl are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, stringof(args[0])); -} +#!/usr/sbin/dtrace -qs + +/*- + * Copyright (c) 2008-2012 Alexander Leidinger + * 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 + * in this position and unchanged. + * 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 ``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 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. + */ + +/* + * Report error conditions: + * - emulation errors (unsupportet stuff, unknown stuff, ...) + * - kernel errors (resource shortage, ...) + * - programming errors (errors which can happen, but should not happen) + */ + +linuxulator*:dummy::not_implemented, +linuxulator*:emul:linux_thread_detach:child_clear_tid_error, +linuxulator*:emul:linux_thread_detach:futex_failed, +linuxulator*:emul:linux_schedtail:copyout_error, +linuxulator*:time:linux_clock_gettime:conversion_error, +linuxulator*:time:linux_clock_gettime:gettime_error, +linuxulator*:time:linux_clock_gettime:copyout_error, +linuxulator*:time:linux_clock_settime:conversion_error, +linuxulator*:time:linux_clock_settime:settime_error, +linuxulator*:time:linux_clock_settime:copyin_error, +linuxulator*:time:linux_clock_getres:conversion_error, +linuxulator*:time:linux_clock_getres:getres_error, +linuxulator*:time:linux_clock_getres:copyout_error, +linuxulator*:time:linux_nanosleep:conversion_error, +linuxulator*:time:linux_nanosleep:nanosleep_error, +linuxulator*:time:linux_nanosleep:copyout_error, +linuxulator*:time:linux_nanosleep:copyin_error, +linuxulator*:time:linux_clock_nanosleep:copyin_error, +linuxulator*:time:linux_clock_nanosleep:conversion_error, +linuxulator*:time:linux_clock_nanosleep:copyout_error, +linuxulator*:time:linux_clock_nanosleep:nanosleep_error, +linuxulator*:sysctl:handle_string:copyout_error, +linuxulator*:sysctl:linux_sysctl:copyin_error, +linuxulator*:mib:linux_sysctl_osname:sysctl_string_error, +linuxulator*:mib:linux_sysctl_osrelease:sysctl_string_error, +linuxulator*:mib:linux_sysctl_oss_version:sysctl_string_error, +linuxulator*:mib:linux_prison_create:vfs_copyopt_error, +linuxulator*:mib:linux_prison_check:vfs_copyopt_error, +linuxulator*:mib:linux_prison_check:vfs_getopt_error, +linuxulator*:mib:linux_prison_set:vfs_copyopt_error, +linuxulator*:mib:linux_prison_set:vfs_getopt_error, +linuxulator*:mib:linux_prison_get:vfs_setopt_error, +linuxulator*:mib:linux_prison_get:vfs_setopts_error +{ + printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod, probefunc); + stack(); + ustack(); +} + +linuxulator*:util:linux_driver_get_name_dev:nullcall, +linuxulator*:util:linux_driver_get_major_minor:nullcall, +linuxulator*:time:linux_clock_getres:nullcall +{ + printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n", probename, probeprov, probemod, probefunc, execname); + stack(); + ustack(); +} + +linuxulator*:util:linux_driver_get_major_minor:notfound +{ + printf("WARNING: Application %s failed to find %s in %s:%s:%s, this may or may not be a problem.\n", execname, stringof(args[0]), probename, probeprov, probemod); + stack(); + ustack(); +} + +linuxulator*:time:linux_to_native_clockid:unknown_clockid +{ + printf("INFO: Application %s tried to use unknown clockid %d. Please report this to freebsd-emulation@FreeBSD.org.\n", execname, arg0); +} + +linuxulator*:time:linux_to_native_clockid:unsupported_clockid, +linuxulator*:time:linux_clock_nanosleep:unsupported_clockid +{ + printf("WARNING: Application %s tried to use unsupported clockid (%d), this may or may not be a problem for the application.\nPatches to support this clockid are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0); +} + +linuxulator*:time:linux_clock_nanosleep:unsupported_flags +{ + printf("WARNING: Application %s tried to use unsupported flags (%d), this may or may not be a problem for the application.\nPatches to support those flags are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0); +} + +linuxulator*:sysctl:linux_sysctl:wrong_length +{ + printf("ERROR: Application %s issued a sysctl which failed the length restrictions.\nThe length passed is %d, the min length supported is 1 and the max length supported is %d.\n", execname, arg0, arg1); + stack(); + ustack(); +} + +linuxulator*:sysctl:linux_sysctl:unsupported_sysctl +{ + printf("ERROR: Application %s issued an unsupported sysctl (%s).\nPatches to support this sysctl are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, stringof(args[0])); +} diff --git a/sys/compat/linux/check_internal_locks.d b/sys/compat/linux/check_internal_locks.d index ceed81b3b0f8..54b60a500fe8 100644 --- a/sys/compat/linux/check_internal_locks.d +++ b/sys/compat/linux/check_internal_locks.d @@ -1,95 +1,95 @@ -#!/usr/sbin/dtrace -qs - -/*- - * Copyright (c) 2008-2012 Alexander Leidinger - * 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 - * in this position and unchanged. - * 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 ``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 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. - */ - -/** - * Check if the internal locks are correctly acquired/released: - * - no recursive locking (mtx locks, write locks) - * - no unlocking of already unlocked one - * - * Print stacktrace if a lock is longer locked than about 10sec or more. - */ - -#pragma D option dynvarsize=32m -#pragma D option specsize=32m - -BEGIN -{ - check["futex_mtx"] = 0; -} - -linuxulator*:locks:futex_mtx:locked -/check[probefunc] > 0/ -{ - printf("ERROR: recursive lock of %s (%p),", probefunc, arg0); - printf(" or missing SDT probe in kernel. Stack trace follows:"); - stack(); -} - -linuxulator*:locks:futex_mtx:locked -{ - ++check[probefunc]; - @stats[probefunc] = count(); - - ts[probefunc] = timestamp; - spec[probefunc] = speculation(); -} - -linuxulator*:locks:futex_mtx:unlock -/check[probefunc] == 0/ -{ - printf("ERROR: unlock attempt of unlocked %s (%p),", probefunc, arg0); - printf(" missing SDT probe in kernel, or dtrace program started"); - printf(" while the %s was already held (race condition).", probefunc); - printf(" Stack trace follows:"); - stack(); -} - -linuxulator*:locks:futex_mtx:unlock -{ - discard(spec[probefunc]); - spec[probefunc] = 0; - --check[probefunc]; -} - -/* Timeout handling */ - -tick-10s -/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/ -{ - commit(spec["futex_mtx"]); - spec["futex_mtx"] = 0; -} - - -/* Statistics */ - -END -{ - printf("Number of locks per type:"); - printa(@stats); -} +#!/usr/sbin/dtrace -qs + +/*- + * Copyright (c) 2008-2012 Alexander Leidinger + * 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 + * in this position and unchanged. + * 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 ``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 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. + */ + +/** + * Check if the internal locks are correctly acquired/released: + * - no recursive locking (mtx locks, write locks) + * - no unlocking of already unlocked one + * + * Print stacktrace if a lock is longer locked than about 10sec or more. + */ + +#pragma D option dynvarsize=32m +#pragma D option specsize=32m + +BEGIN +{ + check["futex_mtx"] = 0; +} + +linuxulator*:locks:futex_mtx:locked +/check[probefunc] > 0/ +{ + printf("ERROR: recursive lock of %s (%p),", probefunc, arg0); + printf(" or missing SDT probe in kernel. Stack trace follows:"); + stack(); +} + +linuxulator*:locks:futex_mtx:locked +{ + ++check[probefunc]; + @stats[probefunc] = count(); + + ts[probefunc] = timestamp; + spec[probefunc] = speculation(); +} + +linuxulator*:locks:futex_mtx:unlock +/check[probefunc] == 0/ +{ + printf("ERROR: unlock attempt of unlocked %s (%p),", probefunc, arg0); + printf(" missing SDT probe in kernel, or dtrace program started"); + printf(" while the %s was already held (race condition).", probefunc); + printf(" Stack trace follows:"); + stack(); +} + +linuxulator*:locks:futex_mtx:unlock +{ + discard(spec[probefunc]); + spec[probefunc] = 0; + --check[probefunc]; +} + +/* Timeout handling */ + +tick-10s +/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/ +{ + commit(spec["futex_mtx"]); + spec["futex_mtx"] = 0; +} + + +/* Statistics */ + +END +{ + printf("Number of locks per type:"); + printa(@stats); +} diff --git a/sys/compat/linux/linux.c b/sys/compat/linux/linux.c index 61b207070963..ef81694449bc 100644 --- a/sys/compat/linux/linux.c +++ b/sys/compat/linux/linux.c @@ -1,887 +1,887 @@ -/*- - * Copyright (c) 2015 Dmitry Chagin - * - * 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 "opt_inet6.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -_Static_assert(LINUX_IFNAMSIZ == IFNAMSIZ, "Linux IFNAMSIZ"); -_Static_assert(sizeof(struct sockaddr) == sizeof(struct l_sockaddr), - "Linux struct sockaddr size"); -_Static_assert(offsetof(struct sockaddr, sa_data) == - offsetof(struct l_sockaddr, sa_data), "Linux struct sockaddr layout"); - -static bool use_real_ifnames = false; -SYSCTL_BOOL(_compat_linux, OID_AUTO, use_real_ifnames, CTLFLAG_RWTUN, - &use_real_ifnames, 0, - "Use FreeBSD interface names instead of generating ethN aliases"); - -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 */ -}; - -#define LINUX_SIGPWREMU (SIGRTMIN + (LINUX_SIGRTMAX - LINUX_SIGRTMIN) + 1) - -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. - */ - LINUX_SIGPWREMU,/* 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 + sig - LINUX_SIGRTMIN); -} - -static inline int -bsd_to_linux_rt_signal(int sig) -{ - - return (sig - SIGRTMIN + 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 == LINUX_SIGPWREMU) - 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 FreeBSD interface name to a Linux interface name - * by interface name, and return the number of bytes copied to lxname. - */ -int -ifname_bsd_to_linux_name(const char *bsdname, char *lxname, size_t len) -{ - struct epoch_tracker et; - struct ifnet *ifp; - int ret; - - CURVNET_ASSERT_SET(); - - ret = 0; - NET_EPOCH_ENTER(et); - ifp = ifunit(bsdname); - if (ifp != NULL) - ret = ifname_bsd_to_linux_ifp(ifp, lxname, len); - NET_EPOCH_EXIT(et); - return (ret); -} - -/* - * Translate a FreeBSD interface name to a Linux interface name - * by interface index, and return the number of bytes copied to lxname. - */ -int -ifname_bsd_to_linux_idx(u_int idx, char *lxname, size_t len) -{ - struct epoch_tracker et; - struct ifnet *ifp; - int ret; - - ret = 0; - CURVNET_SET(TD_TO_VNET(curthread)); - NET_EPOCH_ENTER(et); - ifp = ifnet_byindex(idx); - if (ifp != NULL) - ret = ifname_bsd_to_linux_ifp(ifp, lxname, len); - NET_EPOCH_EXIT(et); - CURVNET_RESTORE(); - return (ret); -} - -/* - * Translate a FreeBSD interface name to a Linux interface name, - * and return the number of bytes copied to lxname, 0 if interface - * not found, -1 on error. - */ -struct ifname_bsd_to_linux_ifp_cb_s { - struct ifnet *ifp; - int ethno; - char *lxname; - size_t len; -}; - -static int -ifname_bsd_to_linux_ifp_cb(if_t ifp, void *arg) -{ - struct ifname_bsd_to_linux_ifp_cb_s *cbs = arg; - - if (ifp == cbs->ifp) - return (snprintf(cbs->lxname, cbs->len, "eth%d", cbs->ethno)); - if (IFP_IS_ETH(ifp)) - cbs->ethno++; - return (0); -} - -int -ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len) -{ - struct ifname_bsd_to_linux_ifp_cb_s arg = { - .ifp = ifp, - .ethno = 0, - .lxname = lxname, - .len = len, - }; - - NET_EPOCH_ASSERT(); - - /* - * Linux loopback interface name is lo (not lo0), - * we translate lo to lo0, loX to loX. - */ - if (IFP_IS_LOOP(ifp) && strncmp(if_name(ifp), "lo0", IFNAMSIZ) == 0) - return (strlcpy(lxname, "lo", len)); - - /* Short-circuit non ethernet interfaces. */ - if (!IFP_IS_ETH(ifp) || linux_use_real_ifname(ifp)) - return (strlcpy(lxname, if_name(ifp), len)); - - /* Determine the (relative) unit number for ethernet interfaces. */ - return (if_foreach(ifname_bsd_to_linux_ifp_cb, &arg)); -} - -/* - * 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 ifname_linux_to_ifp_cb_s { - bool is_lo; - bool is_eth; - int ethno; - int unit; - const char *lxname; - if_t ifp; -}; - -static int -ifname_linux_to_ifp_cb(if_t ifp, void *arg) -{ - struct ifname_linux_to_ifp_cb_s *cbs = arg; - - NET_EPOCH_ASSERT(); - - /* - * 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(if_name(ifp), cbs->lxname, LINUX_IFNAMSIZ) == 0) - goto out; - if (cbs->is_eth && IFP_IS_ETH(ifp) && cbs->unit == cbs->ethno) - goto out; - if (cbs->is_lo && IFP_IS_LOOP(ifp)) - goto out; - if (IFP_IS_ETH(ifp)) - cbs->ethno++; - return (0); - -out: - cbs->ifp = ifp; - return (1); -} - -struct ifnet * -ifname_linux_to_ifp(struct thread *td, const char *lxname) -{ - struct ifname_linux_to_ifp_cb_s arg = { - .ethno = 0, - .lxname = lxname, - .ifp = NULL, - }; - int len; - char *ep; - - NET_EPOCH_ASSERT(); - - 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), - * we translate lo to lo0, loX to loX. - */ - arg.is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0); - arg.unit = (int)strtoul(lxname + len, &ep, 10); - if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) && - arg.is_lo == 0) - return (NULL); - arg.is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0); - - if_foreach(ifname_linux_to_ifp_cb, &arg); - return (arg.ifp); -} - -int -ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) -{ - struct epoch_tracker et; - struct ifnet *ifp; - - CURVNET_SET(TD_TO_VNET(td)); - NET_EPOCH_ENTER(et); - ifp = ifname_linux_to_ifp(td, lxname); - if (ifp != NULL && bsdname != NULL) - strlcpy(bsdname, if_name(ifp), IFNAMSIZ); - NET_EPOCH_EXIT(et); - CURVNET_RESTORE(); - return (ifp != NULL ? 0 : EINVAL); -} - -unsigned short -linux_ifflags(struct ifnet *ifp) -{ - unsigned short flags; - - NET_EPOCH_ASSERT(); - - flags = if_getflags(ifp) | if_getdrvflags(ifp); - return (bsd_to_linux_ifflags(flags)); -} - -unsigned short -bsd_to_linux_ifflags(int fl) -{ - unsigned short 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; - return (flags); -} - -static u_int -linux_ifhwaddr_cb(void *arg, struct ifaddr *ifa, u_int count) -{ - struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr; - struct l_sockaddr *lsa = arg; - - if (count > 0) - return (0); - if (sdl->sdl_type != IFT_ETHER) - return (0); - bzero(lsa, sizeof(*lsa)); - lsa->sa_family = LINUX_ARPHRD_ETHER; - bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN); - return (1); -} - -int -linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa) -{ - - NET_EPOCH_ASSERT(); - - if (IFP_IS_LOOP(ifp)) { - bzero(lsa, sizeof(*lsa)); - lsa->sa_family = LINUX_ARPHRD_LOOPBACK; - return (0); - } - if (!IFP_IS_ETH(ifp)) - return (ENOENT); - if (if_foreach_addr_type(ifp, AF_LINK, linux_ifhwaddr_cb, lsa) > 0) - return (0); - return (ENOENT); -} - -sa_family_t -linux_to_bsd_domain(sa_family_t 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); - case LINUX_AF_NETLINK: - return (AF_NETLINK); - } - return (AF_UNKNOWN); -} - -sa_family_t -bsd_to_linux_domain(sa_family_t 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); - case AF_NETLINK: - return (LINUX_AF_NETLINK); - } - return (AF_UNKNOWN); -} - -/* - * 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; - sa_family_t bdom; - - *lsa = NULL; - if (len < 2 || len > UCHAR_MAX) - return (EINVAL); - bdom = bsd_to_linux_domain(sa->sa_family); - if (bdom == AF_UNKNOWN) - return (EAFNOSUPPORT); - - kosa = malloc(len, M_LINUX, M_WAITOK); - bcopy(sa, kosa, len); - kosa->sa_family = bdom; - *lsa = kosa; - return (0); -} - -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 == AF_UNKNOWN) { - 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; - } - } - - if (bdom == AF_NETLINK) { - if (salen < sizeof(struct sockaddr_nl)) { - error = EINVAL; - goto out; - } - salen = sizeof(struct sockaddr_nl); - } - - 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); -} - -void -linux_to_bsd_poll_events(struct thread *td, int fd, short lev, - short *bev) -{ - struct file *fp; - int error; - short bits = 0; - - if (lev & LINUX_POLLIN) - bits |= POLLIN; - if (lev & LINUX_POLLPRI) - bits |= POLLPRI; - if (lev & LINUX_POLLOUT) - bits |= POLLOUT; - if (lev & LINUX_POLLERR) - bits |= POLLERR; - if (lev & LINUX_POLLHUP) - bits |= POLLHUP; - if (lev & LINUX_POLLNVAL) - bits |= POLLNVAL; - if (lev & LINUX_POLLRDNORM) - bits |= POLLRDNORM; - if (lev & LINUX_POLLRDBAND) - bits |= POLLRDBAND; - if (lev & LINUX_POLLWRBAND) - bits |= POLLWRBAND; - if (lev & LINUX_POLLWRNORM) - bits |= POLLWRNORM; - - if (lev & LINUX_POLLRDHUP) { - /* - * It seems that the Linux silencly ignores POLLRDHUP - * on non-socket file descriptors unlike FreeBSD, where - * events bits is more strictly checked (POLLSTANDARD). - */ - error = fget_unlocked(td, fd, &cap_no_rights, &fp); - if (error == 0) { - /* - * XXX. On FreeBSD POLLRDHUP applies only to - * stream sockets. - */ - if (fp->f_type == DTYPE_SOCKET) - bits |= POLLRDHUP; - fdrop(fp, td); - } - } - - if (lev & LINUX_POLLMSG) - LINUX_RATELIMIT_MSG_OPT1("unsupported POLLMSG, events(%d)", lev); - if (lev & LINUX_POLLREMOVE) - LINUX_RATELIMIT_MSG_OPT1("unsupported POLLREMOVE, events(%d)", lev); - - *bev = bits; -} - -void -bsd_to_linux_poll_events(short bev, short *lev) -{ - short bits = 0; - - if (bev & POLLIN) - bits |= LINUX_POLLIN; - if (bev & POLLPRI) - bits |= LINUX_POLLPRI; - if (bev & (POLLOUT | POLLWRNORM)) - /* - * POLLWRNORM is equal to POLLOUT on FreeBSD, - * but not on Linux - */ - bits |= LINUX_POLLOUT; - if (bev & POLLERR) - bits |= LINUX_POLLERR; - if (bev & POLLHUP) - bits |= LINUX_POLLHUP; - if (bev & POLLNVAL) - bits |= LINUX_POLLNVAL; - if (bev & POLLRDNORM) - bits |= LINUX_POLLRDNORM; - if (bev & POLLRDBAND) - bits |= LINUX_POLLRDBAND; - if (bev & POLLWRBAND) - bits |= LINUX_POLLWRBAND; - if (bev & POLLRDHUP) - bits |= LINUX_POLLRDHUP; - - *lev = bits; -} - -bool -linux_use_real_ifname(const struct ifnet *ifp) -{ - - return (use_real_ifnames); -} +/*- + * Copyright (c) 2015 Dmitry Chagin + * + * 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 "opt_inet6.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +_Static_assert(LINUX_IFNAMSIZ == IFNAMSIZ, "Linux IFNAMSIZ"); +_Static_assert(sizeof(struct sockaddr) == sizeof(struct l_sockaddr), + "Linux struct sockaddr size"); +_Static_assert(offsetof(struct sockaddr, sa_data) == + offsetof(struct l_sockaddr, sa_data), "Linux struct sockaddr layout"); + +static bool use_real_ifnames = false; +SYSCTL_BOOL(_compat_linux, OID_AUTO, use_real_ifnames, CTLFLAG_RWTUN, + &use_real_ifnames, 0, + "Use FreeBSD interface names instead of generating ethN aliases"); + +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 */ +}; + +#define LINUX_SIGPWREMU (SIGRTMIN + (LINUX_SIGRTMAX - LINUX_SIGRTMIN) + 1) + +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. + */ + LINUX_SIGPWREMU,/* 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 + sig - LINUX_SIGRTMIN); +} + +static inline int +bsd_to_linux_rt_signal(int sig) +{ + + return (sig - SIGRTMIN + 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 == LINUX_SIGPWREMU) + 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 FreeBSD interface name to a Linux interface name + * by interface name, and return the number of bytes copied to lxname. + */ +int +ifname_bsd_to_linux_name(const char *bsdname, char *lxname, size_t len) +{ + struct epoch_tracker et; + struct ifnet *ifp; + int ret; + + CURVNET_ASSERT_SET(); + + ret = 0; + NET_EPOCH_ENTER(et); + ifp = ifunit(bsdname); + if (ifp != NULL) + ret = ifname_bsd_to_linux_ifp(ifp, lxname, len); + NET_EPOCH_EXIT(et); + return (ret); +} + +/* + * Translate a FreeBSD interface name to a Linux interface name + * by interface index, and return the number of bytes copied to lxname. + */ +int +ifname_bsd_to_linux_idx(u_int idx, char *lxname, size_t len) +{ + struct epoch_tracker et; + struct ifnet *ifp; + int ret; + + ret = 0; + CURVNET_SET(TD_TO_VNET(curthread)); + NET_EPOCH_ENTER(et); + ifp = ifnet_byindex(idx); + if (ifp != NULL) + ret = ifname_bsd_to_linux_ifp(ifp, lxname, len); + NET_EPOCH_EXIT(et); + CURVNET_RESTORE(); + return (ret); +} + +/* + * Translate a FreeBSD interface name to a Linux interface name, + * and return the number of bytes copied to lxname, 0 if interface + * not found, -1 on error. + */ +struct ifname_bsd_to_linux_ifp_cb_s { + struct ifnet *ifp; + int ethno; + char *lxname; + size_t len; +}; + +static int +ifname_bsd_to_linux_ifp_cb(if_t ifp, void *arg) +{ + struct ifname_bsd_to_linux_ifp_cb_s *cbs = arg; + + if (ifp == cbs->ifp) + return (snprintf(cbs->lxname, cbs->len, "eth%d", cbs->ethno)); + if (IFP_IS_ETH(ifp)) + cbs->ethno++; + return (0); +} + +int +ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len) +{ + struct ifname_bsd_to_linux_ifp_cb_s arg = { + .ifp = ifp, + .ethno = 0, + .lxname = lxname, + .len = len, + }; + + NET_EPOCH_ASSERT(); + + /* + * Linux loopback interface name is lo (not lo0), + * we translate lo to lo0, loX to loX. + */ + if (IFP_IS_LOOP(ifp) && strncmp(if_name(ifp), "lo0", IFNAMSIZ) == 0) + return (strlcpy(lxname, "lo", len)); + + /* Short-circuit non ethernet interfaces. */ + if (!IFP_IS_ETH(ifp) || linux_use_real_ifname(ifp)) + return (strlcpy(lxname, if_name(ifp), len)); + + /* Determine the (relative) unit number for ethernet interfaces. */ + return (if_foreach(ifname_bsd_to_linux_ifp_cb, &arg)); +} + +/* + * 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 ifname_linux_to_ifp_cb_s { + bool is_lo; + bool is_eth; + int ethno; + int unit; + const char *lxname; + if_t ifp; +}; + +static int +ifname_linux_to_ifp_cb(if_t ifp, void *arg) +{ + struct ifname_linux_to_ifp_cb_s *cbs = arg; + + NET_EPOCH_ASSERT(); + + /* + * 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(if_name(ifp), cbs->lxname, LINUX_IFNAMSIZ) == 0) + goto out; + if (cbs->is_eth && IFP_IS_ETH(ifp) && cbs->unit == cbs->ethno) + goto out; + if (cbs->is_lo && IFP_IS_LOOP(ifp)) + goto out; + if (IFP_IS_ETH(ifp)) + cbs->ethno++; + return (0); + +out: + cbs->ifp = ifp; + return (1); +} + +struct ifnet * +ifname_linux_to_ifp(struct thread *td, const char *lxname) +{ + struct ifname_linux_to_ifp_cb_s arg = { + .ethno = 0, + .lxname = lxname, + .ifp = NULL, + }; + int len; + char *ep; + + NET_EPOCH_ASSERT(); + + 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), + * we translate lo to lo0, loX to loX. + */ + arg.is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0); + arg.unit = (int)strtoul(lxname + len, &ep, 10); + if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) && + arg.is_lo == 0) + return (NULL); + arg.is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0); + + if_foreach(ifname_linux_to_ifp_cb, &arg); + return (arg.ifp); +} + +int +ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) +{ + struct epoch_tracker et; + struct ifnet *ifp; + + CURVNET_SET(TD_TO_VNET(td)); + NET_EPOCH_ENTER(et); + ifp = ifname_linux_to_ifp(td, lxname); + if (ifp != NULL && bsdname != NULL) + strlcpy(bsdname, if_name(ifp), IFNAMSIZ); + NET_EPOCH_EXIT(et); + CURVNET_RESTORE(); + return (ifp != NULL ? 0 : EINVAL); +} + +unsigned short +linux_ifflags(struct ifnet *ifp) +{ + unsigned short flags; + + NET_EPOCH_ASSERT(); + + flags = if_getflags(ifp) | if_getdrvflags(ifp); + return (bsd_to_linux_ifflags(flags)); +} + +unsigned short +bsd_to_linux_ifflags(int fl) +{ + unsigned short 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; + return (flags); +} + +static u_int +linux_ifhwaddr_cb(void *arg, struct ifaddr *ifa, u_int count) +{ + struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr; + struct l_sockaddr *lsa = arg; + + if (count > 0) + return (0); + if (sdl->sdl_type != IFT_ETHER) + return (0); + bzero(lsa, sizeof(*lsa)); + lsa->sa_family = LINUX_ARPHRD_ETHER; + bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN); + return (1); +} + +int +linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa) +{ + + NET_EPOCH_ASSERT(); + + if (IFP_IS_LOOP(ifp)) { + bzero(lsa, sizeof(*lsa)); + lsa->sa_family = LINUX_ARPHRD_LOOPBACK; + return (0); + } + if (!IFP_IS_ETH(ifp)) + return (ENOENT); + if (if_foreach_addr_type(ifp, AF_LINK, linux_ifhwaddr_cb, lsa) > 0) + return (0); + return (ENOENT); +} + +sa_family_t +linux_to_bsd_domain(sa_family_t 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); + case LINUX_AF_NETLINK: + return (AF_NETLINK); + } + return (AF_UNKNOWN); +} + +sa_family_t +bsd_to_linux_domain(sa_family_t 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); + case AF_NETLINK: + return (LINUX_AF_NETLINK); + } + return (AF_UNKNOWN); +} + +/* + * 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; + sa_family_t bdom; + + *lsa = NULL; + if (len < 2 || len > UCHAR_MAX) + return (EINVAL); + bdom = bsd_to_linux_domain(sa->sa_family); + if (bdom == AF_UNKNOWN) + return (EAFNOSUPPORT); + + kosa = malloc(len, M_LINUX, M_WAITOK); + bcopy(sa, kosa, len); + kosa->sa_family = bdom; + *lsa = kosa; + return (0); +} + +int +linux_to_bsd_sockaddr(const struct l_sockaddr * __capability 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 == AF_UNKNOWN) { + 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; + } + } + + if (bdom == AF_NETLINK) { + if (salen < sizeof(struct sockaddr_nl)) { + error = EINVAL; + goto out; + } + salen = sizeof(struct sockaddr_nl); + } + + 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); +} + +void +linux_to_bsd_poll_events(struct thread *td, int fd, short lev, + short *bev) +{ + struct file *fp; + int error; + short bits = 0; + + if (lev & LINUX_POLLIN) + bits |= POLLIN; + if (lev & LINUX_POLLPRI) + bits |= POLLPRI; + if (lev & LINUX_POLLOUT) + bits |= POLLOUT; + if (lev & LINUX_POLLERR) + bits |= POLLERR; + if (lev & LINUX_POLLHUP) + bits |= POLLHUP; + if (lev & LINUX_POLLNVAL) + bits |= POLLNVAL; + if (lev & LINUX_POLLRDNORM) + bits |= POLLRDNORM; + if (lev & LINUX_POLLRDBAND) + bits |= POLLRDBAND; + if (lev & LINUX_POLLWRBAND) + bits |= POLLWRBAND; + if (lev & LINUX_POLLWRNORM) + bits |= POLLWRNORM; + + if (lev & LINUX_POLLRDHUP) { + /* + * It seems that the Linux silencly ignores POLLRDHUP + * on non-socket file descriptors unlike FreeBSD, where + * events bits is more strictly checked (POLLSTANDARD). + */ + error = fget_unlocked(td, fd, &cap_no_rights, &fp); + if (error == 0) { + /* + * XXX. On FreeBSD POLLRDHUP applies only to + * stream sockets. + */ + if (fp->f_type == DTYPE_SOCKET) + bits |= POLLRDHUP; + fdrop(fp, td); + } + } + + if (lev & LINUX_POLLMSG) + LINUX_RATELIMIT_MSG_OPT1("unsupported POLLMSG, events(%d)", lev); + if (lev & LINUX_POLLREMOVE) + LINUX_RATELIMIT_MSG_OPT1("unsupported POLLREMOVE, events(%d)", lev); + + *bev = bits; +} + +void +bsd_to_linux_poll_events(short bev, short *lev) +{ + short bits = 0; + + if (bev & POLLIN) + bits |= LINUX_POLLIN; + if (bev & POLLPRI) + bits |= LINUX_POLLPRI; + if (bev & (POLLOUT | POLLWRNORM)) + /* + * POLLWRNORM is equal to POLLOUT on FreeBSD, + * but not on Linux + */ + bits |= LINUX_POLLOUT; + if (bev & POLLERR) + bits |= LINUX_POLLERR; + if (bev & POLLHUP) + bits |= LINUX_POLLHUP; + if (bev & POLLNVAL) + bits |= LINUX_POLLNVAL; + if (bev & POLLRDNORM) + bits |= LINUX_POLLRDNORM; + if (bev & POLLRDBAND) + bits |= LINUX_POLLRDBAND; + if (bev & POLLWRBAND) + bits |= LINUX_POLLWRBAND; + if (bev & POLLRDHUP) + bits |= LINUX_POLLRDHUP; + + *lev = bits; +} + +bool +linux_use_real_ifname(const struct ifnet *ifp) +{ + + return (use_real_ifnames); +} diff --git a/sys/compat/linux/linux.h b/sys/compat/linux/linux.h index 5a0d6e0b68c5..e3a5e895e2af 100644 --- a/sys/compat/linux/linux.h +++ b/sys/compat/linux/linux.h @@ -1,373 +1,405 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2015 Dmitry Chagin - * - * 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. - */ - -#ifndef _LINUX_MI_H_ -#define _LINUX_MI_H_ - -/* - * Machine independent set of types for the Linux types. - */ -typedef uint32_t l_dev_t; - -/* - * Linux dev_t conversion routines. - * - * As of version 2.6.0 of the Linux kernel, dev_t is a 32-bit quantity - * with 12 bits set asaid for the major number and 20 for the minor number. - * The in-kernel dev_t encoded as MMMmmmmm, where M is a hex digit of the - * major number and m is a hex digit of the minor number. - * The user-space dev_t encoded as mmmM MMmm, where M and m is the major - * and minor numbers accordingly. This is downward compatible with legacy - * systems where dev_t is 16 bits wide, encoded as MMmm. - * In glibc dev_t is a 64-bit quantity, with 32-bit major and minor numbers, - * encoded as MMMM Mmmm mmmM MMmm. This is downward compatible with the Linux - * kernel and with legacy systems where dev_t is 16 bits wide. - * - * In the FreeBSD dev_t is a 64-bit quantity. The major and minor numbers - * are encoded as MMMmmmMm, therefore conversion of the device numbers between - * Linux user-space and FreeBSD kernel required. - */ -static __inline l_dev_t -linux_encode_dev(int _major, int _minor) -{ - - return ((_minor & 0xff) | ((_major & 0xfff) << 8) | - (((_minor & ~0xff) << 12) & 0xfff00000)); -} - -static __inline l_dev_t -linux_new_encode_dev(dev_t _dev) -{ - - return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev))); -} - -static __inline int -linux_encode_major(dev_t _dev) -{ - - return (_dev == NODEV ? 0 : major(_dev) & 0xfff); -} - -static __inline int -linux_encode_minor(dev_t _dev) -{ - - return (_dev == NODEV ? 0 : minor(_dev) & 0xfffff); -} - -static __inline int -linux_decode_major(l_dev_t _dev) -{ - - return ((_dev & 0xfff00) >> 8); -} - -static __inline int -linux_decode_minor(l_dev_t _dev) -{ - - return ((_dev & 0xff) | ((_dev & 0xfff00000) >> 12)); -} - -static __inline dev_t -linux_decode_dev(l_dev_t _dev) -{ - - return (makedev(linux_decode_major(_dev), linux_decode_minor(_dev))); -} - -/* - * Private Brandinfo flags - */ -#define LINUX_BI_FUTEX_REQUEUE 0x01000000 - -/* - * poll() - */ -#define LINUX_POLLIN 0x0001 -#define LINUX_POLLPRI 0x0002 -#define LINUX_POLLOUT 0x0004 -#define LINUX_POLLERR 0x0008 -#define LINUX_POLLHUP 0x0010 -#define LINUX_POLLNVAL 0x0020 -#define LINUX_POLLRDNORM 0x0040 -#define LINUX_POLLRDBAND 0x0080 -#define LINUX_POLLWRNORM 0x0100 -#define LINUX_POLLWRBAND 0x0200 -#define LINUX_POLLMSG 0x0400 -#define LINUX_POLLREMOVE 0x1000 -#define LINUX_POLLRDHUP 0x2000 - -#define LINUX_IFHWADDRLEN 6 -#define LINUX_IFNAMSIZ 16 - -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 -#define LINUX_AF_NETLINK 16 - -#define LINUX_NETLINK_ROUTE 0 -#define LINUX_NETLINK_SOCK_DIAG 4 -#define LINUX_NETLINK_NFLOG 5 -#define LINUX_NETLINK_SELINUX 7 -#define LINUX_NETLINK_AUDIT 9 -#define LINUX_NETLINK_FIB_LOOKUP 10 -#define LINUX_NETLINK_NETFILTER 12 -#define LINUX_NETLINK_KOBJECT_UEVENT 15 - -/* - * 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) (1ULL & ((set).__mask >> _SIG_IDX(sig))) -#define LINUX_SIGADDSET(set, sig) (set).__mask |= 1ULL << _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); - -/* sigprocmask actions */ -#define LINUX_SIG_BLOCK 0 -#define LINUX_SIG_UNBLOCK 1 -#define LINUX_SIG_SETMASK 2 - -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); - -/* - * 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 bsd_to_linux_bits(_val, _bmap, _noval) \ - bsd_to_linux_bits_((_val), (_bmap), nitems((_bmap)), (_noval)) -#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) - -int bsd_to_linux_errno(int error); -void linux_check_errtbl(void); - -#define STATX_BASIC_STATS 0x07ff -#define STATX_BTIME 0x0800 -#define STATX_ALL 0x0fff - -#define STATX_ATTR_COMPRESSED 0x0004 -#define STATX_ATTR_IMMUTABLE 0x0010 -#define STATX_ATTR_APPEND 0x0020 -#define STATX_ATTR_NODUMP 0x0040 -#define STATX_ATTR_ENCRYPTED 0x0800 -#define STATX_ATTR_AUTOMOUNT 0x1000 - -struct l_statx_timestamp { - int64_t tv_sec; - int32_t tv_nsec; - int32_t __spare0; -}; - -struct l_statx { - uint32_t stx_mask; - uint32_t stx_blksize; - uint64_t stx_attributes; - uint32_t stx_nlink; - uint32_t stx_uid; - uint32_t stx_gid; - uint16_t stx_mode; - uint16_t __spare0[1]; - uint64_t stx_ino; - uint64_t stx_size; - uint64_t stx_blocks; - uint64_t stx_attributes_mask; - struct l_statx_timestamp stx_atime; - struct l_statx_timestamp stx_btime; - struct l_statx_timestamp stx_ctime; - struct l_statx_timestamp stx_mtime; - uint32_t stx_rdev_major; - uint32_t stx_rdev_minor; - uint32_t stx_dev_major; - uint32_t stx_dev_minor; - uint64_t stx_mnt_id; - uint64_t __spare2[13]; -}; - -/* - * statfs f_flags - */ -#define LINUX_ST_RDONLY 0x0001 -#define LINUX_ST_NOSUID 0x0002 -#define LINUX_ST_NODEV 0x0004 /* No native analogue */ -#define LINUX_ST_NOEXEC 0x0008 -#define LINUX_ST_SYNCHRONOUS 0x0010 -#define LINUX_ST_VALID 0x0020 -#define LINUX_ST_MANDLOCK 0x0040 /* No native analogue */ -#define LINUX_ST_NOATIME 0x0400 -#define LINUX_ST_NODIRATIME 0x0800 /* No native analogue */ -#define LINUX_ST_RELATIME 0x1000 /* No native analogue */ -#define LINUX_ST_NOSYMFOLLOW 0x2000 - -#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff)) - -#ifdef KTRACE -#define linux_ktrsigset(s, l) \ - ktrstruct("l_sigset_t", (s), l) -#endif - -/* - * Criteria for interface name translation - */ -#define IFP_IS_ETH(ifp) (if_gettype(ifp) == IFT_ETHER) -#define IFP_IS_LOOP(ifp) (if_gettype(ifp) == IFT_LOOP) - -struct ifnet; - -bool linux_use_real_ifname(const struct ifnet *); - -void linux_netlink_register(void); -void linux_netlink_deregister(void); - -#endif /* _LINUX_MI_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2015 Dmitry Chagin + * + * 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. + */ + +#ifndef _LINUX_MI_H_ +#define _LINUX_MI_H_ + +/* + * Machine independent set of types for the Linux types. + */ +typedef uint32_t l_dev_t; + +/* + * Linux dev_t conversion routines. + * + * As of version 2.6.0 of the Linux kernel, dev_t is a 32-bit quantity + * with 12 bits set asaid for the major number and 20 for the minor number. + * The in-kernel dev_t encoded as MMMmmmmm, where M is a hex digit of the + * major number and m is a hex digit of the minor number. + * The user-space dev_t encoded as mmmM MMmm, where M and m is the major + * and minor numbers accordingly. This is downward compatible with legacy + * systems where dev_t is 16 bits wide, encoded as MMmm. + * In glibc dev_t is a 64-bit quantity, with 32-bit major and minor numbers, + * encoded as MMMM Mmmm mmmM MMmm. This is downward compatible with the Linux + * kernel and with legacy systems where dev_t is 16 bits wide. + * + * In the FreeBSD dev_t is a 64-bit quantity. The major and minor numbers + * are encoded as MMMmmmMm, therefore conversion of the device numbers between + * Linux user-space and FreeBSD kernel required. + */ +static __inline l_dev_t +linux_encode_dev(int _major, int _minor) +{ + + return ((_minor & 0xff) | ((_major & 0xfff) << 8) | + (((_minor & ~0xff) << 12) & 0xfff00000)); +} + +static __inline l_dev_t +linux_new_encode_dev(dev_t _dev) +{ + + return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev))); +} + +static __inline int +linux_encode_major(dev_t _dev) +{ + + return (_dev == NODEV ? 0 : major(_dev) & 0xfff); +} + +static __inline int +linux_encode_minor(dev_t _dev) +{ + + return (_dev == NODEV ? 0 : minor(_dev) & 0xfffff); +} + +static __inline int +linux_decode_major(l_dev_t _dev) +{ + + return ((_dev & 0xfff00) >> 8); +} + +static __inline int +linux_decode_minor(l_dev_t _dev) +{ + + return ((_dev & 0xff) | ((_dev & 0xfff00000) >> 12)); +} + +static __inline dev_t +linux_decode_dev(l_dev_t _dev) +{ + + return (makedev(linux_decode_major(_dev), linux_decode_minor(_dev))); +} + +/* + * Private Brandinfo flags + */ +#define LINUX_BI_FUTEX_REQUEUE 0x01000000 + +/* + * poll() + */ +#define LINUX_POLLIN 0x0001 +#define LINUX_POLLPRI 0x0002 +#define LINUX_POLLOUT 0x0004 +#define LINUX_POLLERR 0x0008 +#define LINUX_POLLHUP 0x0010 +#define LINUX_POLLNVAL 0x0020 +#define LINUX_POLLRDNORM 0x0040 +#define LINUX_POLLRDBAND 0x0080 +#define LINUX_POLLWRNORM 0x0100 +#define LINUX_POLLWRBAND 0x0200 +#define LINUX_POLLMSG 0x0400 +#define LINUX_POLLREMOVE 0x1000 +#define LINUX_POLLRDHUP 0x2000 + +#define LINUX_IFHWADDRLEN 6 +#define LINUX_IFNAMSIZ 16 + +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 +#define LINUX_AF_NETLINK 16 + +#define LINUX_NETLINK_ROUTE 0 +#define LINUX_NETLINK_SOCK_DIAG 4 +#define LINUX_NETLINK_NFLOG 5 +#define LINUX_NETLINK_SELINUX 7 +#define LINUX_NETLINK_AUDIT 9 +#define LINUX_NETLINK_FIB_LOOKUP 10 +#define LINUX_NETLINK_NETFILTER 12 +#define LINUX_NETLINK_KOBJECT_UEVENT 15 + +/* + * 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) (1ULL & ((set).__mask >> _SIG_IDX(sig))) +#define LINUX_SIGADDSET(set, sig) (set).__mask |= 1ULL << _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); + +/* sigprocmask actions */ +#define LINUX_SIG_BLOCK 0 +#define LINUX_SIG_UNBLOCK 1 +#define LINUX_SIG_SETMASK 2 + +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); + +/* + * 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 bsd_to_linux_bits(_val, _bmap, _noval) \ + bsd_to_linux_bits_((_val), (_bmap), nitems((_bmap)), (_noval)) +#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) + +int bsd_to_linux_errno(int error); +void linux_check_errtbl(void); + +#define STATX_BASIC_STATS 0x07ff +#define STATX_BTIME 0x0800 +#define STATX_ALL 0x0fff + +#define STATX_ATTR_COMPRESSED 0x0004 +#define STATX_ATTR_IMMUTABLE 0x0010 +#define STATX_ATTR_APPEND 0x0020 +#define STATX_ATTR_NODUMP 0x0040 +#define STATX_ATTR_ENCRYPTED 0x0800 +#define STATX_ATTR_AUTOMOUNT 0x1000 + +struct l_statx_timestamp { + int64_t tv_sec; + int32_t tv_nsec; + int32_t __spare0; +}; + +struct l_statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t __spare0[1]; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct l_statx_timestamp stx_atime; + struct l_statx_timestamp stx_btime; + struct l_statx_timestamp stx_ctime; + struct l_statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t stx_mnt_id; + uint64_t __spare2[13]; +}; + +/* + * statfs f_flags + */ +#define LINUX_ST_RDONLY 0x0001 +#define LINUX_ST_NOSUID 0x0002 +#define LINUX_ST_NODEV 0x0004 /* No native analogue */ +#define LINUX_ST_NOEXEC 0x0008 +#define LINUX_ST_SYNCHRONOUS 0x0010 +#define LINUX_ST_VALID 0x0020 +#define LINUX_ST_MANDLOCK 0x0040 /* No native analogue */ +#define LINUX_ST_NOATIME 0x0400 +#define LINUX_ST_NODIRATIME 0x0800 /* No native analogue */ +#define LINUX_ST_RELATIME 0x1000 /* No native analogue */ +#define LINUX_ST_NOSYMFOLLOW 0x2000 + +#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff)) + +#ifdef KTRACE +#define linux_ktrsigset(s, l) \ + ktrstruct("l_sigset_t", (s), l) +#endif + +/* + * Criteria for interface name translation + */ +#define IFP_IS_ETH(ifp) (if_gettype(ifp) == IFT_ETHER) +#define IFP_IS_LOOP(ifp) (if_gettype(ifp) == IFT_LOOP) + +struct ifnet; + +bool linux_use_real_ifname(const struct ifnet *); + +void linux_netlink_register(void); +void linux_netlink_deregister(void); + +/* + * Versions of __USER_CAP and variants that are no-ops when compiling a + * Linuxulator for native (ish) CheriABI userspace, allowing unconditional use + * throughout. + */ +#if defined(COMPAT_LINUX32) || defined(COMPAT_LINUX64) +#define LINUX_USER_CAP_UNBOUND(ptr) __USER_CAP_UNBOUND(ptr) +#define LINUX_USER_CODE_CAP(ptr) __USER_CODE_CAP(ptr) +#define LINUX_USER_CAP(ptr, len) __USER_CAP(ptr, len) +#define LINUX_USER_CAP_ADDR(ptr) __USER_CAP_ADDR(ptr) +#define LINUX_USER_CAP_ARRAY(objp, cnt) __USER_CAP_ARRAY(objp, cnt) +#define LINUX_USER_CAP_OBJ(objp) __USER_CAP_OBJ(objp) +#define LINUX_USER_CAP_STR(strp) __USER_CAP_STR(strp) +#define LINUX_USER_CAP_PATH(path) __USER_CAP_PATH(path) +#else +#define LINUX_USER_CAP_UNBOUND(ptr) ((void * __capability)(uintcap_t)(ptr)) +#define LINUX_USER_CODE_CAP(ptr) ((void * __capability)(uintcap_t)(ptr)) +#define LINUX_USER_CAP(ptr, len) ((void * __capability)(uintcap_t)(ptr)) +#define LINUX_USER_CAP_ADDR(ptr) ((void * __capability)(uintcap_t)(ptr)) +#define LINUX_USER_CAP_ARRAY(objp, cnt) ((void * __capability)(uintcap_t)(objp)) +#define LINUX_USER_CAP_OBJ(objp) ((void * __capability)(uintcap_t)(objp)) +#define LINUX_USER_CAP_STR(strp) ((void * __capability)(uintcap_t)(strp)) +#define LINUX_USER_CAP_PATH(path) ((void * __capability)(uintcap_t)(path)) +#endif +#if defined(COMPAT_LINUX32) || defined(COMPAT_LINUX64) +#define __linuxcap +typedef uintptr_t linuxcap_t; +#else +#define __linuxcap __capability +typedef uintcap_t linuxcap_t; +#endif + +#endif /* _LINUX_MI_H_ */ diff --git a/sys/compat/linux/linux_common.c b/sys/compat/linux/linux_common.c index e22e29ff2b24..72a20c7e207e 100644 --- a/sys/compat/linux/linux_common.c +++ b/sys/compat/linux/linux_common.c @@ -1,82 +1,82 @@ -/*- - * Copyright (c) 2014 Vassilis Laganakos - * 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 -#include -#include -#include -#include -#include - -#include -#include -#include - -SET_DECLARE(linux_device_handler_set, struct linux_device_handler); - -TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers = - TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers); -struct sx linux_ioctl_sx; -SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers"); - -static int -linux_common_modevent(module_t mod, int type, void *data) -{ - struct linux_device_handler **ldhp; - - switch(type) { - case MOD_LOAD: -#ifdef INVARIANTS - linux_check_errtbl(); -#endif - linux_dev_shm_create(); - linux_osd_jail_register(); - SET_FOREACH(ldhp, linux_device_handler_set) - linux_device_register_handler(*ldhp); - linux_netlink_register(); - break; - case MOD_UNLOAD: - linux_dev_shm_destroy(); - linux_osd_jail_deregister(); - SET_FOREACH(ldhp, linux_device_handler_set) - linux_device_unregister_handler(*ldhp); - linux_netlink_deregister(); - break; - default: - return (EOPNOTSUPP); - } - return (0); -} - -static moduledata_t linux_common_mod = { - "linux_common", - linux_common_modevent, - 0 -}; - -DECLARE_MODULE(linux_common, linux_common_mod, SI_SUB_EXEC, SI_ORDER_ANY); -MODULE_VERSION(linux_common, 1); -MODULE_DEPEND(linux_common, netlink, 1, 1, 1); +/*- + * Copyright (c) 2014 Vassilis Laganakos + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +SET_DECLARE(linux_device_handler_set, struct linux_device_handler); + +TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers = + TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers); +struct sx linux_ioctl_sx; +SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers"); + +static int +linux_common_modevent(module_t mod, int type, void *data) +{ + struct linux_device_handler **ldhp; + + switch(type) { + case MOD_LOAD: +#ifdef INVARIANTS + linux_check_errtbl(); +#endif + linux_dev_shm_create(); + linux_osd_jail_register(); + SET_FOREACH(ldhp, linux_device_handler_set) + linux_device_register_handler(*ldhp); + linux_netlink_register(); + break; + case MOD_UNLOAD: + linux_dev_shm_destroy(); + linux_osd_jail_deregister(); + SET_FOREACH(ldhp, linux_device_handler_set) + linux_device_unregister_handler(*ldhp); + linux_netlink_deregister(); + break; + default: + return (EOPNOTSUPP); + } + return (0); +} + +static moduledata_t linux_common_mod = { + "linux_common", + linux_common_modevent, + 0 +}; + +DECLARE_MODULE(linux_common, linux_common_mod, SI_SUB_EXEC, SI_ORDER_ANY); +MODULE_VERSION(linux_common, 1); +MODULE_DEPEND(linux_common, netlink, 1, 1, 1); diff --git a/sys/compat/linux/linux_common.h b/sys/compat/linux/linux_common.h index 97f5a259f300..2170786e6e33 100644 --- a/sys/compat/linux/linux_common.h +++ b/sys/compat/linux/linux_common.h @@ -1,52 +1,52 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2019 Dmitry Chagin - * - * 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. - */ - -#ifndef _LINUX_COMMON_H_ -#define _LINUX_COMMON_H_ - -int ifname_bsd_to_linux_ifp(struct ifnet *, char *, size_t); -int ifname_bsd_to_linux_idx(u_int, char *, size_t); -int ifname_bsd_to_linux_name(const char *, char *, size_t); -struct ifnet *ifname_linux_to_ifp(struct thread *, const char *); -int ifname_linux_to_bsd(struct thread *, const char *, char *); - -unsigned short linux_ifflags(struct ifnet *); -int linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa); - -unsigned short bsd_to_linux_ifflags(int); -sa_family_t linux_to_bsd_domain(sa_family_t domain); -sa_family_t bsd_to_linux_domain(sa_family_t domain); -#define AF_UNKNOWN UINT8_MAX -int bsd_to_linux_sockaddr(const struct sockaddr *sa, - struct l_sockaddr **lsa, socklen_t len); -int linux_to_bsd_sockaddr(const struct l_sockaddr *lsa, - struct sockaddr **sap, socklen_t *len); -void linux_to_bsd_poll_events(struct thread *td, int fd, - short lev, short *bev); -void bsd_to_linux_poll_events(short bev, short *lev); - -#endif /* _LINUX_COMMON_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Dmitry Chagin + * + * 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. + */ + +#ifndef _LINUX_COMMON_H_ +#define _LINUX_COMMON_H_ + +int ifname_bsd_to_linux_ifp(struct ifnet *, char *, size_t); +int ifname_bsd_to_linux_idx(u_int, char *, size_t); +int ifname_bsd_to_linux_name(const char *, char *, size_t); +struct ifnet *ifname_linux_to_ifp(struct thread *, const char *); +int ifname_linux_to_bsd(struct thread *, const char *, char *); + +unsigned short linux_ifflags(struct ifnet *); +int linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa); + +unsigned short bsd_to_linux_ifflags(int); +sa_family_t linux_to_bsd_domain(sa_family_t domain); +sa_family_t bsd_to_linux_domain(sa_family_t domain); +#define AF_UNKNOWN UINT8_MAX +int bsd_to_linux_sockaddr(const struct sockaddr *sa, + struct l_sockaddr **lsa, socklen_t len); +int linux_to_bsd_sockaddr(const struct l_sockaddr * __capability lsa, + struct sockaddr **sap, socklen_t *len); +void linux_to_bsd_poll_events(struct thread *td, int fd, + short lev, short *bev); +void bsd_to_linux_poll_events(short bev, short *lev); + +#endif /* _LINUX_COMMON_H_ */ diff --git a/sys/compat/linux/linux_dtrace.h b/sys/compat/linux/linux_dtrace.h index 2e4c1315aa3d..eb3935c0b2af 100644 --- a/sys/compat/linux/linux_dtrace.h +++ b/sys/compat/linux/linux_dtrace.h @@ -1,90 +1,90 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2008-2012 Alexander Leidinger - * 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 - * in this position and unchanged. - * 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 ``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 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. - */ - -#ifndef _LINUX_DTRACE_H_ -#define _LINUX_DTRACE_H_ - -/** - * DTrace support macros for the linuxulator. - * - * Some wrapper macros to make it more easy to handle the linuxulator - * providers and to allow to make the name depend upon the bitsize. - * - * Basically this is the same as the normal SDT macros in sys/sdt.h. The - * difference is that the provider name is automatically inserted, and - * we do not use a different name for the probe-description. - */ - -#define LIN_SDT_PROVIDER_DEFINE(x) SDT_PROVIDER_DEFINE(x) -#define LIN_SDT_PROVIDER_DECLARE(x) SDT_PROVIDER_DECLARE(x) - -#define _LIN_SDT_PROBE_DECLARE(a, b, c, d) SDT_PROBE_DECLARE(a, b, c, d) -#define LIN_SDT_PROBE_DECLARE(a, b, c) _LIN_SDT_PROBE_DECLARE( \ - LINUX_DTRACE, a, b, c) - -#define _LIN_SDT_PROBE_DEFINE0(a, b, c, d) SDT_PROBE_DEFINE(a, \ - b, c, d) -#define LIN_SDT_PROBE_DEFINE0(a, b, c) _LIN_SDT_PROBE_DEFINE0(\ - LINUX_DTRACE, a, b, c) -#define _LIN_SDT_PROBE_DEFINE1(a, b, c, d, e) SDT_PROBE_DEFINE1(a, \ - b, c, d, e) -#define LIN_SDT_PROBE_DEFINE1(a, b, c, d) _LIN_SDT_PROBE_DEFINE1(\ - LINUX_DTRACE, a, b, c, d) -#define _LIN_SDT_PROBE_DEFINE2(a, b, c, d, e, f) SDT_PROBE_DEFINE2(a, \ - b, c, d, e, f) -#define LIN_SDT_PROBE_DEFINE2(a, b, c, d, e) _LIN_SDT_PROBE_DEFINE2(\ - LINUX_DTRACE, a, b, c, d, e) -#define _LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f, g) SDT_PROBE_DEFINE3(a, \ - b, c, d, e, f, g) -#define LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f) _LIN_SDT_PROBE_DEFINE3(\ - LINUX_DTRACE, a, b, c, d, e, f) -#define _LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g, h) SDT_PROBE_DEFINE4(a, \ - b, c, d, e, f, g, h) -#define LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g) _LIN_SDT_PROBE_DEFINE4(\ - LINUX_DTRACE, a, b, c, d, e, f, g) -#define _LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i) \ - SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i) -#define LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE_DEFINE5(\ - LINUX_DTRACE, a, b, c, d, e, f, g, h) - -#define LIN_SDT_PROBE0(a, b, c) SDT_PROBE0(LINUX_DTRACE, a, b, \ - c) -#define LIN_SDT_PROBE1(a, b, c, d) SDT_PROBE1(LINUX_DTRACE, a, b, \ - c, d) -#define LIN_SDT_PROBE2(a, b, c, d, e) SDT_PROBE2(LINUX_DTRACE, a, b, \ - c, d, e) -#define LIN_SDT_PROBE3(a, b, c, d, e, f) SDT_PROBE3(LINUX_DTRACE, a, b, \ - c, d, e, f) -#define LIN_SDT_PROBE4(a, b, c, d, e, f, g) SDT_PROBE4(LINUX_DTRACE, a, b, \ - c, d, e, f, g) -#define _LIN_SDT_PROBE5(a, b, c, d, e, f, g, h, i) SDT_PROBE5(a, b, c, d, \ - e, f, g, h, i) -#define LIN_SDT_PROBE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE5(LINUX_DTRACE, \ - a, b, c, d, e, f, g, h) - -#endif /* _LINUX_DTRACE_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2008-2012 Alexander Leidinger + * 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 + * in this position and unchanged. + * 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 ``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 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. + */ + +#ifndef _LINUX_DTRACE_H_ +#define _LINUX_DTRACE_H_ + +/** + * DTrace support macros for the linuxulator. + * + * Some wrapper macros to make it more easy to handle the linuxulator + * providers and to allow to make the name depend upon the bitsize. + * + * Basically this is the same as the normal SDT macros in sys/sdt.h. The + * difference is that the provider name is automatically inserted, and + * we do not use a different name for the probe-description. + */ + +#define LIN_SDT_PROVIDER_DEFINE(x) SDT_PROVIDER_DEFINE(x) +#define LIN_SDT_PROVIDER_DECLARE(x) SDT_PROVIDER_DECLARE(x) + +#define _LIN_SDT_PROBE_DECLARE(a, b, c, d) SDT_PROBE_DECLARE(a, b, c, d) +#define LIN_SDT_PROBE_DECLARE(a, b, c) _LIN_SDT_PROBE_DECLARE( \ + LINUX_DTRACE, a, b, c) + +#define _LIN_SDT_PROBE_DEFINE0(a, b, c, d) SDT_PROBE_DEFINE(a, \ + b, c, d) +#define LIN_SDT_PROBE_DEFINE0(a, b, c) _LIN_SDT_PROBE_DEFINE0(\ + LINUX_DTRACE, a, b, c) +#define _LIN_SDT_PROBE_DEFINE1(a, b, c, d, e) SDT_PROBE_DEFINE1(a, \ + b, c, d, e) +#define LIN_SDT_PROBE_DEFINE1(a, b, c, d) _LIN_SDT_PROBE_DEFINE1(\ + LINUX_DTRACE, a, b, c, d) +#define _LIN_SDT_PROBE_DEFINE2(a, b, c, d, e, f) SDT_PROBE_DEFINE2(a, \ + b, c, d, e, f) +#define LIN_SDT_PROBE_DEFINE2(a, b, c, d, e) _LIN_SDT_PROBE_DEFINE2(\ + LINUX_DTRACE, a, b, c, d, e) +#define _LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f, g) SDT_PROBE_DEFINE3(a, \ + b, c, d, e, f, g) +#define LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f) _LIN_SDT_PROBE_DEFINE3(\ + LINUX_DTRACE, a, b, c, d, e, f) +#define _LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g, h) SDT_PROBE_DEFINE4(a, \ + b, c, d, e, f, g, h) +#define LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g) _LIN_SDT_PROBE_DEFINE4(\ + LINUX_DTRACE, a, b, c, d, e, f, g) +#define _LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i) \ + SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i) +#define LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE_DEFINE5(\ + LINUX_DTRACE, a, b, c, d, e, f, g, h) + +#define LIN_SDT_PROBE0(a, b, c) SDT_PROBE0(LINUX_DTRACE, a, b, \ + c) +#define LIN_SDT_PROBE1(a, b, c, d) SDT_PROBE1(LINUX_DTRACE, a, b, \ + c, d) +#define LIN_SDT_PROBE2(a, b, c, d, e) SDT_PROBE2(LINUX_DTRACE, a, b, \ + c, d, e) +#define LIN_SDT_PROBE3(a, b, c, d, e, f) SDT_PROBE3(LINUX_DTRACE, a, b, \ + c, d, e, f) +#define LIN_SDT_PROBE4(a, b, c, d, e, f, g) SDT_PROBE4(LINUX_DTRACE, a, b, \ + c, d, e, f, g) +#define _LIN_SDT_PROBE5(a, b, c, d, e, f, g, h, i) SDT_PROBE5(a, b, c, d, \ + e, f, g, h, i) +#define LIN_SDT_PROBE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE5(LINUX_DTRACE, \ + a, b, c, d, e, f, g, h) + +#endif /* _LINUX_DTRACE_H_ */ diff --git a/sys/compat/linux/linux_dummy.c b/sys/compat/linux/linux_dummy.c index 35d6debe0da9..e88b652e60a2 100644 --- a/sys/compat/linux/linux_dummy.c +++ b/sys/compat/linux/linux_dummy.c @@ -1,164 +1,164 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2013 Dmitry Chagin - * - * 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 -#include -#include -#include - -/* - * Including linux vs linux32 here is arbitrary -- the syscall args structures - * (proto.h) are not dereferenced by the DUMMY stub implementations, and - * suitable for use by both native and compat32 entrypoints. - */ -#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(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(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(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(inotify_add_watch); -DUMMY(inotify_rm_watch); -/* Linux 2.6.16: */ -DUMMY(migrate_pages); -DUMMY(unshare); -/* Linux 2.6.17: */ -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(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.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.18: */ -DUMMY(io_pgetevents); -/* Linux 5.1: */ -DUMMY(pidfd_send_signal); -DUMMY(io_uring_setup); -DUMMY(io_uring_enter); -DUMMY(io_uring_register); -/* Linux 5.2: */ -DUMMY(open_tree); -DUMMY(move_mount); -DUMMY(fsopen); -DUMMY(fsconfig); -DUMMY(fsmount); -DUMMY(fspick); -/* Linux 5.3: */ -DUMMY(pidfd_open); -/* Linux 5.6: */ -DUMMY(openat2); -DUMMY(pidfd_getfd); -/* Linux 5.10: */ -DUMMY(process_madvise); -/* Linux 5.12: */ -DUMMY(mount_setattr); -/* Linux 5.13: */ -DUMMY(landlock_create_ruleset); -DUMMY(landlock_add_rule); -DUMMY(landlock_restrict_self); -/* Linux 5.14: */ -DUMMY(memfd_secret); -DUMMY(quotactl_fd); -/* Linux 5.15: */ -DUMMY(process_mrelease); -/* Linux 5.16: */ -DUMMY(futex_waitv); -DUMMY(set_mempolicy_home_node); -/* Linux 6.5: */ -DUMMY(cachestat); -/* Linux 6.6: */ -DUMMY(fchmodat2); +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2013 Dmitry Chagin + * + * 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 +#include +#include +#include + +/* + * Including linux vs linux32 here is arbitrary -- the syscall args structures + * (proto.h) are not dereferenced by the DUMMY stub implementations, and + * suitable for use by both native and compat32 entrypoints. + */ +#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(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(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(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(inotify_add_watch); +DUMMY(inotify_rm_watch); +/* Linux 2.6.16: */ +DUMMY(migrate_pages); +DUMMY(unshare); +/* Linux 2.6.17: */ +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(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.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.18: */ +DUMMY(io_pgetevents); +/* Linux 5.1: */ +DUMMY(pidfd_send_signal); +DUMMY(io_uring_setup); +DUMMY(io_uring_enter); +DUMMY(io_uring_register); +/* Linux 5.2: */ +DUMMY(open_tree); +DUMMY(move_mount); +DUMMY(fsopen); +DUMMY(fsconfig); +DUMMY(fsmount); +DUMMY(fspick); +/* Linux 5.3: */ +DUMMY(pidfd_open); +/* Linux 5.6: */ +DUMMY(openat2); +DUMMY(pidfd_getfd); +/* Linux 5.10: */ +DUMMY(process_madvise); +/* Linux 5.12: */ +DUMMY(mount_setattr); +/* Linux 5.13: */ +DUMMY(landlock_create_ruleset); +DUMMY(landlock_add_rule); +DUMMY(landlock_restrict_self); +/* Linux 5.14: */ +DUMMY(memfd_secret); +DUMMY(quotactl_fd); +/* Linux 5.15: */ +DUMMY(process_mrelease); +/* Linux 5.16: */ +DUMMY(futex_waitv); +DUMMY(set_mempolicy_home_node); +/* Linux 6.5: */ +DUMMY(cachestat); +/* Linux 6.6: */ +DUMMY(fchmodat2); diff --git a/sys/compat/linux/linux_elf.c b/sys/compat/linux/linux_elf.c index c9eb6aea8373..0ab312698137 100644 --- a/sys/compat/linux/linux_elf.c +++ b/sys/compat/linux/linux_elf.c @@ -1,545 +1,735 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2021 Edward Tomasz Napierala - * Copyright (c) 2018 Chuck Tuffli - * Copyright (c) 2017 Dell EMC - * Copyright (c) 2000 David O'Brien - * Copyright (c) 1995-1996 Søren Schmidt - * Copyright (c) 1996 Peter Wemm - * All rights reserved. - * - * This software was developed by the University of Cambridge Computer - * Laboratory as part of the CHERI for Hypervisors and Operating Systems - * (CHaOS) project, funded by EPSRC grant EP/V000292/1. - * - * 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 - * in this position and unchanged. - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef COMPAT_LINUX32 -#define linux_pt_regset linux_pt_regset32 -#define bsd_to_linux_regset bsd_to_linux_regset32 -#include -#else -#include -#endif -#include -#include -#include - -struct l_elf_siginfo { - l_int si_signo; - l_int si_code; - l_int si_errno; -}; - -typedef struct linux_pt_regset l_elf_gregset_t; - -struct linux_elf_prstatus { - struct l_elf_siginfo pr_info; - l_short pr_cursig; - l_ulong pr_sigpend; - l_ulong pr_sighold; - l_pid_t pr_pid; - l_pid_t pr_ppid; - l_pid_t pr_pgrp; - l_pid_t pr_sid; - l_timeval pr_utime; - l_timeval pr_stime; - l_timeval pr_cutime; - l_timeval pr_cstime; - l_elf_gregset_t pr_reg; - l_int pr_fpvalid; -}; - -#define LINUX_NT_AUXV 6 - -static void __linuxN(note_fpregset)(void *, struct sbuf *, size_t *); -static void __linuxN(note_prpsinfo)(void *, struct sbuf *, size_t *); -static void __linuxN(note_prstatus)(void *, struct sbuf *, size_t *); -static void __linuxN(note_threadmd)(void *, struct sbuf *, size_t *); -static void __linuxN(note_nt_auxv)(void *, struct sbuf *, size_t *); - -void -__linuxN(prepare_notes)(struct thread *td, struct note_info_list *list, - size_t *sizep) -{ - struct proc *p; - struct thread *thr; - size_t size; - - p = td->td_proc; - size = 0; - - /* - * To have the debugger select the right thread (LWP) as the initial - * thread, we dump the state of the thread passed to us in td first. - * This is the thread that causes the core dump and thus likely to - * be the right thread one wants to have selected in the debugger. - */ - thr = td; - while (thr != NULL) { - size += __elfN(register_note)(td, list, - NT_PRSTATUS, __linuxN(note_prstatus), thr); - size += __elfN(register_note)(td, list, - NT_PRPSINFO, __linuxN(note_prpsinfo), p); - size += __elfN(register_note)(td, list, - LINUX_NT_AUXV, __linuxN(note_nt_auxv), p); - size += __elfN(register_note)(td, list, - NT_FPREGSET, __linuxN(note_fpregset), thr); - size += __elfN(register_note)(td, list, - -1, __linuxN(note_threadmd), thr); - - thr = thr == td ? TAILQ_FIRST(&p->p_threads) : - TAILQ_NEXT(thr, td_plist); - if (thr == td) - thr = TAILQ_NEXT(thr, td_plist); - } - - *sizep = size; -} - -typedef struct linux_elf_prstatus linux_elf_prstatus_t; -#ifdef COMPAT_LINUX32 -typedef struct prpsinfo32 linux_elf_prpsinfo_t; -typedef struct fpreg32 linux_elf_prfpregset_t; -#else -typedef prpsinfo_t linux_elf_prpsinfo_t; -typedef prfpregset_t linux_elf_prfpregset_t; -#endif - -static void -__linuxN(note_prpsinfo)(void *arg, struct sbuf *sb, size_t *sizep) -{ - struct sbuf sbarg; - size_t len; - char *cp, *end; - struct proc *p; - linux_elf_prpsinfo_t *psinfo; - int error; - - p = arg; - if (sb != NULL) { - KASSERT(*sizep == sizeof(*psinfo), ("invalid size")); - psinfo = malloc(sizeof(*psinfo), M_TEMP, M_ZERO | M_WAITOK); - psinfo->pr_version = PRPSINFO_VERSION; - psinfo->pr_psinfosz = sizeof(linux_elf_prpsinfo_t); - strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname)); - PROC_LOCK(p); - if (p->p_args != NULL) { - len = sizeof(psinfo->pr_psargs) - 1; - if (len > p->p_args->ar_length) - len = p->p_args->ar_length; - memcpy(psinfo->pr_psargs, p->p_args->ar_args, len); - PROC_UNLOCK(p); - error = 0; - } else { - _PHOLD(p); - PROC_UNLOCK(p); - sbuf_new(&sbarg, psinfo->pr_psargs, - sizeof(psinfo->pr_psargs), SBUF_FIXEDLEN); - error = proc_getargv(curthread, p, &sbarg); - PRELE(p); - if (sbuf_finish(&sbarg) == 0) { - len = sbuf_len(&sbarg) - 1; - if (len > 0) - len--; - } else { - len = sizeof(psinfo->pr_psargs) - 1; - } - sbuf_delete(&sbarg); - } - if (error != 0 || len == 0 || (ssize_t)len == -1) - strlcpy(psinfo->pr_psargs, p->p_comm, - sizeof(psinfo->pr_psargs)); - else { - KASSERT(len < sizeof(psinfo->pr_psargs), - ("len is too long: %zu vs %zu", len, - sizeof(psinfo->pr_psargs))); - cp = psinfo->pr_psargs; - end = cp + len - 1; - for (;;) { - cp = memchr(cp, '\0', end - cp); - if (cp == NULL) - break; - *cp = ' '; - } - } - psinfo->pr_pid = p->p_pid; - sbuf_bcat(sb, psinfo, sizeof(*psinfo)); - free(psinfo, M_TEMP); - } - *sizep = sizeof(*psinfo); -} - -static void -__linuxN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep) -{ - struct thread *td; - linux_elf_prstatus_t *status; -#ifdef COMPAT_LINUX32 - struct reg32 pr_reg; -#else - struct reg pr_reg; -#endif - - td = arg; - if (sb != NULL) { - KASSERT(*sizep == sizeof(*status), ("invalid size")); - status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK); - - /* - * XXX: Some fields missing. - */ - status->pr_cursig = td->td_proc->p_sig; - status->pr_pid = td->td_tid; - -#ifdef COMPAT_LINUX32 - fill_regs32(td, &pr_reg); -#else - fill_regs(td, &pr_reg); -#endif - bsd_to_linux_regset(&pr_reg, &status->pr_reg); - sbuf_bcat(sb, status, sizeof(*status)); - free(status, M_TEMP); - } - *sizep = sizeof(*status); -} - -static void -__linuxN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep) -{ - struct thread *td; - linux_elf_prfpregset_t *fpregset; - - td = arg; - if (sb != NULL) { - KASSERT(*sizep == sizeof(*fpregset), ("invalid size")); - fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK); -#ifdef COMPAT_LINUX32 - fill_fpregs32(td, fpregset); -#else - fill_fpregs(td, fpregset); -#endif - sbuf_bcat(sb, fpregset, sizeof(*fpregset)); - free(fpregset, M_TEMP); - } - *sizep = sizeof(*fpregset); -} - -/* - * Allow for MD specific notes, as well as any MD - * specific preparations for writing MI notes. - */ -static void -__linuxN(note_threadmd)(void *arg, struct sbuf *sb, size_t *sizep) -{ - struct thread *td; - void *buf; - size_t size; - - td = arg; - size = *sizep; - if (size != 0 && sb != NULL) - buf = malloc(size, M_TEMP, M_ZERO | M_WAITOK); - else - buf = NULL; - size = 0; - __elfN(dump_thread)(td, buf, &size); - KASSERT(sb == NULL || *sizep == size, ("invalid size")); - if (size != 0 && sb != NULL) - sbuf_bcat(sb, buf, size); - free(buf, M_TEMP); - *sizep = size; -} - -static void -__linuxN(note_nt_auxv)(void *arg, struct sbuf *sb, size_t *sizep) -{ - struct proc *p; - size_t size; - - p = arg; - if (sb == NULL) { - size = 0; - sb = sbuf_new(NULL, NULL, LINUX_AT_COUNT * sizeof(Elf_Auxinfo), - SBUF_FIXEDLEN); - sbuf_set_drain(sb, sbuf_count_drain, &size); - PHOLD(p); - proc_getauxv(curthread, p, sb); - PRELE(p); - sbuf_finish(sb); - sbuf_delete(sb); - *sizep = size; - } else { - PHOLD(p); - proc_getauxv(curthread, p, sb); - PRELE(p); - } -} - -/* - * Copy strings out to the new process address space, constructing new arg - * and env vector tables. Return a pointer to the base so that it can be used - * as the initial stack pointer. - */ -int -__linuxN(copyout_strings)(struct image_params *imgp, uintptr_t *stack_base) -{ - char canary[LINUX_AT_RANDOM_LEN]; - char **vectp; - char *stringp; - uintptr_t destp, ustringp; - struct ps_strings *arginfo; - struct proc *p; - size_t execpath_len; - int argc, envc; - int error; - - p = imgp->proc; - destp = PROC_PS_STRINGS(p); - arginfo = imgp->ps_strings = (void *)destp; - - /* - * Copy the image path for the rtld. - */ - if (imgp->execpath != NULL && imgp->auxargs != NULL) { - execpath_len = strlen(imgp->execpath) + 1; - destp -= execpath_len; - destp = rounddown2(destp, sizeof(void *)); - imgp->execpathp = (void *)destp; - error = copyout(imgp->execpath, imgp->execpathp, execpath_len); - if (error != 0) - return (error); - } - - /* - * Prepare the canary for SSP. - */ - arc4rand(canary, sizeof(canary), 0); - destp -= sizeof(canary); - imgp->canary = (void *)destp; - error = copyout(canary, imgp->canary, sizeof(canary)); - if (error != 0) - return (error); - imgp->canarylen = sizeof(canary); - - /* - * Allocate room for the argument and environment strings. - */ - destp -= ARG_MAX - imgp->args->stringspace; - destp = rounddown2(destp, sizeof(void *)); - ustringp = destp; - - if (imgp->auxargs) { - /* - * Allocate room on the stack for the ELF auxargs - * array. It has up to LINUX_AT_COUNT entries. - */ - destp -= LINUX_AT_COUNT * sizeof(Elf_Auxinfo); - destp = rounddown2(destp, sizeof(void *)); - } - - vectp = (char **)destp; - - /* - * Allocate room for the argv[] and env vectors including the - * terminating NULL pointers. - */ - vectp -= imgp->args->argc + 1 + imgp->args->envc + 1; - - /* - * Starting with 2.24, glibc depends on a 16-byte stack alignment. - */ - vectp = (char **)((((uintptr_t)vectp + 8) & ~0xF) - 8); - - /* - * vectp also becomes our initial stack base - */ - *stack_base = (uintptr_t)vectp; - - stringp = imgp->args->begin_argv; - argc = imgp->args->argc; - envc = imgp->args->envc; - - /* - * Copy out strings - arguments and environment. - */ - error = copyout(stringp, (void *)ustringp, - ARG_MAX - imgp->args->stringspace); - if (error != 0) - return (error); - - /* - * Fill in "ps_strings" struct for ps, w, etc. - */ - imgp->argv = vectp; - if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 || - suword32(&arginfo->ps_nargvstr, argc) != 0) - return (EFAULT); - - /* - * Fill in argument portion of vector table. - */ - for (; argc > 0; --argc) { - if (suword(vectp++, ustringp) != 0) - return (EFAULT); - while (*stringp++ != 0) - ustringp++; - ustringp++; - } - - /* a null vector table pointer separates the argp's from the envp's */ - if (suword(vectp++, 0) != 0) - return (EFAULT); - - imgp->envv = vectp; - if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 || - suword32(&arginfo->ps_nenvstr, envc) != 0) - return (EFAULT); - - /* - * Fill in environment portion of vector table. - */ - for (; envc > 0; --envc) { - if (suword(vectp++, ustringp) != 0) - return (EFAULT); - while (*stringp++ != 0) - ustringp++; - ustringp++; - } - - /* end of vector table is a null pointer */ - if (suword(vectp, 0) != 0) - return (EFAULT); - - if (imgp->auxargs) { - vectp++; - error = imgp->sysent->sv_copyout_auxargs(imgp, - (uintptr_t)vectp); - if (error != 0) - return (error); - } - - return (0); -} - -bool -linux_trans_osrel(const Elf_Note *note, int32_t *osrel) -{ - const Elf32_Word *desc; - uintptr_t p; - - p = (uintptr_t)(note + 1); - p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); - - desc = (const Elf32_Word *)p; - if (desc[0] != GNU_ABI_LINUX) - return (false); - /* - * For Linux we encode osrel using the Linux convention of - * (version << 16) | (major << 8) | (minor) - * See macro in linux_mib.h - */ - *osrel = LINUX_KERNVER(desc[1], desc[2], desc[3]); - - return (true); -} - -int -__linuxN(copyout_auxargs)(struct image_params *imgp, uintptr_t base) -{ - struct thread *td = curthread; - Elf_Auxargs *args; - Elf_Auxinfo *aarray, *pos; - struct proc *p; - int error, issetugid; - - p = imgp->proc; - issetugid = p->p_flag & P_SUGID ? 1 : 0; - args = imgp->auxargs; - aarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP, - M_WAITOK | M_ZERO); - - __linuxN(arch_copyout_auxargs)(imgp, &pos); - /* - * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, - * as it has appeared in the 2.4.0-rc7 first time. - * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), - * glibc falls back to the hard-coded CLK_TCK value when aux entry - * is not present. - * Also see linux_times() implementation. - */ - if (linux_kernver(td) >= LINUX_KERNVER(2,4,0)) - AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz); - AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); - AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); - AUXARGS_ENTRY(pos, AT_PHENT, args->phent); - AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); - AUXARGS_ENTRY(pos, AT_BASE, args->base); - AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); - AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); - AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); - AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); - AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); - AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); - AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid); - if (linux_kernver(td) >= LINUX_KERNVER(2,6,30)) - AUXARGS_ENTRY_PTR(pos, LINUX_AT_RANDOM, imgp->canary); - if (linux_kernver(td) >= LINUX_KERNVER(2,6,26) && imgp->execpathp != 0) - AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp)); - if (args->execfd != -1) - AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); - if (linux_kernver(td) >= LINUX_KERNVER(5,13,0)) - AUXARGS_ENTRY(pos, LINUX_AT_MINSIGSTKSZ, - imgp->sysent->sv_minsigstksz); - AUXARGS_ENTRY(pos, AT_NULL, 0); - - free(imgp->auxargs, M_TEMP); - imgp->auxargs = NULL; - KASSERT(pos - aarray <= LINUX_AT_COUNT, ("Too many auxargs")); - - error = copyout(aarray, PTRIN(base), sizeof(*aarray) * LINUX_AT_COUNT); - free(aarray, M_TEMP); - return (error); -} +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2021 Edward Tomasz Napierala + * Copyright (c) 2018 Chuck Tuffli + * Copyright (c) 2017 Dell EMC + * Copyright (c) 2000 David O'Brien + * Copyright (c) 1995-1996 Søren Schmidt + * Copyright (c) 1996 Peter Wemm + * All rights reserved. + * + * This software was developed by the University of Cambridge Computer + * Laboratory as part of the CHERI for Hypervisors and Operating Systems + * (CHaOS) project, funded by EPSRC grant EP/V000292/1. + * + * 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 + * in this position and unchanged. + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#if defined(COMPAT_LINUX32) +#define linux_pt_regset linux_pt_regset32 +#define bsd_to_linux_regset bsd_to_linux_regset32 +#include +#elif defined(COMPAT_LINUX64) +#include +#else +#include +#endif + +#include +#include +#include + +struct l_elf_siginfo { + l_int si_signo; + l_int si_code; + l_int si_errno; +}; + +typedef struct linux_pt_regset l_elf_gregset_t; + +struct linux_elf_prstatus { + struct l_elf_siginfo pr_info; + l_short pr_cursig; + l_ulong pr_sigpend; + l_ulong pr_sighold; + l_pid_t pr_pid; + l_pid_t pr_ppid; + l_pid_t pr_pgrp; + l_pid_t pr_sid; + l_timeval pr_utime; + l_timeval pr_stime; + l_timeval pr_cutime; + l_timeval pr_cstime; + l_elf_gregset_t pr_reg; + l_int pr_fpvalid; +}; + +#define LINUX_NT_AUXV 6 + +static void __linuxN(note_fpregset)(void *, struct sbuf *, size_t *); +static void __linuxN(note_prpsinfo)(void *, struct sbuf *, size_t *); +static void __linuxN(note_prstatus)(void *, struct sbuf *, size_t *); +static void __linuxN(note_threadmd)(void *, struct sbuf *, size_t *); +static void __linuxN(note_nt_auxv)(void *, struct sbuf *, size_t *); + +void +__linuxN(prepare_notes)(struct thread *td, struct note_info_list *list, + size_t *sizep) +{ + struct proc *p; + struct thread *thr; + size_t size; + + p = td->td_proc; + size = 0; + + /* + * To have the debugger select the right thread (LWP) as the initial + * thread, we dump the state of the thread passed to us in td first. + * This is the thread that causes the core dump and thus likely to + * be the right thread one wants to have selected in the debugger. + */ + thr = td; + while (thr != NULL) { + size += __elfN(register_note)(td, list, + NT_PRSTATUS, __linuxN(note_prstatus), thr); + size += __elfN(register_note)(td, list, + NT_PRPSINFO, __linuxN(note_prpsinfo), p); + size += __elfN(register_note)(td, list, + LINUX_NT_AUXV, __linuxN(note_nt_auxv), p); + size += __elfN(register_note)(td, list, + NT_FPREGSET, __linuxN(note_fpregset), thr); + size += __elfN(register_note)(td, list, + -1, __linuxN(note_threadmd), thr); + + thr = thr == td ? TAILQ_FIRST(&p->p_threads) : + TAILQ_NEXT(thr, td_plist); + if (thr == td) + thr = TAILQ_NEXT(thr, td_plist); + } + + *sizep = size; +} + +typedef struct linux_elf_prstatus linux_elf_prstatus_t; +#ifdef COMPAT_LINUX32 +typedef struct prpsinfo32 linux_elf_prpsinfo_t; +typedef struct fpreg32 linux_elf_prfpregset_t; +#else +typedef prpsinfo_t linux_elf_prpsinfo_t; +typedef prfpregset_t linux_elf_prfpregset_t; +#endif + +static void +__linuxN(note_prpsinfo)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct sbuf sbarg; + size_t len; + char *cp, *end; + struct proc *p; + linux_elf_prpsinfo_t *psinfo; + int error; + + p = arg; + if (sb != NULL) { + KASSERT(*sizep == sizeof(*psinfo), ("invalid size")); + psinfo = malloc(sizeof(*psinfo), M_TEMP, M_ZERO | M_WAITOK); + psinfo->pr_version = PRPSINFO_VERSION; + psinfo->pr_psinfosz = sizeof(linux_elf_prpsinfo_t); + strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname)); + PROC_LOCK(p); + if (p->p_args != NULL) { + len = sizeof(psinfo->pr_psargs) - 1; + if (len > p->p_args->ar_length) + len = p->p_args->ar_length; + memcpy(psinfo->pr_psargs, p->p_args->ar_args, len); + PROC_UNLOCK(p); + error = 0; + } else { + _PHOLD(p); + PROC_UNLOCK(p); + sbuf_new(&sbarg, psinfo->pr_psargs, + sizeof(psinfo->pr_psargs), SBUF_FIXEDLEN); + error = proc_getargv(curthread, p, &sbarg); + PRELE(p); + if (sbuf_finish(&sbarg) == 0) { + len = sbuf_len(&sbarg) - 1; + if (len > 0) + len--; + } else { + len = sizeof(psinfo->pr_psargs) - 1; + } + sbuf_delete(&sbarg); + } + if (error != 0 || len == 0 || (ssize_t)len == -1) + strlcpy(psinfo->pr_psargs, p->p_comm, + sizeof(psinfo->pr_psargs)); + else { + KASSERT(len < sizeof(psinfo->pr_psargs), + ("len is too long: %zu vs %zu", len, + sizeof(psinfo->pr_psargs))); + cp = psinfo->pr_psargs; + end = cp + len - 1; + for (;;) { + cp = memchr(cp, '\0', end - cp); + if (cp == NULL) + break; + *cp = ' '; + } + } + psinfo->pr_pid = p->p_pid; + sbuf_bcat(sb, psinfo, sizeof(*psinfo)); + free(psinfo, M_TEMP); + } + *sizep = sizeof(*psinfo); +} + +static void +__linuxN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct thread *td; + linux_elf_prstatus_t *status; +#ifdef COMPAT_LINUX32 + struct reg32 pr_reg; +#else + struct reg pr_reg; +#endif + + td = arg; + if (sb != NULL) { + KASSERT(*sizep == sizeof(*status), ("invalid size")); + status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK); + + /* + * XXX: Some fields missing. + */ + status->pr_cursig = td->td_proc->p_sig; + status->pr_pid = td->td_tid; + +#ifdef COMPAT_LINUX32 + fill_regs32(td, &pr_reg); +#else + fill_regs(td, &pr_reg); +#endif + bsd_to_linux_regset(&pr_reg, &status->pr_reg); + sbuf_bcat(sb, status, sizeof(*status)); + free(status, M_TEMP); + } + *sizep = sizeof(*status); +} + +static void +__linuxN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct thread *td; + linux_elf_prfpregset_t *fpregset; + + td = arg; + if (sb != NULL) { + KASSERT(*sizep == sizeof(*fpregset), ("invalid size")); + fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK); +#ifdef COMPAT_LINUX32 + fill_fpregs32(td, fpregset); +#else + fill_fpregs(td, fpregset); +#endif + sbuf_bcat(sb, fpregset, sizeof(*fpregset)); + free(fpregset, M_TEMP); + } + *sizep = sizeof(*fpregset); +} + +/* + * Allow for MD specific notes, as well as any MD + * specific preparations for writing MI notes. + */ +static void +__linuxN(note_threadmd)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct thread *td; + void *buf; + size_t size; + + td = arg; + size = *sizep; + if (size != 0 && sb != NULL) + buf = malloc(size, M_TEMP, M_ZERO | M_WAITOK); + else + buf = NULL; + size = 0; + __elfN(dump_thread)(td, buf, &size); + KASSERT(sb == NULL || *sizep == size, ("invalid size")); + if (size != 0 && sb != NULL) + sbuf_bcat(sb, buf, size); + free(buf, M_TEMP); + *sizep = size; +} + +static void +__linuxN(note_nt_auxv)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size; + + p = arg; + if (sb == NULL) { + size = 0; + sb = sbuf_new(NULL, NULL, LINUX_AT_COUNT * sizeof(Elf_Auxinfo), + SBUF_FIXEDLEN); + sbuf_set_drain(sb, sbuf_count_drain, &size); + PHOLD(p); + proc_getauxv(curthread, p, sb); + PRELE(p); + sbuf_finish(sb); + sbuf_delete(sb); + *sizep = size; + } else { + PHOLD(p); + proc_getauxv(curthread, p, sb); + PRELE(p); + } +} + +/* + * Copy strings out to the new process address space, constructing new arg + * and env vector tables. Return a pointer to the base so that it can be used + * as the initial stack pointer. + */ +int +__linuxN(copyout_strings)(struct image_params *imgp, uintcap_t *stack_base) +{ + char canary[LINUX_AT_RANDOM_LEN]; + l_uintptr_t * __capability vectp; + char *stringp; + uintcap_t destp, ustringp; + struct ps_strings * __capability arginfo; + struct proc *p; + size_t execpath_len, len; + int argc, envc; + int error; + bool strings_on_stack; + + p = imgp->proc; + + strings_on_stack = true; + +#if __has_feature(capabilities) + if (imgp->stack != imgp->strings) + strings_on_stack = false; + destp = (uintcap_t)imgp->strings; + destp = cheri_setaddress(destp, PROC_PS_STRINGS(p)); + arginfo = (struct ps_strings * __capability)cheri_setboundsexact(destp, + sizeof(*arginfo)); +#else + destp = (uintptr_t)PROC_PS_STRINGS(p); + arginfo = (struct ps_strings *)destp; +#endif + + imgp->ps_strings = arginfo; + + /* + * Copy the image path for the rtld. + */ + if (imgp->execpath != NULL && imgp->auxargs != NULL) { + execpath_len = strlen(imgp->execpath) + 1; + destp -= execpath_len; + destp = rounddown2(destp, sizeof(l_uintptr_t)); + imgp->execpathp = (void * __capability)cheri_setboundsexact(destp, execpath_len); + error = copyout(imgp->execpath, imgp->execpathp, execpath_len); + if (error != 0) + return (error); + } + + /* + * Prepare the canary for SSP. + */ + arc4rand(canary, sizeof(canary), 0); + destp -= sizeof(canary); + imgp->canary = (void * __capability)cheri_setboundsexact(destp, sizeof(canary));; + error = copyout(canary, imgp->canary, sizeof(canary)); + if (error != 0) + return (error); + imgp->canarylen = sizeof(canary); + + /* + * Allocate room for the argument and environment strings. + */ + destp -= ARG_MAX - imgp->args->stringspace; + destp = rounddown2(destp, sizeof(l_uintptr_t)); + ustringp = cheri_setbounds(destp, ARG_MAX - imgp->args->stringspace); + + if (imgp->auxargs) { + /* + * Allocate room on the stack for the ELF auxargs + * array. It has up to LINUX_AT_COUNT entries. + */ + destp -= LINUX_AT_COUNT * sizeof(Elf_Auxinfo); + destp = rounddown2(destp, sizeof(l_uintptr_t)); + } + + vectp = (l_uintptr_t * __capability)destp; + + /* + * Allocate room for the argv[] and env vectors including the + * terminating NULL pointers. + */ + vectp -= imgp->args->argc + 1 + imgp->args->envc + 1; + +#if defined(COMPAT_LINUX64) || defined(COMPAT_LINUX32) + /* + * Starting with 2.24, glibc depends on a 16-byte stack alignment. + */ + vectp = (l_uintptr_t * __capability)((((uintcap_t)vectp + 8) & ~0xF) - 8); +#endif + + if (!strings_on_stack) { + *stack_base = (uintcap_t)imgp->stack; + } else { + /* + * vectp also becomes our initial stack base + */ + *stack_base = (uintcap_t)vectp; + } + + stringp = imgp->args->begin_argv; + argc = imgp->args->argc; + envc = imgp->args->envc; + + /* + * Copy out strings - arguments and environment. + */ + error = copyout(stringp, (void * __capability)ustringp, + ARG_MAX - imgp->args->stringspace); + if (error != 0) + return (error); + + /* + * Fill in "ps_strings" struct for ps, w, etc. + */ + imgp->argv = cheri_setbounds(vectp, (argc + 1) * sizeof(*vectp));; + if (suptr(&arginfo->ps_argvstr, (intcap_t)vectp) != 0 || + suword32(&arginfo->ps_nargvstr, argc) != 0) + return (EFAULT); + + /* + * Fill in argument portion of vector table. + */ + for (; argc > 0; --argc) { + len = strlen(stringp) + 1; +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + if (sucap(vectp++, cheri_setbounds(ustringp, len)) != 0) + return (EFAULT); +#else + if (suword(vectp++, ustringp) != 0) + return (EFAULT); +#endif + stringp += len; + ustringp += len; + } + + /* a null vector table pointer separates the argp's from the envp's */ + if (suword(vectp++, 0) != 0) + return (EFAULT); + + imgp->envv = cheri_setbounds(vectp, (envc + 1) * sizeof(*vectp)); + if (suptr(&arginfo->ps_envstr, (intcap_t)vectp) != 0 || + suword32(&arginfo->ps_nenvstr, envc) != 0) + return (EFAULT); + + /* + * Fill in environment portion of vector table. + */ + for (; envc > 0; --envc) { + len = strlen(stringp) + 1; +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) + if (sucap(vectp++, cheri_setbounds(ustringp, len)) != 0) + return (EFAULT); +#else + if (suword(vectp++, ustringp) != 0) + return (EFAULT); +#endif + stringp += len; + ustringp += len; + } + + /* end of vector table is a null pointer */ + if (suword(vectp, 0) != 0) + return (EFAULT); + + if (imgp->auxargs) { + vectp++; + imgp->auxv = cheri_setbounds(vectp, + LINUX_AT_COUNT * sizeof(Elf_Auxinfo)); + error = imgp->sysent->sv_copyout_auxargs(imgp, + (uintcap_t)imgp->auxv); + if (error != 0) + return (error); + } + + return (0); +} + +bool +linux_trans_osrel(const Elf_Note *note, int32_t *osrel) +{ + const Elf32_Word *desc; + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + + desc = (const Elf32_Word *)p; + if (desc[0] != GNU_ABI_LINUX) + return (false); + /* + * For Linux we encode osrel using the Linux convention of + * (version << 16) | (major << 8) | (minor) + * See macro in linux_mib.h + */ + *osrel = LINUX_KERNVER(desc[1], desc[2], desc[3]); + + return (true); +} + +#ifdef __ELF_CHERI +static void * __capability +prog_cap(struct image_params *imgp, uint64_t perms) +{ + Elf_Addr prog_base; + size_t prog_len; + + prog_base = imgp->start_addr; + prog_len = imgp->end_addr - imgp->start_addr; + + /* + * Ensure that a capability spanning the program is representable. + * We don't round here since the mapping code is responsible for + * choosing a sensible start address and length. + */ + KASSERT(prog_len == CHERI_REPRESENTABLE_LENGTH(prog_len) && + prog_base == CHERI_REPRESENTABLE_ALIGN_DOWN(prog_base, prog_len), + ("program capability [%#jx-%#jx] not representable (length=%#zx)", + (uintmax_t)prog_base, (uintmax_t)imgp->end_addr, prog_len)); + + return (cheri_capability_build_user_rwx(perms, prog_base, prog_len, + imgp->start_addr - prog_base)); +} + +static void * __capability +interp_cap(struct image_params *imgp, Elf_Auxargs *args, uint64_t perms) +{ + Elf_Addr interp_base; + size_t interp_len; + + interp_base = imgp->interp_start; + interp_len = imgp->interp_end - imgp->interp_start; + + /* + * Ensure that a capability spanning RTLD is representable. + * We don't round here since the mapping code is responsible for + * choosing a sensible start address. + */ + KASSERT(interp_len == CHERI_REPRESENTABLE_LENGTH(interp_len) && + interp_base == + CHERI_REPRESENTABLE_ALIGN_DOWN(interp_base, interp_len), + ("interp capability [%#jx-%#jx] not representable (length=%#zx)", + (uintmax_t)interp_base, (uintmax_t)imgp->interp_end, interp_len)); + MPASS(args->base >= interp_base); + + return (cheri_capability_build_user_rwx(perms, interp_base, interp_len, + args->base - interp_base)); +} +#endif + +int +__linuxN(copyout_auxargs)(struct image_params *imgp, uintcap_t base) +{ + struct thread *td = curthread; + Elf_Auxargs *args; + Elf_Auxinfo *aarray, *pos; + struct proc *p; + int error, issetugid; +#ifdef __ELF_CHERI + void * __capability entry; +#endif + + p = imgp->proc; + issetugid = p->p_flag & P_SUGID ? 1 : 0; + args = imgp->auxargs; + aarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP, + M_WAITOK | M_ZERO); + + __linuxN(arch_copyout_auxargs)(imgp, &pos); + /* + * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, + * as it has appeared in the 2.4.0-rc7 first time. + * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), + * glibc falls back to the hard-coded CLK_TCK value when aux entry + * is not present. + * Also see linux_times() implementation. + */ + if (linux_kernver(td) >= LINUX_KERNVER(2,4,0)) + AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz); + AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); + + +// Handle AT_PHDR and LINUX_AT_CHERI_EXEC_RW_CAP +#ifdef __ELF_CHERI + /* + * AT_ENTRY gives an executable capability for the whole + * program and AT_PHDR a writable one. RTLD is responsible for + * setting bounds. Needs SW_VMEM so relro pages can be made RO. + */ + + /* + * A valid unsealed capability with the following properties: + * Its address is set to the address of the program headers of the executable (as usual). + * Its bounds include the program headers. + * Its permissions include: + * - Global + * - Load + */ + AUXARGS_ENTRY_PTR(pos, AT_PHDR, cheri_setaddress(prog_cap(imgp, + CHERI_CAP_USER_DATA_PERMS | CHERI_PERM_SW_VMEM), + args->phdr)); + + /* + * If the executable has at least one writable segment, a valid unsealed capability with the following properties: + * Its address is set to the start of the executable's RW region. + * Its bounds include the executable's RW region (see section "Purecap ELF executables"). + * Its permissions include: + * - ROOT_CAP_PERMS + * - READ_CAP_PERMS + * - WRITE_CAP_PERMS + * - BranchSealedPair + * + * Note: This is used for relocation + */ + AUXARGS_ENTRY_PTR(pos, LINUX_AT_CHERI_EXEC_RW_CAP, cheri_setaddress(prog_cap(imgp, + CHERI_CAP_USER_DATA_PERMS | CHERI_PERM_SW_VMEM), + args->phdr)); +#else + AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); +#endif + + +// Handle AT_ENTRY and LINUX_AT_CHERI_EXEC_RX_CAP +#ifdef __ELF_CHERI + entry = cheri_setaddress(prog_cap(imgp, CHERI_CAP_USER_CODE_PERMS), + args->entry); +#ifdef CHERI_FLAGS_CAP_MODE + /* + * On architectures with a mode flag bit, we must ensure the flag is set in + * AT_ENTRY for RTLD to be able to jump to it. + */ + entry = cheri_setflags(entry, CHERI_FLAGS_CAP_MODE); +#endif + /* + * A valid unsealed capability with the following properties: + * Its address is set to the start of the executable's RX region. + * Its bounds include the executable's RX region (see section "Purecap ELF executables"). + * Its permissions include: + * - ROOT_CAP_PERMS + * - READ_CAP_PERMS + * - EXEC_CAP_PERMS + * - BranchSealedPair + * + * Note: This is used for relocation + */ + AUXARGS_ENTRY_PTR(pos, LINUX_AT_CHERI_EXEC_RX_CAP, entry); + + + /* + * A valid sealed capability with the following properties: + * Its address is set to the entry address of the executable (as usual). + * Its bounds include the executable's RX region (see section "Purecap ELF executables"). + * Its permissions are the same as the initial PCC. + * Its object type is set to 1 (RB). + * + * Note: Use sealentry here + */ + entry = cheri_sealentry(entry); + AUXARGS_ENTRY_PTR(pos, AT_ENTRY, entry); +#else + AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); +#endif + +#ifdef __ELF_CHERI + if (imgp->interp_end != 0) { + AUXARGS_ENTRY_PTR(pos, LINUX_AT_CHERI_INTERP_RW_CAP, cheri_setaddress(interp_cap(imgp, args, + CHERI_CAP_USER_DATA_PERMS | CHERI_PERM_SW_VMEM), + imgp->interp_start)); + + AUXARGS_ENTRY_PTR(pos, LINUX_AT_CHERI_INTERP_RX_CAP, cheri_setaddress(interp_cap(imgp, args, + CHERI_CAP_USER_CODE_PERMS), + imgp->interp_start)); + } + AUXARGS_ENTRY_PTR(pos, LINUX_AT_CHERI_STACK_CAP, imgp->stack); + AUXARGS_ENTRY_PTR(pos, LINUX_AT_CHERI_CID_CAP, (void * __capability)userspace_root_cidcap); + AUXARGS_ENTRY_PTR(pos, LINUX_AT_CHERI_SEAL_CAP, (void * __capability)userspace_root_sealcap); + AUXARGS_ENTRY(pos, LINUX_AT_ARGC, imgp->args->argc); + AUXARGS_ENTRY_PTR(pos, LINUX_AT_ARGV, imgp->argv); + AUXARGS_ENTRY(pos, LINUX_AT_ENVC, imgp->args->envc); + AUXARGS_ENTRY_PTR(pos, LINUX_AT_ENVP, imgp->envv); +#endif + + // In PCuABI, we are not using AT_BASE for relocation, unlike CheriABI + AUXARGS_ENTRY(pos, AT_BASE, args->base); + AUXARGS_ENTRY(pos, AT_PHENT, args->phent); + AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); + AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); + AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); + AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); + AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); + AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); + AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid); + if (linux_kernver(td) >= LINUX_KERNVER(2,6,30)) + AUXARGS_ENTRY_PTR(pos, LINUX_AT_RANDOM, imgp->canary); + if (linux_kernver(td) >= LINUX_KERNVER(2,6,26) && imgp->execpathp != 0) + AUXARGS_ENTRY_PTR(pos, LINUX_AT_EXECFN, imgp->execpathp); + if (args->execfd != -1) + AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); + if (linux_kernver(td) >= LINUX_KERNVER(5,13,0)) + AUXARGS_ENTRY(pos, LINUX_AT_MINSIGSTKSZ, + imgp->sysent->sv_minsigstksz); + AUXARGS_ENTRY(pos, AT_NULL, 0); + + free(imgp->auxargs, M_TEMP); + imgp->auxargs = NULL; + KASSERT(pos - aarray <= LINUX_AT_COUNT, ("Too many auxargs")); + + error = copyoutcap(aarray, (void * __capability)(base), sizeof(*aarray) * LINUX_AT_COUNT); + free(aarray, M_TEMP); + return (error); +} diff --git a/sys/compat/linux/linux_elf.h b/sys/compat/linux/linux_elf.h index 2584a8a990c0..7373916446b6 100644 --- a/sys/compat/linux/linux_elf.h +++ b/sys/compat/linux/linux_elf.h @@ -1,50 +1,50 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2018 Chuck Tuffli - * - * 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. - */ - -#ifndef _COMPAT_LINUX_ELF_H_ -#define _COMPAT_LINUX_ELF_H_ - -struct note_info_list; - -/* Linux core notes are labeled "CORE" */ -#define LINUX_ABI_VENDOR "CORE" - -/* Elf notes */ -#define GNU_ABI_VENDOR "GNU" -#define GNU_ABI_LINUX 0 - -/* This adds "linux32_" and "linux64_" prefixes. */ -#define __linuxN(x) __CONCAT(__CONCAT(__CONCAT(linux,__ELF_WORD_SIZE),_),x) - -void __linuxN(prepare_notes)(struct thread *, struct note_info_list *, - size_t *); -void __linuxN(arch_copyout_auxargs)(struct image_params *, Elf_Auxinfo **); -int __linuxN(copyout_auxargs)(struct image_params *, uintptr_t); -int __linuxN(copyout_strings)(struct image_params *, uintptr_t *); -bool linux_trans_osrel(const Elf_Note *note, int32_t *osrel); - -#endif +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 Chuck Tuffli + * + * 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. + */ + +#ifndef _COMPAT_LINUX_ELF_H_ +#define _COMPAT_LINUX_ELF_H_ + +struct note_info_list; + +/* Linux core notes are labeled "CORE" */ +#define LINUX_ABI_VENDOR "CORE" + +/* Elf notes */ +#define GNU_ABI_VENDOR "GNU" +#define GNU_ABI_LINUX 0 + +/* This adds "linux32_" and "linux64_" prefixes. */ +#define __linuxN(x) __CONCAT(__CONCAT(__CONCAT(linux,__ELF_WORD_SIZE),_),x) + +void __linuxN(prepare_notes)(struct thread *, struct note_info_list *, + size_t *); +void __linuxN(arch_copyout_auxargs)(struct image_params *, Elf_Auxinfo **); +int __linuxN(copyout_auxargs)(struct image_params *, uintcap_t); +int __linuxN(copyout_strings)(struct image_params *, uintcap_t *); +bool linux_trans_osrel(const Elf_Note *note, int32_t *osrel); + +#endif diff --git a/sys/compat/linux/linux_elf32.c b/sys/compat/linux/linux_elf32.c index 6bd4b141af85..ac48c334c607 100644 --- a/sys/compat/linux/linux_elf32.c +++ b/sys/compat/linux/linux_elf32.c @@ -1,35 +1,35 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2021 Edward Tomasz Napierala - * Copyright (c) 2002 Doug Rabson - * All rights reserved. - * - * This software was developed by the University of Cambridge Computer - * Laboratory as part of the CHERI for Hypervisors and Operating Systems - * (CHaOS) project, funded by EPSRC grant EP/V000292/1. - * - * 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. - */ - -#define __ELF_WORD_SIZE 32 -#include +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Edward Tomasz Napierala + * Copyright (c) 2002 Doug Rabson + * All rights reserved. + * + * This software was developed by the University of Cambridge Computer + * Laboratory as part of the CHERI for Hypervisors and Operating Systems + * (CHaOS) project, funded by EPSRC grant EP/V000292/1. + * + * 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. + */ + +#define __ELF_WORD_SIZE 32 +#include diff --git a/sys/compat/linux/linux_elf64.c b/sys/compat/linux/linux_elf64.c index 397bcf741fae..d8ff4e9b4f7b 100644 --- a/sys/compat/linux/linux_elf64.c +++ b/sys/compat/linux/linux_elf64.c @@ -1,35 +1,38 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2021 Edward Tomasz Napierala - * Copyright (c) 2002 Doug Rabson - * All rights reserved. - * - * This software was developed by the University of Cambridge Computer - * Laboratory as part of the CHERI for Hypervisors and Operating Systems - * (CHaOS) project, funded by EPSRC grant EP/V000292/1. - * - * 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. - */ - -#define __ELF_WORD_SIZE 64 -#include +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Edward Tomasz Napierala + * Copyright (c) 2002 Doug Rabson + * All rights reserved. + * + * This software was developed by the University of Cambridge Computer + * Laboratory as part of the CHERI for Hypervisors and Operating Systems + * (CHaOS) project, funded by EPSRC grant EP/V000292/1. + * + * 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. + */ + +#define __ELF_WORD_SIZE 64 +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) +#define __ELF_CHERI +#endif +#include diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c index e5ab51802468..ce6a88faf71e 100644 --- a/sys/compat/linux/linux_emul.c +++ b/sys/compat/linux/linux_emul.c @@ -1,353 +1,353 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 1994-1996 Søren Schmidt - * Copyright (c) 2006 Roman Divacky - * All rights reserved. - * Copyright (c) 2013 Dmitry Chagin - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if BYTE_ORDER == LITTLE_ENDIAN -#define SHELLMAGIC 0x2123 /* #! */ -#else -#define SHELLMAGIC 0x2321 -#endif - -/* - * This returns reference to the thread emuldata entry (if found) - * - * Hold PROC_LOCK when referencing emuldata from other threads. - */ -struct linux_emuldata * -em_find(struct thread *td) -{ - struct linux_emuldata *em; - - em = td->td_emuldata; - - return (em); -} - -/* - * This returns reference to the proc pemuldata entry (if found) - * - * Hold PROC_LOCK when referencing proc pemuldata from other threads. - * Hold LINUX_PEM_LOCK wher referencing pemuldata members. - */ -struct linux_pemuldata * -pem_find(struct proc *p) -{ - struct linux_pemuldata *pem; - - pem = p->p_emuldata; - - return (pem); -} - -/* - * Linux apps generally expect the soft open file limit to be set - * to 1024, often iterating over all the file descriptors up to that - * limit instead of using closefrom(2). Give them what they want, - * unless there already is a resource limit in place. - */ -static void -linux_set_default_openfiles(struct thread *td, struct proc *p) -{ - struct rlimit rlim; - int error __diagused; - - if (linux_default_openfiles < 0) - return; - - PROC_LOCK(p); - lim_rlimit_proc(p, RLIMIT_NOFILE, &rlim); - PROC_UNLOCK(p); - if (rlim.rlim_cur != rlim.rlim_max || - rlim.rlim_cur <= linux_default_openfiles) - return; - rlim.rlim_cur = linux_default_openfiles; - error = kern_proc_setrlimit(td, p, RLIMIT_NOFILE, &rlim); - KASSERT(error == 0, ("kern_proc_setrlimit failed")); -} - -/* - * The default stack size limit in Linux is 8MB. - */ -static void -linux_set_default_stacksize(struct thread *td, struct proc *p) -{ - struct rlimit rlim; - int error __diagused; - - if (linux_default_stacksize < 0) - return; - - PROC_LOCK(p); - lim_rlimit_proc(p, RLIMIT_STACK, &rlim); - PROC_UNLOCK(p); - if (rlim.rlim_cur != rlim.rlim_max || - rlim.rlim_cur <= linux_default_stacksize) - return; - rlim.rlim_cur = linux_default_stacksize; - error = kern_proc_setrlimit(td, p, RLIMIT_STACK, &rlim); - KASSERT(error == 0, ("kern_proc_setrlimit failed")); -} - -void -linux_proc_init(struct thread *td, struct thread *newtd, bool init_thread) -{ - struct linux_emuldata *em; - struct linux_pemuldata *pem; - struct proc *p; - - if (newtd != NULL) { - p = newtd->td_proc; - - /* non-exec call */ - em = malloc(sizeof(*em), M_LINUX, M_WAITOK | M_ZERO); - if (init_thread) { - LINUX_CTR1(proc_init, "thread newtd(%d)", - newtd->td_tid); - - em->em_tid = newtd->td_tid; - } else { - LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid); - - em->em_tid = p->p_pid; - - pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO); - sx_init(&pem->pem_sx, "lpemlk"); - p->p_emuldata = pem; - } - newtd->td_emuldata = em; - - linux_set_default_openfiles(td, p); - linux_set_default_stacksize(td, p); - } else { - p = td->td_proc; - - /* exec */ - LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid); - - /* lookup the old one */ - em = em_find(td); - KASSERT(em != NULL, ("proc_init: thread emuldata not found.\n")); - - em->em_tid = p->p_pid; - em->flags = 0; - em->robust_futexes = NULL; - em->child_clear_tid = NULL; - em->child_set_tid = NULL; - - pem = pem_find(p); - KASSERT(pem != NULL, ("proc_init: proc emuldata not found.\n")); - pem->persona = 0; - pem->oom_score_adj = 0; - } -} - -void -linux_on_exit(struct proc *p) -{ - struct linux_pemuldata *pem; - struct thread *td = curthread; - - MPASS(SV_CURPROC_ABI() == SV_ABI_LINUX); - - LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p", - td->td_tid, p->p_pid, p); - - pem = pem_find(p); - if (pem == NULL) - return; - (p->p_sysent->sv_thread_detach)(td); - - p->p_emuldata = NULL; - - sx_destroy(&pem->pem_sx); - free(pem, M_LINUX); -} - -int -linux_common_execve(struct thread *td, struct image_args *eargs) -{ - struct linux_pemuldata *pem; - struct vmspace *oldvmspace; - struct linux_emuldata *em; - struct proc *p; - int error; - - p = td->td_proc; - - error = pre_execve(td, &oldvmspace); - if (error != 0) - return (error); - - error = kern_execve(td, eargs, NULL, oldvmspace); - post_execve(td, error, oldvmspace); - if (error != EJUSTRETURN) - return (error); - - /* - * In a case of transition from Linux binary execing to - * FreeBSD binary we destroy Linux emuldata thread & proc entries. - */ - if (SV_CURPROC_ABI() != SV_ABI_LINUX) { - - /* Clear ABI root directory if set. */ - linux_pwd_onexec_native(td); - - PROC_LOCK(p); - em = em_find(td); - KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n")); - td->td_emuldata = NULL; - - pem = pem_find(p); - KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n")); - p->p_emuldata = NULL; - PROC_UNLOCK(p); - - free(em, M_LINUX); - free(pem, M_LINUX); - } - return (EJUSTRETURN); -} - -int -linux_on_exec(struct proc *p, struct image_params *imgp) -{ - struct thread *td; - struct thread *othertd; -#if defined(__amd64__) - struct linux_pemuldata *pem; -#endif - int error; - - td = curthread; - MPASS((imgp->sysent->sv_flags & SV_ABI_MASK) == SV_ABI_LINUX); - - /* - * When execing to Linux binary, we create Linux emuldata - * thread entry. - */ - if (SV_PROC_ABI(p) == SV_ABI_LINUX) { - /* - * Process already was under Linuxolator - * before exec. Update emuldata to reflect - * single-threaded cleaned state after exec. - */ - linux_proc_init(td, NULL, false); - } else { - /* - * We are switching the process to Linux emulator. - */ - linux_proc_init(td, td, false); - - /* - * Create a transient td_emuldata for all suspended - * threads, so that p->p_sysent->sv_thread_detach() == - * linux_thread_detach() can find expected but unused - * emuldata. - */ - FOREACH_THREAD_IN_PROC(td->td_proc, othertd) { - if (othertd == td) - continue; - linux_proc_init(td, othertd, true); - } - - /* Set ABI root directory. */ - if ((error = linux_pwd_onexec(td)) != 0) - return (error); - } -#if defined(__amd64__) - /* - * An IA32 executable which has executable stack will have the - * READ_IMPLIES_EXEC personality flag set automatically. - */ - if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && - imgp->stack_prot & VM_PROT_EXECUTE) { - pem = pem_find(p); - pem->persona |= LINUX_READ_IMPLIES_EXEC; - } -#endif - return (0); -} - -void -linux_thread_dtor(struct thread *td) -{ - struct linux_emuldata *em; - - em = em_find(td); - if (em == NULL) - return; - td->td_emuldata = NULL; - - LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid); - - free(em, M_LINUX); -} - -void -linux_schedtail(struct thread *td) -{ - struct linux_emuldata *em; -#ifdef KTR - int error; -#else - int error __unused; -#endif - int *child_set_tid; - - em = em_find(td); - KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n")); - child_set_tid = em->child_set_tid; - - if (child_set_tid != NULL) { - error = copyout(&em->em_tid, child_set_tid, - sizeof(em->em_tid)); - LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d", - td->td_tid, child_set_tid, em->em_tid, error); - } else - LINUX_CTR1(schedtail, "thread(%d)", em->em_tid); -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1994-1996 Søren Schmidt + * Copyright (c) 2006 Roman Divacky + * All rights reserved. + * Copyright (c) 2013 Dmitry Chagin + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SHELLMAGIC 0x2123 /* #! */ +#else +#define SHELLMAGIC 0x2321 +#endif + +/* + * This returns reference to the thread emuldata entry (if found) + * + * Hold PROC_LOCK when referencing emuldata from other threads. + */ +struct linux_emuldata * +em_find(struct thread *td) +{ + struct linux_emuldata *em; + + em = td->td_emuldata; + + return (em); +} + +/* + * This returns reference to the proc pemuldata entry (if found) + * + * Hold PROC_LOCK when referencing proc pemuldata from other threads. + * Hold LINUX_PEM_LOCK wher referencing pemuldata members. + */ +struct linux_pemuldata * +pem_find(struct proc *p) +{ + struct linux_pemuldata *pem; + + pem = p->p_emuldata; + + return (pem); +} + +/* + * Linux apps generally expect the soft open file limit to be set + * to 1024, often iterating over all the file descriptors up to that + * limit instead of using closefrom(2). Give them what they want, + * unless there already is a resource limit in place. + */ +static void +linux_set_default_openfiles(struct thread *td, struct proc *p) +{ + struct rlimit rlim; + int error __diagused; + + if (linux_default_openfiles < 0) + return; + + PROC_LOCK(p); + lim_rlimit_proc(p, RLIMIT_NOFILE, &rlim); + PROC_UNLOCK(p); + if (rlim.rlim_cur != rlim.rlim_max || + rlim.rlim_cur <= linux_default_openfiles) + return; + rlim.rlim_cur = linux_default_openfiles; + error = kern_proc_setrlimit(td, p, RLIMIT_NOFILE, &rlim); + KASSERT(error == 0, ("kern_proc_setrlimit failed")); +} + +/* + * The default stack size limit in Linux is 8MB. + */ +static void +linux_set_default_stacksize(struct thread *td, struct proc *p) +{ + struct rlimit rlim; + int error __diagused; + + if (linux_default_stacksize < 0) + return; + + PROC_LOCK(p); + lim_rlimit_proc(p, RLIMIT_STACK, &rlim); + PROC_UNLOCK(p); + if (rlim.rlim_cur != rlim.rlim_max || + rlim.rlim_cur <= linux_default_stacksize) + return; + rlim.rlim_cur = linux_default_stacksize; + error = kern_proc_setrlimit(td, p, RLIMIT_STACK, &rlim); + KASSERT(error == 0, ("kern_proc_setrlimit failed")); +} + +void +linux_proc_init(struct thread *td, struct thread *newtd, bool init_thread) +{ + struct linux_emuldata *em; + struct linux_pemuldata *pem; + struct proc *p; + + if (newtd != NULL) { + p = newtd->td_proc; + + /* non-exec call */ + em = malloc(sizeof(*em), M_LINUX, M_WAITOK | M_ZERO); + if (init_thread) { + LINUX_CTR1(proc_init, "thread newtd(%d)", + newtd->td_tid); + + em->em_tid = newtd->td_tid; + } else { + LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid); + + em->em_tid = p->p_pid; + + pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO); + sx_init(&pem->pem_sx, "lpemlk"); + p->p_emuldata = pem; + } + newtd->td_emuldata = em; + + linux_set_default_openfiles(td, p); + linux_set_default_stacksize(td, p); + } else { + p = td->td_proc; + + /* exec */ + LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid); + + /* lookup the old one */ + em = em_find(td); + KASSERT(em != NULL, ("proc_init: thread emuldata not found.\n")); + + em->em_tid = p->p_pid; + em->flags = 0; + em->robust_futexes = NULL; + em->child_clear_tid = NULL; + em->child_set_tid = NULL; + + pem = pem_find(p); + KASSERT(pem != NULL, ("proc_init: proc emuldata not found.\n")); + pem->persona = 0; + pem->oom_score_adj = 0; + } +} + +void +linux_on_exit(struct proc *p) +{ + struct linux_pemuldata *pem; + struct thread *td = curthread; + + MPASS(SV_CURPROC_ABI() == SV_ABI_LINUX); + + LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p", + td->td_tid, p->p_pid, p); + + pem = pem_find(p); + if (pem == NULL) + return; + (p->p_sysent->sv_thread_detach)(td); + + p->p_emuldata = NULL; + + sx_destroy(&pem->pem_sx); + free(pem, M_LINUX); +} + +int +linux_common_execve(struct thread *td, struct image_args *eargs) +{ + struct linux_pemuldata *pem; + struct vmspace *oldvmspace; + struct linux_emuldata *em; + struct proc *p; + int error; + + p = td->td_proc; + + error = pre_execve(td, &oldvmspace); + if (error != 0) + return (error); + + error = kern_execve(td, eargs, NULL, oldvmspace); + post_execve(td, error, oldvmspace); + if (error != EJUSTRETURN) + return (error); + + /* + * In a case of transition from Linux binary execing to + * FreeBSD binary we destroy Linux emuldata thread & proc entries. + */ + if (SV_CURPROC_ABI() != SV_ABI_LINUX) { + + /* Clear ABI root directory if set. */ + linux_pwd_onexec_native(td); + + PROC_LOCK(p); + em = em_find(td); + KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n")); + td->td_emuldata = NULL; + + pem = pem_find(p); + KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n")); + p->p_emuldata = NULL; + PROC_UNLOCK(p); + + free(em, M_LINUX); + free(pem, M_LINUX); + } + return (EJUSTRETURN); +} + +int +linux_on_exec(struct proc *p, struct image_params *imgp) +{ + struct thread *td; + struct thread *othertd; +#if defined(__amd64__) + struct linux_pemuldata *pem; +#endif + int error; + + td = curthread; + MPASS((imgp->sysent->sv_flags & SV_ABI_MASK) == SV_ABI_LINUX); + + /* + * When execing to Linux binary, we create Linux emuldata + * thread entry. + */ + if (SV_PROC_ABI(p) == SV_ABI_LINUX) { + /* + * Process already was under Linuxolator + * before exec. Update emuldata to reflect + * single-threaded cleaned state after exec. + */ + linux_proc_init(td, NULL, false); + } else { + /* + * We are switching the process to Linux emulator. + */ + linux_proc_init(td, td, false); + + /* + * Create a transient td_emuldata for all suspended + * threads, so that p->p_sysent->sv_thread_detach() == + * linux_thread_detach() can find expected but unused + * emuldata. + */ + FOREACH_THREAD_IN_PROC(td->td_proc, othertd) { + if (othertd == td) + continue; + linux_proc_init(td, othertd, true); + } + + /* Set ABI root directory. */ + if ((error = linux_pwd_onexec(td)) != 0) + return (error); + } +#if defined(__amd64__) + /* + * An IA32 executable which has executable stack will have the + * READ_IMPLIES_EXEC personality flag set automatically. + */ + if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && + imgp->stack_prot & VM_PROT_EXECUTE) { + pem = pem_find(p); + pem->persona |= LINUX_READ_IMPLIES_EXEC; + } +#endif + return (0); +} + +void +linux_thread_dtor(struct thread *td) +{ + struct linux_emuldata *em; + + em = em_find(td); + if (em == NULL) + return; + td->td_emuldata = NULL; + + LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid); + + free(em, M_LINUX); +} + +void +linux_schedtail(struct thread *td) +{ + struct linux_emuldata *em; +#ifdef KTR + int error; +#else + int error __unused; +#endif + int * __capability child_set_tid; + + em = em_find(td); + KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n")); + child_set_tid = em->child_set_tid; + + if (child_set_tid != NULL) { + error = copyout(&em->em_tid, child_set_tid, + sizeof(em->em_tid)); + LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d", + td->td_tid, child_set_tid, em->em_tid, error); + } else + LINUX_CTR1(schedtail, "thread(%d)", em->em_tid); +} diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h index 6dfa31f6edf7..d7175945b20c 100644 --- a/sys/compat/linux/linux_emul.h +++ b/sys/compat/linux/linux_emul.h @@ -1,81 +1,81 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2006 Roman Divacky - * All rights reserved. - * Copyright (c) 2013 Dmitry Chagin - * - * 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. - */ - -#ifndef _LINUX_EMUL_H_ -#define _LINUX_EMUL_H_ - -struct image_params; - -/* - * modeled after similar structure in NetBSD - * this will be extended as we need more functionality - */ -struct linux_emuldata { - int *child_set_tid; /* in clone(): Child's TID to set on clone */ - int *child_clear_tid;/* in clone(): Child's TID to clear on exit */ - - int flags; /* thread emuldata flags */ - int em_tid; /* thread id */ - - struct linux_robust_list_head *robust_futexes; -}; - -struct linux_emuldata *em_find(struct thread *); - -void linux_proc_init(struct thread *, struct thread *, bool); -void linux_on_exit(struct proc *); -void linux_schedtail(struct thread *); -int linux_on_exec(struct proc *, struct image_params *); -void linux_thread_dtor(struct thread *); -int linux_common_execve(struct thread *, struct image_args *); - -/* process emuldata flags */ -#define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated - futex REQUEUE op*/ -#define LINUX_XUNSUP_EPOLL 0x00000002 /* unsupported epoll events */ -#define LINUX_XUNSUP_FUTEXPIOP 0x00000004 /* uses unsupported pi futex */ - -struct linux_pemuldata { - uint32_t flags; /* process emuldata flags */ - struct sx pem_sx; /* lock for this struct */ - uint32_t persona; /* process execution domain */ - uint32_t ptrace_flags; /* used by ptrace(2) */ - uint32_t oom_score_adj; /* /proc/self/oom_score_adj */ - uint32_t so_timestamp; /* requested timeval */ - uint32_t so_timestampns; /* requested timespec */ -}; - -#define LINUX_PEM_XLOCK(p) sx_xlock(&(p)->pem_sx) -#define LINUX_PEM_XUNLOCK(p) sx_xunlock(&(p)->pem_sx) -#define LINUX_PEM_SLOCK(p) sx_slock(&(p)->pem_sx) -#define LINUX_PEM_SUNLOCK(p) sx_sunlock(&(p)->pem_sx) - -struct linux_pemuldata *pem_find(struct proc *); - -#endif /* !_LINUX_EMUL_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2006 Roman Divacky + * All rights reserved. + * Copyright (c) 2013 Dmitry Chagin + * + * 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. + */ + +#ifndef _LINUX_EMUL_H_ +#define _LINUX_EMUL_H_ + +struct image_params; + +/* + * modeled after similar structure in NetBSD + * this will be extended as we need more functionality + */ +struct linux_emuldata { + int * __kerncap child_set_tid; /* in clone(): Child's TID to set on clone */ + int * __kerncap child_clear_tid;/* in clone(): Child's TID to clear on exit */ + + int flags; /* thread emuldata flags */ + int em_tid; /* thread id */ + + struct linux_robust_list_head * __kerncap robust_futexes; +}; + +struct linux_emuldata *em_find(struct thread *); + +void linux_proc_init(struct thread *, struct thread *, bool); +void linux_on_exit(struct proc *); +void linux_schedtail(struct thread *); +int linux_on_exec(struct proc *, struct image_params *); +void linux_thread_dtor(struct thread *); +int linux_common_execve(struct thread *, struct image_args *); + +/* process emuldata flags */ +#define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated + futex REQUEUE op*/ +#define LINUX_XUNSUP_EPOLL 0x00000002 /* unsupported epoll events */ +#define LINUX_XUNSUP_FUTEXPIOP 0x00000004 /* uses unsupported pi futex */ + +struct linux_pemuldata { + uint32_t flags; /* process emuldata flags */ + struct sx pem_sx; /* lock for this struct */ + uint32_t persona; /* process execution domain */ + uint32_t ptrace_flags; /* used by ptrace(2) */ + uint32_t oom_score_adj; /* /proc/self/oom_score_adj */ + uint32_t so_timestamp; /* requested timeval */ + uint32_t so_timestampns; /* requested timespec */ +}; + +#define LINUX_PEM_XLOCK(p) sx_xlock(&(p)->pem_sx) +#define LINUX_PEM_XUNLOCK(p) sx_xunlock(&(p)->pem_sx) +#define LINUX_PEM_SLOCK(p) sx_slock(&(p)->pem_sx) +#define LINUX_PEM_SUNLOCK(p) sx_sunlock(&(p)->pem_sx) + +struct linux_pemuldata *pem_find(struct proc *); + +#endif /* !_LINUX_EMUL_H_ */ diff --git a/sys/compat/linux/linux_errno.c b/sys/compat/linux/linux_errno.c index f04f694e5bec..07c0dee46d58 100644 --- a/sys/compat/linux/linux_errno.c +++ b/sys/compat/linux/linux_errno.c @@ -1,37 +1,37 @@ - -#include -#include -#include - -#include -#include -#include - -int -bsd_to_linux_errno(int error) -{ - - KASSERT(error >= 0 && error <= ELAST, - ("%s: bad error %d", __func__, error)); - - return (linux_errtbl[error]); -} - -#ifdef INVARIANTS -void -linux_check_errtbl(void) -{ - int i; - - for (i = 1; i < nitems(linux_errtbl); i++) { - KASSERT(linux_errtbl[i] != 0, - ("%s: linux_errtbl[%d] == 0", __func__, i)); - } - - for (i = 1; i < nitems(linux_to_bsd_errtbl); i++) { - KASSERT(linux_to_bsd_errtbl[i] != 0, - ("%s: linux_to_bsd_errtbl[%d] == 0", __func__, i)); - } - -} -#endif + +#include +#include +#include + +#include +#include +#include + +int +bsd_to_linux_errno(int error) +{ + + KASSERT(error >= 0 && error <= ELAST, + ("%s: bad error %d", __func__, error)); + + return (linux_errtbl[error]); +} + +#ifdef INVARIANTS +void +linux_check_errtbl(void) +{ + int i; + + for (i = 1; i < nitems(linux_errtbl); i++) { + KASSERT(linux_errtbl[i] != 0, + ("%s: linux_errtbl[%d] == 0", __func__, i)); + } + + for (i = 1; i < nitems(linux_to_bsd_errtbl); i++) { + KASSERT(linux_to_bsd_errtbl[i] != 0, + ("%s: linux_to_bsd_errtbl[%d] == 0", __func__, i)); + } + +} +#endif diff --git a/sys/compat/linux/linux_errno.h b/sys/compat/linux/linux_errno.h index 22c52272bae6..4179f26c9356 100644 --- a/sys/compat/linux/linux_errno.h +++ b/sys/compat/linux/linux_errno.h @@ -1,189 +1,189 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2020 The FreeBSD Foundation - * - * This software was developed by Edward Tomasz Napierala under sponsorship - * from the FreeBSD Foundation. - * - * 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. - */ - -#ifndef _LINUX_ERRNO_H_ -#define _LINUX_ERRNO_H_ - -#define LINUX_EPERM 1 -#define LINUX_ENOENT 2 -#define LINUX_ESRCH 3 -#define LINUX_EINTR 4 -#define LINUX_EIO 5 -#define LINUX_ENXIO 6 -#define LINUX_E2BIG 7 -#define LINUX_ENOEXEC 8 -#define LINUX_EBADF 9 - -#define LINUX_ECHILD 10 -#define LINUX_EAGAIN 11 -#define LINUX_ENOMEM 12 -#define LINUX_EACCES 13 -#define LINUX_EFAULT 14 -#define LINUX_ENOTBLK 15 -#define LINUX_EBUSY 16 -#define LINUX_EEXIST 17 -#define LINUX_EXDEV 18 -#define LINUX_ENODEV 19 - -#define LINUX_ENOTDIR 20 -#define LINUX_EISDIR 21 -#define LINUX_EINVAL 22 -#define LINUX_ENFILE 23 -#define LINUX_EMFILE 24 -#define LINUX_ENOTTY 25 -#define LINUX_ETXTBSY 26 -#define LINUX_EFBIG 27 -#define LINUX_ENOSPC 28 -#define LINUX_ESPIPE 29 - -#define LINUX_EROFS 30 -#define LINUX_EMLINK 31 -#define LINUX_EPIPE 32 -#define LINUX_EDOM 33 -#define LINUX_ERANGE 34 -#define LINUX_EDEADLK 35 -#define LINUX_ENAMETOOLONG 36 -#define LINUX_ENOLCK 37 -#define LINUX_ENOSYS 38 -#define LINUX_ENOTEMPTY 39 - -#define LINUX_ELOOP 40 -/* XXX: errno 41 is not defined in Linux. */ -#define LINUX_ENOMSG 42 -#define LINUX_EIDRM 43 -#define LINUX_ECHRNG 44 -#define LINUX_EL2NSYNC 45 -#define LINUX_EL3HLT 46 -#define LINUX_EL3RST 47 -#define LINUX_ELNRNG 48 -#define LINUX_EUNATCH 49 - -#define LINUX_ENOCSI 50 -#define LINUX_EL2HLT 51 -#define LINUX_EBADE 52 -#define LINUX_EBADR 53 -#define LINUX_EXFULL 54 -#define LINUX_ENOANO 55 -#define LINUX_EBADRQC 56 -#define LINUX_EBADSLT 57 -/* XXX: errno 58 is not defined in Linux. */ -#define LINUX_EBFONT 59 - -#define LINUX_ENOSTR 60 -#define LINUX_ENODATA 61 -#define LINUX_ENOTIME 62 -#define LINUX_ENOSR 63 -#define LINUX_ENONET 64 -#define LINUX_ENOPKG 65 -#define LINUX_EREMOTE 66 -#define LINUX_ENOLINK 67 -#define LINUX_EADV 68 -#define LINUX_ESRMNT 69 - -#define LINUX_ECOMM 70 -#define LINUX_EPROTO 71 -#define LINUX_EMULTIHOP 72 -#define LINUX_EDOTDOT 73 -#define LINUX_EBADMSG 74 -#define LINUX_EOVERFLOW 75 -#define LINUX_ENOTUNIQ 76 -#define LINUX_EBADFD 77 -#define LINUX_EREMCHG 78 -#define LINUX_ELIBACC 79 - -#define LINUX_ELIBBAD 80 -#define LINUX_ELIBSCN 81 -#define LINUX_ELIBMAX 82 -#define LINUX_ELIBEXEC 83 -#define LINUX_EILSEQ 84 -#define LINUX_ERESTART 85 -#define LINUX_ESTRPIPE 86 -#define LINUX_EUSERS 87 -#define LINUX_ENOTSOCK 88 -#define LINUX_EDESTADDRREQ 89 - -#define LINUX_EMSGSIZE 90 -#define LINUX_EPROTOTYPE 91 -#define LINUX_ENOPROTOOPT 92 -#define LINUX_EPROTONOTSUPPORT 93 -#define LINUX_ESOCKNOTSUPPORT 94 -#define LINUX_EOPNOTSUPPORT 95 -#define LINUX_EPFNOTSUPPORT 96 -#define LINUX_EAFNOTSUPPORT 97 -#define LINUX_EADDRINUSE 98 -#define LINUX_EADDRNOTAVAIL 99 - -#define LINUX_ENETDOWN 100 -#define LINUX_ENETUNREACH 101 -#define LINUX_ENETRESET 102 -#define LINUX_ECONNABORTED 103 -#define LINUX_ECONNRESET 104 -#define LINUX_ENOBUFS 105 -#define LINUX_EISCONN 106 -#define LINUX_ENOTCONN 107 -#define LINUX_ESHUTDOWN 108 -#define LINUX_ETOOMANYREFS 109 - -#define LINUX_ETIMEDOUT 110 -#define LINUX_ECONNREFUSED 111 -#define LINUX_EHOSTDOWN 112 -#define LINUX_EHOSTUNREACH 113 -#define LINUX_EALREADY 114 -#define LINUX_EINPROGRESS 115 -#define LINUX_ESTALE 116 -#define LINUX_EUCLEAN 117 -#define LINUX_ENOTNAM 118 -#define LINUX_ENAVAIL 119 - -#define LINUX_EISNAM 120 -#define LINUX_EREMOTEIO 121 -#define LINUX_EDQUOT 122 -#define LINUX_ENOMEDIUM 123 -#define LINUX_EMEDIUMTYPE 124 -#define LINUX_ECANCELED 125 -#define LINUX_ENOKEY 126 -#define LINUX_EKEYEXPIRED 127 -#define LINUX_EKEYREVOKED 128 -#define LINUX_EKEYREJECTED 129 - -#define LINUX_EOWNERDEAD 130 -#define LINUX_ENOTRECOVERABLE 131 -#define LINUX_ERFKILL 132 -#define LINUX_EHWPOISON 133 - -#define LINUX_ELAST LINUX_EHWPOISON - -/* - * This is a special "internal" errno that must never be returned - * to a Linux process, but might be observed via ptrace(2). - */ -#define LINUX_ERESTARTSYS 512 - -#endif /* _LINUX_ERRNO_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020 The FreeBSD Foundation + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * 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. + */ + +#ifndef _LINUX_ERRNO_H_ +#define _LINUX_ERRNO_H_ + +#define LINUX_EPERM 1 +#define LINUX_ENOENT 2 +#define LINUX_ESRCH 3 +#define LINUX_EINTR 4 +#define LINUX_EIO 5 +#define LINUX_ENXIO 6 +#define LINUX_E2BIG 7 +#define LINUX_ENOEXEC 8 +#define LINUX_EBADF 9 + +#define LINUX_ECHILD 10 +#define LINUX_EAGAIN 11 +#define LINUX_ENOMEM 12 +#define LINUX_EACCES 13 +#define LINUX_EFAULT 14 +#define LINUX_ENOTBLK 15 +#define LINUX_EBUSY 16 +#define LINUX_EEXIST 17 +#define LINUX_EXDEV 18 +#define LINUX_ENODEV 19 + +#define LINUX_ENOTDIR 20 +#define LINUX_EISDIR 21 +#define LINUX_EINVAL 22 +#define LINUX_ENFILE 23 +#define LINUX_EMFILE 24 +#define LINUX_ENOTTY 25 +#define LINUX_ETXTBSY 26 +#define LINUX_EFBIG 27 +#define LINUX_ENOSPC 28 +#define LINUX_ESPIPE 29 + +#define LINUX_EROFS 30 +#define LINUX_EMLINK 31 +#define LINUX_EPIPE 32 +#define LINUX_EDOM 33 +#define LINUX_ERANGE 34 +#define LINUX_EDEADLK 35 +#define LINUX_ENAMETOOLONG 36 +#define LINUX_ENOLCK 37 +#define LINUX_ENOSYS 38 +#define LINUX_ENOTEMPTY 39 + +#define LINUX_ELOOP 40 +/* XXX: errno 41 is not defined in Linux. */ +#define LINUX_ENOMSG 42 +#define LINUX_EIDRM 43 +#define LINUX_ECHRNG 44 +#define LINUX_EL2NSYNC 45 +#define LINUX_EL3HLT 46 +#define LINUX_EL3RST 47 +#define LINUX_ELNRNG 48 +#define LINUX_EUNATCH 49 + +#define LINUX_ENOCSI 50 +#define LINUX_EL2HLT 51 +#define LINUX_EBADE 52 +#define LINUX_EBADR 53 +#define LINUX_EXFULL 54 +#define LINUX_ENOANO 55 +#define LINUX_EBADRQC 56 +#define LINUX_EBADSLT 57 +/* XXX: errno 58 is not defined in Linux. */ +#define LINUX_EBFONT 59 + +#define LINUX_ENOSTR 60 +#define LINUX_ENODATA 61 +#define LINUX_ENOTIME 62 +#define LINUX_ENOSR 63 +#define LINUX_ENONET 64 +#define LINUX_ENOPKG 65 +#define LINUX_EREMOTE 66 +#define LINUX_ENOLINK 67 +#define LINUX_EADV 68 +#define LINUX_ESRMNT 69 + +#define LINUX_ECOMM 70 +#define LINUX_EPROTO 71 +#define LINUX_EMULTIHOP 72 +#define LINUX_EDOTDOT 73 +#define LINUX_EBADMSG 74 +#define LINUX_EOVERFLOW 75 +#define LINUX_ENOTUNIQ 76 +#define LINUX_EBADFD 77 +#define LINUX_EREMCHG 78 +#define LINUX_ELIBACC 79 + +#define LINUX_ELIBBAD 80 +#define LINUX_ELIBSCN 81 +#define LINUX_ELIBMAX 82 +#define LINUX_ELIBEXEC 83 +#define LINUX_EILSEQ 84 +#define LINUX_ERESTART 85 +#define LINUX_ESTRPIPE 86 +#define LINUX_EUSERS 87 +#define LINUX_ENOTSOCK 88 +#define LINUX_EDESTADDRREQ 89 + +#define LINUX_EMSGSIZE 90 +#define LINUX_EPROTOTYPE 91 +#define LINUX_ENOPROTOOPT 92 +#define LINUX_EPROTONOTSUPPORT 93 +#define LINUX_ESOCKNOTSUPPORT 94 +#define LINUX_EOPNOTSUPPORT 95 +#define LINUX_EPFNOTSUPPORT 96 +#define LINUX_EAFNOTSUPPORT 97 +#define LINUX_EADDRINUSE 98 +#define LINUX_EADDRNOTAVAIL 99 + +#define LINUX_ENETDOWN 100 +#define LINUX_ENETUNREACH 101 +#define LINUX_ENETRESET 102 +#define LINUX_ECONNABORTED 103 +#define LINUX_ECONNRESET 104 +#define LINUX_ENOBUFS 105 +#define LINUX_EISCONN 106 +#define LINUX_ENOTCONN 107 +#define LINUX_ESHUTDOWN 108 +#define LINUX_ETOOMANYREFS 109 + +#define LINUX_ETIMEDOUT 110 +#define LINUX_ECONNREFUSED 111 +#define LINUX_EHOSTDOWN 112 +#define LINUX_EHOSTUNREACH 113 +#define LINUX_EALREADY 114 +#define LINUX_EINPROGRESS 115 +#define LINUX_ESTALE 116 +#define LINUX_EUCLEAN 117 +#define LINUX_ENOTNAM 118 +#define LINUX_ENAVAIL 119 + +#define LINUX_EISNAM 120 +#define LINUX_EREMOTEIO 121 +#define LINUX_EDQUOT 122 +#define LINUX_ENOMEDIUM 123 +#define LINUX_EMEDIUMTYPE 124 +#define LINUX_ECANCELED 125 +#define LINUX_ENOKEY 126 +#define LINUX_EKEYEXPIRED 127 +#define LINUX_EKEYREVOKED 128 +#define LINUX_EKEYREJECTED 129 + +#define LINUX_EOWNERDEAD 130 +#define LINUX_ENOTRECOVERABLE 131 +#define LINUX_ERFKILL 132 +#define LINUX_EHWPOISON 133 + +#define LINUX_ELAST LINUX_EHWPOISON + +/* + * This is a special "internal" errno that must never be returned + * to a Linux process, but might be observed via ptrace(2). + */ +#define LINUX_ERESTARTSYS 512 + +#endif /* _LINUX_ERRNO_H_ */ diff --git a/sys/compat/linux/linux_errno.inc b/sys/compat/linux/linux_errno.inc index 693338f9babc..bf0771c411ce 100644 --- a/sys/compat/linux/linux_errno.inc +++ b/sys/compat/linux/linux_errno.inc @@ -1,328 +1,328 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 1994-1996 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. - */ - -/* - * Linux syscalls return negative errno's, we do positive and map them - * Reference: - * FreeBSD: src/sys/sys/errno.h - * Linux: include/uapi/asm-generic/errno-base.h - * include/uapi/asm-generic/errno.h - * - * XXX: The "XXX" comments below should be replaced with rationale - * for the errno value chosen. - */ -static const int linux_errtbl[ELAST + 1] = { - /* [0, 9] */ - [0] = -0, - [EPERM] = -LINUX_EPERM, - [ENOENT] = -LINUX_ENOENT, - [ESRCH] = -LINUX_ESRCH, - [EINTR] = -LINUX_EINTR, - [EIO] = -LINUX_EIO, - [ENXIO] = -LINUX_ENXIO, - [E2BIG] = -LINUX_E2BIG, - [ENOEXEC] = -LINUX_ENOEXEC, - [EBADF] = -LINUX_EBADF, - - /* [10, 19] */ - [ECHILD] = -LINUX_ECHILD, - [EDEADLK] = -LINUX_EDEADLK, - [ENOMEM] = -LINUX_ENOMEM, - [EACCES] = -LINUX_EACCES, - [EFAULT] = -LINUX_EFAULT, - [ENOTBLK] = -LINUX_ENOTBLK, - [EBUSY] = -LINUX_EBUSY, - [EEXIST] = -LINUX_EEXIST, - [EXDEV] = -LINUX_EXDEV, - [ENODEV] = -LINUX_ENODEV, - - /* [20, 29] */ - [ENOTDIR] = -LINUX_ENOTDIR, - [EISDIR] = -LINUX_EISDIR, - [EINVAL] = -LINUX_EINVAL, - [ENFILE] = -LINUX_ENFILE, - [EMFILE] = -LINUX_EMFILE, - [ENOTTY] = -LINUX_ENOTTY, - [ETXTBSY] = -LINUX_ETXTBSY, - [EFBIG] = -LINUX_EFBIG, - [ENOSPC] = -LINUX_ENOSPC, - [ESPIPE] = -LINUX_ESPIPE, - - /* [30, 39] */ - [EROFS] = -LINUX_EROFS, - [EMLINK] = -LINUX_EMLINK, - [EPIPE] = -LINUX_EPIPE, - [EDOM] = -LINUX_EDOM, - [ERANGE] = -LINUX_ERANGE, - [EAGAIN] = -LINUX_EAGAIN, - [EINPROGRESS] = -LINUX_EINPROGRESS, - [EALREADY] = -LINUX_EALREADY, - [ENOTSOCK] = -LINUX_ENOTSOCK, - [EDESTADDRREQ] = -LINUX_EDESTADDRREQ, - - /* [40, 49] */ - [EMSGSIZE] = -LINUX_EMSGSIZE, - [EPROTOTYPE] = -LINUX_EPROTOTYPE, - [ENOPROTOOPT] = -LINUX_ENOPROTOOPT, - [EPROTONOSUPPORT] = -LINUX_EPROTONOTSUPPORT, - [ESOCKTNOSUPPORT] = -LINUX_ESOCKNOTSUPPORT, - [EOPNOTSUPP] = -LINUX_EOPNOTSUPPORT, - [EPFNOSUPPORT] = -LINUX_EPFNOTSUPPORT, - [EAFNOSUPPORT] = -LINUX_EAFNOTSUPPORT, - [EADDRINUSE] = -LINUX_EADDRINUSE, - [EADDRNOTAVAIL] = -LINUX_EADDRNOTAVAIL, - - /* [50, 59] */ - [ENETDOWN] = -LINUX_ENETDOWN, - [ENETUNREACH] = -LINUX_ENETUNREACH, - [ENETRESET] = -LINUX_ENETRESET, - [ECONNABORTED] = -LINUX_ECONNABORTED, - [ECONNRESET] = -LINUX_ECONNRESET, - [ENOBUFS] = -LINUX_ENOBUFS, - [EISCONN] = -LINUX_EISCONN, - [ENOTCONN] = -LINUX_ENOTCONN, - [ESHUTDOWN] = -LINUX_ESHUTDOWN, - [ETOOMANYREFS] = -LINUX_ETOOMANYREFS, - - /* [60, 69] */ - [ETIMEDOUT] = -LINUX_ETIMEDOUT, - [ECONNREFUSED] = -LINUX_ECONNREFUSED, - [ELOOP] = -LINUX_ELOOP, - [ENAMETOOLONG] = -LINUX_ENAMETOOLONG, - [EHOSTDOWN] = -LINUX_EHOSTDOWN, - [EHOSTUNREACH] = -LINUX_EHOSTUNREACH, - [ENOTEMPTY] = -LINUX_ENOTEMPTY, - [EPROCLIM] = -LINUX_EAGAIN, /* XXX */ - [EUSERS] = -LINUX_EUSERS, - [EDQUOT] = -LINUX_EDQUOT, - - /* [70, 79] */ - [ESTALE] = -LINUX_ESTALE, - [EREMOTE] = -LINUX_EREMOTE, - [EBADRPC] = -LINUX_ENXIO, /* XXX */ - [ERPCMISMATCH] = -LINUX_ENXIO, /* XXX */ - [EPROGUNAVAIL] = -LINUX_ENXIO, /* XXX */ - [EPROGMISMATCH] = -LINUX_ENXIO, /* XXX */ - [EPROCUNAVAIL] = -LINUX_ENXIO, /* XXX */ - [ENOLCK] = -LINUX_ENOLCK, - [ENOSYS] = -LINUX_ENOSYS, - [EFTYPE] = -LINUX_EBADF, /* XXX */ - - /* [80, 89] */ - [EAUTH] = -LINUX_ENXIO, /* XXX */ - [ENEEDAUTH] = -LINUX_ENXIO, /* XXX */ - [EIDRM] = -LINUX_EIDRM, - [ENOMSG] = -LINUX_ENOMSG, - [EOVERFLOW] = -LINUX_EOVERFLOW, - [ECANCELED] = -LINUX_ECANCELED, - [EILSEQ] = -LINUX_EILSEQ, - [ENOATTR] = -LINUX_ENODATA, /* XXX */ - [EDOOFUS] = -LINUX_EINVAL, /* XXX */ - [EBADMSG] = -LINUX_EBADMSG, - - /* [90, 99] */ - [EMULTIHOP] = -LINUX_EMULTIHOP, - [ENOLINK] = -LINUX_ENOLINK, - [EPROTO] = -LINUX_EPROTO, - [ENOTCAPABLE] = -LINUX_EPERM, /* XXX */ - [ECAPMODE] = -LINUX_EPERM, /* XXX */ - [ENOTRECOVERABLE] = -LINUX_ENOTRECOVERABLE, - [EOWNERDEAD] = -LINUX_EOWNERDEAD, - [EINTEGRITY] = -LINUX_EINVAL, /* XXX */ - [EPROT] = -LINUX_EINVAL, /* XXX */ -}; - -_Static_assert(ELAST == 98, - "missing errno entries in linux_errtbl"); - -static const int linux_to_bsd_errtbl[LINUX_ELAST + 1] = { - /* [0, 9] */ - [0] = 0, - [LINUX_EPERM] = EPERM, - [LINUX_ENOENT] = ENOENT, - [LINUX_ESRCH] = ESRCH, - [LINUX_EINTR] = EINTR, - [LINUX_EIO] = EIO, - [LINUX_ENXIO] = ENXIO, - [LINUX_E2BIG] = E2BIG, - [LINUX_ENOEXEC] = ENOENT, - [LINUX_EBADF] = EBADF, - - /* [10, 19] */ - [LINUX_ECHILD] = ECHILD, - [LINUX_EAGAIN] = EAGAIN, - [LINUX_ENOMEM] = ENOMEM, - [LINUX_EACCES] = EACCES, - [LINUX_EFAULT] = EFAULT, - [LINUX_ENOTBLK] = ENOTBLK, - [LINUX_EBUSY] = EBUSY, - [LINUX_EEXIST] = EEXIST, - [LINUX_EXDEV] = EXDEV, - [LINUX_ENODEV] = ENODEV, - - /* [20, 29] */ - [LINUX_ENOTDIR] = ENOTDIR, - [LINUX_EISDIR] = EISDIR, - [LINUX_EINVAL] = EINVAL, - [LINUX_ENFILE] = ENFILE, - [LINUX_EMFILE] = EMFILE, - [LINUX_ENOTTY] = ENOTTY, - [LINUX_ETXTBSY] = ETXTBSY, - [LINUX_EFBIG] = EFBIG, - [LINUX_ENOSPC] = ENOSPC, - [LINUX_ESPIPE] = ESPIPE, - - /* [30, 39] */ - [LINUX_EROFS] = EROFS, - [LINUX_EMLINK] = EMLINK, - [LINUX_EPIPE] = EPIPE, - [LINUX_EDOM] = EDOM, - [LINUX_ERANGE] = ERANGE, - [LINUX_EDEADLK] = EDEADLK, - [LINUX_ENAMETOOLONG] = ENAMETOOLONG, - [LINUX_ENOLCK] = ENOLCK, - [LINUX_ENOSYS] = ENOSYS, - [LINUX_ENOTEMPTY] = ENOTEMPTY, - - /* [40, 49] */ - [LINUX_ELOOP] = ELOOP, - [41] = EINVAL, - [LINUX_ENOMSG] = ENOMSG, - [LINUX_EIDRM] = EIDRM, - [LINUX_ECHRNG] = EINVAL, /* XXX */ - [LINUX_EL2NSYNC] = EINVAL, /* XXX */ - [LINUX_EL3HLT] = EINVAL, /* XXX */ - [LINUX_EL3RST] = EINVAL, /* XXX */ - [LINUX_ELNRNG] = EINVAL, /* XXX */ - [LINUX_EUNATCH] = EINVAL, /* XXX */ - - /* [50, 59] */ - [LINUX_ENOCSI] = EINVAL, /* XXX */ - [LINUX_EL2HLT] = EINVAL, /* XXX */ - [LINUX_EBADE] = EINVAL, /* XXX */ - [LINUX_EBADR] = EINVAL, /* XXX */ - [LINUX_EXFULL] = EINVAL, /* XXX */ - [LINUX_ENOANO] = EINVAL, /* XXX */ - [LINUX_EBADRQC] = EINVAL, /* XXX */ - [LINUX_EBADSLT] = EINVAL, /* XXX */ - [58] = EINVAL, - [LINUX_EBFONT] = EINVAL, /* XXX */ - - /* [60, 69] */ - [LINUX_ENOSTR] = EINVAL, /* XXX */ - [LINUX_ENODATA] = ENOATTR, /* XXX */ - [LINUX_ENOTIME] = EINVAL, /* XXX */ - [LINUX_ENOSR] = EINVAL, /* XXX */ - [LINUX_ENONET] = EINVAL, /* XXX */ - [LINUX_ENOPKG] = EINVAL, /* XXX */ - [LINUX_EREMOTE] = EREMOTE, - [LINUX_ENOLINK] = ENOLINK, - [LINUX_EADV] = EINVAL, /* XXX */ - [LINUX_ESRMNT] = EINVAL, /* XXX */ - - /* [70, 79] */ - [LINUX_ECOMM] = EINVAL, /* XXX */ - [LINUX_EPROTO] = EPROTO, - [LINUX_EMULTIHOP] = EMULTIHOP, - [LINUX_EDOTDOT] = EINVAL, /* XXX */ - [LINUX_EBADMSG] = EBADMSG, - [LINUX_EOVERFLOW] = EOVERFLOW, - [LINUX_ENOTUNIQ] = EINVAL, /* XXX */ - [LINUX_EBADFD] = EBADF, /* XXX */ - [LINUX_EREMCHG] = EINVAL, /* XXX */ - [LINUX_ELIBACC] = EINVAL, /* XXX */ - - /* [80, 89] */ - [LINUX_ELIBBAD] = EINVAL, /* XXX */ - [LINUX_ELIBSCN] = EINVAL, /* XXX */ - [LINUX_ELIBMAX] = EINVAL, /* XXX */ - [LINUX_ELIBEXEC] = EINVAL, /* XXX */ - [LINUX_EILSEQ] = EILSEQ, - [LINUX_ERESTART] = EAGAIN, /* XXX */ - [LINUX_ESTRPIPE] = EINVAL, /* XXX */ - [LINUX_EUSERS] = EUSERS, - [LINUX_ENOTSOCK] = ENOTSOCK, - [LINUX_EDESTADDRREQ] = EDESTADDRREQ, - - /* [90, 99] */ - [LINUX_EMSGSIZE] = EMSGSIZE, - [LINUX_EPROTOTYPE] = EPROTOTYPE, - [LINUX_ENOPROTOOPT] = ENOPROTOOPT, - [LINUX_EPROTONOTSUPPORT] = EPROTONOSUPPORT, - [LINUX_ESOCKNOTSUPPORT] = EPROTONOSUPPORT, /* XXX */ - [LINUX_EOPNOTSUPPORT] = EOPNOTSUPP, - [LINUX_EPFNOTSUPPORT] = EPFNOSUPPORT, - [LINUX_EAFNOTSUPPORT] = EAFNOSUPPORT, - [LINUX_EADDRINUSE] = EADDRINUSE, - [LINUX_EADDRNOTAVAIL] = EADDRNOTAVAIL, - - /* [100, 109] */ - [LINUX_ENETDOWN] = ENETDOWN, - [LINUX_ENETUNREACH] = ENETUNREACH, - [LINUX_ENETRESET] = ENETRESET, - [LINUX_ECONNABORTED] = ECONNABORTED, - [LINUX_ECONNRESET] = ECONNRESET, - [LINUX_ENOBUFS] = ENOBUFS, - [LINUX_EISCONN] = EISCONN, - [LINUX_ENOTCONN] = ENOTCONN, - [LINUX_ESHUTDOWN] = ESHUTDOWN, - [LINUX_ETOOMANYREFS] = ETOOMANYREFS, - - /* [110, 119] */ - [LINUX_ETIMEDOUT] = ETIMEDOUT, - [LINUX_ECONNREFUSED] = ECONNREFUSED, - [LINUX_EHOSTDOWN] = EHOSTDOWN, - [LINUX_EHOSTUNREACH] = EHOSTUNREACH, - [LINUX_EALREADY] = EALREADY, - [LINUX_EINPROGRESS] = EINPROGRESS, - [LINUX_ESTALE] = ESTALE, - [LINUX_EUCLEAN] = EINVAL, /* XXX */ - [LINUX_ENOTNAM] = EINVAL, /* XXX */ - [LINUX_ENAVAIL] = EINVAL, /* XXX */ - - /* [120, 129] */ - [LINUX_EISNAM] = EINVAL, /* XXX */ - [LINUX_EREMOTEIO] = EINVAL, /* XXX */ - [LINUX_EDQUOT] = EDQUOT, - [LINUX_ENOMEDIUM] = EIO, /* XXX */ - [LINUX_EMEDIUMTYPE] = EIO, /* XXX */ - [LINUX_ECANCELED] = ECANCELED, - [LINUX_ENOKEY] = EIO, /* XXX */ - [LINUX_EKEYEXPIRED] = EIO, /* XXX */ - [LINUX_EKEYREVOKED] = EIO, /* XXX */ - [LINUX_EKEYREJECTED] = EIO, /* XXX */ - - /* [130, 139] */ - [LINUX_EOWNERDEAD] = EOWNERDEAD, - [LINUX_ENOTRECOVERABLE] = ENOTRECOVERABLE, - [LINUX_ERFKILL] = ENETDOWN, /* XXX */ - [LINUX_EHWPOISON] = EINVAL, /* XXX */ -}; - -_Static_assert(LINUX_ELAST == 133, - "missing errno entries in linux_to_bsd_errtbl"); +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1994-1996 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. + */ + +/* + * Linux syscalls return negative errno's, we do positive and map them + * Reference: + * FreeBSD: src/sys/sys/errno.h + * Linux: include/uapi/asm-generic/errno-base.h + * include/uapi/asm-generic/errno.h + * + * XXX: The "XXX" comments below should be replaced with rationale + * for the errno value chosen. + */ +static const int linux_errtbl[ELAST + 1] = { + /* [0, 9] */ + [0] = -0, + [EPERM] = -LINUX_EPERM, + [ENOENT] = -LINUX_ENOENT, + [ESRCH] = -LINUX_ESRCH, + [EINTR] = -LINUX_EINTR, + [EIO] = -LINUX_EIO, + [ENXIO] = -LINUX_ENXIO, + [E2BIG] = -LINUX_E2BIG, + [ENOEXEC] = -LINUX_ENOEXEC, + [EBADF] = -LINUX_EBADF, + + /* [10, 19] */ + [ECHILD] = -LINUX_ECHILD, + [EDEADLK] = -LINUX_EDEADLK, + [ENOMEM] = -LINUX_ENOMEM, + [EACCES] = -LINUX_EACCES, + [EFAULT] = -LINUX_EFAULT, + [ENOTBLK] = -LINUX_ENOTBLK, + [EBUSY] = -LINUX_EBUSY, + [EEXIST] = -LINUX_EEXIST, + [EXDEV] = -LINUX_EXDEV, + [ENODEV] = -LINUX_ENODEV, + + /* [20, 29] */ + [ENOTDIR] = -LINUX_ENOTDIR, + [EISDIR] = -LINUX_EISDIR, + [EINVAL] = -LINUX_EINVAL, + [ENFILE] = -LINUX_ENFILE, + [EMFILE] = -LINUX_EMFILE, + [ENOTTY] = -LINUX_ENOTTY, + [ETXTBSY] = -LINUX_ETXTBSY, + [EFBIG] = -LINUX_EFBIG, + [ENOSPC] = -LINUX_ENOSPC, + [ESPIPE] = -LINUX_ESPIPE, + + /* [30, 39] */ + [EROFS] = -LINUX_EROFS, + [EMLINK] = -LINUX_EMLINK, + [EPIPE] = -LINUX_EPIPE, + [EDOM] = -LINUX_EDOM, + [ERANGE] = -LINUX_ERANGE, + [EAGAIN] = -LINUX_EAGAIN, + [EINPROGRESS] = -LINUX_EINPROGRESS, + [EALREADY] = -LINUX_EALREADY, + [ENOTSOCK] = -LINUX_ENOTSOCK, + [EDESTADDRREQ] = -LINUX_EDESTADDRREQ, + + /* [40, 49] */ + [EMSGSIZE] = -LINUX_EMSGSIZE, + [EPROTOTYPE] = -LINUX_EPROTOTYPE, + [ENOPROTOOPT] = -LINUX_ENOPROTOOPT, + [EPROTONOSUPPORT] = -LINUX_EPROTONOTSUPPORT, + [ESOCKTNOSUPPORT] = -LINUX_ESOCKNOTSUPPORT, + [EOPNOTSUPP] = -LINUX_EOPNOTSUPPORT, + [EPFNOSUPPORT] = -LINUX_EPFNOTSUPPORT, + [EAFNOSUPPORT] = -LINUX_EAFNOTSUPPORT, + [EADDRINUSE] = -LINUX_EADDRINUSE, + [EADDRNOTAVAIL] = -LINUX_EADDRNOTAVAIL, + + /* [50, 59] */ + [ENETDOWN] = -LINUX_ENETDOWN, + [ENETUNREACH] = -LINUX_ENETUNREACH, + [ENETRESET] = -LINUX_ENETRESET, + [ECONNABORTED] = -LINUX_ECONNABORTED, + [ECONNRESET] = -LINUX_ECONNRESET, + [ENOBUFS] = -LINUX_ENOBUFS, + [EISCONN] = -LINUX_EISCONN, + [ENOTCONN] = -LINUX_ENOTCONN, + [ESHUTDOWN] = -LINUX_ESHUTDOWN, + [ETOOMANYREFS] = -LINUX_ETOOMANYREFS, + + /* [60, 69] */ + [ETIMEDOUT] = -LINUX_ETIMEDOUT, + [ECONNREFUSED] = -LINUX_ECONNREFUSED, + [ELOOP] = -LINUX_ELOOP, + [ENAMETOOLONG] = -LINUX_ENAMETOOLONG, + [EHOSTDOWN] = -LINUX_EHOSTDOWN, + [EHOSTUNREACH] = -LINUX_EHOSTUNREACH, + [ENOTEMPTY] = -LINUX_ENOTEMPTY, + [EPROCLIM] = -LINUX_EAGAIN, /* XXX */ + [EUSERS] = -LINUX_EUSERS, + [EDQUOT] = -LINUX_EDQUOT, + + /* [70, 79] */ + [ESTALE] = -LINUX_ESTALE, + [EREMOTE] = -LINUX_EREMOTE, + [EBADRPC] = -LINUX_ENXIO, /* XXX */ + [ERPCMISMATCH] = -LINUX_ENXIO, /* XXX */ + [EPROGUNAVAIL] = -LINUX_ENXIO, /* XXX */ + [EPROGMISMATCH] = -LINUX_ENXIO, /* XXX */ + [EPROCUNAVAIL] = -LINUX_ENXIO, /* XXX */ + [ENOLCK] = -LINUX_ENOLCK, + [ENOSYS] = -LINUX_ENOSYS, + [EFTYPE] = -LINUX_EBADF, /* XXX */ + + /* [80, 89] */ + [EAUTH] = -LINUX_ENXIO, /* XXX */ + [ENEEDAUTH] = -LINUX_ENXIO, /* XXX */ + [EIDRM] = -LINUX_EIDRM, + [ENOMSG] = -LINUX_ENOMSG, + [EOVERFLOW] = -LINUX_EOVERFLOW, + [ECANCELED] = -LINUX_ECANCELED, + [EILSEQ] = -LINUX_EILSEQ, + [ENOATTR] = -LINUX_ENODATA, /* XXX */ + [EDOOFUS] = -LINUX_EINVAL, /* XXX */ + [EBADMSG] = -LINUX_EBADMSG, + + /* [90, 99] */ + [EMULTIHOP] = -LINUX_EMULTIHOP, + [ENOLINK] = -LINUX_ENOLINK, + [EPROTO] = -LINUX_EPROTO, + [ENOTCAPABLE] = -LINUX_EPERM, /* XXX */ + [ECAPMODE] = -LINUX_EPERM, /* XXX */ + [ENOTRECOVERABLE] = -LINUX_ENOTRECOVERABLE, + [EOWNERDEAD] = -LINUX_EOWNERDEAD, + [EINTEGRITY] = -LINUX_EINVAL, /* XXX */ + [EPROT] = -LINUX_EINVAL, /* XXX */ +}; + +_Static_assert(ELAST == 98, + "missing errno entries in linux_errtbl"); + +static const int linux_to_bsd_errtbl[LINUX_ELAST + 1] = { + /* [0, 9] */ + [0] = 0, + [LINUX_EPERM] = EPERM, + [LINUX_ENOENT] = ENOENT, + [LINUX_ESRCH] = ESRCH, + [LINUX_EINTR] = EINTR, + [LINUX_EIO] = EIO, + [LINUX_ENXIO] = ENXIO, + [LINUX_E2BIG] = E2BIG, + [LINUX_ENOEXEC] = ENOENT, + [LINUX_EBADF] = EBADF, + + /* [10, 19] */ + [LINUX_ECHILD] = ECHILD, + [LINUX_EAGAIN] = EAGAIN, + [LINUX_ENOMEM] = ENOMEM, + [LINUX_EACCES] = EACCES, + [LINUX_EFAULT] = EFAULT, + [LINUX_ENOTBLK] = ENOTBLK, + [LINUX_EBUSY] = EBUSY, + [LINUX_EEXIST] = EEXIST, + [LINUX_EXDEV] = EXDEV, + [LINUX_ENODEV] = ENODEV, + + /* [20, 29] */ + [LINUX_ENOTDIR] = ENOTDIR, + [LINUX_EISDIR] = EISDIR, + [LINUX_EINVAL] = EINVAL, + [LINUX_ENFILE] = ENFILE, + [LINUX_EMFILE] = EMFILE, + [LINUX_ENOTTY] = ENOTTY, + [LINUX_ETXTBSY] = ETXTBSY, + [LINUX_EFBIG] = EFBIG, + [LINUX_ENOSPC] = ENOSPC, + [LINUX_ESPIPE] = ESPIPE, + + /* [30, 39] */ + [LINUX_EROFS] = EROFS, + [LINUX_EMLINK] = EMLINK, + [LINUX_EPIPE] = EPIPE, + [LINUX_EDOM] = EDOM, + [LINUX_ERANGE] = ERANGE, + [LINUX_EDEADLK] = EDEADLK, + [LINUX_ENAMETOOLONG] = ENAMETOOLONG, + [LINUX_ENOLCK] = ENOLCK, + [LINUX_ENOSYS] = ENOSYS, + [LINUX_ENOTEMPTY] = ENOTEMPTY, + + /* [40, 49] */ + [LINUX_ELOOP] = ELOOP, + [41] = EINVAL, + [LINUX_ENOMSG] = ENOMSG, + [LINUX_EIDRM] = EIDRM, + [LINUX_ECHRNG] = EINVAL, /* XXX */ + [LINUX_EL2NSYNC] = EINVAL, /* XXX */ + [LINUX_EL3HLT] = EINVAL, /* XXX */ + [LINUX_EL3RST] = EINVAL, /* XXX */ + [LINUX_ELNRNG] = EINVAL, /* XXX */ + [LINUX_EUNATCH] = EINVAL, /* XXX */ + + /* [50, 59] */ + [LINUX_ENOCSI] = EINVAL, /* XXX */ + [LINUX_EL2HLT] = EINVAL, /* XXX */ + [LINUX_EBADE] = EINVAL, /* XXX */ + [LINUX_EBADR] = EINVAL, /* XXX */ + [LINUX_EXFULL] = EINVAL, /* XXX */ + [LINUX_ENOANO] = EINVAL, /* XXX */ + [LINUX_EBADRQC] = EINVAL, /* XXX */ + [LINUX_EBADSLT] = EINVAL, /* XXX */ + [58] = EINVAL, + [LINUX_EBFONT] = EINVAL, /* XXX */ + + /* [60, 69] */ + [LINUX_ENOSTR] = EINVAL, /* XXX */ + [LINUX_ENODATA] = ENOATTR, /* XXX */ + [LINUX_ENOTIME] = EINVAL, /* XXX */ + [LINUX_ENOSR] = EINVAL, /* XXX */ + [LINUX_ENONET] = EINVAL, /* XXX */ + [LINUX_ENOPKG] = EINVAL, /* XXX */ + [LINUX_EREMOTE] = EREMOTE, + [LINUX_ENOLINK] = ENOLINK, + [LINUX_EADV] = EINVAL, /* XXX */ + [LINUX_ESRMNT] = EINVAL, /* XXX */ + + /* [70, 79] */ + [LINUX_ECOMM] = EINVAL, /* XXX */ + [LINUX_EPROTO] = EPROTO, + [LINUX_EMULTIHOP] = EMULTIHOP, + [LINUX_EDOTDOT] = EINVAL, /* XXX */ + [LINUX_EBADMSG] = EBADMSG, + [LINUX_EOVERFLOW] = EOVERFLOW, + [LINUX_ENOTUNIQ] = EINVAL, /* XXX */ + [LINUX_EBADFD] = EBADF, /* XXX */ + [LINUX_EREMCHG] = EINVAL, /* XXX */ + [LINUX_ELIBACC] = EINVAL, /* XXX */ + + /* [80, 89] */ + [LINUX_ELIBBAD] = EINVAL, /* XXX */ + [LINUX_ELIBSCN] = EINVAL, /* XXX */ + [LINUX_ELIBMAX] = EINVAL, /* XXX */ + [LINUX_ELIBEXEC] = EINVAL, /* XXX */ + [LINUX_EILSEQ] = EILSEQ, + [LINUX_ERESTART] = EAGAIN, /* XXX */ + [LINUX_ESTRPIPE] = EINVAL, /* XXX */ + [LINUX_EUSERS] = EUSERS, + [LINUX_ENOTSOCK] = ENOTSOCK, + [LINUX_EDESTADDRREQ] = EDESTADDRREQ, + + /* [90, 99] */ + [LINUX_EMSGSIZE] = EMSGSIZE, + [LINUX_EPROTOTYPE] = EPROTOTYPE, + [LINUX_ENOPROTOOPT] = ENOPROTOOPT, + [LINUX_EPROTONOTSUPPORT] = EPROTONOSUPPORT, + [LINUX_ESOCKNOTSUPPORT] = EPROTONOSUPPORT, /* XXX */ + [LINUX_EOPNOTSUPPORT] = EOPNOTSUPP, + [LINUX_EPFNOTSUPPORT] = EPFNOSUPPORT, + [LINUX_EAFNOTSUPPORT] = EAFNOSUPPORT, + [LINUX_EADDRINUSE] = EADDRINUSE, + [LINUX_EADDRNOTAVAIL] = EADDRNOTAVAIL, + + /* [100, 109] */ + [LINUX_ENETDOWN] = ENETDOWN, + [LINUX_ENETUNREACH] = ENETUNREACH, + [LINUX_ENETRESET] = ENETRESET, + [LINUX_ECONNABORTED] = ECONNABORTED, + [LINUX_ECONNRESET] = ECONNRESET, + [LINUX_ENOBUFS] = ENOBUFS, + [LINUX_EISCONN] = EISCONN, + [LINUX_ENOTCONN] = ENOTCONN, + [LINUX_ESHUTDOWN] = ESHUTDOWN, + [LINUX_ETOOMANYREFS] = ETOOMANYREFS, + + /* [110, 119] */ + [LINUX_ETIMEDOUT] = ETIMEDOUT, + [LINUX_ECONNREFUSED] = ECONNREFUSED, + [LINUX_EHOSTDOWN] = EHOSTDOWN, + [LINUX_EHOSTUNREACH] = EHOSTUNREACH, + [LINUX_EALREADY] = EALREADY, + [LINUX_EINPROGRESS] = EINPROGRESS, + [LINUX_ESTALE] = ESTALE, + [LINUX_EUCLEAN] = EINVAL, /* XXX */ + [LINUX_ENOTNAM] = EINVAL, /* XXX */ + [LINUX_ENAVAIL] = EINVAL, /* XXX */ + + /* [120, 129] */ + [LINUX_EISNAM] = EINVAL, /* XXX */ + [LINUX_EREMOTEIO] = EINVAL, /* XXX */ + [LINUX_EDQUOT] = EDQUOT, + [LINUX_ENOMEDIUM] = EIO, /* XXX */ + [LINUX_EMEDIUMTYPE] = EIO, /* XXX */ + [LINUX_ECANCELED] = ECANCELED, + [LINUX_ENOKEY] = EIO, /* XXX */ + [LINUX_EKEYEXPIRED] = EIO, /* XXX */ + [LINUX_EKEYREVOKED] = EIO, /* XXX */ + [LINUX_EKEYREJECTED] = EIO, /* XXX */ + + /* [130, 139] */ + [LINUX_EOWNERDEAD] = EOWNERDEAD, + [LINUX_ENOTRECOVERABLE] = ENOTRECOVERABLE, + [LINUX_ERFKILL] = ENETDOWN, /* XXX */ + [LINUX_EHWPOISON] = EINVAL, /* XXX */ +}; + +_Static_assert(LINUX_ELAST == 133, + "missing errno entries in linux_to_bsd_errtbl"); diff --git a/sys/compat/linux/linux_event.c b/sys/compat/linux/linux_event.c index e88791659f1f..fb104444f340 100644 --- a/sys/compat/linux/linux_event.c +++ b/sys/compat/linux/linux_event.c @@ -1,716 +1,719 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2007 Roman Divacky - * Copyright (c) 2014 Dmitry Chagin - * - * 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 -#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 -#else -#include -#include -#endif - -#include -#include -#include -#include -#include -#include - -typedef uint64_t epoll_udata_t; - -struct epoll_event { - uint32_t events; - epoll_udata_t data; -} -#if defined(__amd64__) -__attribute__((packed)) -#endif -; - -#define LINUX_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) - -static int epoll_to_kevent(struct thread *td, int fd, - struct epoll_event *l_event, struct kevent *kevent, - int *nkevents); -static void kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event); -static int epoll_kev_copyout(void *arg, struct kevent *kevp, int count); -static int epoll_kev_copyin(void *arg, struct kevent *kevp, int count); -static int epoll_register_kevent(struct thread *td, struct file *epfp, - int fd, int filter, unsigned int flags); -static int epoll_fd_registered(struct thread *td, struct file *epfp, - int fd); -static int epoll_delete_all_events(struct thread *td, struct file *epfp, - int fd); - -struct epoll_copyin_args { - struct kevent *changelist; -}; - -struct epoll_copyout_args { - struct epoll_event *leventlist; - struct proc *p; - uint32_t count; - int error; -}; - -static int -epoll_create_common(struct thread *td, int flags) -{ - - return (kern_kqueue(td, flags, NULL)); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_epoll_create(struct thread *td, struct linux_epoll_create_args *args) -{ - - /* - * args->size is unused. Linux just tests it - * and then forgets it as well. - */ - if (args->size <= 0) - return (EINVAL); - - return (epoll_create_common(td, 0)); -} -#endif - -int -linux_epoll_create1(struct thread *td, struct linux_epoll_create1_args *args) -{ - int flags; - - if ((args->flags & ~(LINUX_O_CLOEXEC)) != 0) - return (EINVAL); - - flags = 0; - if ((args->flags & LINUX_O_CLOEXEC) != 0) - flags |= O_CLOEXEC; - - return (epoll_create_common(td, flags)); -} - -/* Structure converting function from epoll to kevent. */ -static int -epoll_to_kevent(struct thread *td, int fd, struct epoll_event *l_event, - struct kevent *kevent, int *nkevents) -{ - uint32_t levents = l_event->events; - struct linux_pemuldata *pem; - struct proc *p; - unsigned short kev_flags = EV_ADD | EV_ENABLE; - - /* flags related to how event is registered */ - if ((levents & LINUX_EPOLLONESHOT) != 0) - kev_flags |= EV_DISPATCH; - if ((levents & LINUX_EPOLLET) != 0) - kev_flags |= EV_CLEAR; - if ((levents & LINUX_EPOLLERR) != 0) - kev_flags |= EV_ERROR; - if ((levents & LINUX_EPOLLRDHUP) != 0) - kev_flags |= EV_EOF; - - /* flags related to what event is registered */ - if ((levents & LINUX_EPOLL_EVRD) != 0) { - EV_SET(kevent, fd, EVFILT_READ, kev_flags, 0, 0, 0); - kevent->ext[0] = l_event->data; - ++kevent; - ++(*nkevents); - } - if ((levents & LINUX_EPOLL_EVWR) != 0) { - EV_SET(kevent, fd, EVFILT_WRITE, kev_flags, 0, 0, 0); - kevent->ext[0] = l_event->data; - ++kevent; - ++(*nkevents); - } - /* zero event mask is legal */ - if ((levents & (LINUX_EPOLL_EVRD | LINUX_EPOLL_EVWR)) == 0) { - EV_SET(kevent++, fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, 0); - ++(*nkevents); - } - - if ((levents & ~(LINUX_EPOLL_EVSUP)) != 0) { - p = td->td_proc; - - pem = pem_find(p); - KASSERT(pem != NULL, ("epoll proc emuldata not found.\n")); - - LINUX_PEM_XLOCK(pem); - if ((pem->flags & LINUX_XUNSUP_EPOLL) == 0) { - pem->flags |= LINUX_XUNSUP_EPOLL; - LINUX_PEM_XUNLOCK(pem); - linux_msg(td, "epoll_ctl unsupported flags: 0x%x", - levents); - } else - LINUX_PEM_XUNLOCK(pem); - return (EINVAL); - } - - return (0); -} - -/* - * Structure converting function from kevent to epoll. In a case - * this is called on error in registration we store the error in - * event->data and pick it up later in linux_epoll_ctl(). - */ -static void -kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event) -{ - - l_event->data = kevent->ext[0]; - - if ((kevent->flags & EV_ERROR) != 0) { - l_event->events = LINUX_EPOLLERR; - return; - } - - /* XXX EPOLLPRI, EPOLLHUP */ - switch (kevent->filter) { - case EVFILT_READ: - l_event->events = LINUX_EPOLLIN; - if ((kevent->flags & EV_EOF) != 0) - l_event->events |= LINUX_EPOLLRDHUP; - break; - case EVFILT_WRITE: - l_event->events = LINUX_EPOLLOUT; - break; - } -} - -/* - * Copyout callback used by kevent. This converts kevent - * events to epoll events and copies them back to the - * userspace. This is also called on error on registering - * of the filter. - */ -static int -epoll_kev_copyout(void *arg, struct kevent *kevp, int count) -{ - struct epoll_copyout_args *args; - struct epoll_event *eep; - int error, i; - - args = (struct epoll_copyout_args*) arg; - eep = malloc(sizeof(*eep) * count, M_EPOLL, M_WAITOK | M_ZERO); - - for (i = 0; i < count; i++) - kevent_to_epoll(&kevp[i], &eep[i]); - - error = copyout(eep, args->leventlist, count * sizeof(*eep)); - if (error == 0) { - args->leventlist += count; - args->count += count; - } else if (args->error == 0) - args->error = error; - - free(eep, M_EPOLL); - return (error); -} - -/* - * Copyin callback used by kevent. This copies already - * converted filters from kernel memory to the kevent - * internal kernel memory. Hence the memcpy instead of - * copyin. - */ -static int -epoll_kev_copyin(void *arg, struct kevent *kevp, int count) -{ - struct epoll_copyin_args *args; - - args = (struct epoll_copyin_args*) arg; - - memcpy(kevp, args->changelist, count * sizeof(*kevp)); - args->changelist += count; - - return (0); -} - -/* - * Load epoll filter, convert it to kevent filter - * and load it into kevent subsystem. - */ -int -linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args) -{ - struct file *epfp, *fp; - struct epoll_copyin_args ciargs; - struct kevent kev[2]; - struct kevent_copyops k_ops = { &ciargs, - NULL, - epoll_kev_copyin}; - struct epoll_event le; - cap_rights_t rights; - int nchanges = 0; - int error; - - if (args->op != LINUX_EPOLL_CTL_DEL) { - error = copyin(args->event, &le, sizeof(le)); - if (error != 0) - return (error); - } - - error = fget(td, args->epfd, - cap_rights_init_one(&rights, CAP_KQUEUE_CHANGE), &epfp); - if (error != 0) - return (error); - if (epfp->f_type != DTYPE_KQUEUE) { - error = EINVAL; - goto leave1; - } - - /* Protect user data vector from incorrectly supplied fd. */ - error = fget(td, args->fd, - cap_rights_init_one(&rights, CAP_POLL_EVENT), &fp); - if (error != 0) - goto leave1; - - /* Linux disallows spying on himself */ - if (epfp == fp) { - error = EINVAL; - goto leave0; - } - - ciargs.changelist = kev; - - if (args->op != LINUX_EPOLL_CTL_DEL) { - error = epoll_to_kevent(td, args->fd, &le, kev, &nchanges); - if (error != 0) - goto leave0; - } - - switch (args->op) { - case LINUX_EPOLL_CTL_MOD: - error = epoll_delete_all_events(td, epfp, args->fd); - if (error != 0) - goto leave0; - break; - - case LINUX_EPOLL_CTL_ADD: - if (epoll_fd_registered(td, epfp, args->fd)) { - error = EEXIST; - goto leave0; - } - break; - - case LINUX_EPOLL_CTL_DEL: - /* CTL_DEL means unregister this fd with this epoll */ - error = epoll_delete_all_events(td, epfp, args->fd); - goto leave0; - - default: - error = EINVAL; - goto leave0; - } - - error = kern_kevent_fp(td, epfp, nchanges, 0, &k_ops, NULL); - -leave0: - fdrop(fp, td); - -leave1: - fdrop(epfp, td); - return (error); -} - -/* - * Wait for a filter to be triggered on the epoll file descriptor. - */ - -static int -linux_epoll_wait_ts(struct thread *td, int epfd, struct epoll_event *events, - int maxevents, struct timespec *tsp, sigset_t *uset) -{ - struct epoll_copyout_args coargs; - struct kevent_copyops k_ops = { &coargs, - epoll_kev_copyout, - NULL}; - cap_rights_t rights; - struct file *epfp; - sigset_t omask; - int error; - - if (maxevents <= 0 || maxevents > LINUX_MAX_EVENTS) - return (EINVAL); - - error = fget(td, epfd, - cap_rights_init_one(&rights, CAP_KQUEUE_EVENT), &epfp); - if (error != 0) - return (error); - if (epfp->f_type != DTYPE_KQUEUE) { - error = EINVAL; - goto leave; - } - if (uset != NULL) { - error = kern_sigprocmask(td, SIG_SETMASK, uset, - &omask, 0); - if (error != 0) - goto leave; - td->td_pflags |= TDP_OLDMASK; - /* - * Make sure that ast() is called on return to - * usermode and TDP_OLDMASK is cleared, restoring old - * sigmask. - */ - ast_sched(td, TDA_SIGSUSPEND); - } - - coargs.leventlist = events; - coargs.p = td->td_proc; - coargs.count = 0; - coargs.error = 0; - - error = kern_kevent_fp(td, epfp, 0, maxevents, &k_ops, tsp); - if (error == 0 && coargs.error != 0) - error = coargs.error; - - /* - * kern_kevent might return ENOMEM which is not expected from epoll_wait. - * Maybe we should translate that but I don't think it matters at all. - */ - if (error == 0) - td->td_retval[0] = coargs.count; - - if (uset != NULL) - error = kern_sigprocmask(td, SIG_SETMASK, &omask, - NULL, 0); -leave: - fdrop(epfp, td); - return (error); -} - -static int -linux_epoll_wait_common(struct thread *td, int epfd, struct epoll_event *events, - int maxevents, int timeout, sigset_t *uset) -{ - struct timespec ts, *tsp; - - /* - * Linux epoll_wait(2) man page states that timeout of -1 causes caller - * to block indefinitely. Real implementation does it if any negative - * timeout value is passed. - */ - if (timeout >= 0) { - /* Convert from milliseconds to timespec. */ - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - tsp = &ts; - } else { - tsp = NULL; - } - return (linux_epoll_wait_ts(td, epfd, events, maxevents, tsp, uset)); - -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_epoll_wait(struct thread *td, struct linux_epoll_wait_args *args) -{ - - return (linux_epoll_wait_common(td, args->epfd, args->events, - args->maxevents, args->timeout, NULL)); -} -#endif - -int -linux_epoll_pwait(struct thread *td, struct linux_epoll_pwait_args *args) -{ - sigset_t mask, *pmask; - int error; - - error = linux_copyin_sigset(td, args->mask, sizeof(l_sigset_t), - &mask, &pmask); - if (error != 0) - return (error); - - return (linux_epoll_wait_common(td, args->epfd, args->events, - args->maxevents, args->timeout, pmask)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_epoll_pwait2_64(struct thread *td, struct linux_epoll_pwait2_64_args *args) -{ - struct timespec ts, *tsa; - sigset_t mask, *pmask; - int error; - - error = linux_copyin_sigset(td, args->mask, sizeof(l_sigset_t), - &mask, &pmask); - if (error != 0) - return (error); - - if (args->timeout) { - error = linux_get_timespec64(&ts, args->timeout); - if (error != 0) - return (error); - tsa = &ts; - } else - tsa = NULL; - - return (linux_epoll_wait_ts(td, args->epfd, args->events, - args->maxevents, tsa, pmask)); -} -#else -int -linux_epoll_pwait2(struct thread *td, struct linux_epoll_pwait2_args *args) -{ - struct timespec ts, *tsa; - sigset_t mask, *pmask; - int error; - - error = linux_copyin_sigset(td, args->mask, sizeof(l_sigset_t), - &mask, &pmask); - if (error != 0) - return (error); - - if (args->timeout) { - error = linux_get_timespec(&ts, args->timeout); - if (error != 0) - return (error); - tsa = &ts; - } else - tsa = NULL; - - return (linux_epoll_wait_ts(td, args->epfd, args->events, - args->maxevents, tsa, pmask)); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -static int -epoll_register_kevent(struct thread *td, struct file *epfp, int fd, int filter, - unsigned int flags) -{ - struct epoll_copyin_args ciargs; - struct kevent kev; - struct kevent_copyops k_ops = { &ciargs, - NULL, - epoll_kev_copyin}; - - ciargs.changelist = &kev; - EV_SET(&kev, fd, filter, flags, 0, 0, 0); - - return (kern_kevent_fp(td, epfp, 1, 0, &k_ops, NULL)); -} - -static int -epoll_fd_registered(struct thread *td, struct file *epfp, int fd) -{ - /* - * Set empty filter flags to avoid accidental modification of already - * registered events. In the case of event re-registration: - * 1. If event does not exists kevent() does nothing and returns ENOENT - * 2. If event does exists, it's enabled/disabled state is preserved - * but fflags, data and udata fields are overwritten. So we can not - * set socket lowats and store user's context pointer in udata. - */ - if (epoll_register_kevent(td, epfp, fd, EVFILT_READ, 0) != ENOENT || - epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, 0) != ENOENT) - return (1); - - return (0); -} - -static int -epoll_delete_all_events(struct thread *td, struct file *epfp, int fd) -{ - int error1, error2; - - error1 = epoll_register_kevent(td, epfp, fd, EVFILT_READ, EV_DELETE); - error2 = epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, EV_DELETE); - - /* return 0 if at least one result positive */ - return (error1 == 0 ? 0 : error2); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_eventfd(struct thread *td, struct linux_eventfd_args *args) -{ - struct specialfd_eventfd ae; - - bzero(&ae, sizeof(ae)); - ae.initval = args->initval; - return (kern_specialfd(td, SPECIALFD_EVENTFD, &ae)); -} -#endif - -int -linux_eventfd2(struct thread *td, struct linux_eventfd2_args *args) -{ - struct specialfd_eventfd ae; - int flags; - - if ((args->flags & ~(LINUX_O_CLOEXEC | LINUX_O_NONBLOCK | - LINUX_EFD_SEMAPHORE)) != 0) - return (EINVAL); - flags = 0; - if ((args->flags & LINUX_O_CLOEXEC) != 0) - flags |= EFD_CLOEXEC; - if ((args->flags & LINUX_O_NONBLOCK) != 0) - flags |= EFD_NONBLOCK; - if ((args->flags & LINUX_EFD_SEMAPHORE) != 0) - flags |= EFD_SEMAPHORE; - - bzero(&ae, sizeof(ae)); - ae.flags = flags; - ae.initval = args->initval; - return (kern_specialfd(td, SPECIALFD_EVENTFD, &ae)); -} - -int -linux_timerfd_create(struct thread *td, struct linux_timerfd_create_args *args) -{ - clockid_t clockid; - int error, flags; - - error = linux_to_native_clockid(&clockid, args->clockid); - if (error != 0) - return (error); - flags = 0; - if ((args->flags & LINUX_TFD_CLOEXEC) != 0) - flags |= O_CLOEXEC; - if ((args->flags & LINUX_TFD_NONBLOCK) != 0) - flags |= TFD_NONBLOCK; - - return (kern_timerfd_create(td, clockid, flags)); -} - -int -linux_timerfd_gettime(struct thread *td, struct linux_timerfd_gettime_args *args) -{ - struct l_itimerspec lots; - struct itimerspec ots; - int error; - - error = kern_timerfd_gettime(td, args->fd, &ots); - if (error != 0) - return (error); - - error = native_to_linux_itimerspec(&lots, &ots); - if (error == 0) - error = copyout(&lots, args->old_value, sizeof(lots)); - - return (error); -} - -int -linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args) -{ - struct l_itimerspec lots; - struct itimerspec nts, ots; - int error; - - error = copyin(args->new_value, &lots, sizeof(lots)); - if (error != 0) - return (error); - error = linux_to_native_itimerspec(&nts, &lots); - if (error != 0) - return (error); - if (args->old_value == NULL) - error = kern_timerfd_settime(td, args->fd, args->flags, &nts, NULL); - else - error = kern_timerfd_settime(td, args->fd, args->flags, &nts, &ots); - if (error == 0 && args->old_value != NULL) { - error = native_to_linux_itimerspec(&lots, &ots); - if (error == 0) - error = copyout(&lots, args->old_value, sizeof(lots)); - } - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_timerfd_gettime64(struct thread *td, struct linux_timerfd_gettime64_args *args) -{ - struct l_itimerspec64 lots; - struct itimerspec ots; - int error; - - error = kern_timerfd_gettime(td, args->fd, &ots); - if (error != 0) - return (error); - - error = native_to_linux_itimerspec64(&lots, &ots); - if (error == 0) - error = copyout(&lots, args->old_value, sizeof(lots)); - - return (error); -} - -int -linux_timerfd_settime64(struct thread *td, struct linux_timerfd_settime64_args *args) -{ - struct l_itimerspec64 lots; - struct itimerspec nts, ots; - int error; - - error = copyin(args->new_value, &lots, sizeof(lots)); - if (error != 0) - return (error); - error = linux_to_native_itimerspec64(&nts, &lots); - if (error != 0) - return (error); - if (args->old_value == NULL) - error = kern_timerfd_settime(td, args->fd, args->flags, &nts, NULL); - else - error = kern_timerfd_settime(td, args->fd, args->flags, &nts, &ots); - if (error == 0 && args->old_value != NULL) { - error = native_to_linux_itimerspec64(&lots, &ots); - if (error == 0) - error = copyout(&lots, args->old_value, sizeof(lots)); - } - - return (error); -} -#endif +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2007 Roman Divacky + * Copyright (c) 2014 Dmitry Chagin + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +typedef uint64_t epoll_udata_t; + +struct epoll_event { + uint32_t events; + epoll_udata_t data; +} +#if defined(__amd64__) +__attribute__((packed)) +#endif +; + +#define LINUX_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) + +static int epoll_to_kevent(struct thread *td, int fd, + struct epoll_event *l_event, struct kevent *kevent, + int *nkevents); +static void kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event); +static int epoll_kev_copyout(void *arg, struct kevent *kevp, int count); +static int epoll_kev_copyin(void *arg, struct kevent *kevp, int count); +static int epoll_register_kevent(struct thread *td, struct file *epfp, + int fd, int filter, unsigned int flags); +static int epoll_fd_registered(struct thread *td, struct file *epfp, + int fd); +static int epoll_delete_all_events(struct thread *td, struct file *epfp, + int fd); + +struct epoll_copyin_args { + struct kevent *changelist; +}; + +struct epoll_copyout_args { + struct epoll_event * __kerncap leventlist; + struct proc *p; + uint32_t count; + int error; +}; + +static int +epoll_create_common(struct thread *td, int flags) +{ + + return (kern_kqueue(td, flags, NULL)); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_epoll_create(struct thread *td, struct linux_epoll_create_args *args) +{ + + /* + * args->size is unused. Linux just tests it + * and then forgets it as well. + */ + if (args->size <= 0) + return (EINVAL); + + return (epoll_create_common(td, 0)); +} +#endif + +int +linux_epoll_create1(struct thread *td, struct linux_epoll_create1_args *args) +{ + int flags; + + if ((args->flags & ~(LINUX_O_CLOEXEC)) != 0) + return (EINVAL); + + flags = 0; + if ((args->flags & LINUX_O_CLOEXEC) != 0) + flags |= O_CLOEXEC; + + return (epoll_create_common(td, flags)); +} + +/* Structure converting function from epoll to kevent. */ +static int +epoll_to_kevent(struct thread *td, int fd, struct epoll_event *l_event, + struct kevent *kevent, int *nkevents) +{ + uint32_t levents = l_event->events; + struct linux_pemuldata *pem; + struct proc *p; + unsigned short kev_flags = EV_ADD | EV_ENABLE; + + /* flags related to how event is registered */ + if ((levents & LINUX_EPOLLONESHOT) != 0) + kev_flags |= EV_DISPATCH; + if ((levents & LINUX_EPOLLET) != 0) + kev_flags |= EV_CLEAR; + if ((levents & LINUX_EPOLLERR) != 0) + kev_flags |= EV_ERROR; + if ((levents & LINUX_EPOLLRDHUP) != 0) + kev_flags |= EV_EOF; + + /* flags related to what event is registered */ + if ((levents & LINUX_EPOLL_EVRD) != 0) { + EV_SET(kevent, fd, EVFILT_READ, kev_flags, 0, 0, 0); + kevent->ext[0] = l_event->data; + ++kevent; + ++(*nkevents); + } + if ((levents & LINUX_EPOLL_EVWR) != 0) { + EV_SET(kevent, fd, EVFILT_WRITE, kev_flags, 0, 0, 0); + kevent->ext[0] = l_event->data; + ++kevent; + ++(*nkevents); + } + /* zero event mask is legal */ + if ((levents & (LINUX_EPOLL_EVRD | LINUX_EPOLL_EVWR)) == 0) { + EV_SET(kevent++, fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, 0); + ++(*nkevents); + } + + if ((levents & ~(LINUX_EPOLL_EVSUP)) != 0) { + p = td->td_proc; + + pem = pem_find(p); + KASSERT(pem != NULL, ("epoll proc emuldata not found.\n")); + + LINUX_PEM_XLOCK(pem); + if ((pem->flags & LINUX_XUNSUP_EPOLL) == 0) { + pem->flags |= LINUX_XUNSUP_EPOLL; + LINUX_PEM_XUNLOCK(pem); + linux_msg(td, "epoll_ctl unsupported flags: 0x%x", + levents); + } else + LINUX_PEM_XUNLOCK(pem); + return (EINVAL); + } + + return (0); +} + +/* + * Structure converting function from kevent to epoll. In a case + * this is called on error in registration we store the error in + * event->data and pick it up later in linux_epoll_ctl(). + */ +static void +kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event) +{ + + l_event->data = kevent->ext[0]; + + if ((kevent->flags & EV_ERROR) != 0) { + l_event->events = LINUX_EPOLLERR; + return; + } + + /* XXX EPOLLPRI, EPOLLHUP */ + switch (kevent->filter) { + case EVFILT_READ: + l_event->events = LINUX_EPOLLIN; + if ((kevent->flags & EV_EOF) != 0) + l_event->events |= LINUX_EPOLLRDHUP; + break; + case EVFILT_WRITE: + l_event->events = LINUX_EPOLLOUT; + break; + } +} + +/* + * Copyout callback used by kevent. This converts kevent + * events to epoll events and copies them back to the + * userspace. This is also called on error on registering + * of the filter. + */ +static int +epoll_kev_copyout(void *arg, struct kevent *kevp, int count) +{ + struct epoll_copyout_args *args; + struct epoll_event *eep; + int error, i; + + args = (struct epoll_copyout_args*) arg; + eep = malloc(sizeof(*eep) * count, M_EPOLL, M_WAITOK | M_ZERO); + + for (i = 0; i < count; i++) + kevent_to_epoll(&kevp[i], &eep[i]); + + error = copyout(eep, args->leventlist, count * sizeof(*eep)); + if (error == 0) { + args->leventlist += count; + args->count += count; + } else if (args->error == 0) + args->error = error; + + free(eep, M_EPOLL); + return (error); +} + +/* + * Copyin callback used by kevent. This copies already + * converted filters from kernel memory to the kevent + * internal kernel memory. Hence the memcpy instead of + * copyin. + */ +static int +epoll_kev_copyin(void *arg, struct kevent *kevp, int count) +{ + struct epoll_copyin_args *args; + + args = (struct epoll_copyin_args*) arg; + + memcpy(kevp, args->changelist, count * sizeof(*kevp)); + args->changelist += count; + + return (0); +} + +/* + * Load epoll filter, convert it to kevent filter + * and load it into kevent subsystem. + */ +int +linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args) +{ + struct file *epfp, *fp; + struct epoll_copyin_args ciargs; + struct kevent kev[2]; + struct kevent_copyops k_ops = { &ciargs, + NULL, + epoll_kev_copyin}; + struct epoll_event le; + cap_rights_t rights; + int nchanges = 0; + int error; + + if (args->op != LINUX_EPOLL_CTL_DEL) { + error = copyin(LINUX_USER_CAP_OBJ(args->event), &le, sizeof(le)); + if (error != 0) + return (error); + } + + error = fget(td, args->epfd, + cap_rights_init_one(&rights, CAP_KQUEUE_CHANGE), &epfp); + if (error != 0) + return (error); + if (epfp->f_type != DTYPE_KQUEUE) { + error = EINVAL; + goto leave1; + } + + /* Protect user data vector from incorrectly supplied fd. */ + error = fget(td, args->fd, + cap_rights_init_one(&rights, CAP_POLL_EVENT), &fp); + if (error != 0) + goto leave1; + + /* Linux disallows spying on himself */ + if (epfp == fp) { + error = EINVAL; + goto leave0; + } + + ciargs.changelist = kev; + + if (args->op != LINUX_EPOLL_CTL_DEL) { + error = epoll_to_kevent(td, args->fd, &le, kev, &nchanges); + if (error != 0) + goto leave0; + } + + switch (args->op) { + case LINUX_EPOLL_CTL_MOD: + error = epoll_delete_all_events(td, epfp, args->fd); + if (error != 0) + goto leave0; + break; + + case LINUX_EPOLL_CTL_ADD: + if (epoll_fd_registered(td, epfp, args->fd)) { + error = EEXIST; + goto leave0; + } + break; + + case LINUX_EPOLL_CTL_DEL: + /* CTL_DEL means unregister this fd with this epoll */ + error = epoll_delete_all_events(td, epfp, args->fd); + goto leave0; + + default: + error = EINVAL; + goto leave0; + } + + error = kern_kevent_fp(td, epfp, nchanges, 0, &k_ops, NULL); + +leave0: + fdrop(fp, td); + +leave1: + fdrop(epfp, td); + return (error); +} + +/* + * Wait for a filter to be triggered on the epoll file descriptor. + */ + +static int +linux_epoll_wait_ts(struct thread *td, int epfd, struct epoll_event * __capability events, + int maxevents, struct timespec *tsp, sigset_t *uset) +{ + struct epoll_copyout_args coargs; + struct kevent_copyops k_ops = { &coargs, + epoll_kev_copyout, + NULL}; + cap_rights_t rights; + struct file *epfp; + sigset_t omask; + int error; + + if (maxevents <= 0 || maxevents > LINUX_MAX_EVENTS) + return (EINVAL); + + error = fget(td, epfd, + cap_rights_init_one(&rights, CAP_KQUEUE_EVENT), &epfp); + if (error != 0) + return (error); + if (epfp->f_type != DTYPE_KQUEUE) { + error = EINVAL; + goto leave; + } + if (uset != NULL) { + error = kern_sigprocmask(td, SIG_SETMASK, uset, + &omask, 0); + if (error != 0) + goto leave; + td->td_pflags |= TDP_OLDMASK; + /* + * Make sure that ast() is called on return to + * usermode and TDP_OLDMASK is cleared, restoring old + * sigmask. + */ + ast_sched(td, TDA_SIGSUSPEND); + } + + coargs.leventlist = events; + coargs.p = td->td_proc; + coargs.count = 0; + coargs.error = 0; + + error = kern_kevent_fp(td, epfp, 0, maxevents, &k_ops, tsp); + if (error == 0 && coargs.error != 0) + error = coargs.error; + + /* + * kern_kevent might return ENOMEM which is not expected from epoll_wait. + * Maybe we should translate that but I don't think it matters at all. + */ + if (error == 0) + td->td_retval[0] = coargs.count; + + if (uset != NULL) + error = kern_sigprocmask(td, SIG_SETMASK, &omask, + NULL, 0); +leave: + fdrop(epfp, td); + return (error); +} + +static int +linux_epoll_wait_common(struct thread *td, int epfd, struct epoll_event * __capability events, + int maxevents, int timeout, sigset_t *uset) +{ + struct timespec ts, *tsp; + + /* + * Linux epoll_wait(2) man page states that timeout of -1 causes caller + * to block indefinitely. Real implementation does it if any negative + * timeout value is passed. + */ + if (timeout >= 0) { + /* Convert from milliseconds to timespec. */ + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + tsp = &ts; + } else { + tsp = NULL; + } + return (linux_epoll_wait_ts(td, epfd, events, maxevents, tsp, uset)); + +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_epoll_wait(struct thread *td, struct linux_epoll_wait_args *args) +{ + + return (linux_epoll_wait_common(td, args->epfd, LINUX_USER_CAP_ARRAY(args->events, args->maxevents), + args->maxevents, args->timeout, NULL)); +} +#endif + +int +linux_epoll_pwait(struct thread *td, struct linux_epoll_pwait_args *args) +{ + sigset_t mask, *pmask; + int error; + + error = linux_copyin_sigset(td, LINUX_USER_CAP_OBJ(args->mask), sizeof(l_sigset_t), + &mask, &pmask); + if (error != 0) + return (error); + + return (linux_epoll_wait_common(td, args->epfd, LINUX_USER_CAP_ARRAY(args->events, args->maxevents), + args->maxevents, args->timeout, pmask)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_epoll_pwait2_64(struct thread *td, struct linux_epoll_pwait2_64_args *args) +{ + struct timespec ts, *tsa; + sigset_t mask, *pmask; + int error; + + error = linux_copyin_sigset(td, args->mask, sizeof(l_sigset_t), + &mask, &pmask); + if (error != 0) + return (error); + + if (args->timeout) { + error = linux_get_timespec64(&ts, args->timeout); + if (error != 0) + return (error); + tsa = &ts; + } else + tsa = NULL; + + return (linux_epoll_wait_ts(td, args->epfd, args->events, + args->maxevents, tsa, pmask)); +} +#else +int +linux_epoll_pwait2(struct thread *td, struct linux_epoll_pwait2_args *args) +{ + struct timespec ts, *tsa; + sigset_t mask, *pmask; + int error; + + error = linux_copyin_sigset(td, LINUX_USER_CAP_OBJ(args->mask), sizeof(l_sigset_t), + &mask, &pmask); + if (error != 0) + return (error); + + if (args->timeout) { + error = linux_get_timespec(&ts, args->timeout); + if (error != 0) + return (error); + tsa = &ts; + } else + tsa = NULL; + + return (linux_epoll_wait_ts(td, args->epfd, LINUX_USER_CAP_ARRAY(args->events, args->maxevents), + args->maxevents, tsa, pmask)); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +static int +epoll_register_kevent(struct thread *td, struct file *epfp, int fd, int filter, + unsigned int flags) +{ + struct epoll_copyin_args ciargs; + struct kevent kev; + struct kevent_copyops k_ops = { &ciargs, + NULL, + epoll_kev_copyin}; + + ciargs.changelist = &kev; + EV_SET(&kev, fd, filter, flags, 0, 0, 0); + + return (kern_kevent_fp(td, epfp, 1, 0, &k_ops, NULL)); +} + +static int +epoll_fd_registered(struct thread *td, struct file *epfp, int fd) +{ + /* + * Set empty filter flags to avoid accidental modification of already + * registered events. In the case of event re-registration: + * 1. If event does not exists kevent() does nothing and returns ENOENT + * 2. If event does exists, it's enabled/disabled state is preserved + * but fflags, data and udata fields are overwritten. So we can not + * set socket lowats and store user's context pointer in udata. + */ + if (epoll_register_kevent(td, epfp, fd, EVFILT_READ, 0) != ENOENT || + epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, 0) != ENOENT) + return (1); + + return (0); +} + +static int +epoll_delete_all_events(struct thread *td, struct file *epfp, int fd) +{ + int error1, error2; + + error1 = epoll_register_kevent(td, epfp, fd, EVFILT_READ, EV_DELETE); + error2 = epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, EV_DELETE); + + /* return 0 if at least one result positive */ + return (error1 == 0 ? 0 : error2); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_eventfd(struct thread *td, struct linux_eventfd_args *args) +{ + struct specialfd_eventfd ae; + + bzero(&ae, sizeof(ae)); + ae.initval = args->initval; + return (kern_specialfd(td, SPECIALFD_EVENTFD, &ae)); +} +#endif + +int +linux_eventfd2(struct thread *td, struct linux_eventfd2_args *args) +{ + struct specialfd_eventfd ae; + int flags; + + if ((args->flags & ~(LINUX_O_CLOEXEC | LINUX_O_NONBLOCK | + LINUX_EFD_SEMAPHORE)) != 0) + return (EINVAL); + flags = 0; + if ((args->flags & LINUX_O_CLOEXEC) != 0) + flags |= EFD_CLOEXEC; + if ((args->flags & LINUX_O_NONBLOCK) != 0) + flags |= EFD_NONBLOCK; + if ((args->flags & LINUX_EFD_SEMAPHORE) != 0) + flags |= EFD_SEMAPHORE; + + bzero(&ae, sizeof(ae)); + ae.flags = flags; + ae.initval = args->initval; + return (kern_specialfd(td, SPECIALFD_EVENTFD, &ae)); +} + +int +linux_timerfd_create(struct thread *td, struct linux_timerfd_create_args *args) +{ + clockid_t clockid; + int error, flags; + + error = linux_to_native_clockid(&clockid, args->clockid); + if (error != 0) + return (error); + flags = 0; + if ((args->flags & LINUX_TFD_CLOEXEC) != 0) + flags |= O_CLOEXEC; + if ((args->flags & LINUX_TFD_NONBLOCK) != 0) + flags |= TFD_NONBLOCK; + + return (kern_timerfd_create(td, clockid, flags)); +} + +int +linux_timerfd_gettime(struct thread *td, struct linux_timerfd_gettime_args *args) +{ + struct l_itimerspec lots; + struct itimerspec ots; + int error; + + error = kern_timerfd_gettime(td, args->fd, &ots); + if (error != 0) + return (error); + + error = native_to_linux_itimerspec(&lots, &ots); + if (error == 0) + error = copyout(&lots, LINUX_USER_CAP_OBJ(args->old_value), sizeof(lots)); + + return (error); +} + +int +linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args) +{ + struct l_itimerspec lots; + struct itimerspec nts, ots; + int error; + + error = copyin(LINUX_USER_CAP_OBJ(args->new_value), &lots, sizeof(lots)); + if (error != 0) + return (error); + error = linux_to_native_itimerspec(&nts, &lots); + if (error != 0) + return (error); + if (args->old_value == NULL) + error = kern_timerfd_settime(td, args->fd, args->flags, &nts, NULL); + else + error = kern_timerfd_settime(td, args->fd, args->flags, &nts, &ots); + if (error == 0 && args->old_value != NULL) { + error = native_to_linux_itimerspec(&lots, &ots); + if (error == 0) + error = copyout(&lots, LINUX_USER_CAP_OBJ(args->old_value), sizeof(lots)); + } + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_timerfd_gettime64(struct thread *td, struct linux_timerfd_gettime64_args *args) +{ + struct l_itimerspec64 lots; + struct itimerspec ots; + int error; + + error = kern_timerfd_gettime(td, args->fd, &ots); + if (error != 0) + return (error); + + error = native_to_linux_itimerspec64(&lots, &ots); + if (error == 0) + error = copyout(&lots, args->old_value, sizeof(lots)); + + return (error); +} + +int +linux_timerfd_settime64(struct thread *td, struct linux_timerfd_settime64_args *args) +{ + struct l_itimerspec64 lots; + struct itimerspec nts, ots; + int error; + + error = copyin(args->new_value, &lots, sizeof(lots)); + if (error != 0) + return (error); + error = linux_to_native_itimerspec64(&nts, &lots); + if (error != 0) + return (error); + if (args->old_value == NULL) + error = kern_timerfd_settime(td, args->fd, args->flags, &nts, NULL); + else + error = kern_timerfd_settime(td, args->fd, args->flags, &nts, &ots); + if (error == 0 && args->old_value != NULL) { + error = native_to_linux_itimerspec64(&lots, &ots); + if (error == 0) + error = copyout(&lots, args->old_value, sizeof(lots)); + } + + return (error); +} +#endif diff --git a/sys/compat/linux/linux_event.h b/sys/compat/linux/linux_event.h index 8c6758fefcc9..462b766b3da0 100644 --- a/sys/compat/linux/linux_event.h +++ b/sys/compat/linux/linux_event.h @@ -1,60 +1,60 @@ -/*- - * Copyright (c) 2007 Roman Divacky - * Copyright (c) 2014 Dmitry Chagin - * - * 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. - */ - -#ifndef _LINUX_EVENT_H_ -#define _LINUX_EVENT_H_ - -#define LINUX_EPOLLIN 0x001 -#define LINUX_EPOLLPRI 0x002 -#define LINUX_EPOLLOUT 0x004 -#define LINUX_EPOLLRDNORM 0x040 -#define LINUX_EPOLLRDBAND 0x080 -#define LINUX_EPOLLWRNORM 0x100 -#define LINUX_EPOLLWRBAND 0x200 -#define LINUX_EPOLLMSG 0x400 -#define LINUX_EPOLLERR 0x008 -#define LINUX_EPOLLHUP 0x010 -#define LINUX_EPOLLRDHUP 0x2000 -#define LINUX_EPOLLWAKEUP 1u<<29 -#define LINUX_EPOLLONESHOT 1u<<30 -#define LINUX_EPOLLET 1u<<31 - -#define LINUX_EPOLL_EVRD (LINUX_EPOLLIN|LINUX_EPOLLRDNORM) -#define LINUX_EPOLL_EVWR (LINUX_EPOLLOUT|LINUX_EPOLLWRNORM) -#define LINUX_EPOLL_EVSUP (LINUX_EPOLLET|LINUX_EPOLLONESHOT \ - |LINUX_EPOLLHUP|LINUX_EPOLLERR|LINUX_EPOLLPRI \ - |LINUX_EPOLL_EVRD|LINUX_EPOLL_EVWR|LINUX_EPOLLRDHUP) - -#define LINUX_EPOLL_CTL_ADD 1 -#define LINUX_EPOLL_CTL_DEL 2 -#define LINUX_EPOLL_CTL_MOD 3 - -#define LINUX_EFD_SEMAPHORE (1 << 0) - -#define LINUX_TFD_CLOEXEC LINUX_O_CLOEXEC -#define LINUX_TFD_NONBLOCK LINUX_O_NONBLOCK - -#endif /* !_LINUX_EVENT_H_ */ +/*- + * Copyright (c) 2007 Roman Divacky + * Copyright (c) 2014 Dmitry Chagin + * + * 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. + */ + +#ifndef _LINUX_EVENT_H_ +#define _LINUX_EVENT_H_ + +#define LINUX_EPOLLIN 0x001 +#define LINUX_EPOLLPRI 0x002 +#define LINUX_EPOLLOUT 0x004 +#define LINUX_EPOLLRDNORM 0x040 +#define LINUX_EPOLLRDBAND 0x080 +#define LINUX_EPOLLWRNORM 0x100 +#define LINUX_EPOLLWRBAND 0x200 +#define LINUX_EPOLLMSG 0x400 +#define LINUX_EPOLLERR 0x008 +#define LINUX_EPOLLHUP 0x010 +#define LINUX_EPOLLRDHUP 0x2000 +#define LINUX_EPOLLWAKEUP 1u<<29 +#define LINUX_EPOLLONESHOT 1u<<30 +#define LINUX_EPOLLET 1u<<31 + +#define LINUX_EPOLL_EVRD (LINUX_EPOLLIN|LINUX_EPOLLRDNORM) +#define LINUX_EPOLL_EVWR (LINUX_EPOLLOUT|LINUX_EPOLLWRNORM) +#define LINUX_EPOLL_EVSUP (LINUX_EPOLLET|LINUX_EPOLLONESHOT \ + |LINUX_EPOLLHUP|LINUX_EPOLLERR|LINUX_EPOLLPRI \ + |LINUX_EPOLL_EVRD|LINUX_EPOLL_EVWR|LINUX_EPOLLRDHUP) + +#define LINUX_EPOLL_CTL_ADD 1 +#define LINUX_EPOLL_CTL_DEL 2 +#define LINUX_EPOLL_CTL_MOD 3 + +#define LINUX_EFD_SEMAPHORE (1 << 0) + +#define LINUX_TFD_CLOEXEC LINUX_O_CLOEXEC +#define LINUX_TFD_NONBLOCK LINUX_O_NONBLOCK + +#endif /* !_LINUX_EVENT_H_ */ diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 6a51e02229a1..129fd3c42646 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -1,1888 +1,1943 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#include -#include -#else -#include -#include -#endif -#include -#include -#include - -static int linux_common_open(struct thread *, int, const char *, int, int, - enum uio_seg); -static int linux_do_accessat(struct thread *t, int, const 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) -{ - - return (kern_openat(td, AT_FDCWD, __USER_CAP_PATH(args->path), - UIO_USERSPACE, O_WRONLY | O_CREAT | O_TRUNC, args->mode)); -} -#endif - -int -linux_common_openflags(int l_flags) -{ - int bsd_flags; - - 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; - if (l_flags & LINUX_O_PATH) - bsd_flags |= O_PATH; - /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ - return (bsd_flags); -} - -static int -linux_common_open(struct thread *td, int dirfd, const char * __capability path, - int l_flags, int mode, enum uio_seg seg) -{ - struct proc *p = td->td_proc; - struct file *fp; - int fd; - int bsd_flags, error; - - bsd_flags = linux_common_openflags(l_flags); - error = kern_openat(td, dirfd, path, seg, 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: - return (error); -} - -int -linux_openat(struct thread *td, struct linux_openat_args *args) -{ - int dfd; - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - return (linux_common_open(td, dfd, args->filename, args->flags, - args->mode, UIO_USERSPACE)); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_open(struct thread *td, struct linux_open_args *args) -{ - - return (linux_common_open(td, AT_FDCWD, args->path, args->flags, - args->mode, UIO_USERSPACE)); -} -#endif - -int -linux_name_to_handle_at(struct thread *td, - struct linux_name_to_handle_at_args *args) -{ - static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW | - LINUX_AT_EMPTY_PATH); - static const l_uint fh_size = sizeof(fhandle_t); - - fhandle_t fh; - l_uint fh_bytes; - l_int mount_id; - int error, fd, bsd_flags; - - if (args->flags & ~valid_flags) - return (EINVAL); - - fd = args->dirfd; - if (fd == LINUX_AT_FDCWD) - fd = AT_FDCWD; - - bsd_flags = 0; - if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW)) - bsd_flags |= AT_SYMLINK_NOFOLLOW; - if ((args->flags & LINUX_AT_EMPTY_PATH) != 0) - bsd_flags |= AT_EMPTY_PATH; - - error = kern_getfhat(td, bsd_flags, fd, args->name, - UIO_USERSPACE, &fh, UIO_SYSSPACE); - if (error != 0) - return (error); - - /* Emit mount_id -- required before EOVERFLOW case. */ - mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]); - error = copyout(&mount_id, args->mnt_id, sizeof(mount_id)); - if (error != 0) - return (error); - - /* Check if there is room for handle. */ - error = copyin(&args->handle->handle_bytes, &fh_bytes, - sizeof(fh_bytes)); - if (error != 0) - return (error); - - if (fh_bytes < fh_size) { - error = copyout(&fh_size, &args->handle->handle_bytes, - sizeof(fh_size)); - if (error == 0) - error = EOVERFLOW; - return (error); - } - - /* Emit handle. */ - mount_id = 0; - /* - * We don't use handle_type for anything yet, but initialize a known - * value. - */ - error = copyout(&mount_id, &args->handle->handle_type, - sizeof(mount_id)); - if (error != 0) - return (error); - - error = copyout(&fh, &args->handle->f_handle, - sizeof(fh)); - return (error); -} - -int -linux_open_by_handle_at(struct thread *td, - struct linux_open_by_handle_at_args *args) -{ - l_uint fh_bytes; - int bsd_flags, error; - - error = copyin(&args->handle->handle_bytes, &fh_bytes, - sizeof(fh_bytes)); - if (error != 0) - return (error); - - if (fh_bytes < sizeof(fhandle_t)) - return (EINVAL); - - bsd_flags = linux_common_openflags(args->flags); - return (kern_fhopen(td, (void *)&args->handle->f_handle, bsd_flags)); -} - -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_LINUX, M_WAITOK); - - error = kern_getdirentries(td, args->fd, PTR2CAP(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_LINUX, 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 = bdp->d_off; - 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_LINUX); -out1: - free(buf, M_LINUX); - 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 */ - off_t base; - struct l_dirent64 *linux_dirent64; - int buflen, error; - size_t retval; - - buflen = min(args->count, MAXBSIZE); - buf = malloc(buflen, M_LINUX, M_WAITOK); - - error = kern_getdirentries(td, args->fd, PTR2CAP(buf), buflen, - &base, NULL, UIO_SYSSPACE); - if (error != 0) { - error = linux_getdents_error(td, args->fd, error); - goto out1; - } - - linux_dirent64 = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_LINUX, - 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->d_ino = bdp->d_fileno; - linux_dirent64->d_off = bdp->d_off; - 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(linux_dirent64, M_LINUX); -out1: - free(buf, M_LINUX); - 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 */ - off_t base; - struct l_dirent *linux_dirent; /* Linux-format */ - int buflen, error; - - buflen = sizeof(*bdp); - buf = malloc(buflen, M_LINUX, M_WAITOK); - - error = kern_getdirentries(td, args->fd, PTR2CAP(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; - - linux_dirent = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_LINUX, - M_WAITOK | M_ZERO); - - bdp = (struct dirent *) buf; - linuxreclen = LINUX_RECLEN(bdp->d_namlen); - - linux_dirent->d_ino = bdp->d_fileno; - linux_dirent->d_off = bdp->d_off; - 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(linux_dirent, M_LINUX); -out: - free(buf, M_LINUX); - 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) -{ - - /* Linux convention. */ - if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) - return (EINVAL); - - return (kern_accessat(td, AT_FDCWD, __USER_CAP_PATH(args->path), - UIO_USERSPACE, 0, args->amode)); -} -#endif - -static int -linux_do_accessat(struct thread *td, int ldfd, const char *filename, - int amode, int flags) -{ - int dfd; - - /* Linux convention. */ - if (amode & ~(F_OK | X_OK | W_OK | R_OK)) - return (EINVAL); - - dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd; - return (kern_accessat(td, dfd, __USER_CAP_PATH(filename), - UIO_USERSPACE, flags, amode)); -} - -int -linux_faccessat(struct thread *td, struct linux_faccessat_args *args) -{ - - return (linux_do_accessat(td, args->dfd, args->filename, args->amode, - 0)); -} - -int -linux_faccessat2(struct thread *td, struct linux_faccessat2_args *args) -{ - int flags, unsupported; - - /* XXX. AT_SYMLINK_NOFOLLOW is not supported by kern_accessat */ - unsupported = args->flags & ~(LINUX_AT_EACCESS | LINUX_AT_EMPTY_PATH); - if (unsupported != 0) { - linux_msg(td, "faccessat2 unsupported flag 0x%x", unsupported); - return (EINVAL); - } - - flags = (args->flags & LINUX_AT_EACCESS) == 0 ? 0 : - AT_EACCESS; - flags |= (args->flags & LINUX_AT_EMPTY_PATH) == 0 ? 0 : - AT_EMPTY_PATH; - return (linux_do_accessat(td, args->dfd, args->filename, args->amode, - flags)); -} - - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_unlink(struct thread *td, struct linux_unlink_args *args) -{ - int error; - struct stat st; - - error = kern_funlinkat(td, AT_FDCWD, __USER_CAP_PATH(args->path), - FD_NONE, UIO_USERSPACE, 0, 0); - if (error == EPERM) { - /* Introduce POSIX noncompliant behaviour of Linux */ - if (kern_statat(td, 0, AT_FDCWD, __USER_CAP_PATH(args->path), - UIO_USERSPACE, &st) == 0) { - if (S_ISDIR(st.st_mode)) - error = EISDIR; - } - } - - return (error); -} -#endif - -static int -linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, - const char * __capability path, - int dfd, struct linux_unlinkat_args *args) -{ - struct stat st; - int error; - - if (args->flag & LINUX_AT_REMOVEDIR) - error = kern_frmdirat(td, dfd, path, FD_NONE, pathseg, 0); - else - error = kern_funlinkat(td, dfd, path, FD_NONE, pathseg, 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, - pathseg, &st) == 0 && S_ISDIR(st.st_mode)) - error = EISDIR; - } - return (error); -} - -int -linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) -{ - int dfd; - - if (args->flag & ~LINUX_AT_REMOVEDIR) - return (EINVAL); - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - return (linux_unlinkat_impl(td, UIO_USERSPACE, - __USER_CAP_PATH(args->pathname), dfd, args)); -} - -int -linux_chdir(struct thread *td, struct linux_chdir_args *args) -{ - - return (kern_chdir(td, args->path, UIO_USERSPACE)); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_chmod(struct thread *td, struct linux_chmod_args *args) -{ - - return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE, - args->mode, 0)); -} -#endif - -int -linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) -{ - int dfd; - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE, - args->mode, 0)); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_mkdir(struct thread *td, struct linux_mkdir_args *args) -{ - - return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode)); -} -#endif - -int -linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) -{ - int dfd; - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode)); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_rmdir(struct thread *td, struct linux_rmdir_args *args) -{ - - return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE, - UIO_USERSPACE, 0)); -} - -int -linux_rename(struct thread *td, struct linux_rename_args *args) -{ - - return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD, - args->to, UIO_USERSPACE)); -} -#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) -{ - int 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); -#if 0 - /* - * This spams the console on Ubuntu Focal. - * - * What's needed here is a general mechanism to let users know - * about missing features without hogging the system. - */ - linux_msg(td, "renameat2 unsupported flags 0x%x", - args->flags); -#endif - return (EINVAL); - } - - olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; - newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; - return (kern_renameat(td, olddfd, args->oldname, newdfd, - args->newname, UIO_USERSPACE)); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_symlink(struct thread *td, struct linux_symlink_args *args) -{ - - return (kern_symlinkat(td, args->path, AT_FDCWD, args->to, - UIO_USERSPACE)); -} -#endif - -int -linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) -{ - int dfd; - - dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; - return (kern_symlinkat(td, args->oldname, dfd, args->newname, - UIO_USERSPACE)); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_readlink(struct thread *td, struct linux_readlink_args *args) -{ - - if (args->count <= 0) - return (EINVAL); - - return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE, - args->buf, UIO_USERSPACE, args->count)); -} -#endif - -int -linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) -{ - int dfd; - - if (args->bufsiz <= 0) - return (EINVAL); - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE, - args->buf, UIO_USERSPACE, args->bufsiz)); -} - -int -linux_truncate(struct thread *td, struct linux_truncate_args *args) -{ - - return (kern_truncate(td, args->path, UIO_USERSPACE, args->length)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_truncate64(struct thread *td, struct linux_truncate64_args *args) -{ - off_t length; - -#if defined(__amd64__) && defined(COMPAT_LINUX32) - length = PAIR32TO64(off_t, args->length); -#else - length = args->length; -#endif - - return (kern_truncate(td, args->path, UIO_USERSPACE, length)); -} -#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) -{ - - return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to, - UIO_USERSPACE, AT_SYMLINK_FOLLOW)); -} -#endif - -int -linux_linkat(struct thread *td, struct linux_linkat_args *args) -{ - int olddfd, newdfd, flag; - - if (args->flag & ~(LINUX_AT_SYMLINK_FOLLOW | LINUX_AT_EMPTY_PATH)) - return (EINVAL); - - flag = (args->flag & LINUX_AT_SYMLINK_FOLLOW) != 0 ? AT_SYMLINK_FOLLOW : - 0; - flag |= (args->flag & LINUX_AT_EMPTY_PATH) != 0 ? AT_EMPTY_PATH : 0; - - olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; - newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; - return (kern_linkat(td, olddfd, newdfd, args->oldname, - args->newname, UIO_USERSPACE, flag)); -} - -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 (linux_enobufs2eagain(td, uap->fd, - kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset))); -} - -#define HALF_LONG_BITS ((sizeof(l_long) * NBBY / 2)) - -static inline off_t -pos_from_hilo(unsigned long high, unsigned long low) -{ - - return (((off_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low; -} - -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 = pos_from_hilo(uap->pos_h, uap->pos_l); - if (offset < 0) - return (EINVAL); -#ifdef COMPAT_LINUX32 - error = freebsd32_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); - freeuio(auio); - 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 = pos_from_hilo(uap->pos_h, uap->pos_l); - if (offset < 0) - return (EINVAL); -#ifdef COMPAT_LINUX32 - error = freebsd32_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); - freeuio(auio); - return (linux_enobufs2eagain(td, uap->fd, error)); -} - -int -linux_mount(struct thread *td, struct linux_mount_args *args) -{ - struct mntarg *ma = NULL; - char *fstypename, *mntonname, *mntfromname, *data; - int error, fsflags; - - fstypename = malloc(MNAMELEN, M_TEMP, M_WAITOK); - mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK); - mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK); - data = NULL; - error = copyinstr(args->filesystemtype, fstypename, MNAMELEN - 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"); - } else if (strcmp(fstypename, "fuse") == 0 || - strncmp(fstypename, "fuse.", 5) == 0) { - char *fuse_options, *fuse_option, *fuse_name; - - strcpy(mntfromname, "/dev/fuse"); - strcpy(fstypename, "fusefs"); - data = malloc(MNAMELEN, M_TEMP, M_WAITOK); - error = copyinstr(args->data, data, MNAMELEN - 1, NULL); - if (error != 0) - goto out; - - fuse_options = data; - while ((fuse_option = strsep(&fuse_options, ",")) != NULL) { - fuse_name = strsep(&fuse_option, "="); - if (fuse_name == NULL || fuse_option == NULL) - goto out; - ma = mount_arg(ma, fuse_name, fuse_option, -1); - } - - /* - * The FUSE server uses Linux errno values instead of FreeBSD - * ones; add a flag to tell fuse(4) to do errno translation. - */ - ma = mount_arg(ma, "linux_errnos", "1", -1); - } - - 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; - - ma = mount_arg(ma, "fstype", fstypename, -1); - ma = mount_arg(ma, "fspath", mntonname, -1); - ma = mount_arg(ma, "from", mntfromname, -1); - error = kernel_mount(ma, fsflags); -out: - free(fstypename, M_TEMP); - free(mntonname, M_TEMP); - free(mntfromname, M_TEMP); - free(data, 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 pipe *fpipe; - 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))); - - case LINUX_F_GETPIPE_SZ: - error = fget(td, args->fd, - &cap_fcntl_rights, &fp); - if (error != 0) - return (error); - if (fp->f_type != DTYPE_PIPE) { - fdrop(fp, td); - return (EINVAL); - } - fpipe = fp->f_data; - td->td_retval[0] = fpipe->pipe_buffer.size; - fdrop(fp, td); - return (0); - - default: - linux_msg(td, "unsupported fcntl cmd %d", 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) -{ - - return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, - args->uid, args->gid, 0)); -} -#endif - -int -linux_fchownat(struct thread *td, struct linux_fchownat_args *args) -{ - int dfd, flag, unsupported; - - unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); - if (unsupported != 0) { - linux_msg(td, "fchownat unsupported flag 0x%x", unsupported); - return (EINVAL); - } - - flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : - AT_SYMLINK_NOFOLLOW; - flag |= (args->flag & LINUX_AT_EMPTY_PATH) == 0 ? 0 : - AT_EMPTY_PATH; - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - return (kern_fchownat(td, dfd, __USER_CAP_PATH(args->filename), - UIO_USERSPACE, args->uid, args->gid, flag)); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_lchown(struct thread *td, struct linux_lchown_args *args) -{ - - return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid, - args->gid, AT_SYMLINK_NOFOLLOW)); -} -#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 (EOPNOTSUPP); - -#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 = SHM_GROW_ON_WRITE; - 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)); -} - -int -linux_splice(struct thread *td, struct linux_splice_args *args) -{ - - linux_msg(td, "syscall splice not really implemented"); - - /* - * splice(2) is documented to return EINVAL in various circumstances; - * returning it instead of ENOSYS should hint the caller to use fallback - * instead. - */ - return (EINVAL); -} - -int -linux_close_range(struct thread *td, struct linux_close_range_args *args) -{ - u_int flags = 0; - - /* - * Implementing close_range(CLOSE_RANGE_UNSHARE) allows Linux to - * unshare filedesc table of the calling thread from others threads - * in a thread group (i.e., process in the FreeBSD) or others processes, - * which shares the same table, before closing the files. FreeBSD does - * not have compatible unsharing mechanism due to the fact that sharing - * process resources, including filedesc table, is at thread level in the - * Linux, while in the FreeBSD it is at the process level. - * Return EINVAL for now if the CLOSE_RANGE_UNSHARE flag is specified - * until this new Linux API stabilizes. - */ - - if ((args->flags & ~(LINUX_CLOSE_RANGE_CLOEXEC)) != 0) - return (EINVAL); - if (args->first > args->last) - return (EINVAL); - if ((args->flags & LINUX_CLOSE_RANGE_CLOEXEC) != 0) - flags |= CLOSE_RANGE_CLOEXEC; - return (kern_close_range(td, flags, args->first, args->last)); -} - -int -linux_enobufs2eagain(struct thread *td, int fd, int error) -{ - struct file *fp; - - if (error != ENOBUFS) - return (error); - if (fget(td, fd, &cap_no_rights, &fp) != 0) - return (error); - if (fp->f_type == DTYPE_SOCKET && (fp->f_flag & FNONBLOCK) != 0) - error = EAGAIN; - fdrop(fp, td); - return (error); -} - -int -linux_write(struct thread *td, struct linux_write_args *args) -{ - struct write_args bargs = { - .fd = args->fd, - .buf = args->buf, - .nbyte = args->nbyte, - }; - - return (linux_enobufs2eagain(td, args->fd, sys_write(td, &bargs))); -} - -int -linux_writev(struct thread *td, struct linux_writev_args *args) -{ - struct uio *auio; - int error; - -#ifdef COMPAT_LINUX32 - error = freebsd32_copyinuio(PTRIN(args->iovp), args->iovcnt, &auio); -#else - error = copyinuio(args->iovp, args->iovcnt, &auio); -#endif - if (error != 0) - return (error); - error = kern_writev(td, args->fd, auio); - freeuio(auio); - return (linux_enobufs2eagain(td, args->fd, error)); -} -// CHERI CHANGES START -// { -// "updated": 20230509, -// "target_type": "kernel", -// "changes": [ -// "user_capabilities" -// ] -// } -// CHERI CHANGES END +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include + +static int linux_common_open(struct thread *, int, const char * __capability, int, int, + enum uio_seg); +static int linux_do_accessat(struct thread *t, int, const char * __capability, 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) +{ + + return (kern_openat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, O_WRONLY | O_CREAT | O_TRUNC, args->mode)); +} +#endif + +int +linux_common_openflags(int l_flags) +{ + int bsd_flags; + + 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; + if (l_flags & LINUX_O_PATH) + bsd_flags |= O_PATH; + /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ + return (bsd_flags); +} + +static int +linux_common_open(struct thread *td, int dirfd, const char * __capability path, + int l_flags, int mode, enum uio_seg seg) +{ + struct proc *p = td->td_proc; + struct file *fp; + int fd; + int bsd_flags, error; + + bsd_flags = linux_common_openflags(l_flags); + error = kern_openat(td, dirfd, path, seg, 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: + return (error); +} + +int +linux_openat(struct thread *td, struct linux_openat_args *args) +{ + int dfd; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + return (linux_common_open(td, dfd, LINUX_USER_CAP_PATH(args->filename), args->flags, + args->mode, UIO_USERSPACE)); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_open(struct thread *td, struct linux_open_args *args) +{ + + return (linux_common_open(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), args->flags, + args->mode, UIO_USERSPACE)); +} +#endif + +int +linux_name_to_handle_at(struct thread *td, + struct linux_name_to_handle_at_args *args) +{ + static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW | + LINUX_AT_EMPTY_PATH); + static const l_uint fh_size = sizeof(fhandle_t); + + fhandle_t fh; + l_uint fh_bytes; + l_int mount_id; + int error, fd, bsd_flags; + + if (args->flags & ~valid_flags) + return (EINVAL); + + fd = args->dirfd; + if (fd == LINUX_AT_FDCWD) + fd = AT_FDCWD; + + bsd_flags = 0; + if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW)) + bsd_flags |= AT_SYMLINK_NOFOLLOW; + if ((args->flags & LINUX_AT_EMPTY_PATH) != 0) + bsd_flags |= AT_EMPTY_PATH; + + error = kern_getfhat(td, bsd_flags, fd, LINUX_USER_CAP_PATH(args->name), + UIO_USERSPACE, &fh, UIO_SYSSPACE); + if (error != 0) + return (error); + + /* Emit mount_id -- required before EOVERFLOW case. */ + mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]); + error = copyout(&mount_id, LINUX_USER_CAP_OBJ(args->mnt_id), sizeof(mount_id)); + if (error != 0) + return (error); + + /* Check if there is room for handle. */ + error = copyin(&args->handle->handle_bytes, &fh_bytes, + sizeof(fh_bytes)); + if (error != 0) + return (error); + + if (fh_bytes < fh_size) { + error = copyout(&fh_size, &args->handle->handle_bytes, + sizeof(fh_size)); + if (error == 0) + error = EOVERFLOW; + return (error); + } + + /* Emit handle. */ + mount_id = 0; + /* + * We don't use handle_type for anything yet, but initialize a known + * value. + */ + error = copyout(&mount_id, &args->handle->handle_type, + sizeof(mount_id)); + if (error != 0) + return (error); + + error = copyout(&fh, &args->handle->f_handle, + sizeof(fh)); + return (error); +} + +int +linux_open_by_handle_at(struct thread *td, + struct linux_open_by_handle_at_args *args) +{ + l_uint fh_bytes; + int bsd_flags, error; + + error = copyin(&args->handle->handle_bytes, &fh_bytes, + sizeof(fh_bytes)); + if (error != 0) + return (error); + + if (fh_bytes < sizeof(fhandle_t)) + return (EINVAL); + + bsd_flags = linux_common_openflags(args->flags); + return (kern_fhopen(td, (void * __capability)&args->handle->f_handle, bsd_flags)); +} + +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_LINUX, M_WAITOK); + + error = kern_getdirentries(td, args->fd, PTR2CAP(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_LINUX, 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 = bdp->d_off; + 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, LINUX_USER_CAP(outp, linuxreclen), 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_LINUX); +out1: + free(buf, M_LINUX); + 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 */ + char * __capability outp; /* Linux-format */ + int resid, linuxreclen; /* 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_LINUX, M_WAITOK); + + error = kern_getdirentries(td, args->fd, PTR2CAP(buf), buflen, + &base, NULL, UIO_SYSSPACE); + if (error != 0) { + error = linux_getdents_error(td, args->fd, error); + goto out1; + } + + linux_dirent64 = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_LINUX, + M_WAITOK | M_ZERO); + + len = td->td_retval[0]; + inp = buf; + outp = LINUX_USER_CAP(args->dirent, args->count); + 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->d_ino = bdp->d_fileno; + linux_dirent64->d_off = bdp->d_off; + 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(linux_dirent64, M_LINUX); +out1: + free(buf, M_LINUX); + 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 */ + off_t base; + struct l_dirent *linux_dirent; /* Linux-format */ + int buflen, error; + + buflen = sizeof(*bdp); + buf = malloc(buflen, M_LINUX, M_WAITOK); + + error = kern_getdirentries(td, args->fd, PTR2CAP(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; + + linux_dirent = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_LINUX, + M_WAITOK | M_ZERO); + + bdp = (struct dirent *) buf; + linuxreclen = LINUX_RECLEN(bdp->d_namlen); + + linux_dirent->d_ino = bdp->d_fileno; + linux_dirent->d_off = bdp->d_off; + 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, LINUX_USER_CAP(args->dent, linuxreclen), linuxreclen); + if (error == 0) + td->td_retval[0] = linuxreclen; + + free(linux_dirent, M_LINUX); +out: + free(buf, M_LINUX); + 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) +{ + + /* Linux convention. */ + if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) + return (EINVAL); + + return (kern_accessat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, 0, args->amode)); +} +#endif + +static int +linux_do_accessat(struct thread *td, int ldfd, const char * __capability filename, + int amode, int flags) +{ + int dfd; + + /* Linux convention. */ + if (amode & ~(F_OK | X_OK | W_OK | R_OK)) + return (EINVAL); + + dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd; + return (kern_accessat(td, dfd, filename, + UIO_USERSPACE, flags, amode)); +} + +int +linux_faccessat(struct thread *td, struct linux_faccessat_args *args) +{ + + return (linux_do_accessat(td, args->dfd, LINUX_USER_CAP_PATH(args->filename), args->amode, + 0)); +} + +int +linux_faccessat2(struct thread *td, struct linux_faccessat2_args *args) +{ + int flags, unsupported; + + /* XXX. AT_SYMLINK_NOFOLLOW is not supported by kern_accessat */ + unsupported = args->flags & ~(LINUX_AT_EACCESS | LINUX_AT_EMPTY_PATH); + if (unsupported != 0) { + linux_msg(td, "faccessat2 unsupported flag 0x%x", unsupported); + return (EINVAL); + } + + flags = (args->flags & LINUX_AT_EACCESS) == 0 ? 0 : + AT_EACCESS; + flags |= (args->flags & LINUX_AT_EMPTY_PATH) == 0 ? 0 : + AT_EMPTY_PATH; + return (linux_do_accessat(td, args->dfd, LINUX_USER_CAP_PATH(args->filename), args->amode, + flags)); +} + + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_unlink(struct thread *td, struct linux_unlink_args *args) +{ + int error; + struct stat st; + + error = kern_funlinkat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), + FD_NONE, UIO_USERSPACE, 0, 0); + if (error == EPERM) { + /* Introduce POSIX noncompliant behaviour of Linux */ + if (kern_statat(td, 0, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, &st) == 0) { + if (S_ISDIR(st.st_mode)) + error = EISDIR; + } + } + + return (error); +} +#endif + +static int +linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, + const char * __capability path, + int dfd, struct linux_unlinkat_args *args) +{ + struct stat st; + int error; + + if (args->flag & LINUX_AT_REMOVEDIR) + error = kern_frmdirat(td, dfd, path, FD_NONE, pathseg, 0); + else + error = kern_funlinkat(td, dfd, path, FD_NONE, pathseg, 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, + pathseg, &st) == 0 && S_ISDIR(st.st_mode)) + error = EISDIR; + } + return (error); +} + +int +linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) +{ + int dfd; + + if (args->flag & ~LINUX_AT_REMOVEDIR) + return (EINVAL); + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + return (linux_unlinkat_impl(td, UIO_USERSPACE, + LINUX_USER_CAP_PATH(args->pathname), dfd, args)); +} + +int +linux_chdir(struct thread *td, struct linux_chdir_args *args) +{ + + return (kern_chdir(td, LINUX_USER_CAP_PATH(args->path), UIO_USERSPACE)); +} + +int +linux_chroot(struct thread *td, struct linux_chroot_args *args) +{ + + return (kern_chroot(td, LINUX_USER_CAP_PATH(args->path))); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_chmod(struct thread *td, struct linux_chmod_args *args) +{ + + return (kern_fchmodat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), UIO_USERSPACE, + args->mode, 0)); +} +#endif + +int +linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) +{ + int dfd; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + return (kern_fchmodat(td, dfd, LINUX_USER_CAP_PATH(args->filename), UIO_USERSPACE, + args->mode, 0)); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_mkdir(struct thread *td, struct linux_mkdir_args *args) +{ + + return (kern_mkdirat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), UIO_USERSPACE, args->mode)); +} +#endif + +int +linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) +{ + int dfd; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + return (kern_mkdirat(td, dfd, LINUX_USER_CAP_PATH(args->pathname), UIO_USERSPACE, args->mode)); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_rmdir(struct thread *td, struct linux_rmdir_args *args) +{ + + return (kern_frmdirat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), FD_NONE, + UIO_USERSPACE, 0)); +} + +int +linux_rename(struct thread *td, struct linux_rename_args *args) +{ + + return (kern_renameat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->from), AT_FDCWD, + LINUX_USER_CAP_PATH(args->to), UIO_USERSPACE)); +} +#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) +{ + int 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); +#if 0 + /* + * This spams the console on Ubuntu Focal. + * + * What's needed here is a general mechanism to let users know + * about missing features without hogging the system. + */ + linux_msg(td, "renameat2 unsupported flags 0x%x", + args->flags); +#endif + return (EINVAL); + } + + olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; + newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; + return (kern_renameat(td, olddfd, LINUX_USER_CAP_PATH(args->oldname), newdfd, + LINUX_USER_CAP_PATH(args->newname), UIO_USERSPACE)); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_symlink(struct thread *td, struct linux_symlink_args *args) +{ + + return (kern_symlinkat(td, LINUX_USER_CAP_PATH(args->path), AT_FDCWD, LINUX_USER_CAP_PATH(args->to), + UIO_USERSPACE)); +} +#endif + +int +linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) +{ + int dfd; + + dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; + return (kern_symlinkat(td, LINUX_USER_CAP_PATH(args->oldname), dfd, LINUX_USER_CAP_PATH(args->newname), + UIO_USERSPACE)); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_readlink(struct thread *td, struct linux_readlink_args *args) +{ + + if (args->count <= 0) + return (EINVAL); + + return (kern_readlinkat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->name), UIO_USERSPACE, + LINUX_USER_CAP(args->buf, args->count), UIO_USERSPACE, args->count)); +} +#endif + +int +linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) +{ + int dfd; + + if (args->bufsiz <= 0) + return (EINVAL); + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + return (kern_readlinkat(td, dfd, LINUX_USER_CAP_PATH(args->path), UIO_USERSPACE, + LINUX_USER_CAP(args->buf, args->bufsiz), UIO_USERSPACE, args->bufsiz)); +} + +int +linux_truncate(struct thread *td, struct linux_truncate_args *args) +{ + + return (kern_truncate(td, LINUX_USER_CAP_PATH(args->path), UIO_USERSPACE, args->length)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_truncate64(struct thread *td, struct linux_truncate64_args *args) +{ + off_t length; + +#if defined(__amd64__) && defined(COMPAT_LINUX32) + length = PAIR32TO64(off_t, args->length); +#else + length = args->length; +#endif + + return (kern_truncate(td, LINUX_USER_CAP_PATH(args->path), UIO_USERSPACE, length)); +} +#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) +{ + + return (kern_linkat(td, AT_FDCWD, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), LINUX_USER_CAP_PATH(args->to), + UIO_USERSPACE, AT_SYMLINK_FOLLOW)); +} +#endif + +int +linux_linkat(struct thread *td, struct linux_linkat_args *args) +{ + int olddfd, newdfd, flag; + + if (args->flag & ~(LINUX_AT_SYMLINK_FOLLOW | LINUX_AT_EMPTY_PATH)) + return (EINVAL); + + flag = (args->flag & LINUX_AT_SYMLINK_FOLLOW) != 0 ? AT_SYMLINK_FOLLOW : + 0; + flag |= (args->flag & LINUX_AT_EMPTY_PATH) != 0 ? AT_EMPTY_PATH : 0; + + olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; + newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; + return (kern_linkat(td, olddfd, newdfd, LINUX_USER_CAP_PATH(args->oldname), + LINUX_USER_CAP_PATH(args->newname), UIO_USERSPACE, flag)); +} + +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, LINUX_USER_CAP(uap->buf, uap->nbyte), 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 (linux_enobufs2eagain(td, uap->fd, + kern_pwrite(td, uap->fd, LINUX_USER_CAP(uap->buf, uap->nbyte), uap->nbyte, offset))); +} + +#define HALF_LONG_BITS ((sizeof(l_long) * NBBY / 2)) + +static inline off_t +pos_from_hilo(unsigned long high, unsigned long low) +{ + + return (((off_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low; +} + +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 = pos_from_hilo(uap->pos_h, uap->pos_l); + if (offset < 0) + return (EINVAL); +#if defined(COMPAT_LINUX32) + error = freebsd32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); +#elif defined(COMPAT_LINUX64) + error = linux64_copyinuio(LINUX_USER_CAP_ARRAY(((struct l_iovec64*)uap->vec), uap->vlen), uap->vlen, &auio); +#else + error = copyinuio((void * __capability)uap->vec, uap->vlen, &auio); +#endif + if (error != 0) + return (error); + error = kern_preadv(td, uap->fd, auio, offset); + freeuio(auio); + 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 = pos_from_hilo(uap->pos_h, uap->pos_l); + if (offset < 0) + return (EINVAL); +#if defined(OMPAT_LINUX32) + error = freebsd32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); +#elif defined(COMPAT_LINUX64) + error = linux64_copyinuio(LINUX_USER_CAP_ARRAY(((struct l_iovec64*)uap->vec), uap->vlen), uap->vlen, &auio); +#else + error = copyinuio((void * __capability)uap->vec, uap->vlen, &auio); +#endif + if (error != 0) + return (error); + error = kern_pwritev(td, uap->fd, auio, offset); + freeuio(auio); + return (linux_enobufs2eagain(td, uap->fd, error)); +} + +int +linux_mount(struct thread *td, struct linux_mount_args *args) +{ + struct mntarg *ma = NULL; + char *fstypename, *mntonname, *mntfromname, *data; + int error, fsflags; + + fstypename = malloc(MNAMELEN, M_TEMP, M_WAITOK); + mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK); + mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK); + data = NULL; + error = copyinstr(LINUX_USER_CAP_STR(args->filesystemtype), fstypename, MNAMELEN - 1, + NULL); + if (error != 0) + goto out; + if (args->specialfile != NULL) { + error = copyinstr(LINUX_USER_CAP_STR(args->specialfile), mntfromname, MNAMELEN - 1, NULL); + if (error != 0) + goto out; + } else { + mntfromname[0] = '\0'; + } + error = copyinstr(LINUX_USER_CAP_PATH(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"); + } else if (strcmp(fstypename, "fuse") == 0 || + strncmp(fstypename, "fuse.", 5) == 0) { + char *fuse_options, *fuse_option, *fuse_name; + + strcpy(mntfromname, "/dev/fuse"); + strcpy(fstypename, "fusefs"); + data = malloc(MNAMELEN, M_TEMP, M_WAITOK); + error = copyinstr(LINUX_USER_CAP_STR(args->data), data, MNAMELEN - 1, NULL); + if (error != 0) + goto out; + + fuse_options = data; + while ((fuse_option = strsep(&fuse_options, ",")) != NULL) { + fuse_name = strsep(&fuse_option, "="); + if (fuse_name == NULL || fuse_option == NULL) + goto out; + ma = mount_arg(ma, fuse_name, fuse_option, -1); + } + + /* + * The FUSE server uses Linux errno values instead of FreeBSD + * ones; add a flag to tell fuse(4) to do errno translation. + */ + ma = mount_arg(ma, "linux_errnos", "1", -1); + } + + 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; + + ma = mount_arg(ma, "fstype", fstypename, -1); + ma = mount_arg(ma, "fspath", mntonname, -1); + ma = mount_arg(ma, "from", mntfromname, -1); + error = kernel_mount(ma, fsflags); +out: + free(fstypename, M_TEMP); + free(mntonname, M_TEMP); + free(mntfromname, M_TEMP); + free(data, 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, LINUX_USER_CAP_PATH(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, LINUX_USER_CAP_PATH(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 pipe *fpipe; + 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(LINUX_USER_CAP(args->arg, sizeof(linux_flock)), &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, LINUX_USER_CAP(args->arg, sizeof(linux_flock)), + sizeof(linux_flock))); + + case LINUX_F_SETLK: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(linux_flock)), &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(LINUX_USER_CAP(args->arg, sizeof(linux_flock)), &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))); + + case LINUX_F_GETPIPE_SZ: + error = fget(td, args->fd, + &cap_fcntl_rights, &fp); + if (error != 0) + return (error); + if (fp->f_type != DTYPE_PIPE) { + fdrop(fp, td); + return (EINVAL); + } + fpipe = fp->f_data; + td->td_retval[0] = fpipe->pipe_buffer.size; + fdrop(fp, td); + return (0); + + default: + linux_msg(td, "unsupported fcntl cmd %d", 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(LINUX_USER_CAP(args->arg, sizeof(linux_flock)), &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, LINUX_USER_CAP(args->arg, sizeof(linux_flock)), + sizeof(linux_flock))); + + case LINUX_F_SETLK64: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(linux_flock)), &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(LINUX_USER_CAP(args->arg, sizeof(linux_flock)), &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) +{ + + return (kern_fchownat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), UIO_USERSPACE, + args->uid, args->gid, 0)); +} +#endif + +int +linux_fchownat(struct thread *td, struct linux_fchownat_args *args) +{ + int dfd, flag, unsupported; + + unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); + if (unsupported != 0) { + linux_msg(td, "fchownat unsupported flag 0x%x", unsupported); + return (EINVAL); + } + + flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : + AT_SYMLINK_NOFOLLOW; + flag |= (args->flag & LINUX_AT_EMPTY_PATH) == 0 ? 0 : + AT_EMPTY_PATH; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + return (kern_fchownat(td, dfd, LINUX_USER_CAP_PATH(args->filename), + UIO_USERSPACE, args->uid, args->gid, flag)); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_lchown(struct thread *td, struct linux_lchown_args *args) +{ + + return (kern_fchownat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), UIO_USERSPACE, args->uid, + args->gid, AT_SYMLINK_NOFOLLOW)); +} +#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, LINUX_USER_CAP(args->pipefds, sizeof(fildes)), 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, LINUX_USER_CAP(args->pipefds, sizeof(fildes)), 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 (EOPNOTSUPP); + +#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(LINUX_USER_CAP_OBJ(args->off_in), &inoff, sizeof(l_loff_t)); + if (error != 0) + return (error); + inoffp = &inoff; + } + if (args->off_out != NULL) { + error = copyin(LINUX_USER_CAP_OBJ(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, LINUX_USER_CAP_OBJ(args->off_in), sizeof(l_loff_t)); + if (error == 0 && args->off_out != NULL) + error = copyout(outoffp, LINUX_USER_CAP_OBJ(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(LINUX_USER_CAP_STR(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 = SHM_GROW_ON_WRITE; + 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)); +} + +int +linux_splice(struct thread *td, struct linux_splice_args *args) +{ + + linux_msg(td, "syscall splice not really implemented"); + + /* + * splice(2) is documented to return EINVAL in various circumstances; + * returning it instead of ENOSYS should hint the caller to use fallback + * instead. + */ + return (EINVAL); +} + +int +linux_close_range(struct thread *td, struct linux_close_range_args *args) +{ + u_int flags = 0; + + /* + * Implementing close_range(CLOSE_RANGE_UNSHARE) allows Linux to + * unshare filedesc table of the calling thread from others threads + * in a thread group (i.e., process in the FreeBSD) or others processes, + * which shares the same table, before closing the files. FreeBSD does + * not have compatible unsharing mechanism due to the fact that sharing + * process resources, including filedesc table, is at thread level in the + * Linux, while in the FreeBSD it is at the process level. + * Return EINVAL for now if the CLOSE_RANGE_UNSHARE flag is specified + * until this new Linux API stabilizes. + */ + + if ((args->flags & ~(LINUX_CLOSE_RANGE_CLOEXEC)) != 0) + return (EINVAL); + if (args->first > args->last) + return (EINVAL); + if ((args->flags & LINUX_CLOSE_RANGE_CLOEXEC) != 0) + flags |= CLOSE_RANGE_CLOEXEC; + return (kern_close_range(td, flags, args->first, args->last)); +} + +int +linux_enobufs2eagain(struct thread *td, int fd, int error) +{ + struct file *fp; + + if (error != ENOBUFS) + return (error); + if (fget(td, fd, &cap_no_rights, &fp) != 0) + return (error); + if (fp->f_type == DTYPE_SOCKET && (fp->f_flag & FNONBLOCK) != 0) + error = EAGAIN; + fdrop(fp, td); + return (error); +} + +// Currently linux_read() and linux_readv() are only used in arm64 to handle pointer-capability conversion +// Unused in other architecture (they will call sys_ versions directly) + +int +linux_read(struct thread *td, struct linux_read_args *args) +{ + struct read_args bargs = { + .fd = args->fd, + .buf = LINUX_USER_CAP(args->buf, args->nbyte), + .nbyte = args->nbyte, + }; + + return (sys_read(td, &bargs)); +} + +int +linux_readv(struct thread *td, struct linux_readv_args *args) +{ + struct uio *auio; + int error; + +#if defined(COMPAT_LINUX32) + error = freebsd32_copyinuio(PTRIN(args->iovp), args->iovcnt, &auio); +#elif defined(COMPAT_LINUX64) + error = linux64_copyinuio(LINUX_USER_CAP_ARRAY(((struct l_iovec64*)args->iovp), args->iovcnt), args->iovcnt, &auio); +#else + error = copyinuio((void * __capability)args->iovp, args->iovcnt, &auio); +#endif + if (error != 0) + return (error); + error = kern_readv(td, args->fd, auio); + freeuio(auio); + return error; +} + +int +linux_write(struct thread *td, struct linux_write_args *args) +{ + struct write_args bargs = { + .fd = args->fd, + .buf = LINUX_USER_CAP(args->buf, args->nbyte), + .nbyte = args->nbyte, + }; + + return (linux_enobufs2eagain(td, args->fd, sys_write(td, &bargs))); +} + +int +linux_writev(struct thread *td, struct linux_writev_args *args) +{ + struct uio *auio; + int error; + +#if defined(COMPAT_LINUX32) + error = freebsd32_copyinuio(PTRIN(args->iovp), args->iovcnt, &auio); +#elif defined(COMPAT_LINUX64) + error = linux64_copyinuio(LINUX_USER_CAP_ARRAY(((struct l_iovec64*)args->iovp), args->iovcnt), args->iovcnt, &auio); +#else + error = copyinuio((void * __capability)args->iovp, args->iovcnt, &auio); +#endif + if (error != 0) + return (error); + error = kern_writev(td, args->fd, auio); + freeuio(auio); + return (linux_enobufs2eagain(td, args->fd, error)); +} +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "kernel", +// "changes": [ +// "user_capabilities" +// ] +// } +// CHERI CHANGES END diff --git a/sys/compat/linux/linux_file.h b/sys/compat/linux/linux_file.h index 2e56942b0f40..32084e23c459 100644 --- a/sys/compat/linux/linux_file.h +++ b/sys/compat/linux/linux_file.h @@ -1,210 +1,210 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * 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. - */ - -#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 -#define LINUX_AT_NO_AUTOMOUNT 0x800 - /* - * Specific to Linux AT_NO_AUTOMOUNT flag tells the kernel to - * not automount the terminal component of pathname if it is a - * directory that is an automount point. As FreeBSD does not - * have such facility (automount), we can simply ignore this flag. - */ -#define LINUX_AT_EMPTY_PATH 0x1000 - -/* - * 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 000000000 -#define LINUX_O_WRONLY 000000001 -#define LINUX_O_RDWR 000000002 -#define LINUX_O_ACCMODE 000000003 -#define LINUX_O_CREAT 000000100 -#define LINUX_O_EXCL 000000200 -#define LINUX_O_NOCTTY 000000400 -#define LINUX_O_TRUNC 000001000 -#define LINUX_O_APPEND 000002000 -#define LINUX_O_NONBLOCK 000004000 -#define LINUX_O_NDELAY LINUX_O_NONBLOCK -#define LINUX_O_SYNC 000010000 -#define LINUX_O_ASYNC 000020000 -#ifndef LINUX_O_DIRECT -#define LINUX_O_DIRECT 000040000 /* Direct disk access hint */ -#endif -#ifndef LINUX_O_LARGEFILE -#define LINUX_O_LARGEFILE 000100000 -#endif -#ifndef LINUX_O_DIRECTORY -#define LINUX_O_DIRECTORY 000200000 /* Must be a directory */ -#endif -#ifndef LINUX_O_NOFOLLOW -#define LINUX_O_NOFOLLOW 000400000 /* Do not follow links */ -#endif -#define LINUX_O_NOATIME 001000000 -#define LINUX_O_CLOEXEC 002000000 -#define LINUX_O_PATH 010000000 - -#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) - -#if defined(_KERNEL) -struct l_file_handle { - l_uint handle_bytes; - l_int handle_type; - unsigned char f_handle[0]; -}; - -int linux_enobufs2eagain(struct thread *, int, int); -int linux_common_openflags(int); -#endif - -/* - * Look at linux_close_range() for an explanation. - * - * #define LINUX_CLOSE_RANGE_UNSHARE (1U << 1) - */ -#define LINUX_CLOSE_RANGE_CLOEXEC (1U << 2) - -#endif /* !_LINUX_FILE_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#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 +#define LINUX_AT_NO_AUTOMOUNT 0x800 + /* + * Specific to Linux AT_NO_AUTOMOUNT flag tells the kernel to + * not automount the terminal component of pathname if it is a + * directory that is an automount point. As FreeBSD does not + * have such facility (automount), we can simply ignore this flag. + */ +#define LINUX_AT_EMPTY_PATH 0x1000 + +/* + * 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 000000000 +#define LINUX_O_WRONLY 000000001 +#define LINUX_O_RDWR 000000002 +#define LINUX_O_ACCMODE 000000003 +#define LINUX_O_CREAT 000000100 +#define LINUX_O_EXCL 000000200 +#define LINUX_O_NOCTTY 000000400 +#define LINUX_O_TRUNC 000001000 +#define LINUX_O_APPEND 000002000 +#define LINUX_O_NONBLOCK 000004000 +#define LINUX_O_NDELAY LINUX_O_NONBLOCK +#define LINUX_O_SYNC 000010000 +#define LINUX_O_ASYNC 000020000 +#ifndef LINUX_O_DIRECT +#define LINUX_O_DIRECT 000040000 /* Direct disk access hint */ +#endif +#ifndef LINUX_O_LARGEFILE +#define LINUX_O_LARGEFILE 000100000 +#endif +#ifndef LINUX_O_DIRECTORY +#define LINUX_O_DIRECTORY 000200000 /* Must be a directory */ +#endif +#ifndef LINUX_O_NOFOLLOW +#define LINUX_O_NOFOLLOW 000400000 /* Do not follow links */ +#endif +#define LINUX_O_NOATIME 001000000 +#define LINUX_O_CLOEXEC 002000000 +#define LINUX_O_PATH 010000000 + +#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) + +#if defined(_KERNEL) +struct l_file_handle { + l_uint handle_bytes; + l_int handle_type; + unsigned char f_handle[0]; +}; + +int linux_enobufs2eagain(struct thread *, int, int); +int linux_common_openflags(int); +#endif + +/* + * Look at linux_close_range() for an explanation. + * + * #define LINUX_CLOSE_RANGE_UNSHARE (1U << 1) + */ +#define LINUX_CLOSE_RANGE_CLOEXEC (1U << 2) + +#endif /* !_LINUX_FILE_H_ */ diff --git a/sys/compat/linux/linux_fork.c b/sys/compat/linux/linux_fork.c index 4ce3bc192b4e..da92c713f090 100644 --- a/sys/compat/linux/linux_fork.c +++ b/sys/compat/linux/linux_fork.c @@ -1,551 +1,554 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004 Tim J. Robbins - * Copyright (c) 2002 Doug Rabson - * Copyright (c) 2000 Marcel Moolenaar - * 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 - * in this position and unchanged. - * 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 ``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 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_fork(struct thread *td, struct linux_fork_args *args) -{ - struct fork_req fr; - int error; - struct proc *p2; - struct thread *td2; - - bzero(&fr, sizeof(fr)); - fr.fr_flags = RFFDG | RFPROC | RFSTOPPED; - fr.fr_procp = &p2; - if ((error = fork1(td, &fr)) != 0) - return (error); - - td2 = FIRST_THREAD_IN_PROC(p2); - - linux_proc_init(td, td2, false); - - td->td_retval[0] = p2->p_pid; - - /* - * Make this runnable after we are finished with it. - */ - thread_lock(td2); - TD_SET_CAN_RUN(td2); - sched_add(td2, SRQ_BORING); - - return (0); -} - -int -linux_vfork(struct thread *td, struct linux_vfork_args *args) -{ - struct fork_req fr; - int error; - struct proc *p2; - struct thread *td2; - - bzero(&fr, sizeof(fr)); - fr.fr_flags = RFFDG | RFPROC | RFMEM | RFPPWAIT | RFSTOPPED; - fr.fr_procp = &p2; - if ((error = fork1(td, &fr)) != 0) - return (error); - - td2 = FIRST_THREAD_IN_PROC(p2); - - linux_proc_init(td, td2, false); - - td->td_retval[0] = p2->p_pid; - - /* - * Make this runnable after we are finished with it. - */ - thread_lock(td2); - TD_SET_CAN_RUN(td2); - sched_add(td2, SRQ_BORING); - - return (0); -} -#endif - -static int -linux_clone_proc(struct thread *td, struct l_clone_args *args) -{ - struct fork_req fr; - int error, ff, f2; - struct proc *p2; - struct thread *td2; - int exit_signal; - struct linux_emuldata *em; - - f2 = 0; - ff = RFPROC | RFSTOPPED; - if (LINUX_SIG_VALID(args->exit_signal)) { - exit_signal = linux_to_bsd_signal(args->exit_signal); - } else if (args->exit_signal != 0) - return (EINVAL); - else - exit_signal = 0; - - if (args->flags & LINUX_CLONE_VM) - ff |= RFMEM; - if (args->flags & LINUX_CLONE_SIGHAND) - ff |= RFSIGSHARE; - if ((args->flags & LINUX_CLONE_CLEAR_SIGHAND) != 0) - f2 |= FR2_DROPSIG_CAUGHT; - if (args->flags & LINUX_CLONE_FILES) { - if (!(args->flags & LINUX_CLONE_FS)) - f2 |= FR2_SHARE_PATHS; - } else { - ff |= RFFDG; - if (args->flags & LINUX_CLONE_FS) - f2 |= FR2_SHARE_PATHS; - } - - if (args->flags & LINUX_CLONE_PARENT_SETTID) - if (args->parent_tid == NULL) - return (EINVAL); - - if (args->flags & LINUX_CLONE_VFORK) - ff |= RFPPWAIT; - - bzero(&fr, sizeof(fr)); - fr.fr_flags = ff; - fr.fr_flags2 = f2; - fr.fr_procp = &p2; - error = fork1(td, &fr); - if (error) - return (error); - - td2 = FIRST_THREAD_IN_PROC(p2); - - /* create the emuldata */ - linux_proc_init(td, td2, false); - - em = em_find(td2); - KASSERT(em != NULL, ("clone_proc: emuldata not found.\n")); - - if (args->flags & LINUX_CLONE_CHILD_SETTID) - em->child_set_tid = args->child_tid; - else - em->child_set_tid = NULL; - - if (args->flags & LINUX_CLONE_CHILD_CLEARTID) - em->child_clear_tid = args->child_tid; - else - em->child_clear_tid = NULL; - - if (args->flags & LINUX_CLONE_PARENT_SETTID) { - error = copyout(&p2->p_pid, args->parent_tid, - sizeof(p2->p_pid)); - if (error) - linux_msg(td, "copyout p_pid failed!"); - } - - PROC_LOCK(p2); - p2->p_sigparent = exit_signal; - PROC_UNLOCK(p2); - /* - * In a case of stack = NULL, we are supposed to COW calling process - * stack. This is what normal fork() does, so we just keep tf_rsp arg - * intact. - */ - linux_set_upcall(td2, args->stack); - - if (args->flags & LINUX_CLONE_SETTLS) - linux_set_cloned_tls(td2, PTRIN(args->tls)); - - /* - * If CLONE_PARENT is set, then the parent of the new process will be - * the same as that of the calling process. - */ - if (args->flags & LINUX_CLONE_PARENT) { - sx_xlock(&proctree_lock); - PROC_LOCK(p2); - proc_reparent(p2, td->td_proc->p_pptr, true); - PROC_UNLOCK(p2); - sx_xunlock(&proctree_lock); - } - - /* - * Make this runnable after we are finished with it. - */ - thread_lock(td2); - TD_SET_CAN_RUN(td2); - sched_add(td2, SRQ_BORING); - - td->td_retval[0] = p2->p_pid; - - return (0); -} - -static int -linux_clone_thread(struct thread *td, struct l_clone_args *args) -{ - struct linux_emuldata *em; - struct thread *newtd; - struct proc *p; - int error; - - LINUX_CTR4(clone_thread, "thread(%d) flags %x ptid %p ctid %p", - td->td_tid, (unsigned)args->flags, - args->parent_tid, args->child_tid); - - if ((args->flags & LINUX_CLONE_PARENT) != 0) - return (EINVAL); - if (args->flags & LINUX_CLONE_PARENT_SETTID) - if (args->parent_tid == NULL) - return (EINVAL); - - /* Threads should be created with own stack */ - if (PTRIN(args->stack) == NULL) - return (EINVAL); - - p = td->td_proc; - -#ifdef RACCT - if (racct_enable) { - PROC_LOCK(p); - error = racct_add(p, RACCT_NTHR, 1); - PROC_UNLOCK(p); - if (error != 0) - return (EPROCLIM); - } -#endif - - /* Initialize our td */ - error = kern_thr_alloc(p, 0, &newtd); - if (error) - goto fail; - - bzero(&newtd->td_startzero, - __rangeof(struct thread, td_startzero, td_endzero)); - bcopy(&td->td_startcopy, &newtd->td_startcopy, - __rangeof(struct thread, td_startcopy, td_endcopy)); - - newtd->td_proc = p; - thread_cow_get(newtd, td); - - cpu_copy_thread(newtd, td); - - /* create the emuldata */ - linux_proc_init(td, newtd, true); - - em = em_find(newtd); - KASSERT(em != NULL, ("clone_thread: emuldata not found.\n")); - - if (args->flags & LINUX_CLONE_SETTLS) - linux_set_cloned_tls(newtd, PTRIN(args->tls)); - - if (args->flags & LINUX_CLONE_CHILD_SETTID) - em->child_set_tid = args->child_tid; - else - em->child_set_tid = NULL; - - if (args->flags & LINUX_CLONE_CHILD_CLEARTID) - em->child_clear_tid = args->child_tid; - else - em->child_clear_tid = NULL; - - cpu_thread_clean(newtd); - - linux_set_upcall(newtd, args->stack); - - PROC_LOCK(p); - p->p_flag |= P_HADTHREADS; - thread_link(newtd, p); - bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name)); - - thread_lock(td); - /* let the scheduler know about these things. */ - sched_fork_thread(td, newtd); - thread_unlock(td); - if (P_SHOULDSTOP(p)) - ast_sched(newtd, TDA_SUSPEND); - - if (p->p_ptevents & PTRACE_LWP) - newtd->td_dbgflags |= TDB_BORN; - PROC_UNLOCK(p); - - tidhash_add(newtd); - - LINUX_CTR2(clone_thread, "thread(%d) successful clone to %d", - td->td_tid, newtd->td_tid); - - if (args->flags & LINUX_CLONE_PARENT_SETTID) { - error = copyout(&newtd->td_tid, args->parent_tid, - sizeof(newtd->td_tid)); - if (error) - linux_msg(td, "clone_thread: copyout td_tid failed!"); - } - - /* - * Make this runnable after we are finished with it. - */ - thread_lock(newtd); - TD_SET_CAN_RUN(newtd); - sched_add(newtd, SRQ_BORING); - - td->td_retval[0] = newtd->td_tid; - - return (0); - -fail: -#ifdef RACCT - if (racct_enable) { - PROC_LOCK(p); - racct_sub(p, RACCT_NTHR, 1); - PROC_UNLOCK(p); - } -#endif - return (error); -} - -int -linux_clone(struct thread *td, struct linux_clone_args *args) -{ - struct l_clone_args ca = { - .flags = (lower_32_bits(args->flags) & ~LINUX_CSIGNAL), - .child_tid = args->child_tidptr, - .parent_tid = args->parent_tidptr, - .exit_signal = (lower_32_bits(args->flags) & LINUX_CSIGNAL), - .stack = args->stack, - .tls = args->tls, - }; - - if (args->flags & LINUX_CLONE_THREAD) - return (linux_clone_thread(td, &ca)); - else - return (linux_clone_proc(td, &ca)); -} - - -static int -linux_clone3_args_valid(struct l_user_clone_args *uca) -{ - - /* Verify that no unknown flags are passed along. */ - if ((uca->flags & ~(LINUX_CLONE_LEGACY_FLAGS | - LINUX_CLONE_CLEAR_SIGHAND | LINUX_CLONE_INTO_CGROUP)) != 0) - return (EINVAL); - if ((uca->flags & (LINUX_CLONE_DETACHED | LINUX_CSIGNAL)) != 0) - return (EINVAL); - - if ((uca->flags & (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND)) == - (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND)) - return (EINVAL); - if ((uca->flags & (LINUX_CLONE_THREAD | LINUX_CLONE_PARENT)) != 0 && - uca->exit_signal != 0) - return (EINVAL); - - /* We don't support set_tid, only validate input. */ - if (uca->set_tid_size > LINUX_MAX_PID_NS_LEVEL) - return (EINVAL); - if (uca->set_tid == 0 && uca->set_tid_size > 0) - return (EINVAL); - if (uca->set_tid != 0 && uca->set_tid_size == 0) - return (EINVAL); - - if (uca->stack == 0 && uca->stack_size > 0) - return (EINVAL); - if (uca->stack != 0 && uca->stack_size == 0) - return (EINVAL); - - /* Verify that higher 32bits of exit_signal are unset. */ - if ((uca->exit_signal & ~(uint64_t)LINUX_CSIGNAL) != 0) - return (EINVAL); - - /* Verify that no unsupported flags are passed along. */ - if ((uca->flags & LINUX_CLONE_NEWTIME) != 0) { - LINUX_RATELIMIT_MSG("unsupported clone3 option CLONE_NEWTIME"); - return (ENOSYS); - } - if ((uca->flags & LINUX_CLONE_INTO_CGROUP) != 0) { - LINUX_RATELIMIT_MSG("unsupported clone3 option CLONE_INTO_CGROUP"); - return (ENOSYS); - } - if (uca->set_tid != 0 || uca->set_tid_size != 0) { - LINUX_RATELIMIT_MSG("unsupported clone3 set_tid"); - return (ENOSYS); - } - - return (0); -} - -int -linux_clone3(struct thread *td, struct linux_clone3_args *args) -{ - struct l_user_clone_args *uca; - struct l_clone_args *ca; - size_t size; - int error; - - if (args->usize > PAGE_SIZE) - return (E2BIG); - if (args->usize < LINUX_CLONE_ARGS_SIZE_VER0) - return (EINVAL); - - /* - * usize can be less than size of struct clone_args, to avoid using - * of uninitialized data of struct clone_args, allocate at least - * sizeof(struct clone_args) storage and zero it. - */ - size = max(args->usize, sizeof(*uca)); - uca = malloc(size, M_LINUX, M_WAITOK | M_ZERO); - error = copyin(args->uargs, uca, args->usize); - if (error != 0) - goto out; - error = linux_clone3_args_valid(uca); - if (error != 0) - goto out; - ca = malloc(sizeof(*ca), M_LINUX, M_WAITOK | M_ZERO); - ca->flags = uca->flags; - ca->child_tid = PTRIN(uca->child_tid); - ca->parent_tid = PTRIN(uca->parent_tid); - ca->exit_signal = uca->exit_signal; - ca->stack = uca->stack + uca->stack_size; - ca->stack_size = uca->stack_size; - ca->tls = uca->tls; - - if ((ca->flags & LINUX_CLONE_THREAD) != 0) - error = linux_clone_thread(td, ca); - else - error = linux_clone_proc(td, ca); - free(ca, M_LINUX); -out: - free(uca, M_LINUX); - return (error); -} - -int -linux_exit(struct thread *td, struct linux_exit_args *args) -{ - struct linux_emuldata *em __diagused; - - em = em_find(td); - KASSERT(em != NULL, ("exit: emuldata not found.\n")); - - LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval); - - linux_thread_detach(td); - - /* - * XXX. When the last two threads of a process - * exit via pthread_exit() try thr_exit() first. - */ - kern_thr_exit(td); - exit1(td, args->rval, 0); - /* NOTREACHED */ -} - -int -linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) -{ - struct linux_emuldata *em; - - em = em_find(td); - KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); - - em->child_clear_tid = args->tidptr; - - td->td_retval[0] = em->em_tid; - - LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d", - em->em_tid, args->tidptr, td->td_retval[0]); - - return (0); -} - -void -linux_thread_detach(struct thread *td) -{ - struct linux_emuldata *em; - int *child_clear_tid; - int error; - - em = em_find(td); - KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); - - LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid); - - release_futexes(td, em); - - child_clear_tid = em->child_clear_tid; - - if (child_clear_tid != NULL) { - LINUX_CTR2(thread_detach, "thread(%d) %p", - em->em_tid, child_clear_tid); - - error = suword32(child_clear_tid, 0); - if (error != 0) - return; - - error = futex_wake(td, child_clear_tid, 1, false); - /* - * this cannot happen at the moment and if this happens it - * probably means there is a user space bug - */ - if (error != 0) - linux_msg(td, "futex stuff in thread_detach failed."); - } - - /* - * Do not rely on the robust list which is maintained by userspace, - * cleanup remaining pi (if any) after release_futexes anyway. - */ - umtx_thread_exit(td); -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004 Tim J. Robbins + * Copyright (c) 2002 Doug Rabson + * Copyright (c) 2000 Marcel Moolenaar + * 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 + * in this position and unchanged. + * 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 ``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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_fork(struct thread *td, struct linux_fork_args *args) +{ + struct fork_req fr; + int error; + struct proc *p2; + struct thread *td2; + + bzero(&fr, sizeof(fr)); + fr.fr_flags = RFFDG | RFPROC | RFSTOPPED; + fr.fr_procp = &p2; + if ((error = fork1(td, &fr)) != 0) + return (error); + + td2 = FIRST_THREAD_IN_PROC(p2); + + linux_proc_init(td, td2, false); + + td->td_retval[0] = p2->p_pid; + + /* + * Make this runnable after we are finished with it. + */ + thread_lock(td2); + TD_SET_CAN_RUN(td2); + sched_add(td2, SRQ_BORING); + + return (0); +} + +int +linux_vfork(struct thread *td, struct linux_vfork_args *args) +{ + struct fork_req fr; + int error; + struct proc *p2; + struct thread *td2; + + bzero(&fr, sizeof(fr)); + fr.fr_flags = RFFDG | RFPROC | RFMEM | RFPPWAIT | RFSTOPPED; + fr.fr_procp = &p2; + if ((error = fork1(td, &fr)) != 0) + return (error); + + td2 = FIRST_THREAD_IN_PROC(p2); + + linux_proc_init(td, td2, false); + + td->td_retval[0] = p2->p_pid; + + /* + * Make this runnable after we are finished with it. + */ + thread_lock(td2); + TD_SET_CAN_RUN(td2); + sched_add(td2, SRQ_BORING); + + return (0); +} +#endif + +static int +linux_clone_proc(struct thread *td, struct l_clone_args *args) +{ + struct fork_req fr; + int error, ff, f2; + struct proc *p2; + struct thread *td2; + int exit_signal; + struct linux_emuldata *em; + + f2 = 0; + ff = RFPROC | RFSTOPPED; + if (LINUX_SIG_VALID(args->exit_signal)) { + exit_signal = linux_to_bsd_signal(args->exit_signal); + } else if (args->exit_signal != 0) + return (EINVAL); + else + exit_signal = 0; + + if (args->flags & LINUX_CLONE_VM) + ff |= RFMEM; + if (args->flags & LINUX_CLONE_SIGHAND) + ff |= RFSIGSHARE; + if ((args->flags & LINUX_CLONE_CLEAR_SIGHAND) != 0) + f2 |= FR2_DROPSIG_CAUGHT; + if (args->flags & LINUX_CLONE_FILES) { + if (!(args->flags & LINUX_CLONE_FS)) + f2 |= FR2_SHARE_PATHS; + } else { + ff |= RFFDG; + if (args->flags & LINUX_CLONE_FS) + f2 |= FR2_SHARE_PATHS; + } + + if (args->flags & LINUX_CLONE_PARENT_SETTID) + if (args->parent_tid == NULL) + return (EINVAL); + + if (args->flags & LINUX_CLONE_VFORK) + ff |= RFPPWAIT; + + bzero(&fr, sizeof(fr)); + fr.fr_flags = ff; + fr.fr_flags2 = f2; + fr.fr_procp = &p2; + error = fork1(td, &fr); + if (error) + return (error); + + td2 = FIRST_THREAD_IN_PROC(p2); + + /* create the emuldata */ + linux_proc_init(td, td2, false); + + em = em_find(td2); + KASSERT(em != NULL, ("clone_proc: emuldata not found.\n")); + + if (args->flags & LINUX_CLONE_CHILD_SETTID) + em->child_set_tid = args->child_tid; + else + em->child_set_tid = NULL; + + if (args->flags & LINUX_CLONE_CHILD_CLEARTID) + em->child_clear_tid = args->child_tid; + else + em->child_clear_tid = NULL; + + if (args->flags & LINUX_CLONE_PARENT_SETTID) { + error = copyout(&p2->p_pid, args->parent_tid, + sizeof(p2->p_pid)); + if (error) + linux_msg(td, "copyout p_pid failed!"); + } + + PROC_LOCK(p2); + p2->p_sigparent = exit_signal; + PROC_UNLOCK(p2); + /* + * In a case of stack = NULL, we are supposed to COW calling process + * stack. This is what normal fork() does, so we just keep tf_rsp arg + * intact. + */ + linux_set_upcall(td2, args->stack); + + if (args->flags & LINUX_CLONE_SETTLS) + linux_set_cloned_tls(td2, args->tls); + + /* + * If CLONE_PARENT is set, then the parent of the new process will be + * the same as that of the calling process. + */ + if (args->flags & LINUX_CLONE_PARENT) { + sx_xlock(&proctree_lock); + PROC_LOCK(p2); + proc_reparent(p2, td->td_proc->p_pptr, true); + PROC_UNLOCK(p2); + sx_xunlock(&proctree_lock); + } + + /* + * Make this runnable after we are finished with it. + */ + thread_lock(td2); + TD_SET_CAN_RUN(td2); + sched_add(td2, SRQ_BORING); + + td->td_retval[0] = p2->p_pid; + + return (0); +} + +static int +linux_clone_thread(struct thread *td, struct l_clone_args *args) +{ + struct linux_emuldata *em; + struct thread *newtd; + struct proc *p; + int error; + + LINUX_CTR4(clone_thread, "thread(%d) flags %x ptid %p ctid %p", + td->td_tid, (unsigned)args->flags, + args->parent_tid, args->child_tid); + + if ((args->flags & LINUX_CLONE_PARENT) != 0) + return (EINVAL); + if (args->flags & LINUX_CLONE_PARENT_SETTID) + if (args->parent_tid == NULL) + return (EINVAL); + + /* Threads should be created with own stack */ + if (args->stack == NULL) + return (EINVAL); + + p = td->td_proc; + +#ifdef RACCT + if (racct_enable) { + PROC_LOCK(p); + error = racct_add(p, RACCT_NTHR, 1); + PROC_UNLOCK(p); + if (error != 0) + return (EPROCLIM); + } +#endif + + /* Initialize our td */ + error = kern_thr_alloc(p, 0, &newtd); + if (error) + goto fail; + + bzero(&newtd->td_startzero, + __rangeof(struct thread, td_startzero, td_endzero)); + bcopy(&td->td_startcopy, &newtd->td_startcopy, + __rangeof(struct thread, td_startcopy, td_endcopy)); + + newtd->td_proc = p; + thread_cow_get(newtd, td); + + cpu_copy_thread(newtd, td); + + /* create the emuldata */ + linux_proc_init(td, newtd, true); + + em = em_find(newtd); + KASSERT(em != NULL, ("clone_thread: emuldata not found.\n")); + + if (args->flags & LINUX_CLONE_SETTLS) + linux_set_cloned_tls(newtd, args->tls); + + if (args->flags & LINUX_CLONE_CHILD_SETTID) + em->child_set_tid = args->child_tid; + else + em->child_set_tid = NULL; + + if (args->flags & LINUX_CLONE_CHILD_CLEARTID) + em->child_clear_tid = args->child_tid; + else + em->child_clear_tid = NULL; + + cpu_thread_clean(newtd); + + linux_set_upcall(newtd, args->stack); + + PROC_LOCK(p); + p->p_flag |= P_HADTHREADS; + thread_link(newtd, p); + bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name)); + + thread_lock(td); + /* let the scheduler know about these things. */ + sched_fork_thread(td, newtd); + thread_unlock(td); + if (P_SHOULDSTOP(p)) + ast_sched(newtd, TDA_SUSPEND); + + if (p->p_ptevents & PTRACE_LWP) + newtd->td_dbgflags |= TDB_BORN; + PROC_UNLOCK(p); + + tidhash_add(newtd); + + LINUX_CTR2(clone_thread, "thread(%d) successful clone to %d", + td->td_tid, newtd->td_tid); + + if (args->flags & LINUX_CLONE_PARENT_SETTID) { + error = copyout(&newtd->td_tid, args->parent_tid, + sizeof(newtd->td_tid)); + if (error) + linux_msg(td, "clone_thread: copyout td_tid failed!"); + } + + /* + * Make this runnable after we are finished with it. + */ + thread_lock(newtd); + TD_SET_CAN_RUN(newtd); + sched_add(newtd, SRQ_BORING); + + td->td_retval[0] = newtd->td_tid; + + return (0); + +fail: +#ifdef RACCT + if (racct_enable) { + PROC_LOCK(p); + racct_sub(p, RACCT_NTHR, 1); + PROC_UNLOCK(p); + } +#endif + return (error); +} + +int +linux_clone(struct thread *td, struct linux_clone_args *args) +{ + struct l_clone_args ca = { + .flags = (lower_32_bits(args->flags) & ~LINUX_CSIGNAL), + .child_tid = LINUX_USER_CAP_OBJ(args->child_tidptr), + .parent_tid = LINUX_USER_CAP_OBJ(args->parent_tidptr), + .exit_signal = (lower_32_bits(args->flags) & LINUX_CSIGNAL), + .stack = LINUX_USER_CAP_UNBOUND(args->stack), + .tls = LINUX_USER_CAP_UNBOUND(args->tls), + }; + + if (args->flags & LINUX_CLONE_THREAD) + return (linux_clone_thread(td, &ca)); + else + return (linux_clone_proc(td, &ca)); +} + + +static int +linux_clone3_args_valid(struct l_user_clone_args *uca) +{ + + /* Verify that no unknown flags are passed along. */ + if ((uca->flags & ~(LINUX_CLONE_LEGACY_FLAGS | + LINUX_CLONE_CLEAR_SIGHAND | LINUX_CLONE_INTO_CGROUP)) != 0) + return (EINVAL); + if ((uca->flags & (LINUX_CLONE_DETACHED | LINUX_CSIGNAL)) != 0) + return (EINVAL); + + if ((uca->flags & (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND)) == + (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND)) + return (EINVAL); + if ((uca->flags & (LINUX_CLONE_THREAD | LINUX_CLONE_PARENT)) != 0 && + uca->exit_signal != 0) + return (EINVAL); + + /* We don't support set_tid, only validate input. */ + if (uca->set_tid_size > LINUX_MAX_PID_NS_LEVEL) + return (EINVAL); + if (uca->set_tid == 0 && uca->set_tid_size > 0) + return (EINVAL); + if (uca->set_tid != 0 && uca->set_tid_size == 0) + return (EINVAL); + + if (uca->stack == 0 && uca->stack_size > 0) + return (EINVAL); + if (uca->stack != 0 && uca->stack_size == 0) + return (EINVAL); + + /* Verify that higher 32bits of exit_signal are unset. */ + if ((uca->exit_signal & ~(uint64_t)LINUX_CSIGNAL) != 0) + return (EINVAL); + + /* Verify that no unsupported flags are passed along. */ + if ((uca->flags & LINUX_CLONE_NEWTIME) != 0) { + LINUX_RATELIMIT_MSG("unsupported clone3 option CLONE_NEWTIME"); + return (ENOSYS); + } + if ((uca->flags & LINUX_CLONE_INTO_CGROUP) != 0) { + LINUX_RATELIMIT_MSG("unsupported clone3 option CLONE_INTO_CGROUP"); + return (ENOSYS); + } + if (uca->set_tid != 0 || uca->set_tid_size != 0) { + LINUX_RATELIMIT_MSG("unsupported clone3 set_tid"); + return (ENOSYS); + } + + return (0); +} + +int +linux_clone3(struct thread *td, struct linux_clone3_args *args) +{ + struct l_user_clone_args *uca; + struct l_clone_args *ca; + size_t size; + int error; + + if (args->usize > PAGE_SIZE) + return (E2BIG); + if (args->usize < LINUX_CLONE_ARGS_SIZE_VER0) + return (EINVAL); + + /* + * usize can be less than size of struct clone_args, to avoid using + * of uninitialized data of struct clone_args, allocate at least + * sizeof(struct clone_args) storage and zero it. + */ + size = max(args->usize, sizeof(*uca)); + uca = malloc(size, M_LINUX, M_WAITOK | M_ZERO); + error = copyincap(LINUX_USER_CAP(args->uargs, args->usize), uca, args->usize); + if (error != 0) + goto out; + error = linux_clone3_args_valid(uca); + if (error != 0) + goto out; + ca = malloc(sizeof(*ca), M_LINUX, M_WAITOK | M_ZERO); + ca->flags = uca->flags; + ca->child_tid = LINUX_USER_CAP(uca->child_tid, sizeof(l_int)); + ca->parent_tid = LINUX_USER_CAP(uca->parent_tid, sizeof(l_int)); + ca->exit_signal = uca->exit_signal; + ca->stack = (void * __capability)((uintcap_t)LINUX_USER_CAP(uca->stack, uca->stack_size) + uca->stack_size); + ca->stack_size = uca->stack_size; + ca->tls = LINUX_USER_CAP_UNBOUND(uca->tls); + + if ((ca->flags & LINUX_CLONE_THREAD) != 0) + error = linux_clone_thread(td, ca); + else + error = linux_clone_proc(td, ca); + free(ca, M_LINUX); +out: + free(uca, M_LINUX); + return (error); +} + +int +linux_exit(struct thread *td, struct linux_exit_args *args) +{ + struct linux_emuldata *em __diagused; + + em = em_find(td); + KASSERT(em != NULL, ("exit: emuldata not found.\n")); + + LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval); + + linux_thread_detach(td); + + /* + * XXX. When the last two threads of a process + * exit via pthread_exit() try thr_exit() first. + */ + kern_thr_exit(td); + exit1(td, args->rval, 0); + /* NOTREACHED */ +} + +int +linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) +{ + struct linux_emuldata *em; + + em = em_find(td); + KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); + + em->child_clear_tid = LINUX_USER_CAP_OBJ(args->tidptr); + + td->td_retval[0] = em->em_tid; + + LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d", + em->em_tid, args->tidptr, td->td_retval[0]); + + return (0); +} + +void +linux_thread_detach(struct thread *td) +{ + struct linux_emuldata *em; + int * __capability child_clear_tid; + int error; + + em = em_find(td); + KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); + + LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid); + + release_futexes(td, em); + + child_clear_tid = em->child_clear_tid; + + if (child_clear_tid != NULL) { + LINUX_CTR2(thread_detach, "thread(%d) %p", + em->em_tid, child_clear_tid); + + error = suword32(child_clear_tid, 0); + if (error != 0) + return; + + error = futex_wake(td, child_clear_tid, 1, false); + /* + * this cannot happen at the moment and if this happens it + * probably means there is a user space bug + */ + if (error != 0) + linux_msg(td, "futex stuff in thread_detach failed."); + } + + /* + * Do not rely on the robust list which is maintained by userspace, + * cleanup remaining pi (if any) after release_futexes anyway. + */ + umtx_thread_exit(td); +} diff --git a/sys/compat/linux/linux_fork.h b/sys/compat/linux/linux_fork.h index 6e2d204a81ea..d555d669043e 100644 --- a/sys/compat/linux/linux_fork.h +++ b/sys/compat/linux/linux_fork.h @@ -1,103 +1,103 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2021 Dmitry Chagin - * - * 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. - */ - -#ifndef _LINUX_FORK_H_ -#define _LINUX_FORK_H_ - -#define LINUX_CLONE_VM 0x00000100 -#define LINUX_CLONE_FS 0x00000200 -#define LINUX_CLONE_FILES 0x00000400 -#define LINUX_CLONE_SIGHAND 0x00000800 -#define LINUX_CLONE_PIDFD 0x00001000 /* since Linux 5.2 */ -#define LINUX_CLONE_PTRACE 0x00002000 -#define LINUX_CLONE_VFORK 0x00004000 -#define LINUX_CLONE_PARENT 0x00008000 -#define LINUX_CLONE_THREAD 0x00010000 -#define LINUX_CLONE_NEWNS 0x00020000 /* New mount NS */ -#define LINUX_CLONE_SYSVSEM 0x00040000 -#define LINUX_CLONE_SETTLS 0x00080000 -#define LINUX_CLONE_PARENT_SETTID 0x00100000 -#define LINUX_CLONE_CHILD_CLEARTID 0x00200000 -#define LINUX_CLONE_DETACHED 0x00400000 /* Unused */ -#define LINUX_CLONE_UNTRACED 0x00800000 -#define LINUX_CLONE_CHILD_SETTID 0x01000000 -#define LINUX_CLONE_NEWCGROUP 0x02000000 /* New cgroup NS */ -#define LINUX_CLONE_NEWUTS 0x04000000 -#define LINUX_CLONE_NEWIPC 0x08000000 -#define LINUX_CLONE_NEWUSER 0x10000000 -#define LINUX_CLONE_NEWPID 0x20000000 -#define LINUX_CLONE_NEWNET 0x40000000 -#define LINUX_CLONE_IO 0x80000000 - -/* Flags for the clone3() syscall. */ -#define LINUX_CLONE_CLEAR_SIGHAND 0x100000000ULL -#define LINUX_CLONE_INTO_CGROUP 0x200000000ULL -#define LINUX_CLONE_NEWTIME 0x00000080 - -#define LINUX_CLONE_LEGACY_FLAGS 0xffffffffULL - -#define LINUX_CSIGNAL 0x000000ff - -#if defined(_KERNEL) -/* - * User-space clone3 args layout. - */ -struct l_user_clone_args { - uint64_t flags; - uint64_t pidfd; - uint64_t child_tid; - uint64_t parent_tid; - uint64_t exit_signal; - uint64_t stack; - uint64_t stack_size; - uint64_t tls; - uint64_t set_tid; - uint64_t set_tid_size; - uint64_t cgroup; -}; - -/* - * Kernel clone3 args layout. - */ -struct l_clone_args { - uint64_t flags; - l_int *child_tid; - l_int *parent_tid; - l_int exit_signal; - l_ulong stack; - l_ulong stack_size; - l_ulong tls; -}; - -#define LINUX_CLONE_ARGS_SIZE_VER0 64 - -int linux_set_upcall(struct thread *, register_t); -int linux_set_cloned_tls(struct thread *, void *); -void linux_thread_detach(struct thread *); -#endif /* defined(_KERNEL) */ - -#endif /* _LINUX_FORK_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Dmitry Chagin + * + * 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. + */ + +#ifndef _LINUX_FORK_H_ +#define _LINUX_FORK_H_ + +#define LINUX_CLONE_VM 0x00000100 +#define LINUX_CLONE_FS 0x00000200 +#define LINUX_CLONE_FILES 0x00000400 +#define LINUX_CLONE_SIGHAND 0x00000800 +#define LINUX_CLONE_PIDFD 0x00001000 /* since Linux 5.2 */ +#define LINUX_CLONE_PTRACE 0x00002000 +#define LINUX_CLONE_VFORK 0x00004000 +#define LINUX_CLONE_PARENT 0x00008000 +#define LINUX_CLONE_THREAD 0x00010000 +#define LINUX_CLONE_NEWNS 0x00020000 /* New mount NS */ +#define LINUX_CLONE_SYSVSEM 0x00040000 +#define LINUX_CLONE_SETTLS 0x00080000 +#define LINUX_CLONE_PARENT_SETTID 0x00100000 +#define LINUX_CLONE_CHILD_CLEARTID 0x00200000 +#define LINUX_CLONE_DETACHED 0x00400000 /* Unused */ +#define LINUX_CLONE_UNTRACED 0x00800000 +#define LINUX_CLONE_CHILD_SETTID 0x01000000 +#define LINUX_CLONE_NEWCGROUP 0x02000000 /* New cgroup NS */ +#define LINUX_CLONE_NEWUTS 0x04000000 +#define LINUX_CLONE_NEWIPC 0x08000000 +#define LINUX_CLONE_NEWUSER 0x10000000 +#define LINUX_CLONE_NEWPID 0x20000000 +#define LINUX_CLONE_NEWNET 0x40000000 +#define LINUX_CLONE_IO 0x80000000 + +/* Flags for the clone3() syscall. */ +#define LINUX_CLONE_CLEAR_SIGHAND 0x100000000ULL +#define LINUX_CLONE_INTO_CGROUP 0x200000000ULL +#define LINUX_CLONE_NEWTIME 0x00000080 + +#define LINUX_CLONE_LEGACY_FLAGS 0xffffffffULL + +#define LINUX_CSIGNAL 0x000000ff + +#if defined(_KERNEL) +/* + * User-space clone3 args layout. + */ +struct l_user_clone_args { + uint64_t flags; + l_uintptr_t pidfd; + l_uintptr_t child_tid; + l_uintptr_t parent_tid; + uint64_t exit_signal; + l_uintptr_t stack; + uint64_t stack_size; + l_uintptr_t tls; + l_uintptr_t set_tid; + uint64_t set_tid_size; + uint64_t cgroup; +}; + +/* + * Kernel clone3 args layout. + */ +struct l_clone_args { + uint64_t flags; + l_int * __kerncap child_tid; + l_int * __kerncap parent_tid; + l_int exit_signal; + void * __kerncap stack; + l_ulong stack_size; + void * __kerncap tls; +}; + +#define LINUX_CLONE_ARGS_SIZE_VER0 64 + +int linux_set_upcall(struct thread *, void * __capability); +int linux_set_cloned_tls(struct thread *, void * __capability); +void linux_thread_detach(struct thread *); +#endif /* defined(_KERNEL) */ + +#endif /* _LINUX_FORK_H_ */ diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c index ab2760859e16..bd9afb0ddc28 100644 --- a/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -1,1075 +1,1104 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2009-2021 Dmitry Chagin - * Copyright (c) 2008 Roman Divacky - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif -#include -#include -#include -#include -#include - -#define FUTEX_SHARED 0x8 /* shared futex */ -#define FUTEX_UNOWNED 0 - -#define GET_SHARED(a) (a->flags & FUTEX_SHARED) ? AUTO_SHARE : THREAD_SHARE - -static int futex_atomic_op(struct thread *, int, uint32_t *, int *); -static int handle_futex_death(struct thread *td, struct linux_emuldata *, - uint32_t *, unsigned int, bool); -static int fetch_robust_entry(struct linux_robust_list **, - struct linux_robust_list **, unsigned int *); - -struct linux_futex_args { - uint32_t *uaddr; - int32_t op; - uint32_t flags; - bool clockrt; - uint32_t val; - struct timespec *ts; - uint32_t *uaddr2; - uint32_t val3; - bool val3_compare; - struct timespec kts; -}; - -static inline int futex_key_get(const void *, int, int, struct umtx_key *); -static void linux_umtx_abs_timeout_init(struct umtx_abs_timeout *, - struct linux_futex_args *); -static int linux_futex(struct thread *, struct linux_futex_args *); -static int linux_futex_wait(struct thread *, struct linux_futex_args *); -static int linux_futex_wake(struct thread *, struct linux_futex_args *); -static int linux_futex_requeue(struct thread *, struct linux_futex_args *); -static int linux_futex_wakeop(struct thread *, struct linux_futex_args *); -static int linux_futex_lock_pi(struct thread *, bool, struct linux_futex_args *); -static int linux_futex_unlock_pi(struct thread *, bool, - struct linux_futex_args *); -static int futex_wake_pi(struct thread *, uint32_t *, bool); - -static int -futex_key_get(const void *uaddr, int type, int share, struct umtx_key *key) -{ - - /* Check that futex address is a 32bit aligned. */ - if (!__is_aligned(uaddr, sizeof(uint32_t))) - return (EINVAL); - return (umtx_key_get(uaddr, type, share, key)); -} - -int -futex_wake(struct thread *td, uint32_t *uaddr, int val, bool shared) -{ - struct linux_futex_args args; - - bzero(&args, sizeof(args)); - args.op = LINUX_FUTEX_WAKE; - args.uaddr = uaddr; - args.flags = shared == true ? FUTEX_SHARED : 0; - args.val = val; - args.val3 = FUTEX_BITSET_MATCH_ANY; - - return (linux_futex_wake(td, &args)); -} - -static int -futex_wake_pi(struct thread *td, uint32_t *uaddr, bool shared) -{ - struct linux_futex_args args; - - bzero(&args, sizeof(args)); - args.op = LINUX_FUTEX_UNLOCK_PI; - args.uaddr = uaddr; - args.flags = shared == true ? FUTEX_SHARED : 0; - - return (linux_futex_unlock_pi(td, true, &args)); -} - -static int -futex_atomic_op(struct thread *td, int encoded_op, uint32_t *uaddr, - int *res) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - switch (op) { - case FUTEX_OP_SET: - ret = futex_xchgl(oparg, uaddr, &oldval); - break; - case FUTEX_OP_ADD: - ret = futex_addl(oparg, uaddr, &oldval); - break; - case FUTEX_OP_OR: - ret = futex_orl(oparg, uaddr, &oldval); - break; - case FUTEX_OP_ANDN: - ret = futex_andl(~oparg, uaddr, &oldval); - break; - case FUTEX_OP_XOR: - ret = futex_xorl(oparg, uaddr, &oldval); - break; - default: - ret = ENOSYS; - break; - } - - if (ret != 0) - return (ret); - - switch (cmp) { - case FUTEX_OP_CMP_EQ: - *res = (oldval == cmparg); - break; - case FUTEX_OP_CMP_NE: - *res = (oldval != cmparg); - break; - case FUTEX_OP_CMP_LT: - *res = (oldval < cmparg); - break; - case FUTEX_OP_CMP_GE: - *res = (oldval >= cmparg); - break; - case FUTEX_OP_CMP_LE: - *res = (oldval <= cmparg); - break; - case FUTEX_OP_CMP_GT: - *res = (oldval > cmparg); - break; - default: - ret = ENOSYS; - } - - return (ret); -} - -static int -linux_futex(struct thread *td, struct linux_futex_args *args) -{ - struct linux_pemuldata *pem; - struct proc *p; - - if (args->op & LINUX_FUTEX_PRIVATE_FLAG) { - args->flags = 0; - args->op &= ~LINUX_FUTEX_PRIVATE_FLAG; - } else - args->flags = FUTEX_SHARED; - - args->clockrt = args->op & LINUX_FUTEX_CLOCK_REALTIME; - args->op = args->op & ~LINUX_FUTEX_CLOCK_REALTIME; - - if (args->clockrt && - args->op != LINUX_FUTEX_WAIT_BITSET && - args->op != LINUX_FUTEX_WAIT_REQUEUE_PI && - args->op != LINUX_FUTEX_LOCK_PI2) - return (ENOSYS); - - switch (args->op) { - case LINUX_FUTEX_WAIT: - args->val3 = FUTEX_BITSET_MATCH_ANY; - /* FALLTHROUGH */ - - case LINUX_FUTEX_WAIT_BITSET: - LINUX_CTR3(sys_futex, "WAIT uaddr %p val 0x%x bitset 0x%x", - args->uaddr, args->val, args->val3); - - return (linux_futex_wait(td, args)); - - case LINUX_FUTEX_WAKE: - args->val3 = FUTEX_BITSET_MATCH_ANY; - /* FALLTHROUGH */ - - case LINUX_FUTEX_WAKE_BITSET: - LINUX_CTR3(sys_futex, "WAKE uaddr %p nrwake 0x%x bitset 0x%x", - args->uaddr, args->val, args->val3); - - return (linux_futex_wake(td, args)); - - case LINUX_FUTEX_REQUEUE: - /* - * Glibc does not use this operation since version 2.3.3, - * as it is racy and replaced by FUTEX_CMP_REQUEUE operation. - * Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when - * FUTEX_REQUEUE returned EINVAL. - */ - pem = pem_find(td->td_proc); - if ((pem->flags & LINUX_XDEPR_REQUEUEOP) == 0) { - linux_msg(td, "unsupported FUTEX_REQUEUE"); - pem->flags |= LINUX_XDEPR_REQUEUEOP; - } - - /* - * The above is true, however musl libc does make use of the - * futex requeue operation, allow operation for brands which - * set LINUX_BI_FUTEX_REQUEUE bit of Brandinfo flags. - */ - p = td->td_proc; - Elf_Brandinfo *bi = p->p_elf_brandinfo; - if (bi == NULL || ((bi->flags & LINUX_BI_FUTEX_REQUEUE)) == 0) - return (EINVAL); - args->val3_compare = false; - /* FALLTHROUGH */ - - case LINUX_FUTEX_CMP_REQUEUE: - LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p " - "nrwake 0x%x uval 0x%x uaddr2 %p nrequeue 0x%x", - args->uaddr, args->val, args->val3, args->uaddr2, - args->ts); - - return (linux_futex_requeue(td, args)); - - case LINUX_FUTEX_WAKE_OP: - LINUX_CTR5(sys_futex, "WAKE_OP " - "uaddr %p nrwake 0x%x uaddr2 %p op 0x%x nrwake2 0x%x", - args->uaddr, args->val, args->uaddr2, args->val3, - args->ts); - - return (linux_futex_wakeop(td, args)); - - case LINUX_FUTEX_LOCK_PI: - args->clockrt = true; - /* FALLTHROUGH */ - - case LINUX_FUTEX_LOCK_PI2: - LINUX_CTR2(sys_futex, "LOCKPI uaddr %p val 0x%x", - args->uaddr, args->val); - - return (linux_futex_lock_pi(td, false, args)); - - case LINUX_FUTEX_UNLOCK_PI: - LINUX_CTR1(sys_futex, "UNLOCKPI uaddr %p", - args->uaddr); - - return (linux_futex_unlock_pi(td, false, args)); - - case LINUX_FUTEX_TRYLOCK_PI: - LINUX_CTR1(sys_futex, "TRYLOCKPI uaddr %p", - args->uaddr); - - return (linux_futex_lock_pi(td, true, args)); - - /* - * Current implementation of FUTEX_WAIT_REQUEUE_PI and FUTEX_CMP_REQUEUE_PI - * can't be used anymore to implement conditional variables. - * A detailed explanation can be found here: - * - * https://sourceware.org/bugzilla/show_bug.cgi?id=13165 - * and here http://austingroupbugs.net/view.php?id=609 - * - * And since commit - * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=ed19993b5b0d05d62cc883571519a67dae481a14 - * glibc does not use them. - */ - case LINUX_FUTEX_WAIT_REQUEUE_PI: - /* not yet implemented */ - pem = pem_find(td->td_proc); - if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { - linux_msg(td, "unsupported FUTEX_WAIT_REQUEUE_PI"); - pem->flags |= LINUX_XUNSUP_FUTEXPIOP; - } - return (ENOSYS); - - case LINUX_FUTEX_CMP_REQUEUE_PI: - /* not yet implemented */ - pem = pem_find(td->td_proc); - if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { - linux_msg(td, "unsupported FUTEX_CMP_REQUEUE_PI"); - pem->flags |= LINUX_XUNSUP_FUTEXPIOP; - } - return (ENOSYS); - - default: - linux_msg(td, "unsupported futex op %d", args->op); - return (ENOSYS); - } -} - -/* - * pi protocol: - * - 0 futex word value means unlocked. - * - TID futex word value means locked. - * Userspace uses atomic ops to lock/unlock these futexes without entering the - * kernel. If the lock-acquire fastpath fails, (transition from 0 to TID fails), - * then FUTEX_LOCK_PI is called. - * The kernel atomically set FUTEX_WAITERS bit in the futex word value, if no - * other waiters exists looks up the thread that owns the futex (it has put its - * own TID into the futex value) and made this thread the owner of the internal - * pi-aware lock object (mutex). Then the kernel tries to lock the internal lock - * object, on which it blocks. Once it returns, it has the mutex acquired, and it - * sets the futex value to its own TID and returns (futex value contains - * FUTEX_WAITERS|TID). - * The unlock fastpath would fail (because the FUTEX_WAITERS bit is set) and - * FUTEX_UNLOCK_PI will be called. - * If a futex is found to be held at exit time, the kernel sets the OWNER_DIED - * bit of the futex word and wakes up the next futex waiter (if any), WAITERS - * bit is preserved (if any). - * If OWNER_DIED bit is set the kernel sanity checks the futex word value against - * the internal futex state and if correct, acquire futex. - */ -static int -linux_futex_lock_pi(struct thread *td, bool try, struct linux_futex_args *args) -{ - struct umtx_abs_timeout timo; - struct linux_emuldata *em; - struct umtx_pi *pi, *new_pi; - struct thread *td1; - struct umtx_q *uq; - int error, rv; - uint32_t owner, old_owner; - - em = em_find(td); - uq = td->td_umtxq; - error = futex_key_get(args->uaddr, TYPE_PI_FUTEX, GET_SHARED(args), - &uq->uq_key); - if (error != 0) - return (error); - if (args->ts != NULL) - linux_umtx_abs_timeout_init(&timo, args); - - umtxq_lock(&uq->uq_key); - pi = umtx_pi_lookup(&uq->uq_key); - if (pi == NULL) { - new_pi = umtx_pi_alloc(M_NOWAIT); - if (new_pi == NULL) { - umtxq_unlock(&uq->uq_key); - new_pi = umtx_pi_alloc(M_WAITOK); - umtxq_lock(&uq->uq_key); - pi = umtx_pi_lookup(&uq->uq_key); - if (pi != NULL) { - umtx_pi_free(new_pi); - new_pi = NULL; - } - } - if (new_pi != NULL) { - new_pi->pi_key = uq->uq_key; - umtx_pi_insert(new_pi); - pi = new_pi; - } - } - umtx_pi_ref(pi); - umtxq_unlock(&uq->uq_key); - for (;;) { - /* Try uncontested case first. */ - rv = casueword32(args->uaddr, FUTEX_UNOWNED, &owner, em->em_tid); - /* The acquire succeeded. */ - if (rv == 0) { - error = 0; - break; - } - if (rv == -1) { - error = EFAULT; - break; - } - - /* - * Nobody owns it, but the acquire failed. This can happen - * with ll/sc atomic. - */ - if (owner == FUTEX_UNOWNED) { - error = thread_check_susp(td, true); - if (error != 0) - break; - continue; - } - - /* - * Avoid overwriting a possible error from sleep due - * to the pending signal with suspension check result. - */ - if (error == 0) { - error = thread_check_susp(td, true); - if (error != 0) - break; - } - - /* The futex word at *uaddr is already locked by the caller. */ - if ((owner & FUTEX_TID_MASK) == em->em_tid) { - error = EDEADLK; - break; - } - - /* - * Futex owner died, handle_futex_death() set the OWNER_DIED bit - * and clear tid. Try to acquire it. - */ - if ((owner & FUTEX_TID_MASK) == FUTEX_UNOWNED) { - old_owner = owner; - owner = owner & (FUTEX_WAITERS | FUTEX_OWNER_DIED); - owner |= em->em_tid; - rv = casueword32(args->uaddr, old_owner, &owner, owner); - if (rv == -1) { - error = EFAULT; - break; - } - if (rv == 1) { - if (error == 0) { - error = thread_check_susp(td, true); - if (error != 0) - break; - } - - /* - * If this failed the lock could - * changed, restart. - */ - continue; - } - - umtxq_lock(&uq->uq_key); - umtxq_busy(&uq->uq_key); - error = umtx_pi_claim(pi, td); - umtxq_unbusy(&uq->uq_key); - umtxq_unlock(&uq->uq_key); - if (error != 0) { - /* - * Since we're going to return an - * error, restore the futex to its - * previous, unowned state to avoid - * compounding the problem. - */ - (void)casuword32(args->uaddr, owner, old_owner); - } - break; - } - - /* - * Inconsistent state: OWNER_DIED is set and tid is not 0. - * Linux does some checks of futex state, we return EINVAL, - * as the user space can take care of this. - */ - if ((owner & FUTEX_OWNER_DIED) != FUTEX_UNOWNED) { - error = EINVAL; - break; - } - - if (try != 0) { - error = EBUSY; - break; - } - - /* - * If we caught a signal, we have retried and now - * exit immediately. - */ - if (error != 0) - break; - - umtxq_lock(&uq->uq_key); - umtxq_busy(&uq->uq_key); - umtxq_unlock(&uq->uq_key); - - /* - * Set the contested bit so that a release in user space knows - * to use the system call for unlock. If this fails either some - * one else has acquired the lock or it has been released. - */ - rv = casueword32(args->uaddr, owner, &owner, - owner | FUTEX_WAITERS); - if (rv == -1) { - umtxq_unbusy_unlocked(&uq->uq_key); - error = EFAULT; - break; - } - if (rv == 1) { - umtxq_unbusy_unlocked(&uq->uq_key); - error = thread_check_susp(td, true); - if (error != 0) - break; - - /* - * The lock changed and we need to retry or we - * lost a race to the thread unlocking the umtx. - */ - continue; - } - - /* - * Substitute Linux thread id by native thread id to - * avoid refactoring code of umtxq_sleep_pi(). - */ - td1 = linux_tdfind(td, owner & FUTEX_TID_MASK, -1); - if (td1 != NULL) { - owner = td1->td_tid; - PROC_UNLOCK(td1->td_proc); - } else { - umtxq_unbusy_unlocked(&uq->uq_key); - error = EINVAL; - break; - } - - umtxq_lock(&uq->uq_key); - - /* We set the contested bit, sleep. */ - error = umtxq_sleep_pi(uq, pi, owner, "futexp", - args->ts == NULL ? NULL : &timo, - (args->flags & FUTEX_SHARED) != 0); - if (error != 0) - continue; - - error = thread_check_susp(td, false); - if (error != 0) - break; - } - - umtxq_lock(&uq->uq_key); - umtx_pi_unref(pi); - umtxq_unlock(&uq->uq_key); - umtx_key_release(&uq->uq_key); - return (error); -} - -static int -linux_futex_unlock_pi(struct thread *td, bool rb, struct linux_futex_args *args) -{ - struct linux_emuldata *em; - struct umtx_key key; - uint32_t old, owner, new_owner; - int count, error; - - em = em_find(td); - - /* - * Make sure we own this mtx. - */ - error = fueword32(args->uaddr, &owner); - if (error == -1) - return (EFAULT); - if (!rb && (owner & FUTEX_TID_MASK) != em->em_tid) - return (EPERM); - - error = futex_key_get(args->uaddr, TYPE_PI_FUTEX, GET_SHARED(args), &key); - if (error != 0) - return (error); - umtxq_lock(&key); - umtxq_busy(&key); - error = umtx_pi_drop(td, &key, rb, &count); - if (error != 0 || rb) { - umtxq_unbusy(&key); - umtxq_unlock(&key); - umtx_key_release(&key); - return (error); - } - umtxq_unlock(&key); - - /* - * When unlocking the futex, it must be marked as unowned if - * there is zero or one thread only waiting for it. - * Otherwise, it must be marked as contested. - */ - if (count > 1) - new_owner = FUTEX_WAITERS; - else - new_owner = FUTEX_UNOWNED; - -again: - error = casueword32(args->uaddr, owner, &old, new_owner); - if (error == 1) { - error = thread_check_susp(td, false); - if (error == 0) - goto again; - } - umtxq_unbusy_unlocked(&key); - umtx_key_release(&key); - if (error == -1) - return (EFAULT); - if (error == 0 && old != owner) - return (EINVAL); - return (error); -} - -static int -linux_futex_wakeop(struct thread *td, struct linux_futex_args *args) -{ - struct umtx_key key, key2; - int nrwake, op_ret, ret; - int error, count; - - if (args->uaddr == args->uaddr2) - return (EINVAL); - - error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); - if (error != 0) - return (error); - error = futex_key_get(args->uaddr2, TYPE_FUTEX, GET_SHARED(args), &key2); - if (error != 0) { - umtx_key_release(&key); - return (error); - } - umtxq_lock(&key); - umtxq_busy(&key); - umtxq_unlock(&key); - error = futex_atomic_op(td, args->val3, args->uaddr2, &op_ret); - umtxq_lock(&key); - umtxq_unbusy(&key); - if (error != 0) - goto out; - ret = umtxq_signal_mask(&key, args->val, args->val3); - if (op_ret > 0) { - nrwake = (int)(unsigned long)args->ts; - umtxq_lock(&key2); - count = umtxq_count(&key2); - if (count > 0) - ret += umtxq_signal_mask(&key2, nrwake, args->val3); - else - ret += umtxq_signal_mask(&key, nrwake, args->val3); - umtxq_unlock(&key2); - } - td->td_retval[0] = ret; -out: - umtxq_unlock(&key); - umtx_key_release(&key2); - umtx_key_release(&key); - return (error); -} - -static int -linux_futex_requeue(struct thread *td, struct linux_futex_args *args) -{ - int nrwake, nrrequeue; - struct umtx_key key, key2; - int error; - uint32_t uval; - - /* - * Linux allows this, we would not, it is an incorrect - * usage of declared ABI, so return EINVAL. - */ - if (args->uaddr == args->uaddr2) - return (EINVAL); - - nrrequeue = (int)(unsigned long)args->ts; - nrwake = args->val; - /* - * Sanity check to prevent signed integer overflow, - * see Linux CVE-2018-6927 - */ - if (nrwake < 0 || nrrequeue < 0) - return (EINVAL); - - error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); - if (error != 0) - return (error); - error = futex_key_get(args->uaddr2, TYPE_FUTEX, GET_SHARED(args), &key2); - if (error != 0) { - umtx_key_release(&key); - return (error); - } - umtxq_lock(&key); - umtxq_busy(&key); - umtxq_unlock(&key); - error = fueword32(args->uaddr, &uval); - if (error != 0) - error = EFAULT; - else if (args->val3_compare == true && uval != args->val3) - error = EWOULDBLOCK; - umtxq_lock(&key); - umtxq_unbusy(&key); - if (error == 0) { - umtxq_lock(&key2); - td->td_retval[0] = umtxq_requeue(&key, nrwake, &key2, nrrequeue); - umtxq_unlock(&key2); - } - umtxq_unlock(&key); - umtx_key_release(&key2); - umtx_key_release(&key); - return (error); -} - -static int -linux_futex_wake(struct thread *td, struct linux_futex_args *args) -{ - struct umtx_key key; - int error; - - if (args->val3 == 0) - return (EINVAL); - - error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); - if (error != 0) - return (error); - umtxq_lock(&key); - td->td_retval[0] = umtxq_signal_mask(&key, args->val, args->val3); - umtxq_unlock(&key); - umtx_key_release(&key); - return (0); -} - -static int -linux_futex_wait(struct thread *td, struct linux_futex_args *args) -{ - struct umtx_abs_timeout timo; - struct umtx_q *uq; - uint32_t uval; - int error; - - if (args->val3 == 0) - error = EINVAL; - - uq = td->td_umtxq; - error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), - &uq->uq_key); - if (error != 0) - return (error); - if (args->ts != NULL) - linux_umtx_abs_timeout_init(&timo, args); - umtxq_lock(&uq->uq_key); - umtxq_busy(&uq->uq_key); - uq->uq_bitset = args->val3; - umtxq_insert(uq); - umtxq_unlock(&uq->uq_key); - error = fueword32(args->uaddr, &uval); - if (error != 0) - error = EFAULT; - else if (uval != args->val) - error = EWOULDBLOCK; - umtxq_lock(&uq->uq_key); - umtxq_unbusy(&uq->uq_key); - if (error == 0) { - error = umtxq_sleep(uq, "futex", - args->ts == NULL ? NULL : &timo); - if ((uq->uq_flags & UQF_UMTXQ) == 0) - error = 0; - else - umtxq_remove(uq); - } else if ((uq->uq_flags & UQF_UMTXQ) != 0) { - umtxq_remove(uq); - } - umtxq_unlock(&uq->uq_key); - umtx_key_release(&uq->uq_key); - if (error == ERESTART) - error = EINTR; - return (error); -} - -static void -linux_umtx_abs_timeout_init(struct umtx_abs_timeout *timo, - struct linux_futex_args *args) -{ - int clockid, absolute; - - /* - * The FUTEX_CLOCK_REALTIME option bit can be employed only with the - * FUTEX_WAIT_BITSET, FUTEX_WAIT_REQUEUE_PI, FUTEX_LOCK_PI2. - * For FUTEX_WAIT, timeout is interpreted as a relative value, for other - * futex operations timeout is interpreted as an absolute value. - * If FUTEX_CLOCK_REALTIME option bit is set, the Linux kernel measures - * the timeout against the CLOCK_REALTIME clock, otherwise the kernel - * measures the timeout against the CLOCK_MONOTONIC clock. - */ - clockid = args->clockrt ? CLOCK_REALTIME : CLOCK_MONOTONIC; - absolute = args->op == LINUX_FUTEX_WAIT ? false : true; - umtx_abs_timeout_init(timo, clockid, absolute, args->ts); -} - -int -linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) -{ - struct linux_futex_args fargs = { - .uaddr = args->uaddr, - .op = args->op, - .val = args->val, - .ts = NULL, - .uaddr2 = args->uaddr2, - .val3 = args->val3, - .val3_compare = true, - }; - int error; - - switch (args->op & LINUX_FUTEX_CMD_MASK) { - case LINUX_FUTEX_WAIT: - case LINUX_FUTEX_WAIT_BITSET: - case LINUX_FUTEX_LOCK_PI: - case LINUX_FUTEX_LOCK_PI2: - if (args->timeout != NULL) { - error = linux_get_timespec(&fargs.kts, args->timeout); - if (error != 0) - return (error); - fargs.ts = &fargs.kts; - } - break; - default: - fargs.ts = PTRIN(args->timeout); - } - return (linux_futex(td, &fargs)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_sys_futex_time64(struct thread *td, - struct linux_sys_futex_time64_args *args) -{ - struct linux_futex_args fargs = { - .uaddr = args->uaddr, - .op = args->op, - .val = args->val, - .ts = NULL, - .uaddr2 = args->uaddr2, - .val3 = args->val3, - .val3_compare = true, - }; - int error; - - switch (args->op & LINUX_FUTEX_CMD_MASK) { - case LINUX_FUTEX_WAIT: - case LINUX_FUTEX_WAIT_BITSET: - case LINUX_FUTEX_LOCK_PI: - case LINUX_FUTEX_LOCK_PI2: - if (args->timeout != NULL) { - error = linux_get_timespec64(&fargs.kts, args->timeout); - if (error != 0) - return (error); - fargs.ts = &fargs.kts; - } - break; - default: - fargs.ts = PTRIN(args->timeout); - } - return (linux_futex(td, &fargs)); -} -#endif - -int -linux_set_robust_list(struct thread *td, struct linux_set_robust_list_args *args) -{ - struct linux_emuldata *em; - - if (args->len != sizeof(struct linux_robust_list_head)) - return (EINVAL); - - em = em_find(td); - em->robust_futexes = args->head; - - return (0); -} - -int -linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args) -{ - struct linux_emuldata *em; - struct linux_robust_list_head *head; - l_size_t len; - struct thread *td2; - int error; - - if (!args->pid) { - em = em_find(td); - KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n")); - head = em->robust_futexes; - } else { - td2 = linux_tdfind(td, args->pid, -1); - if (td2 == NULL) - return (ESRCH); - if (SV_PROC_ABI(td2->td_proc) != SV_ABI_LINUX) { - PROC_UNLOCK(td2->td_proc); - return (EPERM); - } - - em = em_find(td2); - KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n")); - /* XXX: ptrace? */ - if (priv_check(td, PRIV_CRED_SETUID) || - priv_check(td, PRIV_CRED_SETEUID) || - p_candebug(td, td2->td_proc)) { - PROC_UNLOCK(td2->td_proc); - return (EPERM); - } - head = em->robust_futexes; - - PROC_UNLOCK(td2->td_proc); - } - - len = sizeof(struct linux_robust_list_head); - error = copyout(&len, args->len, sizeof(l_size_t)); - if (error != 0) - return (EFAULT); - - return (copyout(&head, args->head, sizeof(l_uintptr_t))); -} - -static int -handle_futex_death(struct thread *td, struct linux_emuldata *em, uint32_t *uaddr, - unsigned int pi, bool pending_op) -{ - uint32_t uval, nval, mval; - int error; - -retry: - error = fueword32(uaddr, &uval); - if (error != 0) - return (EFAULT); - - /* - * Special case for regular (non PI) futexes. The unlock path in - * user space has two race scenarios: - * - * 1. The unlock path releases the user space futex value and - * before it can execute the futex() syscall to wake up - * waiters it is killed. - * - * 2. A woken up waiter is killed before it can acquire the - * futex in user space. - * - * In both cases the TID validation below prevents a wakeup of - * potential waiters which can cause these waiters to block - * forever. - * - * In both cases it is safe to attempt waking up a potential - * waiter without touching the user space futex value and trying - * to set the OWNER_DIED bit. - */ - if (pending_op && !pi && !uval) { - (void)futex_wake(td, uaddr, 1, true); - return (0); - } - - if ((uval & FUTEX_TID_MASK) == em->em_tid) { - mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED; - error = casueword32(uaddr, uval, &nval, mval); - if (error == -1) - return (EFAULT); - if (error == 1) { - error = thread_check_susp(td, false); - if (error != 0) - return (error); - goto retry; - } - - if (!pi && (uval & FUTEX_WAITERS)) { - error = futex_wake(td, uaddr, 1, true); - if (error != 0) - return (error); - } else if (pi && (uval & FUTEX_WAITERS)) { - error = futex_wake_pi(td, uaddr, true); - if (error != 0) - return (error); - } - } - - return (0); -} - -static int -fetch_robust_entry(struct linux_robust_list **entry, - struct linux_robust_list **head, unsigned int *pi) -{ - l_ulong uentry; - int error; - - error = copyin((const void *)head, &uentry, sizeof(uentry)); - if (error != 0) - return (EFAULT); - - *entry = (void *)(uentry & ~1UL); - *pi = uentry & 1; - - return (0); -} - -#define LINUX_HANDLE_DEATH_PENDING true -#define LINUX_HANDLE_DEATH_LIST false - -/* This walks the list of robust futexes releasing them. */ -void -release_futexes(struct thread *td, struct linux_emuldata *em) -{ - struct linux_robust_list_head *head; - struct linux_robust_list *entry, *next_entry, *pending; - unsigned int limit = 2048, pi, next_pi, pip; - uint32_t *uaddr; - l_long futex_offset; - int error; - - head = em->robust_futexes; - if (head == NULL) - return; - - if (fetch_robust_entry(&entry, PTRIN(&head->list.next), &pi)) - return; - - error = copyin(&head->futex_offset, &futex_offset, - sizeof(futex_offset)); - if (error != 0) - return; - - if (fetch_robust_entry(&pending, PTRIN(&head->pending_list), &pip)) - return; - - while (entry != &head->list) { - error = fetch_robust_entry(&next_entry, PTRIN(&entry->next), - &next_pi); - - /* - * A pending lock might already be on the list, so - * don't process it twice. - */ - if (entry != pending) { - uaddr = (uint32_t *)((caddr_t)entry + futex_offset); - if (handle_futex_death(td, em, uaddr, pi, - LINUX_HANDLE_DEATH_LIST)) - return; - } - if (error != 0) - return; - - entry = next_entry; - pi = next_pi; - - if (!--limit) - break; - - sched_relinquish(curthread); - } - - if (pending) { - uaddr = (uint32_t *)((caddr_t)pending + futex_offset); - (void)handle_futex_death(td, em, uaddr, pip, - LINUX_HANDLE_DEATH_PENDING); - } -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2009-2021 Dmitry Chagin + * Copyright (c) 2008 Roman Divacky + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include + +#define FUTEX_SHARED 0x8 /* shared futex */ +#define FUTEX_UNOWNED 0 + +#define GET_SHARED(a) (a->flags & FUTEX_SHARED) ? AUTO_SHARE : THREAD_SHARE + +static int futex_atomic_op(struct thread *, int, uint32_t * __capability, int *); +static int handle_futex_death(struct thread *td, struct linux_emuldata *, + uint32_t * __capability, unsigned int, bool); +static int fetch_robust_entry(struct linux_robust_list * __capability *, + struct linux_robust_list * __capability * __capability, unsigned int *); + +struct linux_futex_args { + uint32_t * __kerncap uaddr; + int32_t op; + uint32_t flags; + bool clockrt; + uint32_t val; + // Normally should be a kernel space address so no __kerncap (Already copied in) + // In case LINUX_FUTEX_CMD is not LINUX_FUTEX_WAIT, LINUX_FUTEX_WAIT_BITSET, LINUX_FUTEX_LOCK_PI or LINUX_FUTEX_LOCK_PI2, use the user-supplied data directly with fromcap. + struct timespec *ts; + uint32_t * __kerncap uaddr2; + uint32_t val3; + bool val3_compare; + struct timespec kts; +}; + +static inline int futex_key_get(const void * __capability, int, int, struct umtx_key *); +static void linux_umtx_abs_timeout_init(struct umtx_abs_timeout *, + struct linux_futex_args *); +static int linux_futex(struct thread *, struct linux_futex_args *); +static int linux_futex_wait(struct thread *, struct linux_futex_args *); +static int linux_futex_wake(struct thread *, struct linux_futex_args *); +static int linux_futex_requeue(struct thread *, struct linux_futex_args *); +static int linux_futex_wakeop(struct thread *, struct linux_futex_args *); +static int linux_futex_lock_pi(struct thread *, bool, struct linux_futex_args *); +static int linux_futex_unlock_pi(struct thread *, bool, + struct linux_futex_args *); +static int futex_wake_pi(struct thread *, uint32_t * __capability, bool); + +static int +futex_key_get(const void * __capability uaddr, int type, int share, struct umtx_key *key) +{ + + /* Check that futex address is a 32bit aligned. */ + if (!__is_aligned(uaddr, sizeof(uint32_t))) + return (EINVAL); + return (umtx_key_get(uaddr, type, share, key)); +} + +int +futex_wake(struct thread *td, uint32_t * __capability uaddr, int val, bool shared) +{ + struct linux_futex_args args; + + bzero(&args, sizeof(args)); + args.op = LINUX_FUTEX_WAKE; + args.uaddr = uaddr; + args.flags = shared == true ? FUTEX_SHARED : 0; + args.val = val; + args.val3 = FUTEX_BITSET_MATCH_ANY; + + return (linux_futex_wake(td, &args)); +} + +static int +futex_wake_pi(struct thread *td, uint32_t * __capability uaddr, bool shared) +{ + struct linux_futex_args args; + + bzero(&args, sizeof(args)); + args.op = LINUX_FUTEX_UNLOCK_PI; + args.uaddr = uaddr; + args.flags = shared == true ? FUTEX_SHARED : 0; + + return (linux_futex_unlock_pi(td, true, &args)); +} + +static int +futex_atomic_op(struct thread *td, int encoded_op, uint32_t * __capability uaddr, + int *res) +{ + int op = (encoded_op >> 28) & 7; + int cmp = (encoded_op >> 24) & 15; + int oparg = (encoded_op << 8) >> 20; + int cmparg = (encoded_op << 20) >> 20; + int oldval = 0, ret; + + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) + oparg = 1 << oparg; + + switch (op) { + case FUTEX_OP_SET: + ret = futex_xchgl(oparg, uaddr, &oldval); + break; + case FUTEX_OP_ADD: + ret = futex_addl(oparg, uaddr, &oldval); + break; + case FUTEX_OP_OR: + ret = futex_orl(oparg, uaddr, &oldval); + break; + case FUTEX_OP_ANDN: + ret = futex_andl(~oparg, uaddr, &oldval); + break; + case FUTEX_OP_XOR: + ret = futex_xorl(oparg, uaddr, &oldval); + break; + default: + ret = ENOSYS; + break; + } + + if (ret != 0) + return (ret); + + switch (cmp) { + case FUTEX_OP_CMP_EQ: + *res = (oldval == cmparg); + break; + case FUTEX_OP_CMP_NE: + *res = (oldval != cmparg); + break; + case FUTEX_OP_CMP_LT: + *res = (oldval < cmparg); + break; + case FUTEX_OP_CMP_GE: + *res = (oldval >= cmparg); + break; + case FUTEX_OP_CMP_LE: + *res = (oldval <= cmparg); + break; + case FUTEX_OP_CMP_GT: + *res = (oldval > cmparg); + break; + default: + ret = ENOSYS; + } + + return (ret); +} + +static int +linux_futex(struct thread *td, struct linux_futex_args *args) +{ + struct linux_pemuldata *pem; + struct proc *p; + + if (args->op & LINUX_FUTEX_PRIVATE_FLAG) { + args->flags = 0; + args->op &= ~LINUX_FUTEX_PRIVATE_FLAG; + } else + args->flags = FUTEX_SHARED; + + args->clockrt = args->op & LINUX_FUTEX_CLOCK_REALTIME; + args->op = args->op & ~LINUX_FUTEX_CLOCK_REALTIME; + + if (args->clockrt && + args->op != LINUX_FUTEX_WAIT_BITSET && + args->op != LINUX_FUTEX_WAIT_REQUEUE_PI && + args->op != LINUX_FUTEX_LOCK_PI2) + return (ENOSYS); + + switch (args->op) { + case LINUX_FUTEX_WAIT: + args->val3 = FUTEX_BITSET_MATCH_ANY; + /* FALLTHROUGH */ + + case LINUX_FUTEX_WAIT_BITSET: + LINUX_CTR3(sys_futex, "WAIT uaddr %p val 0x%x bitset 0x%x", + args->uaddr, args->val, args->val3); + + return (linux_futex_wait(td, args)); + + case LINUX_FUTEX_WAKE: + args->val3 = FUTEX_BITSET_MATCH_ANY; + /* FALLTHROUGH */ + + case LINUX_FUTEX_WAKE_BITSET: + LINUX_CTR3(sys_futex, "WAKE uaddr %p nrwake 0x%x bitset 0x%x", + args->uaddr, args->val, args->val3); + + return (linux_futex_wake(td, args)); + + case LINUX_FUTEX_REQUEUE: + /* + * Glibc does not use this operation since version 2.3.3, + * as it is racy and replaced by FUTEX_CMP_REQUEUE operation. + * Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when + * FUTEX_REQUEUE returned EINVAL. + */ + pem = pem_find(td->td_proc); + if ((pem->flags & LINUX_XDEPR_REQUEUEOP) == 0) { + linux_msg(td, "unsupported FUTEX_REQUEUE"); + pem->flags |= LINUX_XDEPR_REQUEUEOP; + } + + /* + * The above is true, however musl libc does make use of the + * futex requeue operation, allow operation for brands which + * set LINUX_BI_FUTEX_REQUEUE bit of Brandinfo flags. + */ + p = td->td_proc; + Elf_Brandinfo *bi = p->p_elf_brandinfo; + if (bi == NULL || ((bi->flags & LINUX_BI_FUTEX_REQUEUE)) == 0) + return (EINVAL); + args->val3_compare = false; + /* FALLTHROUGH */ + + case LINUX_FUTEX_CMP_REQUEUE: + LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p " + "nrwake 0x%x uval 0x%x uaddr2 %p nrequeue 0x%x", + args->uaddr, args->val, args->val3, args->uaddr2, + args->ts); + + return (linux_futex_requeue(td, args)); + + case LINUX_FUTEX_WAKE_OP: + LINUX_CTR5(sys_futex, "WAKE_OP " + "uaddr %p nrwake 0x%x uaddr2 %p op 0x%x nrwake2 0x%x", + args->uaddr, args->val, args->uaddr2, args->val3, + args->ts); + + return (linux_futex_wakeop(td, args)); + + case LINUX_FUTEX_LOCK_PI: + args->clockrt = true; + /* FALLTHROUGH */ + + case LINUX_FUTEX_LOCK_PI2: + LINUX_CTR2(sys_futex, "LOCKPI uaddr %p val 0x%x", + args->uaddr, args->val); + + return (linux_futex_lock_pi(td, false, args)); + + case LINUX_FUTEX_UNLOCK_PI: + LINUX_CTR1(sys_futex, "UNLOCKPI uaddr %p", + args->uaddr); + + return (linux_futex_unlock_pi(td, false, args)); + + case LINUX_FUTEX_TRYLOCK_PI: + LINUX_CTR1(sys_futex, "TRYLOCKPI uaddr %p", + args->uaddr); + + return (linux_futex_lock_pi(td, true, args)); + + /* + * Current implementation of FUTEX_WAIT_REQUEUE_PI and FUTEX_CMP_REQUEUE_PI + * can't be used anymore to implement conditional variables. + * A detailed explanation can be found here: + * + * https://sourceware.org/bugzilla/show_bug.cgi?id=13165 + * and here http://austingroupbugs.net/view.php?id=609 + * + * And since commit + * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=ed19993b5b0d05d62cc883571519a67dae481a14 + * glibc does not use them. + */ + case LINUX_FUTEX_WAIT_REQUEUE_PI: + /* not yet implemented */ + pem = pem_find(td->td_proc); + if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { + linux_msg(td, "unsupported FUTEX_WAIT_REQUEUE_PI"); + pem->flags |= LINUX_XUNSUP_FUTEXPIOP; + } + return (ENOSYS); + + case LINUX_FUTEX_CMP_REQUEUE_PI: + /* not yet implemented */ + pem = pem_find(td->td_proc); + if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { + linux_msg(td, "unsupported FUTEX_CMP_REQUEUE_PI"); + pem->flags |= LINUX_XUNSUP_FUTEXPIOP; + } + return (ENOSYS); + + default: + linux_msg(td, "unsupported futex op %d", args->op); + return (ENOSYS); + } +} + +/* + * pi protocol: + * - 0 futex word value means unlocked. + * - TID futex word value means locked. + * Userspace uses atomic ops to lock/unlock these futexes without entering the + * kernel. If the lock-acquire fastpath fails, (transition from 0 to TID fails), + * then FUTEX_LOCK_PI is called. + * The kernel atomically set FUTEX_WAITERS bit in the futex word value, if no + * other waiters exists looks up the thread that owns the futex (it has put its + * own TID into the futex value) and made this thread the owner of the internal + * pi-aware lock object (mutex). Then the kernel tries to lock the internal lock + * object, on which it blocks. Once it returns, it has the mutex acquired, and it + * sets the futex value to its own TID and returns (futex value contains + * FUTEX_WAITERS|TID). + * The unlock fastpath would fail (because the FUTEX_WAITERS bit is set) and + * FUTEX_UNLOCK_PI will be called. + * If a futex is found to be held at exit time, the kernel sets the OWNER_DIED + * bit of the futex word and wakes up the next futex waiter (if any), WAITERS + * bit is preserved (if any). + * If OWNER_DIED bit is set the kernel sanity checks the futex word value against + * the internal futex state and if correct, acquire futex. + */ +static int +linux_futex_lock_pi(struct thread *td, bool try, struct linux_futex_args *args) +{ + struct umtx_abs_timeout timo; + struct linux_emuldata *em; + struct umtx_pi *pi, *new_pi; + struct thread *td1; + struct umtx_q *uq; + int error, rv; + uint32_t owner, old_owner; + + em = em_find(td); + uq = td->td_umtxq; + error = futex_key_get(args->uaddr, TYPE_PI_FUTEX, GET_SHARED(args), + &uq->uq_key); + if (error != 0) + return (error); + if (args->ts != NULL) + linux_umtx_abs_timeout_init(&timo, args); + + umtxq_lock(&uq->uq_key); + pi = umtx_pi_lookup(&uq->uq_key); + if (pi == NULL) { + new_pi = umtx_pi_alloc(M_NOWAIT); + if (new_pi == NULL) { + umtxq_unlock(&uq->uq_key); + new_pi = umtx_pi_alloc(M_WAITOK); + umtxq_lock(&uq->uq_key); + pi = umtx_pi_lookup(&uq->uq_key); + if (pi != NULL) { + umtx_pi_free(new_pi); + new_pi = NULL; + } + } + if (new_pi != NULL) { + new_pi->pi_key = uq->uq_key; + umtx_pi_insert(new_pi); + pi = new_pi; + } + } + umtx_pi_ref(pi); + umtxq_unlock(&uq->uq_key); + for (;;) { + /* Try uncontested case first. */ + rv = casueword32(args->uaddr, FUTEX_UNOWNED, &owner, em->em_tid); + /* The acquire succeeded. */ + if (rv == 0) { + error = 0; + break; + } + if (rv == -1) { + error = EFAULT; + break; + } + + /* + * Nobody owns it, but the acquire failed. This can happen + * with ll/sc atomic. + */ + if (owner == FUTEX_UNOWNED) { + error = thread_check_susp(td, true); + if (error != 0) + break; + continue; + } + + /* + * Avoid overwriting a possible error from sleep due + * to the pending signal with suspension check result. + */ + if (error == 0) { + error = thread_check_susp(td, true); + if (error != 0) + break; + } + + /* The futex word at *uaddr is already locked by the caller. */ + if ((owner & FUTEX_TID_MASK) == em->em_tid) { + error = EDEADLK; + break; + } + + /* + * Futex owner died, handle_futex_death() set the OWNER_DIED bit + * and clear tid. Try to acquire it. + */ + if ((owner & FUTEX_TID_MASK) == FUTEX_UNOWNED) { + old_owner = owner; + owner = owner & (FUTEX_WAITERS | FUTEX_OWNER_DIED); + owner |= em->em_tid; + rv = casueword32(args->uaddr, old_owner, &owner, owner); + if (rv == -1) { + error = EFAULT; + break; + } + if (rv == 1) { + if (error == 0) { + error = thread_check_susp(td, true); + if (error != 0) + break; + } + + /* + * If this failed the lock could + * changed, restart. + */ + continue; + } + + umtxq_lock(&uq->uq_key); + umtxq_busy(&uq->uq_key); + error = umtx_pi_claim(pi, td); + umtxq_unbusy(&uq->uq_key); + umtxq_unlock(&uq->uq_key); + if (error != 0) { + /* + * Since we're going to return an + * error, restore the futex to its + * previous, unowned state to avoid + * compounding the problem. + */ + (void)casuword32(args->uaddr, owner, old_owner); + } + break; + } + + /* + * Inconsistent state: OWNER_DIED is set and tid is not 0. + * Linux does some checks of futex state, we return EINVAL, + * as the user space can take care of this. + */ + if ((owner & FUTEX_OWNER_DIED) != FUTEX_UNOWNED) { + error = EINVAL; + break; + } + + if (try != 0) { + error = EBUSY; + break; + } + + /* + * If we caught a signal, we have retried and now + * exit immediately. + */ + if (error != 0) + break; + + umtxq_lock(&uq->uq_key); + umtxq_busy(&uq->uq_key); + umtxq_unlock(&uq->uq_key); + + /* + * Set the contested bit so that a release in user space knows + * to use the system call for unlock. If this fails either some + * one else has acquired the lock or it has been released. + */ + rv = casueword32(args->uaddr, owner, &owner, + owner | FUTEX_WAITERS); + if (rv == -1) { + umtxq_unbusy_unlocked(&uq->uq_key); + error = EFAULT; + break; + } + if (rv == 1) { + umtxq_unbusy_unlocked(&uq->uq_key); + error = thread_check_susp(td, true); + if (error != 0) + break; + + /* + * The lock changed and we need to retry or we + * lost a race to the thread unlocking the umtx. + */ + continue; + } + + /* + * Substitute Linux thread id by native thread id to + * avoid refactoring code of umtxq_sleep_pi(). + */ + td1 = linux_tdfind(td, owner & FUTEX_TID_MASK, -1); + if (td1 != NULL) { + owner = td1->td_tid; + PROC_UNLOCK(td1->td_proc); + } else { + umtxq_unbusy_unlocked(&uq->uq_key); + error = EINVAL; + break; + } + + umtxq_lock(&uq->uq_key); + + /* We set the contested bit, sleep. */ + error = umtxq_sleep_pi(uq, pi, owner, "futexp", + args->ts == NULL ? NULL : &timo, + (args->flags & FUTEX_SHARED) != 0); + if (error != 0) + continue; + + error = thread_check_susp(td, false); + if (error != 0) + break; + } + + umtxq_lock(&uq->uq_key); + umtx_pi_unref(pi); + umtxq_unlock(&uq->uq_key); + umtx_key_release(&uq->uq_key); + return (error); +} + +static int +linux_futex_unlock_pi(struct thread *td, bool rb, struct linux_futex_args *args) +{ + struct linux_emuldata *em; + struct umtx_key key; + uint32_t old, owner, new_owner; + int count, error; + + em = em_find(td); + + /* + * Make sure we own this mtx. + */ + error = fueword32(args->uaddr, &owner); + if (error == -1) + return (EFAULT); + if (!rb && (owner & FUTEX_TID_MASK) != em->em_tid) + return (EPERM); + + error = futex_key_get(args->uaddr, TYPE_PI_FUTEX, GET_SHARED(args), &key); + if (error != 0) + return (error); + umtxq_lock(&key); + umtxq_busy(&key); + error = umtx_pi_drop(td, &key, rb, &count); + if (error != 0 || rb) { + umtxq_unbusy(&key); + umtxq_unlock(&key); + umtx_key_release(&key); + return (error); + } + umtxq_unlock(&key); + + /* + * When unlocking the futex, it must be marked as unowned if + * there is zero or one thread only waiting for it. + * Otherwise, it must be marked as contested. + */ + if (count > 1) + new_owner = FUTEX_WAITERS; + else + new_owner = FUTEX_UNOWNED; + +again: + error = casueword32(args->uaddr, owner, &old, new_owner); + if (error == 1) { + error = thread_check_susp(td, false); + if (error == 0) + goto again; + } + umtxq_unbusy_unlocked(&key); + umtx_key_release(&key); + if (error == -1) + return (EFAULT); + if (error == 0 && old != owner) + return (EINVAL); + return (error); +} + +static int +linux_futex_wakeop(struct thread *td, struct linux_futex_args *args) +{ + struct umtx_key key, key2; + int nrwake, op_ret, ret; + int error, count; + + // Try to support this case temporarily to pass PCuABI test + if (args->uaddr == args->uaddr2) + { + error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); + if (error != 0) + return (error); + + error = futex_atomic_op(td, args->val3, args->uaddr2, &op_ret); + + umtxq_lock(&key); + if (error != 0) + goto same_mutex_out; + ret = umtxq_signal_mask(&key, args->val, args->val3); + if (op_ret > 0) { + nrwake = (int)(unsigned long)args->ts; + ret += umtxq_signal_mask(&key, nrwake, args->val3); + } + td->td_retval[0] = ret; +same_mutex_out: + umtxq_unlock(&key); + umtx_key_release(&key); + return (error); + } + + error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); + if (error != 0) + return (error); + error = futex_key_get(args->uaddr2, TYPE_FUTEX, GET_SHARED(args), &key2); + if (error != 0) { + umtx_key_release(&key); + return (error); + } + umtxq_lock(&key); + umtxq_busy(&key); + umtxq_unlock(&key); + error = futex_atomic_op(td, args->val3, args->uaddr2, &op_ret); + umtxq_lock(&key); + umtxq_unbusy(&key); + if (error != 0) + goto out; + ret = umtxq_signal_mask(&key, args->val, args->val3); + if (op_ret > 0) { + nrwake = (int)(unsigned long)args->ts; + umtxq_lock(&key2); + count = umtxq_count(&key2); + if (count > 0) + ret += umtxq_signal_mask(&key2, nrwake, args->val3); + else + ret += umtxq_signal_mask(&key, nrwake, args->val3); + umtxq_unlock(&key2); + } + td->td_retval[0] = ret; +out: + umtxq_unlock(&key); + umtx_key_release(&key2); + umtx_key_release(&key); + return (error); +} + +static int +linux_futex_requeue(struct thread *td, struct linux_futex_args *args) +{ + int nrwake, nrrequeue; + struct umtx_key key, key2; + int error; + uint32_t uval; + + /* + * Linux allows this, we would not, it is an incorrect + * usage of declared ABI, so return EINVAL. + */ + if (args->uaddr == args->uaddr2) + return (EINVAL); + + nrrequeue = (int)(unsigned long)args->ts; + nrwake = args->val; + /* + * Sanity check to prevent signed integer overflow, + * see Linux CVE-2018-6927 + */ + if (nrwake < 0 || nrrequeue < 0) + return (EINVAL); + + error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); + if (error != 0) + return (error); + error = futex_key_get(args->uaddr2, TYPE_FUTEX, GET_SHARED(args), &key2); + if (error != 0) { + umtx_key_release(&key); + return (error); + } + umtxq_lock(&key); + umtxq_busy(&key); + umtxq_unlock(&key); + error = fueword32(args->uaddr, &uval); + if (error != 0) + error = EFAULT; + else if (args->val3_compare == true && uval != args->val3) + error = EWOULDBLOCK; + umtxq_lock(&key); + umtxq_unbusy(&key); + if (error == 0) { + umtxq_lock(&key2); + td->td_retval[0] = umtxq_requeue(&key, nrwake, &key2, nrrequeue); + umtxq_unlock(&key2); + } + umtxq_unlock(&key); + umtx_key_release(&key2); + umtx_key_release(&key); + return (error); +} + +static int +linux_futex_wake(struct thread *td, struct linux_futex_args *args) +{ + struct umtx_key key; + int error; + + if (args->val3 == 0) + return (EINVAL); + + error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), &key); + if (error != 0) + return (error); + umtxq_lock(&key); + td->td_retval[0] = umtxq_signal_mask(&key, args->val, args->val3); + umtxq_unlock(&key); + umtx_key_release(&key); + return (0); +} + +static int +linux_futex_wait(struct thread *td, struct linux_futex_args *args) +{ + struct umtx_abs_timeout timo; + struct umtx_q *uq; + uint32_t uval; + int error; + + if (args->val3 == 0) + error = EINVAL; + + uq = td->td_umtxq; + error = futex_key_get(args->uaddr, TYPE_FUTEX, GET_SHARED(args), + &uq->uq_key); + if (error != 0) + return (error); + if (args->ts != NULL) + linux_umtx_abs_timeout_init(&timo, args); + umtxq_lock(&uq->uq_key); + umtxq_busy(&uq->uq_key); + uq->uq_bitset = args->val3; + umtxq_insert(uq); + umtxq_unlock(&uq->uq_key); + error = fueword32(args->uaddr, &uval); + if (error != 0) + error = EFAULT; + else if (uval != args->val) + error = EWOULDBLOCK; + umtxq_lock(&uq->uq_key); + umtxq_unbusy(&uq->uq_key); + if (error == 0) { + error = umtxq_sleep(uq, "futex", + args->ts == NULL ? NULL : &timo); + if ((uq->uq_flags & UQF_UMTXQ) == 0) + error = 0; + else + umtxq_remove(uq); + } else if ((uq->uq_flags & UQF_UMTXQ) != 0) { + umtxq_remove(uq); + } + umtxq_unlock(&uq->uq_key); + umtx_key_release(&uq->uq_key); + if (error == ERESTART) + error = EINTR; + return (error); +} + +static void +linux_umtx_abs_timeout_init(struct umtx_abs_timeout *timo, + struct linux_futex_args *args) +{ + int clockid, absolute; + + /* + * The FUTEX_CLOCK_REALTIME option bit can be employed only with the + * FUTEX_WAIT_BITSET, FUTEX_WAIT_REQUEUE_PI, FUTEX_LOCK_PI2. + * For FUTEX_WAIT, timeout is interpreted as a relative value, for other + * futex operations timeout is interpreted as an absolute value. + * If FUTEX_CLOCK_REALTIME option bit is set, the Linux kernel measures + * the timeout against the CLOCK_REALTIME clock, otherwise the kernel + * measures the timeout against the CLOCK_MONOTONIC clock. + */ + clockid = args->clockrt ? CLOCK_REALTIME : CLOCK_MONOTONIC; + absolute = args->op == LINUX_FUTEX_WAIT ? false : true; + umtx_abs_timeout_init(timo, clockid, absolute, args->ts); +} + +int +linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) +{ + struct linux_futex_args fargs = { + .uaddr = LINUX_USER_CAP_UNBOUND(args->uaddr), + .op = args->op, + .val = args->val, + .ts = NULL, + .uaddr2 = LINUX_USER_CAP_UNBOUND(args->uaddr2), + .val3 = args->val3, + .val3_compare = true, + }; + int error; + + switch (args->op & LINUX_FUTEX_CMD_MASK) { + case LINUX_FUTEX_WAIT: + case LINUX_FUTEX_WAIT_BITSET: + case LINUX_FUTEX_LOCK_PI: + case LINUX_FUTEX_LOCK_PI2: + if (args->timeout != NULL) { + error = linux_get_timespec(&fargs.kts, args->timeout); + if (error != 0) + return (error); + fargs.ts = &fargs.kts; + } + break; + default: + // LINUX_FUTEX_CMD is not the four mentioned above + // copy directly without copying in the timespec + fargs.ts = (void *)(uintptr_t)(linuxcap_t)(args->timeout); + } + return (linux_futex(td, &fargs)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_sys_futex_time64(struct thread *td, + struct linux_sys_futex_time64_args *args) +{ + struct linux_futex_args fargs = { + .uaddr = LINUX_USER_CAP_UNBOUND(args->uaddr), + .op = args->op, + .val = args->val, + .ts = NULL, + .uaddr2 = LINUX_USER_CAP_UNBOUND(args->uaddr2), + .val3 = args->val3, + .val3_compare = true, + }; + int error; + + switch (args->op & LINUX_FUTEX_CMD_MASK) { + case LINUX_FUTEX_WAIT: + case LINUX_FUTEX_WAIT_BITSET: + case LINUX_FUTEX_LOCK_PI: + case LINUX_FUTEX_LOCK_PI2: + if (args->timeout != NULL) { + error = linux_get_timespec64(&fargs.kts, args->timeout); + if (error != 0) + return (error); + fargs.ts = &fargs.kts; + } + break; + default: + fargs.ts = PTRIN(args->timeout); + } + return (linux_futex(td, &fargs)); +} +#endif + +int +linux_set_robust_list(struct thread *td, struct linux_set_robust_list_args *args) +{ + struct linux_emuldata *em; + + if (args->len != sizeof(struct linux_robust_list_head)) + return (EINVAL); + + em = em_find(td); + em->robust_futexes = LINUX_USER_CAP_OBJ(args->head); + + return (0); +} + +int +linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args) +{ + struct linux_emuldata *em; + struct linux_robust_list_head * __capability head; + l_size_t len; + struct thread *td2; + int error; + + if (!args->pid) { + em = em_find(td); + KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n")); + head = em->robust_futexes; + } else { + td2 = linux_tdfind(td, args->pid, -1); + if (td2 == NULL) + return (ESRCH); + if (SV_PROC_ABI(td2->td_proc) != SV_ABI_LINUX) { + PROC_UNLOCK(td2->td_proc); + return (EPERM); + } + + em = em_find(td2); + KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n")); + /* XXX: ptrace? */ + if (priv_check(td, PRIV_CRED_SETUID) || + priv_check(td, PRIV_CRED_SETEUID) || + p_candebug(td, td2->td_proc)) { + PROC_UNLOCK(td2->td_proc); + return (EPERM); + } + head = em->robust_futexes; + + PROC_UNLOCK(td2->td_proc); + } + + len = sizeof(struct linux_robust_list_head); + error = copyout(&len, LINUX_USER_CAP_OBJ(args->len), sizeof(l_size_t)); + if (error != 0) + return (EFAULT); + + return (copyout(&head, LINUX_USER_CAP_OBJ(args->head), sizeof(l_uintptr_t))); +} + +static int +handle_futex_death(struct thread *td, struct linux_emuldata *em, uint32_t * __capability uaddr, + unsigned int pi, bool pending_op) +{ + uint32_t uval, nval, mval; + int error; + +retry: + error = fueword32(uaddr, &uval); + if (error != 0) + return (EFAULT); + + /* + * Special case for regular (non PI) futexes. The unlock path in + * user space has two race scenarios: + * + * 1. The unlock path releases the user space futex value and + * before it can execute the futex() syscall to wake up + * waiters it is killed. + * + * 2. A woken up waiter is killed before it can acquire the + * futex in user space. + * + * In both cases the TID validation below prevents a wakeup of + * potential waiters which can cause these waiters to block + * forever. + * + * In both cases it is safe to attempt waking up a potential + * waiter without touching the user space futex value and trying + * to set the OWNER_DIED bit. + */ + if (pending_op && !pi && !uval) { + (void)futex_wake(td, uaddr, 1, true); + return (0); + } + + if ((uval & FUTEX_TID_MASK) == em->em_tid) { + mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED; + error = casueword32(uaddr, uval, &nval, mval); + if (error == -1) + return (EFAULT); + if (error == 1) { + error = thread_check_susp(td, false); + if (error != 0) + return (error); + goto retry; + } + + if (!pi && (uval & FUTEX_WAITERS)) { + error = futex_wake(td, uaddr, 1, true); + if (error != 0) + return (error); + } else if (pi && (uval & FUTEX_WAITERS)) { + error = futex_wake_pi(td, uaddr, true); + if (error != 0) + return (error); + } + } + + return (0); +} + +// TODO: This is probably wrong... +static int +fetch_robust_entry(struct linux_robust_list * __capability *entry, + struct linux_robust_list * __capability * __capability head, unsigned int *pi) +{ + uintcap_t uentry; + int error; + + error = copyin((const void * __capability)head, &uentry, sizeof(uentry)); + if (error != 0) + return (EFAULT); + + *entry = (void * __capability)(uentry & ~1UL); + *pi = uentry & 1; + + return (0); +} + +#define LINUX_HANDLE_DEATH_PENDING true +#define LINUX_HANDLE_DEATH_LIST false + +/* This walks the list of robust futexes releasing them. */ +void +release_futexes(struct thread *td, struct linux_emuldata *em) +{ + struct linux_robust_list_head * __capability head; + struct linux_robust_list * __capability entry, * __capability next_entry, * __capability pending; + unsigned int limit = 2048, pi, next_pi, pip; + uint32_t * __capability uaddr; + l_long futex_offset; + int error; + + head = em->robust_futexes; + if (head == NULL) + return; + + if (fetch_robust_entry(&entry, (void * __capability)(&head->list.next), &pi)) + return; + + error = copyin(&head->futex_offset, &futex_offset, + sizeof(futex_offset)); + if (error != 0) + return; + + if (fetch_robust_entry(&pending, (void * __capability)(&head->pending_list), &pip)) + return; + + while (entry != &head->list) { + error = fetch_robust_entry(&next_entry, (void * __capability)(&entry->next), + &next_pi); + + /* + * A pending lock might already be on the list, so + * don't process it twice. + */ + if (entry != pending) { + uaddr = (uint32_t * __capability)((char * __capability)entry + futex_offset); + if (handle_futex_death(td, em, uaddr, pi, + LINUX_HANDLE_DEATH_LIST)) + return; + } + if (error != 0) + return; + + entry = next_entry; + pi = next_pi; + + if (!--limit) + break; + + sched_relinquish(curthread); + } + + if (pending) { + uaddr = (uint32_t * __capability)((char * __capability)pending + futex_offset); + (void)handle_futex_death(td, em, uaddr, pip, + LINUX_HANDLE_DEATH_PENDING); + } +} diff --git a/sys/compat/linux/linux_futex.h b/sys/compat/linux/linux_futex.h index b6b6b0c98573..0b1270c26744 100644 --- a/sys/compat/linux/linux_futex.h +++ b/sys/compat/linux/linux_futex.h @@ -1,100 +1,100 @@ -/* $NetBSD: linux_futex.h,v 1.2 2005/12/11 12:20:19 christos Exp $ */ - -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 2005 Emmanuel Dreyfus, 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Emmanuel Dreyfus - * 4. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE 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. - */ - -#ifndef _LINUX_FUTEX_H -#define _LINUX_FUTEX_H - -#define LINUX_FUTEX_WAIT 0 -#define LINUX_FUTEX_WAKE 1 -#define LINUX_FUTEX_FD 2 /* unused */ -#define LINUX_FUTEX_REQUEUE 3 -#define LINUX_FUTEX_CMP_REQUEUE 4 -#define LINUX_FUTEX_WAKE_OP 5 -#define LINUX_FUTEX_LOCK_PI 6 -#define LINUX_FUTEX_UNLOCK_PI 7 -#define LINUX_FUTEX_TRYLOCK_PI 8 -#define LINUX_FUTEX_WAIT_BITSET 9 -#define LINUX_FUTEX_WAKE_BITSET 10 -#define LINUX_FUTEX_WAIT_REQUEUE_PI 11 -#define LINUX_FUTEX_CMP_REQUEUE_PI 12 -#define LINUX_FUTEX_LOCK_PI2 13 - -#define LINUX_FUTEX_PRIVATE_FLAG 128 -#define LINUX_FUTEX_CLOCK_REALTIME 256 - -#define LINUX_FUTEX_CMD_MASK ~(LINUX_FUTEX_PRIVATE_FLAG | \ - LINUX_FUTEX_CLOCK_REALTIME) - -#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ -#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ -#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ -#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */ -#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */ - -#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */ - -#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */ -#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */ -#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */ -#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */ -#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */ -#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */ - -#define FUTEX_WAITERS 0x80000000 -#define FUTEX_OWNER_DIED 0x40000000 -#define FUTEX_TID_MASK 0x3fffffff -#define FUTEX_BITSET_MATCH_ANY 0xffffffff - -/* robust futexes */ -struct linux_robust_list { - l_uintptr_t next; -}; - -struct linux_robust_list_head { - struct linux_robust_list list; - l_long futex_offset; - l_uintptr_t pending_list; -}; - -int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval); -int futex_addl(int oparg, uint32_t *uaddr, int *oldval); -int futex_orl(int oparg, uint32_t *uaddr, int *oldval); -int futex_andl(int oparg, uint32_t *uaddr, int *oldval); -int futex_xorl(int oparg, uint32_t *uaddr, int *oldval); -int futex_wake(struct thread *td, uint32_t *uaddr, int val, bool shared); -void release_futexes(struct thread *, - struct linux_emuldata *); - -#endif /* !_LINUX_FUTEX_H */ +/* $NetBSD: linux_futex.h,v 1.2 2005/12/11 12:20:19 christos Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 2005 Emmanuel Dreyfus, 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Emmanuel Dreyfus + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE 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. + */ + +#ifndef _LINUX_FUTEX_H +#define _LINUX_FUTEX_H + +#define LINUX_FUTEX_WAIT 0 +#define LINUX_FUTEX_WAKE 1 +#define LINUX_FUTEX_FD 2 /* unused */ +#define LINUX_FUTEX_REQUEUE 3 +#define LINUX_FUTEX_CMP_REQUEUE 4 +#define LINUX_FUTEX_WAKE_OP 5 +#define LINUX_FUTEX_LOCK_PI 6 +#define LINUX_FUTEX_UNLOCK_PI 7 +#define LINUX_FUTEX_TRYLOCK_PI 8 +#define LINUX_FUTEX_WAIT_BITSET 9 +#define LINUX_FUTEX_WAKE_BITSET 10 +#define LINUX_FUTEX_WAIT_REQUEUE_PI 11 +#define LINUX_FUTEX_CMP_REQUEUE_PI 12 +#define LINUX_FUTEX_LOCK_PI2 13 + +#define LINUX_FUTEX_PRIVATE_FLAG 128 +#define LINUX_FUTEX_CLOCK_REALTIME 256 + +#define LINUX_FUTEX_CMD_MASK ~(LINUX_FUTEX_PRIVATE_FLAG | \ + LINUX_FUTEX_CLOCK_REALTIME) + +#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ +#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ +#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ +#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */ +#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */ + +#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */ + +#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */ +#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */ +#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */ +#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */ +#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */ +#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */ + +#define FUTEX_WAITERS 0x80000000 +#define FUTEX_OWNER_DIED 0x40000000 +#define FUTEX_TID_MASK 0x3fffffff +#define FUTEX_BITSET_MATCH_ANY 0xffffffff + +/* robust futexes */ +struct linux_robust_list { + l_uintptr_t next; +}; + +struct linux_robust_list_head { + struct linux_robust_list list; + l_long futex_offset; + l_uintptr_t pending_list; +}; + +int futex_xchgl(int oparg, uint32_t * __capability uaddr, int *oldval); +int futex_addl(int oparg, uint32_t * __capability uaddr, int *oldval); +int futex_orl(int oparg, uint32_t * __capability uaddr, int *oldval); +int futex_andl(int oparg, uint32_t * __capability uaddr, int *oldval); +int futex_xorl(int oparg, uint32_t * __capability uaddr, int *oldval); +int futex_wake(struct thread *td, uint32_t * __capability uaddr, int val, bool shared); +void release_futexes(struct thread *, + struct linux_emuldata *); + +#endif /* !_LINUX_FUTEX_H */ diff --git a/sys/compat/linux/linux_getcwd.c b/sys/compat/linux/linux_getcwd.c index 4511345664af..69e35b57c30c 100644 --- a/sys/compat/linux/linux_getcwd.c +++ b/sys/compat/linux/linux_getcwd.c @@ -1,88 +1,91 @@ -/* $OpenBSD: linux_getcwd.c,v 1.2 2001/05/16 12:50:21 ho Exp $ */ -/* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 1999 The NetBSD Foundation, Inc. - * Copyright (c) 2015 The FreeBSD Foundation - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Bill Sommerfeld. - * - * Portions of this software were developed by Edward Tomasz Napierala - * under sponsorship from the FreeBSD Foundation. - * - * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif -#include - -/* - * Find pathname of process's current directory. - */ -int -linux_getcwd(struct thread *td, struct linux_getcwd_args *uap) -{ - char *buf, *retbuf; - size_t buflen; - int error; - - buflen = uap->bufsize; - if (__predict_false(buflen < 2)) - return (ERANGE); - if (buflen > LINUX_PATH_MAX) - buflen = LINUX_PATH_MAX; - - buf = malloc(buflen, M_TEMP, M_WAITOK); - error = vn_getcwd(buf, &retbuf, &buflen); - if (error == ENOMEM) - error = ERANGE; - if (error == 0) { - error = copyout(retbuf, uap->buf, buflen); - if (error == 0) - td->td_retval[0] = buflen; - } - free(buf, M_TEMP); - return (error); -} -// CHERI CHANGES START -// { -// "updated": 20230509, -// "target_type": "kernel", -// "changes": [ -// "user_capabilities" -// ] -// } -// CHERI CHANGES END +/* $OpenBSD: linux_getcwd.c,v 1.2 2001/05/16 12:50:21 ho Exp $ */ +/* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * Copyright (c) 2015 The FreeBSD Foundation + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld. + * + * Portions of this software were developed by Edward Tomasz Napierala + * under sponsorship from the FreeBSD Foundation. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif +#include + +/* + * Find pathname of process's current directory. + */ +int +linux_getcwd(struct thread *td, struct linux_getcwd_args *uap) +{ + char *buf, *retbuf; + size_t buflen; + int error; + + buflen = uap->bufsize; + if (__predict_false(buflen < 2)) + return (ERANGE); + if (buflen > LINUX_PATH_MAX) + buflen = LINUX_PATH_MAX; + + buf = malloc(buflen, M_TEMP, M_WAITOK); + error = vn_getcwd(buf, &retbuf, &buflen); + if (error == ENOMEM) + error = ERANGE; + if (error == 0) { + error = copyout(retbuf, LINUX_USER_CAP(uap->buf, buflen), buflen); + if (error == 0) + td->td_retval[0] = buflen; + } + free(buf, M_TEMP); + return (error); +} +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "kernel", +// "changes": [ +// "user_capabilities" +// ] +// } +// CHERI CHANGES END diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index aa2c9ce7f273..2b6ba2e4d93b 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -1,3794 +1,3809 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#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 -#else -#include -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#include - -#define DEFINE_LINUX_IOCTL_SET(shortname, SHORTNAME) \ -static linux_ioctl_function_t linux_ioctl_ ## shortname; \ -static struct linux_ioctl_handler shortname ## _handler = { \ - .func = linux_ioctl_ ## shortname, \ - .low = LINUX_IOCTL_ ## SHORTNAME ## _MIN, \ - .high = LINUX_IOCTL_ ## SHORTNAME ## _MAX, \ -}; \ -DATA_SET(linux_ioctl_handler_set, shortname ## _handler) - -DEFINE_LINUX_IOCTL_SET(cdrom, CDROM); -DEFINE_LINUX_IOCTL_SET(vfat, VFAT); -DEFINE_LINUX_IOCTL_SET(console, CONSOLE); -DEFINE_LINUX_IOCTL_SET(hdio, HDIO); -DEFINE_LINUX_IOCTL_SET(disk, DISK); -DEFINE_LINUX_IOCTL_SET(socket, SOCKET); -DEFINE_LINUX_IOCTL_SET(sound, SOUND); -DEFINE_LINUX_IOCTL_SET(termio, TERMIO); -DEFINE_LINUX_IOCTL_SET(private, PRIVATE); -DEFINE_LINUX_IOCTL_SET(drm, DRM); -DEFINE_LINUX_IOCTL_SET(sg, SG); -DEFINE_LINUX_IOCTL_SET(v4l, VIDEO); -DEFINE_LINUX_IOCTL_SET(v4l2, VIDEO2); -DEFINE_LINUX_IOCTL_SET(fbsd_usb, FBSD_LUSB); -DEFINE_LINUX_IOCTL_SET(evdev, EVDEV); -DEFINE_LINUX_IOCTL_SET(kcov, KCOV); -#ifndef COMPAT_LINUX32 -DEFINE_LINUX_IOCTL_SET(nvme, NVME); -#endif - -#undef DEFINE_LINUX_IOCTL_SET - -static int linux_ioctl_special(struct thread *, struct linux_ioctl_args *); - -/* - * Keep sorted by low. - */ -static struct linux_ioctl_handler linux_ioctls[] = { - { .func = linux_ioctl_termio, .low = LINUX_IOCTL_TERMIO_MIN, - .high = LINUX_IOCTL_TERMIO_MAX }, -}; - -#ifdef __i386__ -static TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers = - TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers); -static struct sx linux_ioctl_sx; -SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers"); -#else -extern TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers; -extern struct sx linux_ioctl_sx; -#endif -#ifdef COMPAT_LINUX32 -static TAILQ_HEAD(, linux_ioctl_handler_element) linux32_ioctl_handlers = - TAILQ_HEAD_INITIALIZER(linux32_ioctl_handlers); -#endif - -/* - * hdio related ioctls for VMWare support - */ - -struct linux_hd_geometry { - uint8_t heads; - uint8_t sectors; - uint16_t cylinders; - uint32_t start; -}; - -struct linux_hd_big_geometry { - uint8_t heads; - uint8_t sectors; - uint32_t cylinders; - uint32_t start; -}; - -static int -linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - int error; - u_int sectorsize, fwcylinders, fwheads, fwsectors; - off_t mediasize, bytespercyl; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - switch (args->cmd & 0xffff) { - case LINUX_HDIO_GET_GEO: - case LINUX_HDIO_GET_GEO_BIG: - error = fo_ioctl(fp, DIOCGMEDIASIZE, - (caddr_t)&mediasize, td->td_ucred, td); - if (!error) - error = fo_ioctl(fp, DIOCGSECTORSIZE, - (caddr_t)§orsize, td->td_ucred, td); - if (!error) - error = fo_ioctl(fp, DIOCGFWHEADS, - (caddr_t)&fwheads, td->td_ucred, td); - if (!error) - error = fo_ioctl(fp, DIOCGFWSECTORS, - (caddr_t)&fwsectors, td->td_ucred, td); - /* - * XXX: DIOCGFIRSTOFFSET is not yet implemented, so - * so pretend that GEOM always says 0. This is NOT VALID - * for slices or partitions, only the per-disk raw devices. - */ - - fdrop(fp, td); - if (error) - return (error); - /* - * 1. Calculate the number of bytes in a cylinder, - * given the firmware's notion of heads and sectors - * per cylinder. - * 2. Calculate the number of cylinders, given the total - * size of the media. - * All internal calculations should have 64-bit precision. - */ - bytespercyl = (off_t) sectorsize * fwheads * fwsectors; - fwcylinders = mediasize / bytespercyl; - - if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) { - struct linux_hd_geometry hdg; - - hdg.cylinders = fwcylinders; - hdg.heads = fwheads; - hdg.sectors = fwsectors; - hdg.start = 0; - error = copyout(&hdg, (void *)args->arg, sizeof(hdg)); - } else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) { - struct linux_hd_big_geometry hdbg; - - memset(&hdbg, 0, sizeof(hdbg)); - hdbg.cylinders = fwcylinders; - hdbg.heads = fwheads; - hdbg.sectors = fwsectors; - hdbg.start = 0; - error = copyout(&hdbg, (void *)args->arg, sizeof(hdbg)); - } - return (error); - break; - default: - /* XXX */ - linux_msg(td, - "%s fd=%d, cmd=0x%x ('%c',%d) is not implemented", - __func__, args->fd, args->cmd, - (int)(args->cmd & 0xff00) >> 8, - (int)(args->cmd & 0xff)); - break; - } - fdrop(fp, td); - return (ENOIOCTL); -} - -static int -linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - int error; - u_int sectorsize, psectorsize; - uint64_t blksize64; - off_t mediasize, stripesize; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - switch (args->cmd & 0xffff) { - case LINUX_BLKGETSIZE: - error = fo_ioctl(fp, DIOCGSECTORSIZE, - (caddr_t)§orsize, td->td_ucred, td); - if (!error) - error = fo_ioctl(fp, DIOCGMEDIASIZE, - (caddr_t)&mediasize, td->td_ucred, td); - fdrop(fp, td); - if (error) - return (error); - sectorsize = mediasize / sectorsize; - /* - * XXX: How do we know we return the right size of integer ? - */ - return (copyout(§orsize, (void *)args->arg, - sizeof(sectorsize))); - break; - case LINUX_BLKGETSIZE64: - error = fo_ioctl(fp, DIOCGMEDIASIZE, - (caddr_t)&mediasize, td->td_ucred, td); - fdrop(fp, td); - if (error) - return (error); - blksize64 = mediasize; - return (copyout(&blksize64, (void *)args->arg, - sizeof(blksize64))); - case LINUX_BLKSSZGET: - error = fo_ioctl(fp, DIOCGSECTORSIZE, - (caddr_t)§orsize, td->td_ucred, td); - fdrop(fp, td); - if (error) - return (error); - return (copyout(§orsize, (void *)args->arg, - sizeof(sectorsize))); - break; - case LINUX_BLKPBSZGET: - error = fo_ioctl(fp, DIOCGSTRIPESIZE, - (caddr_t)&stripesize, td->td_ucred, td); - if (error != 0) { - fdrop(fp, td); - return (error); - } - if (stripesize > 0 && stripesize <= 4096) { - psectorsize = stripesize; - } else { - error = fo_ioctl(fp, DIOCGSECTORSIZE, - (caddr_t)§orsize, td->td_ucred, td); - if (error != 0) { - fdrop(fp, td); - return (error); - } - psectorsize = sectorsize; - } - fdrop(fp, td); - return (copyout(&psectorsize, (void *)args->arg, - sizeof(psectorsize))); - } - fdrop(fp, td); - return (ENOIOCTL); -} - -/* - * termio related ioctls - */ - -struct linux_termio { - unsigned short c_iflag; - unsigned short c_oflag; - unsigned short c_cflag; - unsigned short c_lflag; - unsigned char c_line; - unsigned char c_cc[LINUX_NCC]; -}; - -struct linux_termios { - unsigned int c_iflag; - unsigned int c_oflag; - unsigned int c_cflag; - unsigned int c_lflag; - unsigned char c_line; - unsigned char c_cc[LINUX_NCCS]; -}; - -struct linux_winsize { - unsigned short ws_row, ws_col; - unsigned short ws_xpixel, ws_ypixel; -}; - -struct speedtab { - int sp_speed; /* Speed. */ - int sp_code; /* Code. */ -}; - -static struct speedtab sptab[] = { - { B0, LINUX_B0 }, { B50, LINUX_B50 }, - { B75, LINUX_B75 }, { B110, LINUX_B110 }, - { B134, LINUX_B134 }, { B150, LINUX_B150 }, - { B200, LINUX_B200 }, { B300, LINUX_B300 }, - { B600, LINUX_B600 }, { B1200, LINUX_B1200 }, - { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 }, - { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 }, - { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 }, - { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 }, - {-1, -1 } -}; - -struct linux_serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; - unsigned short closing_wait; - unsigned short closing_wait2; - int reserved[4]; -}; - -static int -linux_to_bsd_speed(int code, struct speedtab *table) -{ - for ( ; table->sp_code != -1; table++) - if (table->sp_code == code) - return (table->sp_speed); - return (-1); -} - -static int -bsd_to_linux_speed(int speed, struct speedtab *table) -{ - for ( ; table->sp_speed != -1; table++) - if (table->sp_speed == speed) - return (table->sp_code); - return (-1); -} - -static void -bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios) -{ - int i; - - lios->c_iflag = 0; - if (bios->c_iflag & IGNBRK) - lios->c_iflag |= LINUX_IGNBRK; - if (bios->c_iflag & BRKINT) - lios->c_iflag |= LINUX_BRKINT; - if (bios->c_iflag & IGNPAR) - lios->c_iflag |= LINUX_IGNPAR; - if (bios->c_iflag & PARMRK) - lios->c_iflag |= LINUX_PARMRK; - if (bios->c_iflag & INPCK) - lios->c_iflag |= LINUX_INPCK; - if (bios->c_iflag & ISTRIP) - lios->c_iflag |= LINUX_ISTRIP; - if (bios->c_iflag & INLCR) - lios->c_iflag |= LINUX_INLCR; - if (bios->c_iflag & IGNCR) - lios->c_iflag |= LINUX_IGNCR; - if (bios->c_iflag & ICRNL) - lios->c_iflag |= LINUX_ICRNL; - if (bios->c_iflag & IXON) - lios->c_iflag |= LINUX_IXON; - if (bios->c_iflag & IXANY) - lios->c_iflag |= LINUX_IXANY; - if (bios->c_iflag & IXOFF) - lios->c_iflag |= LINUX_IXOFF; - if (bios->c_iflag & IMAXBEL) - lios->c_iflag |= LINUX_IMAXBEL; - - lios->c_oflag = 0; - if (bios->c_oflag & OPOST) - lios->c_oflag |= LINUX_OPOST; - if (bios->c_oflag & ONLCR) - lios->c_oflag |= LINUX_ONLCR; - if (bios->c_oflag & TAB3) - lios->c_oflag |= LINUX_XTABS; - - lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab); - lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4; - if (bios->c_cflag & CSTOPB) - lios->c_cflag |= LINUX_CSTOPB; - if (bios->c_cflag & CREAD) - lios->c_cflag |= LINUX_CREAD; - if (bios->c_cflag & PARENB) - lios->c_cflag |= LINUX_PARENB; - if (bios->c_cflag & PARODD) - lios->c_cflag |= LINUX_PARODD; - if (bios->c_cflag & HUPCL) - lios->c_cflag |= LINUX_HUPCL; - if (bios->c_cflag & CLOCAL) - lios->c_cflag |= LINUX_CLOCAL; - if (bios->c_cflag & CRTSCTS) - lios->c_cflag |= LINUX_CRTSCTS; - - lios->c_lflag = 0; - if (bios->c_lflag & ISIG) - lios->c_lflag |= LINUX_ISIG; - if (bios->c_lflag & ICANON) - lios->c_lflag |= LINUX_ICANON; - if (bios->c_lflag & ECHO) - lios->c_lflag |= LINUX_ECHO; - if (bios->c_lflag & ECHOE) - lios->c_lflag |= LINUX_ECHOE; - if (bios->c_lflag & ECHOK) - lios->c_lflag |= LINUX_ECHOK; - if (bios->c_lflag & ECHONL) - lios->c_lflag |= LINUX_ECHONL; - if (bios->c_lflag & NOFLSH) - lios->c_lflag |= LINUX_NOFLSH; - if (bios->c_lflag & TOSTOP) - lios->c_lflag |= LINUX_TOSTOP; - if (bios->c_lflag & ECHOCTL) - lios->c_lflag |= LINUX_ECHOCTL; - if (bios->c_lflag & ECHOPRT) - lios->c_lflag |= LINUX_ECHOPRT; - if (bios->c_lflag & ECHOKE) - lios->c_lflag |= LINUX_ECHOKE; - if (bios->c_lflag & FLUSHO) - lios->c_lflag |= LINUX_FLUSHO; - if (bios->c_lflag & PENDIN) - lios->c_lflag |= LINUX_PENDIN; - if (bios->c_lflag & IEXTEN) - lios->c_lflag |= LINUX_IEXTEN; - - for (i=0; ic_cc[i] = LINUX_POSIX_VDISABLE; - lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR]; - lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT]; - lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE]; - lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL]; - lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF]; - lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL]; - lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN]; - lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME]; - lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2]; - lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP]; - lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART]; - lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP]; - lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT]; - lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD]; - lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE]; - lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT]; - if (linux_preserve_vstatus) - lios->c_cc[LINUX_VSTATUS] = bios->c_cc[VSTATUS]; - - for (i=0; ic_cc[i] == _POSIX_VDISABLE) - lios->c_cc[i] = LINUX_POSIX_VDISABLE; - } - lios->c_line = 0; -} - -static void -linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios) -{ - int i; - - bios->c_iflag = 0; - if (lios->c_iflag & LINUX_IGNBRK) - bios->c_iflag |= IGNBRK; - if (lios->c_iflag & LINUX_BRKINT) - bios->c_iflag |= BRKINT; - if (lios->c_iflag & LINUX_IGNPAR) - bios->c_iflag |= IGNPAR; - if (lios->c_iflag & LINUX_PARMRK) - bios->c_iflag |= PARMRK; - if (lios->c_iflag & LINUX_INPCK) - bios->c_iflag |= INPCK; - if (lios->c_iflag & LINUX_ISTRIP) - bios->c_iflag |= ISTRIP; - if (lios->c_iflag & LINUX_INLCR) - bios->c_iflag |= INLCR; - if (lios->c_iflag & LINUX_IGNCR) - bios->c_iflag |= IGNCR; - if (lios->c_iflag & LINUX_ICRNL) - bios->c_iflag |= ICRNL; - if (lios->c_iflag & LINUX_IXON) - bios->c_iflag |= IXON; - if (lios->c_iflag & LINUX_IXANY) - bios->c_iflag |= IXANY; - if (lios->c_iflag & LINUX_IXOFF) - bios->c_iflag |= IXOFF; - if (lios->c_iflag & LINUX_IMAXBEL) - bios->c_iflag |= IMAXBEL; - - bios->c_oflag = 0; - if (lios->c_oflag & LINUX_OPOST) - bios->c_oflag |= OPOST; - if (lios->c_oflag & LINUX_ONLCR) - bios->c_oflag |= ONLCR; - if (lios->c_oflag & LINUX_XTABS) - bios->c_oflag |= TAB3; - - bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4; - if (lios->c_cflag & LINUX_CSTOPB) - bios->c_cflag |= CSTOPB; - if (lios->c_cflag & LINUX_CREAD) - bios->c_cflag |= CREAD; - if (lios->c_cflag & LINUX_PARENB) - bios->c_cflag |= PARENB; - if (lios->c_cflag & LINUX_PARODD) - bios->c_cflag |= PARODD; - if (lios->c_cflag & LINUX_HUPCL) - bios->c_cflag |= HUPCL; - if (lios->c_cflag & LINUX_CLOCAL) - bios->c_cflag |= CLOCAL; - if (lios->c_cflag & LINUX_CRTSCTS) - bios->c_cflag |= CRTSCTS; - - bios->c_lflag = 0; - if (lios->c_lflag & LINUX_ISIG) - bios->c_lflag |= ISIG; - if (lios->c_lflag & LINUX_ICANON) - bios->c_lflag |= ICANON; - if (lios->c_lflag & LINUX_ECHO) - bios->c_lflag |= ECHO; - if (lios->c_lflag & LINUX_ECHOE) - bios->c_lflag |= ECHOE; - if (lios->c_lflag & LINUX_ECHOK) - bios->c_lflag |= ECHOK; - if (lios->c_lflag & LINUX_ECHONL) - bios->c_lflag |= ECHONL; - if (lios->c_lflag & LINUX_NOFLSH) - bios->c_lflag |= NOFLSH; - if (lios->c_lflag & LINUX_TOSTOP) - bios->c_lflag |= TOSTOP; - if (lios->c_lflag & LINUX_ECHOCTL) - bios->c_lflag |= ECHOCTL; - if (lios->c_lflag & LINUX_ECHOPRT) - bios->c_lflag |= ECHOPRT; - if (lios->c_lflag & LINUX_ECHOKE) - bios->c_lflag |= ECHOKE; - if (lios->c_lflag & LINUX_FLUSHO) - bios->c_lflag |= FLUSHO; - if (lios->c_lflag & LINUX_PENDIN) - bios->c_lflag |= PENDIN; - if (lios->c_lflag & LINUX_IEXTEN) - bios->c_lflag |= IEXTEN; - - for (i=0; ic_cc[i] = _POSIX_VDISABLE; - bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR]; - bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT]; - bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE]; - bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL]; - bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF]; - bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL]; - bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN]; - bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME]; - bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2]; - bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP]; - bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART]; - bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP]; - bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT]; - bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD]; - bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE]; - bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT]; - if (linux_preserve_vstatus) - bios->c_cc[VSTATUS] = lios->c_cc[LINUX_VSTATUS]; - - for (i=0; ic_cc[i] == LINUX_POSIX_VDISABLE) - bios->c_cc[i] = _POSIX_VDISABLE; - } - - bios->c_ispeed = bios->c_ospeed = - linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab); -} - -static void -bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio) -{ - struct linux_termios lios; - - memset(lio, 0, sizeof(*lio)); - bsd_to_linux_termios(bios, &lios); - lio->c_iflag = lios.c_iflag; - lio->c_oflag = lios.c_oflag; - lio->c_cflag = lios.c_cflag; - lio->c_lflag = lios.c_lflag; - lio->c_line = lios.c_line; - memcpy(lio->c_cc, lios.c_cc, LINUX_NCC); -} - -static void -linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios) -{ - struct linux_termios lios; - int i; - - lios.c_iflag = lio->c_iflag; - lios.c_oflag = lio->c_oflag; - lios.c_cflag = lio->c_cflag; - lios.c_lflag = lio->c_lflag; - for (i=LINUX_NCC; ic_cc, LINUX_NCC); - linux_to_bsd_termios(&lios, bios); -} - -static int -linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args) -{ - struct termios bios; - struct linux_termios lios; - struct linux_termio lio; - struct file *fp; - int error; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - - switch (args->cmd & 0xffff) { - case LINUX_TCGETS: - error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred, - td); - if (error) - break; - bsd_to_linux_termios(&bios, &lios); - error = copyout(&lios, (void *)args->arg, sizeof(lios)); - break; - - case LINUX_TCSETS: - error = copyin((void *)args->arg, &lios, sizeof(lios)); - if (error) - break; - linux_to_bsd_termios(&lios, &bios); - error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred, - td)); - break; - - case LINUX_TCSETSW: - error = copyin((void *)args->arg, &lios, sizeof(lios)); - if (error) - break; - linux_to_bsd_termios(&lios, &bios); - error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred, - td)); - break; - - case LINUX_TCSETSF: - error = copyin((void *)args->arg, &lios, sizeof(lios)); - if (error) - break; - linux_to_bsd_termios(&lios, &bios); - error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred, - td)); - break; - - case LINUX_TCGETA: - error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred, - td); - if (error) - break; - bsd_to_linux_termio(&bios, &lio); - error = (copyout(&lio, (void *)args->arg, sizeof(lio))); - break; - - case LINUX_TCSETA: - error = copyin((void *)args->arg, &lio, sizeof(lio)); - if (error) - break; - linux_to_bsd_termio(&lio, &bios); - error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred, - td)); - break; - - case LINUX_TCSETAW: - error = copyin((void *)args->arg, &lio, sizeof(lio)); - if (error) - break; - linux_to_bsd_termio(&lio, &bios); - error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred, - td)); - break; - - case LINUX_TCSETAF: - error = copyin((void *)args->arg, &lio, sizeof(lio)); - if (error) - break; - linux_to_bsd_termio(&lio, &bios); - error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred, - td)); - break; - - case LINUX_TCSBRK: - if (args->arg != 0) { - error = (fo_ioctl(fp, TIOCDRAIN, (caddr_t)&bios, td->td_ucred, - td)); - } else { - linux_msg(td, "ioctl TCSBRK arg 0 not implemented"); - error = ENOIOCTL; - } - break; - - case LINUX_TCXONC: { - switch (args->arg) { - case LINUX_TCOOFF: - args->cmd = TIOCSTOP; - break; - case LINUX_TCOON: - args->cmd = TIOCSTART; - break; - case LINUX_TCIOFF: - case LINUX_TCION: { - int c; - struct write_args wr; - error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, - td->td_ucred, td); - if (error) - break; - fdrop(fp, td); - c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART; - c = bios.c_cc[c]; - if (c != _POSIX_VDISABLE) { - wr.fd = args->fd; - wr.buf = &c; - wr.nbyte = sizeof(c); - return (sys_write(td, &wr)); - } else - return (0); - } - default: - fdrop(fp, td); - return (EINVAL); - } - args->arg = 0; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - } - - case LINUX_TCFLSH: { - int val; - switch (args->arg) { - case LINUX_TCIFLUSH: - val = FREAD; - break; - case LINUX_TCOFLUSH: - val = FWRITE; - break; - case LINUX_TCIOFLUSH: - val = FREAD | FWRITE; - break; - default: - fdrop(fp, td); - return (EINVAL); - } - error = (fo_ioctl(fp,TIOCFLUSH,(caddr_t)&val,td->td_ucred,td)); - break; - } - - case LINUX_TIOCEXCL: - args->cmd = TIOCEXCL; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCNXCL: - args->cmd = TIOCNXCL; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCSCTTY: - args->cmd = TIOCSCTTY; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCGPGRP: - args->cmd = TIOCGPGRP; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCSPGRP: - args->cmd = TIOCSPGRP; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - /* LINUX_TIOCOUTQ */ - /* LINUX_TIOCSTI */ - - case LINUX_TIOCGWINSZ: - args->cmd = TIOCGWINSZ; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCSWINSZ: - args->cmd = TIOCSWINSZ; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCMGET: - args->cmd = TIOCMGET; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCMBIS: - args->cmd = TIOCMBIS; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCMBIC: - args->cmd = TIOCMBIC; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCMSET: - args->cmd = TIOCMSET; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - /* TIOCGSOFTCAR */ - /* TIOCSSOFTCAR */ - - case LINUX_FIONREAD: /* LINUX_TIOCINQ */ - args->cmd = FIONREAD; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - /* LINUX_TIOCLINUX */ - - case LINUX_TIOCCONS: - args->cmd = TIOCCONS; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCGSERIAL: { - struct linux_serial_struct lss; - - bzero(&lss, sizeof(lss)); - lss.type = LINUX_PORT_16550A; - lss.flags = 0; - lss.close_delay = 0; - error = copyout(&lss, (void *)args->arg, sizeof(lss)); - break; - } - - case LINUX_TIOCSSERIAL: { - struct linux_serial_struct lss; - error = copyin((void *)args->arg, &lss, sizeof(lss)); - if (error) - break; - /* XXX - It really helps to have an implementation that - * does nothing. NOT! - */ - error = 0; - break; - } - - case LINUX_TIOCPKT: - args->cmd = TIOCPKT; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_FIONBIO: - args->cmd = FIONBIO; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCNOTTY: - args->cmd = TIOCNOTTY; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCSETD: { - int line; - switch (args->arg) { - case LINUX_N_TTY: - line = TTYDISC; - break; - case LINUX_N_SLIP: - line = SLIPDISC; - break; - case LINUX_N_PPP: - line = PPPDISC; - break; - default: - fdrop(fp, td); - return (EINVAL); - } - error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td->td_ucred, - td)); - break; - } - - case LINUX_TIOCGETD: { - int linux_line; - int bsd_line = TTYDISC; - error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, - td->td_ucred, td); - if (error) - break; - switch (bsd_line) { - case TTYDISC: - linux_line = LINUX_N_TTY; - break; - case SLIPDISC: - linux_line = LINUX_N_SLIP; - break; - case PPPDISC: - linux_line = LINUX_N_PPP; - break; - default: - fdrop(fp, td); - return (EINVAL); - } - error = (copyout(&linux_line, (void *)args->arg, sizeof(int))); - break; - } - - /* LINUX_TCSBRKP */ - /* LINUX_TIOCTTYGSTRUCT */ - - case LINUX_FIONCLEX: - args->cmd = FIONCLEX; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_FIOCLEX: - args->cmd = FIOCLEX; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_FIOASYNC: - args->cmd = FIOASYNC; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - /* LINUX_TIOCSERCONFIG */ - /* LINUX_TIOCSERGWILD */ - /* LINUX_TIOCSERSWILD */ - /* LINUX_TIOCGLCKTRMIOS */ - /* LINUX_TIOCSLCKTRMIOS */ - - case LINUX_TIOCSBRK: - args->cmd = TIOCSBRK; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_TIOCCBRK: - args->cmd = TIOCCBRK; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - case LINUX_TIOCGPTN: { - int nb; - - error = fo_ioctl(fp, TIOCGPTN, (caddr_t)&nb, td->td_ucred, td); - if (!error) - error = copyout(&nb, (void *)args->arg, - sizeof(int)); - break; - } - case LINUX_TIOCGPTPEER: - linux_msg(td, "unsupported ioctl TIOCGPTPEER"); - error = ENOIOCTL; - break; - case LINUX_TIOCSPTLCK: - /* - * Our unlockpt() does nothing. Check that fd refers - * to a pseudo-terminal master device. - */ - args->cmd = TIOCPTMASTER; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - default: - error = ENOIOCTL; - break; - } - - fdrop(fp, td); - return (error); -} - -/* - * CDROM related ioctls - */ - -struct linux_cdrom_msf -{ - u_char cdmsf_min0; - u_char cdmsf_sec0; - u_char cdmsf_frame0; - u_char cdmsf_min1; - u_char cdmsf_sec1; - u_char cdmsf_frame1; -}; - -struct linux_cdrom_tochdr -{ - u_char cdth_trk0; - u_char cdth_trk1; -}; - -union linux_cdrom_addr -{ - struct { - u_char minute; - u_char second; - u_char frame; - } msf; - int lba; -}; - -struct linux_cdrom_tocentry -{ - u_char cdte_track; - u_char cdte_adr:4; - u_char cdte_ctrl:4; - u_char cdte_format; - union linux_cdrom_addr cdte_addr; - u_char cdte_datamode; -}; - -struct linux_cdrom_subchnl -{ - u_char cdsc_format; - u_char cdsc_audiostatus; - u_char cdsc_adr:4; - u_char cdsc_ctrl:4; - u_char cdsc_trk; - u_char cdsc_ind; - union linux_cdrom_addr cdsc_absaddr; - union linux_cdrom_addr cdsc_reladdr; -}; - -struct l_cdrom_read_audio { - union linux_cdrom_addr addr; - u_char addr_format; - l_int nframes; - u_char *buf; -}; - -struct l_dvd_layer { - u_char book_version:4; - u_char book_type:4; - u_char min_rate:4; - u_char disc_size:4; - u_char layer_type:4; - u_char track_path:1; - u_char nlayers:2; - u_char track_density:4; - u_char linear_density:4; - u_char bca:1; - uint32_t start_sector; - uint32_t end_sector; - uint32_t end_sector_l0; -}; - -struct l_dvd_physical { - u_char type; - u_char layer_num; - struct l_dvd_layer layer[4]; -}; - -struct l_dvd_copyright { - u_char type; - u_char layer_num; - u_char cpst; - u_char rmi; -}; - -struct l_dvd_disckey { - u_char type; - l_uint agid:2; - u_char value[2048]; -}; - -struct l_dvd_bca { - u_char type; - l_int len; - u_char value[188]; -}; - -struct l_dvd_manufact { - u_char type; - u_char layer_num; - l_int len; - u_char value[2048]; -}; - -typedef union { - u_char type; - struct l_dvd_physical physical; - struct l_dvd_copyright copyright; - struct l_dvd_disckey disckey; - struct l_dvd_bca bca; - struct l_dvd_manufact manufact; -} l_dvd_struct; - -typedef u_char l_dvd_key[5]; -typedef u_char l_dvd_challenge[10]; - -struct l_dvd_lu_send_agid { - u_char type; - l_uint agid:2; -}; - -struct l_dvd_host_send_challenge { - u_char type; - l_uint agid:2; - l_dvd_challenge chal; -}; - -struct l_dvd_send_key { - u_char type; - l_uint agid:2; - l_dvd_key key; -}; - -struct l_dvd_lu_send_challenge { - u_char type; - l_uint agid:2; - l_dvd_challenge chal; -}; - -struct l_dvd_lu_send_title_key { - u_char type; - l_uint agid:2; - l_dvd_key title_key; - l_int lba; - l_uint cpm:1; - l_uint cp_sec:1; - l_uint cgms:2; -}; - -struct l_dvd_lu_send_asf { - u_char type; - l_uint agid:2; - l_uint asf:1; -}; - -struct l_dvd_host_send_rpcstate { - u_char type; - u_char pdrc; -}; - -struct l_dvd_lu_send_rpcstate { - u_char type:2; - u_char vra:3; - u_char ucca:3; - u_char region_mask; - u_char rpc_scheme; -}; - -typedef union { - u_char type; - struct l_dvd_lu_send_agid lsa; - struct l_dvd_host_send_challenge hsc; - struct l_dvd_send_key lsk; - struct l_dvd_lu_send_challenge lsc; - struct l_dvd_send_key hsk; - struct l_dvd_lu_send_title_key lstk; - struct l_dvd_lu_send_asf lsasf; - struct l_dvd_host_send_rpcstate hrpcs; - struct l_dvd_lu_send_rpcstate lrpcs; -} l_dvd_authinfo; - -static void -bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp) -{ - if (af == CD_LBA_FORMAT) - lp->lba = bp->lba; - else { - lp->msf.minute = bp->msf.minute; - lp->msf.second = bp->msf.second; - lp->msf.frame = bp->msf.frame; - } -} - -static void -set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba) -{ - if (format == LINUX_CDROM_MSF) { - addr->msf.frame = lba % 75; - lba /= 75; - lba += 2; - addr->msf.second = lba % 60; - addr->msf.minute = lba / 60; - } else - addr->lba = lba; -} - -static int -linux_to_bsd_dvd_struct(l_dvd_struct *lp, struct dvd_struct *bp) -{ - bp->format = lp->type; - switch (bp->format) { - case DVD_STRUCT_PHYSICAL: - if (bp->layer_num >= 4) - return (EINVAL); - bp->layer_num = lp->physical.layer_num; - break; - case DVD_STRUCT_COPYRIGHT: - bp->layer_num = lp->copyright.layer_num; - break; - case DVD_STRUCT_DISCKEY: - bp->agid = lp->disckey.agid; - break; - case DVD_STRUCT_BCA: - case DVD_STRUCT_MANUFACT: - break; - default: - return (EINVAL); - } - return (0); -} - -static int -bsd_to_linux_dvd_struct(struct dvd_struct *bp, l_dvd_struct *lp) -{ - switch (bp->format) { - case DVD_STRUCT_PHYSICAL: { - struct dvd_layer *blp = (struct dvd_layer *)bp->data; - struct l_dvd_layer *llp = &lp->physical.layer[bp->layer_num]; - memset(llp, 0, sizeof(*llp)); - llp->book_version = blp->book_version; - llp->book_type = blp->book_type; - llp->min_rate = blp->max_rate; - llp->disc_size = blp->disc_size; - llp->layer_type = blp->layer_type; - llp->track_path = blp->track_path; - llp->nlayers = blp->nlayers; - llp->track_density = blp->track_density; - llp->linear_density = blp->linear_density; - llp->bca = blp->bca; - llp->start_sector = blp->start_sector; - llp->end_sector = blp->end_sector; - llp->end_sector_l0 = blp->end_sector_l0; - break; - } - case DVD_STRUCT_COPYRIGHT: - lp->copyright.cpst = bp->cpst; - lp->copyright.rmi = bp->rmi; - break; - case DVD_STRUCT_DISCKEY: - memcpy(lp->disckey.value, bp->data, sizeof(lp->disckey.value)); - break; - case DVD_STRUCT_BCA: - lp->bca.len = bp->length; - memcpy(lp->bca.value, bp->data, sizeof(lp->bca.value)); - break; - case DVD_STRUCT_MANUFACT: - lp->manufact.len = bp->length; - memcpy(lp->manufact.value, bp->data, - sizeof(lp->manufact.value)); - /* lp->manufact.layer_num is unused in Linux (redhat 7.0). */ - break; - default: - return (EINVAL); - } - return (0); -} - -static int -linux_to_bsd_dvd_authinfo(l_dvd_authinfo *lp, int *bcode, - struct dvd_authinfo *bp) -{ - switch (lp->type) { - case LINUX_DVD_LU_SEND_AGID: - *bcode = DVDIOCREPORTKEY; - bp->format = DVD_REPORT_AGID; - bp->agid = lp->lsa.agid; - break; - case LINUX_DVD_HOST_SEND_CHALLENGE: - *bcode = DVDIOCSENDKEY; - bp->format = DVD_SEND_CHALLENGE; - bp->agid = lp->hsc.agid; - memcpy(bp->keychal, lp->hsc.chal, 10); - break; - case LINUX_DVD_LU_SEND_KEY1: - *bcode = DVDIOCREPORTKEY; - bp->format = DVD_REPORT_KEY1; - bp->agid = lp->lsk.agid; - break; - case LINUX_DVD_LU_SEND_CHALLENGE: - *bcode = DVDIOCREPORTKEY; - bp->format = DVD_REPORT_CHALLENGE; - bp->agid = lp->lsc.agid; - break; - case LINUX_DVD_HOST_SEND_KEY2: - *bcode = DVDIOCSENDKEY; - bp->format = DVD_SEND_KEY2; - bp->agid = lp->hsk.agid; - memcpy(bp->keychal, lp->hsk.key, 5); - break; - case LINUX_DVD_LU_SEND_TITLE_KEY: - *bcode = DVDIOCREPORTKEY; - bp->format = DVD_REPORT_TITLE_KEY; - bp->agid = lp->lstk.agid; - bp->lba = lp->lstk.lba; - break; - case LINUX_DVD_LU_SEND_ASF: - *bcode = DVDIOCREPORTKEY; - bp->format = DVD_REPORT_ASF; - bp->agid = lp->lsasf.agid; - break; - case LINUX_DVD_INVALIDATE_AGID: - *bcode = DVDIOCREPORTKEY; - bp->format = DVD_INVALIDATE_AGID; - bp->agid = lp->lsa.agid; - break; - case LINUX_DVD_LU_SEND_RPC_STATE: - *bcode = DVDIOCREPORTKEY; - bp->format = DVD_REPORT_RPC; - break; - case LINUX_DVD_HOST_SEND_RPC_STATE: - *bcode = DVDIOCSENDKEY; - bp->format = DVD_SEND_RPC; - bp->region = lp->hrpcs.pdrc; - break; - default: - return (EINVAL); - } - return (0); -} - -static int -bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp) -{ - switch (lp->type) { - case LINUX_DVD_LU_SEND_AGID: - lp->lsa.agid = bp->agid; - break; - case LINUX_DVD_HOST_SEND_CHALLENGE: - lp->type = LINUX_DVD_LU_SEND_KEY1; - break; - case LINUX_DVD_LU_SEND_KEY1: - memcpy(lp->lsk.key, bp->keychal, sizeof(lp->lsk.key)); - break; - case LINUX_DVD_LU_SEND_CHALLENGE: - memcpy(lp->lsc.chal, bp->keychal, sizeof(lp->lsc.chal)); - break; - case LINUX_DVD_HOST_SEND_KEY2: - lp->type = LINUX_DVD_AUTH_ESTABLISHED; - break; - case LINUX_DVD_LU_SEND_TITLE_KEY: - memcpy(lp->lstk.title_key, bp->keychal, - sizeof(lp->lstk.title_key)); - lp->lstk.cpm = bp->cpm; - lp->lstk.cp_sec = bp->cp_sec; - lp->lstk.cgms = bp->cgms; - break; - case LINUX_DVD_LU_SEND_ASF: - lp->lsasf.asf = bp->asf; - break; - case LINUX_DVD_INVALIDATE_AGID: - break; - case LINUX_DVD_LU_SEND_RPC_STATE: - lp->lrpcs.type = bp->reg_type; - lp->lrpcs.vra = bp->vend_rsts; - lp->lrpcs.ucca = bp->user_rsts; - lp->lrpcs.region_mask = bp->region; - lp->lrpcs.rpc_scheme = bp->rpc_scheme; - break; - case LINUX_DVD_HOST_SEND_RPC_STATE: - break; - default: - return (EINVAL); - } - return (0); -} - -static int -linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - int error; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - switch (args->cmd & 0xffff) { - case LINUX_CDROMPAUSE: - args->cmd = CDIOCPAUSE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_CDROMRESUME: - args->cmd = CDIOCRESUME; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_CDROMPLAYMSF: - args->cmd = CDIOCPLAYMSF; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_CDROMPLAYTRKIND: - args->cmd = CDIOCPLAYTRACKS; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_CDROMREADTOCHDR: { - struct ioc_toc_header th; - struct linux_cdrom_tochdr lth; - error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, - td->td_ucred, td); - if (!error) { - lth.cdth_trk0 = th.starting_track; - lth.cdth_trk1 = th.ending_track; - error = copyout(<h, (void *)args->arg, sizeof(lth)); - } - break; - } - - case LINUX_CDROMREADTOCENTRY: { - struct linux_cdrom_tocentry lte; - struct ioc_read_toc_single_entry irtse; - - error = copyin((void *)args->arg, <e, sizeof(lte)); - if (error) - break; - irtse.address_format = lte.cdte_format; - irtse.track = lte.cdte_track; - error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, - td->td_ucred, td); - if (!error) { - lte.cdte_ctrl = irtse.entry.control; - lte.cdte_adr = irtse.entry.addr_type; - bsd_to_linux_msf_lba(irtse.address_format, - &irtse.entry.addr, <e.cdte_addr); - error = copyout(<e, (void *)args->arg, sizeof(lte)); - } - break; - } - - case LINUX_CDROMSTOP: - args->cmd = CDIOCSTOP; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_CDROMSTART: - args->cmd = CDIOCSTART; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_CDROMEJECT: - args->cmd = CDIOCEJECT; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - /* LINUX_CDROMVOLCTRL */ - - case LINUX_CDROMSUBCHNL: { - struct linux_cdrom_subchnl sc; - struct ioc_read_subchannel bsdsc; - struct cd_sub_channel_info bsdinfo; - - error = copyin((void *)args->arg, &sc, sizeof(sc)); - if (error) - break; - - /* - * Invoke the native ioctl and bounce the returned data through - * the userspace buffer. This works because the Linux structure - * is the same size as our structures for the subchannel header - * and position data. - */ - bsdsc.address_format = CD_LBA_FORMAT; - bsdsc.data_format = CD_CURRENT_POSITION; - bsdsc.track = 0; - bsdsc.data_len = sizeof(sc); - bsdsc.data = (void *)args->arg; - error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, - td->td_ucred, td); - if (error) - break; - error = copyin((void *)args->arg, &bsdinfo, sizeof(bsdinfo)); - if (error) - break; - sc.cdsc_audiostatus = bsdinfo.header.audio_status; - sc.cdsc_adr = bsdinfo.what.position.addr_type; - sc.cdsc_ctrl = bsdinfo.what.position.control; - sc.cdsc_trk = bsdinfo.what.position.track_number; - sc.cdsc_ind = bsdinfo.what.position.index_number; - set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format, - bsdinfo.what.position.absaddr.lba); - set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format, - bsdinfo.what.position.reladdr.lba); - error = copyout(&sc, (void *)args->arg, sizeof(sc)); - break; - } - - /* LINUX_CDROMREADMODE2 */ - /* LINUX_CDROMREADMODE1 */ - /* LINUX_CDROMREADAUDIO */ - /* LINUX_CDROMEJECT_SW */ - /* LINUX_CDROMMULTISESSION */ - /* LINUX_CDROM_GET_UPC */ - - case LINUX_CDROMRESET: - args->cmd = CDIOCRESET; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - /* LINUX_CDROMVOLREAD */ - /* LINUX_CDROMREADRAW */ - /* LINUX_CDROMREADCOOKED */ - /* LINUX_CDROMSEEK */ - /* LINUX_CDROMPLAYBLK */ - /* LINUX_CDROMREADALL */ - /* LINUX_CDROMCLOSETRAY */ - /* LINUX_CDROMLOADFROMSLOT */ - /* LINUX_CDROMGETSPINDOWN */ - /* LINUX_CDROMSETSPINDOWN */ - /* LINUX_CDROM_SET_OPTIONS */ - /* LINUX_CDROM_CLEAR_OPTIONS */ - /* LINUX_CDROM_SELECT_SPEED */ - /* LINUX_CDROM_SELECT_DISC */ - /* LINUX_CDROM_MEDIA_CHANGED */ - /* LINUX_CDROM_DRIVE_STATUS */ - /* LINUX_CDROM_DISC_STATUS */ - /* LINUX_CDROM_CHANGER_NSLOTS */ - /* LINUX_CDROM_LOCKDOOR */ - /* LINUX_CDROM_DEBUG */ - /* LINUX_CDROM_GET_CAPABILITY */ - /* LINUX_CDROMAUDIOBUFSIZ */ - - case LINUX_DVD_READ_STRUCT: { - l_dvd_struct *lds; - struct dvd_struct *bds; - - lds = malloc(sizeof(*lds), M_LINUX, M_WAITOK); - bds = malloc(sizeof(*bds), M_LINUX, M_WAITOK); - error = copyin((void *)args->arg, lds, sizeof(*lds)); - if (error) - goto out; - error = linux_to_bsd_dvd_struct(lds, bds); - if (error) - goto out; - error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)bds, - td->td_ucred, td); - if (error) - goto out; - error = bsd_to_linux_dvd_struct(bds, lds); - if (error) - goto out; - error = copyout(lds, (void *)args->arg, sizeof(*lds)); - out: - free(bds, M_LINUX); - free(lds, M_LINUX); - break; - } - - /* LINUX_DVD_WRITE_STRUCT */ - - case LINUX_DVD_AUTH: { - l_dvd_authinfo lda; - struct dvd_authinfo bda; - int bcode; - - error = copyin((void *)args->arg, &lda, sizeof(lda)); - if (error) - break; - error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda); - if (error) - break; - error = fo_ioctl(fp, bcode, (caddr_t)&bda, td->td_ucred, - td); - if (error) { - if (lda.type == LINUX_DVD_HOST_SEND_KEY2) { - lda.type = LINUX_DVD_AUTH_FAILURE; - (void)copyout(&lda, (void *)args->arg, - sizeof(lda)); - } - break; - } - error = bsd_to_linux_dvd_authinfo(&bda, &lda); - if (error) - break; - error = copyout(&lda, (void *)args->arg, sizeof(lda)); - break; - } - - case LINUX_SCSI_GET_BUS_NUMBER: - { - struct sg_scsi_id id; - - error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id, - td->td_ucred, td); - if (error) - break; - error = copyout(&id.channel, (void *)args->arg, sizeof(int)); - break; - } - - case LINUX_SCSI_GET_IDLUN: - { - struct sg_scsi_id id; - struct scsi_idlun idl; - - error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id, - td->td_ucred, td); - if (error) - break; - idl.dev_id = (id.scsi_id & 0xff) + ((id.lun & 0xff) << 8) + - ((id.channel & 0xff) << 16) + ((id.host_no & 0xff) << 24); - idl.host_unique_id = id.host_no; - error = copyout(&idl, (void *)args->arg, sizeof(idl)); - break; - } - - /* LINUX_CDROM_SEND_PACKET */ - /* LINUX_CDROM_NEXT_WRITABLE */ - /* LINUX_CDROM_LAST_WRITTEN */ - - default: - error = ENOIOCTL; - break; - } - - fdrop(fp, td); - return (error); -} - -static int -linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args) -{ - - return (ENOTTY); -} - -/* - * Sound related ioctls - */ - -struct linux_old_mixer_info { - char id[16]; - char name[32]; -}; - -static uint32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT }; - -#define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30]) - -static int -linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args) -{ - - switch (args->cmd & 0xffff) { - case LINUX_SOUND_MIXER_WRITE_VOLUME: - args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_BASS: - args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_TREBLE: - args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_SYNTH: - args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_PCM: - args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_SPEAKER: - args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_LINE: - args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_MIC: - args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_CD: - args->cmd = SETDIR(SOUND_MIXER_WRITE_CD); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_IMIX: - args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_ALTPCM: - args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_RECLEV: - args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_IGAIN: - args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_OGAIN: - args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_LINE1: - args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_LINE2: - args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_LINE3: - args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_MONITOR: - args->cmd = SETDIR(SOUND_MIXER_WRITE_MONITOR); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_INFO: { - /* Key on encoded length */ - switch ((args->cmd >> 16) & 0x1fff) { - case 0x005c: { /* SOUND_MIXER_INFO */ - args->cmd = SOUND_MIXER_INFO; - return (sys_ioctl(td, (struct ioctl_args *)args)); - } - case 0x0030: { /* SOUND_OLD_MIXER_INFO */ - struct linux_old_mixer_info info; - bzero(&info, sizeof(info)); - strncpy(info.id, "OSS", sizeof(info.id) - 1); - strncpy(info.name, "FreeBSD OSS Mixer", - sizeof(info.name) - 1); - return (copyout(&info, (void *)args->arg, - sizeof(info))); - } - default: - return (ENOIOCTL); - } - break; - } - - case LINUX_OSS_GETVERSION: { - int version = linux_get_oss_version(td); - return (copyout(&version, (void *)args->arg, sizeof(int))); - } - - case LINUX_SOUND_MIXER_READ_STEREODEVS: - args->cmd = SOUND_MIXER_READ_STEREODEVS; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_READ_CAPS: - args->cmd = SOUND_MIXER_READ_CAPS; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_READ_RECMASK: - args->cmd = SOUND_MIXER_READ_RECMASK; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_READ_DEVMASK: - args->cmd = SOUND_MIXER_READ_DEVMASK; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_MIXER_WRITE_RECSRC: - args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC); - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_RESET: - args->cmd = SNDCTL_DSP_RESET; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_SYNC: - args->cmd = SNDCTL_DSP_SYNC; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_SPEED: - args->cmd = SNDCTL_DSP_SPEED; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_STEREO: - args->cmd = SNDCTL_DSP_STEREO; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */ - args->cmd = SNDCTL_DSP_GETBLKSIZE; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_SETFMT: - args->cmd = SNDCTL_DSP_SETFMT; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_PCM_WRITE_CHANNELS: - args->cmd = SOUND_PCM_WRITE_CHANNELS; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SOUND_PCM_WRITE_FILTER: - args->cmd = SOUND_PCM_WRITE_FILTER; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_POST: - args->cmd = SNDCTL_DSP_POST; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_SUBDIVIDE: - args->cmd = SNDCTL_DSP_SUBDIVIDE; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_SETFRAGMENT: - args->cmd = SNDCTL_DSP_SETFRAGMENT; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_GETFMTS: - args->cmd = SNDCTL_DSP_GETFMTS; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_GETOSPACE: - args->cmd = SNDCTL_DSP_GETOSPACE; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_GETISPACE: - args->cmd = SNDCTL_DSP_GETISPACE; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_NONBLOCK: - args->cmd = SNDCTL_DSP_NONBLOCK; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_GETCAPS: - args->cmd = SNDCTL_DSP_GETCAPS; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */ - args->cmd = SNDCTL_DSP_SETTRIGGER; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_GETIPTR: - args->cmd = SNDCTL_DSP_GETIPTR; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_GETOPTR: - args->cmd = SNDCTL_DSP_GETOPTR; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_SETDUPLEX: - args->cmd = SNDCTL_DSP_SETDUPLEX; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_DSP_GETODELAY: - args->cmd = SNDCTL_DSP_GETODELAY; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_RESET: - args->cmd = SNDCTL_SEQ_RESET; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_SYNC: - args->cmd = SNDCTL_SEQ_SYNC; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SYNTH_INFO: - args->cmd = SNDCTL_SYNTH_INFO; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_CTRLRATE: - args->cmd = SNDCTL_SEQ_CTRLRATE; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_GETOUTCOUNT: - args->cmd = SNDCTL_SEQ_GETOUTCOUNT; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_GETINCOUNT: - args->cmd = SNDCTL_SEQ_GETINCOUNT; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_PERCMODE: - args->cmd = SNDCTL_SEQ_PERCMODE; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_FM_LOAD_INSTR: - args->cmd = SNDCTL_FM_LOAD_INSTR; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_TESTMIDI: - args->cmd = SNDCTL_SEQ_TESTMIDI; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_RESETSAMPLES: - args->cmd = SNDCTL_SEQ_RESETSAMPLES; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_NRSYNTHS: - args->cmd = SNDCTL_SEQ_NRSYNTHS; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_NRMIDIS: - args->cmd = SNDCTL_SEQ_NRMIDIS; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_MIDI_INFO: - args->cmd = SNDCTL_MIDI_INFO; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SEQ_TRESHOLD: - args->cmd = SNDCTL_SEQ_TRESHOLD; - return (sys_ioctl(td, (struct ioctl_args *)args)); - - case LINUX_SNDCTL_SYNTH_MEMAVL: - args->cmd = SNDCTL_SYNTH_MEMAVL; - return (sys_ioctl(td, (struct ioctl_args *)args)); - } - - return (ENOIOCTL); -} - -/* - * Console related ioctls - */ - -static int -linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - int error; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - switch (args->cmd & 0xffff) { - case LINUX_KIOCSOUND: - args->cmd = KIOCSOUND; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_KDMKTONE: - args->cmd = KDMKTONE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_KDGETLED: - args->cmd = KDGETLED; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_KDSETLED: - args->cmd = KDSETLED; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_KDSETMODE: - args->cmd = KDSETMODE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_KDGETMODE: - args->cmd = KDGETMODE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_KDGKBMODE: - args->cmd = KDGKBMODE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_KDSKBMODE: { - int kbdmode; - switch (args->arg) { - case LINUX_KBD_RAW: - kbdmode = K_RAW; - break; - case LINUX_KBD_XLATE: - kbdmode = K_XLATE; - break; - case LINUX_KBD_MEDIUMRAW: - kbdmode = K_RAW; - break; - default: - fdrop(fp, td); - return (EINVAL); - } - error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, - td->td_ucred, td)); - break; - } - - case LINUX_VT_OPENQRY: - args->cmd = VT_OPENQRY; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_VT_GETMODE: - args->cmd = VT_GETMODE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_VT_SETMODE: { - struct vt_mode mode; - if ((error = copyin((void *)args->arg, &mode, sizeof(mode)))) - break; - if (LINUX_SIG_VALID(mode.relsig)) - mode.relsig = linux_to_bsd_signal(mode.relsig); - else - mode.relsig = 0; - if (LINUX_SIG_VALID(mode.acqsig)) - mode.acqsig = linux_to_bsd_signal(mode.acqsig); - else - mode.acqsig = 0; - /* XXX. Linux ignores frsig and set it to 0. */ - mode.frsig = 0; - if ((error = copyout(&mode, (void *)args->arg, sizeof(mode)))) - break; - args->cmd = VT_SETMODE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - } - - case LINUX_VT_GETSTATE: - args->cmd = VT_GETACTIVE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_VT_RELDISP: - args->cmd = VT_RELDISP; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_VT_ACTIVATE: - args->cmd = VT_ACTIVATE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - case LINUX_VT_WAITACTIVE: - args->cmd = VT_WAITACTIVE; - error = (sys_ioctl(td, (struct ioctl_args *)args)); - break; - - default: - error = ENOIOCTL; - break; - } - - fdrop(fp, td); - return (error); -} - -/* - * Implement the SIOCGIFNAME ioctl - */ - -static int -linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr) -{ - struct l_ifreq ifr; - int error, ret; - - error = copyin(uifr, &ifr, sizeof(ifr)); - if (error != 0) - return (error); - ret = ifname_bsd_to_linux_idx(ifr.ifr_index, ifr.ifr_name, - LINUX_IFNAMSIZ); - if (ret > 0) - return (copyout(&ifr, uifr, sizeof(ifr))); - else - return (ENODEV); -} - -/* - * Implement the SIOCGIFCONF ioctl - */ -static u_int -linux_ifconf_ifaddr_cb(void *arg, struct ifaddr *ifa, u_int count) -{ -#ifdef COMPAT_LINUX32 - struct l_ifconf *ifc; -#else - struct ifconf *ifc; -#endif - - ifc = arg; - ifc->ifc_len += sizeof(struct l_ifreq); - return (1); -} - -static int -linux_ifconf_ifnet_cb(if_t ifp, void *arg) -{ - - if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb, arg); - return (0); -} - -struct linux_ifconfig_ifaddr_cb2_s { - struct l_ifreq ifr; - struct sbuf *sb; - size_t max_len; - size_t valid_len; -}; - -static u_int -linux_ifconf_ifaddr_cb2(void *arg, struct ifaddr *ifa, u_int len) -{ - struct linux_ifconfig_ifaddr_cb2_s *cbs = arg; - struct sockaddr *sa = ifa->ifa_addr; - - cbs->ifr.ifr_addr.sa_family = LINUX_AF_INET; - memcpy(cbs->ifr.ifr_addr.sa_data, sa->sa_data, - sizeof(cbs->ifr.ifr_addr.sa_data)); - sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr)); - cbs->max_len += sizeof(cbs->ifr); - - if (sbuf_error(cbs->sb) == 0) - cbs->valid_len = sbuf_len(cbs->sb); - return (1); -} - -static int -linux_ifconf_ifnet_cb2(if_t ifp, void *arg) -{ - struct linux_ifconfig_ifaddr_cb2_s *cbs = arg; - - bzero(&cbs->ifr, sizeof(cbs->ifr)); - ifname_bsd_to_linux_ifp(ifp, cbs->ifr.ifr_name, - sizeof(cbs->ifr.ifr_name)); - - /* Walk the address list */ - if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb2, cbs); - return (0); -} - -static int -linux_ifconf(struct thread *td, struct ifconf *uifc) -{ - struct linux_ifconfig_ifaddr_cb2_s cbs; - struct epoch_tracker et; -#ifdef COMPAT_LINUX32 - struct l_ifconf ifc; -#else - struct ifconf ifc; -#endif - struct sbuf *sb; - int error, full; - - error = copyin(uifc, &ifc, sizeof(ifc)); - if (error != 0) - return (error); - - /* handle the 'request buffer size' case */ - if (PTRIN(ifc.ifc_buf) == NULL) { - ifc.ifc_len = 0; - NET_EPOCH_ENTER(et); - if_foreach(linux_ifconf_ifnet_cb, &ifc); - NET_EPOCH_EXIT(et); - return (copyout(&ifc, uifc, sizeof(ifc))); - } - if (ifc.ifc_len <= 0) - return (EINVAL); - - full = 0; - cbs.max_len = maxphys - 1; - -again: - if (ifc.ifc_len <= cbs.max_len) { - cbs.max_len = ifc.ifc_len; - full = 1; - } - cbs.sb = sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN); - cbs.max_len = 0; - cbs.valid_len = 0; - - /* Return all AF_INET addresses of all interfaces */ - NET_EPOCH_ENTER(et); - if_foreach(linux_ifconf_ifnet_cb2, &cbs); - NET_EPOCH_EXIT(et); - - if (cbs.valid_len != cbs.max_len && !full) { - sbuf_delete(sb); - goto again; - } - - ifc.ifc_len = cbs.valid_len; - sbuf_finish(sb); - error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len); - if (error == 0) - error = copyout(&ifc, uifc, sizeof(ifc)); - sbuf_delete(sb); - - return (error); -} - -static int -linux_ioctl_socket_ifreq(struct thread *td, int fd, u_int cmd, - struct l_ifreq *uifr) -{ - struct l_ifreq lifr; - struct ifreq bifr; - size_t ifrusiz; - int error, temp_flags; - - switch (cmd) { - case LINUX_SIOCGIFINDEX: - cmd = SIOCGIFINDEX; - break; - case LINUX_SIOCGIFFLAGS: - cmd = SIOCGIFFLAGS; - break; - case LINUX_SIOCGIFADDR: - cmd = SIOCGIFADDR; - break; - case LINUX_SIOCSIFADDR: - cmd = SIOCSIFADDR; - break; - case LINUX_SIOCGIFDSTADDR: - cmd = SIOCGIFDSTADDR; - break; - case LINUX_SIOCGIFBRDADDR: - cmd = SIOCGIFBRDADDR; - break; - case LINUX_SIOCGIFNETMASK: - cmd = SIOCGIFNETMASK; - break; - case LINUX_SIOCSIFNETMASK: - cmd = SIOCSIFNETMASK; - break; - case LINUX_SIOCGIFMTU: - cmd = SIOCGIFMTU; - break; - case LINUX_SIOCSIFMTU: - cmd = SIOCSIFMTU; - break; - case LINUX_SIOCGIFHWADDR: - cmd = SIOCGHWADDR; - break; - case LINUX_SIOCGIFMETRIC: - cmd = SIOCGIFMETRIC; - break; - case LINUX_SIOCSIFMETRIC: - cmd = SIOCSIFMETRIC; - break; - /* - * XXX This is slightly bogus, but these ioctls are currently - * XXX only used by the aironet (if_an) network driver. - */ - case LINUX_SIOCDEVPRIVATE: - cmd = SIOCGPRIVATE_0; - break; - case LINUX_SIOCDEVPRIVATE+1: - cmd = SIOCGPRIVATE_1; - break; - default: - LINUX_RATELIMIT_MSG_OPT2( - "ioctl_socket_ifreq fd=%d, cmd=0x%x is not implemented", - fd, cmd); - return (ENOIOCTL); - } - - error = copyin(uifr, &lifr, sizeof(lifr)); - if (error != 0) - return (error); - bzero(&bifr, sizeof(bifr)); - - /* - * The size of Linux enum ifr_ifru is bigger than - * the FreeBSD size due to the struct ifmap. - */ - ifrusiz = (sizeof(lifr) > sizeof(bifr) ? sizeof(bifr) : - sizeof(lifr)) - offsetof(struct l_ifreq, ifr_ifru); - bcopy(&lifr.ifr_ifru, &bifr.ifr_ifru, ifrusiz); - - error = ifname_linux_to_bsd(td, lifr.ifr_name, bifr.ifr_name); - if (error != 0) - return (error); - - /* Translate in values. */ - switch (cmd) { - case SIOCGIFINDEX: - bifr.ifr_index = lifr.ifr_index; - break; - case SIOCSIFADDR: - case SIOCSIFNETMASK: - bifr.ifr_addr.sa_len = sizeof(struct sockaddr); - bifr.ifr_addr.sa_family = - linux_to_bsd_domain(lifr.ifr_addr.sa_family); - break; - default: - break; - } - - error = kern_ioctl(td, fd, cmd, (caddr_t)&bifr); - if (error != 0) - return (error); - bzero(&lifr.ifr_ifru, sizeof(lifr.ifr_ifru)); - - /* Translate out values. */ - switch (cmd) { - case SIOCGIFINDEX: - lifr.ifr_index = bifr.ifr_index; - break; - case SIOCGIFFLAGS: - temp_flags = bifr.ifr_flags | (bifr.ifr_flagshigh << 16); - lifr.ifr_flags = bsd_to_linux_ifflags(temp_flags); - break; - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCGIFNETMASK: - bcopy(&bifr.ifr_addr, &lifr.ifr_addr, sizeof(bifr.ifr_addr)); - lifr.ifr_addr.sa_family = - bsd_to_linux_domain(bifr.ifr_addr.sa_family); - break; - case SIOCGHWADDR: - bcopy(&bifr.ifr_addr, &lifr.ifr_hwaddr, sizeof(bifr.ifr_addr)); - lifr.ifr_hwaddr.sa_family = LINUX_ARPHRD_ETHER; - break; - default: - bcopy(&bifr.ifr_ifru, &lifr.ifr_ifru, ifrusiz); - break; - } - - return (copyout(&lifr, uifr, sizeof(lifr))); -} - -/* - * Socket related ioctls - */ - -static int -linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - int error, type; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - type = fp->f_type; - fdrop(fp, td); - - CURVNET_SET(TD_TO_VNET(td)); - - if (type != DTYPE_SOCKET) { - /* not a socket - probably a tap / vmnet device */ - switch (args->cmd) { - case LINUX_SIOCGIFADDR: - case LINUX_SIOCSIFADDR: - case LINUX_SIOCGIFFLAGS: - error = linux_ioctl_special(td, args); - break; - default: - error = ENOIOCTL; - break; - } - CURVNET_RESTORE(); - return (error); - } - - switch (args->cmd) { - case LINUX_FIOSETOWN: - args->cmd = FIOSETOWN; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCSPGRP: - args->cmd = SIOCSPGRP; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_FIOGETOWN: - args->cmd = FIOGETOWN; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCGPGRP: - args->cmd = SIOCGPGRP; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCATMARK: - args->cmd = SIOCATMARK; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - /* LINUX_SIOCGSTAMP */ - - case LINUX_SIOCGIFNAME: - error = linux_ioctl_ifname(td, (struct l_ifreq *)args->arg); - break; - - case LINUX_SIOCGIFCONF: - error = linux_ifconf(td, (struct ifconf *)args->arg); - break; - - case LINUX_SIOCADDMULTI: - args->cmd = SIOCADDMULTI; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCDELMULTI: - args->cmd = SIOCDELMULTI; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - - case LINUX_SIOCGIFCOUNT: - error = 0; - break; - - default: - error = linux_ioctl_socket_ifreq(td, args->fd, args->cmd, - PTRIN(args->arg)); - break; - } - - CURVNET_RESTORE(); - return (error); -} - -/* - * Device private ioctl handler - */ -static int -linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - int error, type; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - type = fp->f_type; - fdrop(fp, td); - if (type == DTYPE_SOCKET) - return (linux_ioctl_socket(td, args)); - return (ENOIOCTL); -} - -/* - * DRM ioctl handler (sys/dev/drm) - */ -static int -linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args) -{ - args->cmd = SETDIR(args->cmd); - return (sys_ioctl(td, (struct ioctl_args *)args)); -} - -#ifdef COMPAT_LINUX32 -static int -linux_ioctl_sg_io(struct thread *td, struct linux_ioctl_args *args) -{ - struct sg_io_hdr io; - struct sg_io_hdr32 io32; - struct file *fp; - int error; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) { - printf("sg_linux_ioctl: fget returned %d\n", error); - return (error); - } - - if ((error = copyin((void *)args->arg, &io32, sizeof(io32))) != 0) - goto out; - - CP(io32, io, interface_id); - CP(io32, io, dxfer_direction); - CP(io32, io, cmd_len); - CP(io32, io, mx_sb_len); - CP(io32, io, iovec_count); - CP(io32, io, dxfer_len); - PTRIN_CP(io32, io, dxferp); - PTRIN_CP(io32, io, cmdp); - PTRIN_CP(io32, io, sbp); - CP(io32, io, timeout); - CP(io32, io, flags); - CP(io32, io, pack_id); - PTRIN_CP(io32, io, usr_ptr); - CP(io32, io, status); - CP(io32, io, masked_status); - CP(io32, io, msg_status); - CP(io32, io, sb_len_wr); - CP(io32, io, host_status); - CP(io32, io, driver_status); - CP(io32, io, resid); - CP(io32, io, duration); - CP(io32, io, info); - - if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0) - goto out; - - CP(io, io32, interface_id); - CP(io, io32, dxfer_direction); - CP(io, io32, cmd_len); - CP(io, io32, mx_sb_len); - CP(io, io32, iovec_count); - CP(io, io32, dxfer_len); - PTROUT_CP(io, io32, dxferp); - PTROUT_CP(io, io32, cmdp); - PTROUT_CP(io, io32, sbp); - CP(io, io32, timeout); - CP(io, io32, flags); - CP(io, io32, pack_id); - PTROUT_CP(io, io32, usr_ptr); - CP(io, io32, status); - CP(io, io32, masked_status); - CP(io, io32, msg_status); - CP(io, io32, sb_len_wr); - CP(io, io32, host_status); - CP(io, io32, driver_status); - CP(io, io32, resid); - CP(io, io32, duration); - CP(io, io32, info); - - error = copyout(&io32, (void *)args->arg, sizeof(io32)); - -out: - fdrop(fp, td); - return (error); -} -#endif - -static int -linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args) -{ - - switch (args->cmd) { - case LINUX_SG_GET_VERSION_NUM: - args->cmd = SG_GET_VERSION_NUM; - break; - case LINUX_SG_SET_TIMEOUT: - args->cmd = SG_SET_TIMEOUT; - break; - case LINUX_SG_GET_TIMEOUT: - args->cmd = SG_GET_TIMEOUT; - break; - case LINUX_SG_IO: - args->cmd = SG_IO; -#ifdef COMPAT_LINUX32 - return (linux_ioctl_sg_io(td, args)); -#endif - break; - case LINUX_SG_GET_RESERVED_SIZE: - args->cmd = SG_GET_RESERVED_SIZE; - break; - case LINUX_SG_GET_SCSI_ID: - args->cmd = SG_GET_SCSI_ID; - break; - case LINUX_SG_GET_SG_TABLESIZE: - args->cmd = SG_GET_SG_TABLESIZE; - break; - default: - return (ENODEV); - } - return (sys_ioctl(td, (struct ioctl_args *)args)); -} - -/* - * Video4Linux (V4L) ioctl handler - */ -static int -linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt) -{ - vt->tuner = lvt->tuner; - strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE); - vt->rangelow = lvt->rangelow; /* possible long size conversion */ - vt->rangehigh = lvt->rangehigh; /* possible long size conversion */ - vt->flags = lvt->flags; - vt->mode = lvt->mode; - vt->signal = lvt->signal; - return (0); -} - -static int -bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt) -{ - lvt->tuner = vt->tuner; - strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE); - lvt->rangelow = vt->rangelow; /* possible long size conversion */ - lvt->rangehigh = vt->rangehigh; /* possible long size conversion */ - lvt->flags = vt->flags; - lvt->mode = vt->mode; - lvt->signal = vt->signal; - return (0); -} - -#ifdef COMPAT_LINUX_V4L_CLIPLIST -static int -linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc) -{ - vc->x = lvc->x; - vc->y = lvc->y; - vc->width = lvc->width; - vc->height = lvc->height; - vc->next = PTRIN(lvc->next); /* possible pointer size conversion */ - return (0); -} -#endif - -static int -linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw) -{ - vw->x = lvw->x; - vw->y = lvw->y; - vw->width = lvw->width; - vw->height = lvw->height; - vw->chromakey = lvw->chromakey; - vw->flags = lvw->flags; - vw->clips = PTRIN(lvw->clips); /* possible pointer size conversion */ - vw->clipcount = lvw->clipcount; - return (0); -} - -static int -bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw) -{ - memset(lvw, 0, sizeof(*lvw)); - - lvw->x = vw->x; - lvw->y = vw->y; - lvw->width = vw->width; - lvw->height = vw->height; - lvw->chromakey = vw->chromakey; - lvw->flags = vw->flags; - lvw->clips = PTROUT(vw->clips); /* possible pointer size conversion */ - lvw->clipcount = vw->clipcount; - return (0); -} - -static int -linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb) -{ - vb->base = PTRIN(lvb->base); /* possible pointer size conversion */ - vb->height = lvb->height; - vb->width = lvb->width; - vb->depth = lvb->depth; - vb->bytesperline = lvb->bytesperline; - return (0); -} - -static int -bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb) -{ - lvb->base = PTROUT(vb->base); /* possible pointer size conversion */ - lvb->height = vb->height; - lvb->width = vb->width; - lvb->depth = vb->depth; - lvb->bytesperline = vb->bytesperline; - return (0); -} - -static int -linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc) -{ - strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE); - vc->datasize = lvc->datasize; - vc->data = PTRIN(lvc->data); /* possible pointer size conversion */ - return (0); -} - -#ifdef COMPAT_LINUX_V4L_CLIPLIST -static int -linux_v4l_clip_copy(void *lvc, struct video_clip **ppvc) -{ - int error; - struct video_clip vclip; - struct l_video_clip l_vclip; - - error = copyin(lvc, &l_vclip, sizeof(l_vclip)); - if (error) return (error); - linux_to_bsd_v4l_clip(&l_vclip, &vclip); - /* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */ - if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL) - return (ENOMEM); /* XXX: Linux has no ENOMEM here. */ - memcpy(*ppvc, &vclip, sizeof(vclip)); - (*ppvc)->next = NULL; - return (0); -} - -static int -linux_v4l_cliplist_free(struct video_window *vw) -{ - struct video_clip **ppvc; - struct video_clip **ppvc_next; - - for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) { - ppvc_next = &((*ppvc)->next); - free(*ppvc, M_LINUX); - } - vw->clips = NULL; - - return (0); -} - -static int -linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw) -{ - int error; - int clipcount; - void *plvc; - struct video_clip **ppvc; - - /* - * XXX: The cliplist is used to pass in a list of clipping - * rectangles or, if clipcount == VIDEO_CLIP_BITMAP, a - * clipping bitmap. Some Linux apps, however, appear to - * leave cliplist and clips uninitialized. In any case, - * the cliplist is not used by pwc(4), at the time of - * writing, FreeBSD's only V4L driver. When a driver - * that uses the cliplist is developed, this code may - * need re-examiniation. - */ - error = 0; - clipcount = vw->clipcount; - if (clipcount == VIDEO_CLIP_BITMAP) { - /* - * In this case, the pointer (clips) is overloaded - * to be a "void *" to a bitmap, therefore there - * is no struct video_clip to copy now. - */ - } else if (clipcount > 0 && clipcount <= 16384) { - /* - * Clips points to list of clip rectangles, so - * copy the list. - * - * XXX: Upper limit of 16384 was used here to try to - * avoid cases when clipcount and clips pointer - * are uninitialized and therefore have high random - * values, as is the case in the Linux Skype - * application. The value 16384 was chosen as that - * is what is used in the Linux stradis(4) MPEG - * decoder driver, the only place we found an - * example of cliplist use. - */ - plvc = PTRIN(lvw->clips); - vw->clips = NULL; - ppvc = &(vw->clips); - while (clipcount-- > 0) { - if (plvc == NULL) { - error = EFAULT; - break; - } else { - error = linux_v4l_clip_copy(plvc, ppvc); - if (error) { - linux_v4l_cliplist_free(vw); - break; - } - } - ppvc = &((*ppvc)->next); - plvc = PTRIN(((struct l_video_clip *) plvc)->next); - } - } else { - /* - * clipcount == 0 or negative (but not VIDEO_CLIP_BITMAP) - * Force cliplist to null. - */ - vw->clipcount = 0; - vw->clips = NULL; - } - return (error); -} -#endif - -static int -linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - int error; - struct video_tuner vtun; - struct video_window vwin; - struct video_buffer vbuf; - struct video_code vcode; - struct l_video_tuner l_vtun; - struct l_video_window l_vwin; - struct l_video_buffer l_vbuf; - struct l_video_code l_vcode; - - switch (args->cmd & 0xffff) { - case LINUX_VIDIOCGCAP: args->cmd = VIDIOCGCAP; break; - case LINUX_VIDIOCGCHAN: args->cmd = VIDIOCGCHAN; break; - case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break; - - case LINUX_VIDIOCGTUNER: - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); - if (error) { - fdrop(fp, td); - return (error); - } - linux_to_bsd_v4l_tuner(&l_vtun, &vtun); - error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td); - if (!error) { - bsd_to_linux_v4l_tuner(&vtun, &l_vtun); - error = copyout(&l_vtun, (void *) args->arg, - sizeof(l_vtun)); - } - fdrop(fp, td); - return (error); - - case LINUX_VIDIOCSTUNER: - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); - if (error) { - fdrop(fp, td); - return (error); - } - linux_to_bsd_v4l_tuner(&l_vtun, &vtun); - error = fo_ioctl(fp, VIDIOCSTUNER, &vtun, td->td_ucred, td); - fdrop(fp, td); - return (error); - - case LINUX_VIDIOCGPICT: args->cmd = VIDIOCGPICT; break; - case LINUX_VIDIOCSPICT: args->cmd = VIDIOCSPICT; break; - case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break; - - case LINUX_VIDIOCGWIN: - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td); - if (!error) { - bsd_to_linux_v4l_window(&vwin, &l_vwin); - error = copyout(&l_vwin, (void *) args->arg, - sizeof(l_vwin)); - } - fdrop(fp, td); - return (error); - - case LINUX_VIDIOCSWIN: - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin)); - if (error) { - fdrop(fp, td); - return (error); - } - linux_to_bsd_v4l_window(&l_vwin, &vwin); -#ifdef COMPAT_LINUX_V4L_CLIPLIST - error = linux_v4l_cliplist_copy(&l_vwin, &vwin); - if (error) { - fdrop(fp, td); - return (error); - } -#endif - error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td); - fdrop(fp, td); -#ifdef COMPAT_LINUX_V4L_CLIPLIST - linux_v4l_cliplist_free(&vwin); -#endif - return (error); - - case LINUX_VIDIOCGFBUF: - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td); - if (!error) { - bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf); - error = copyout(&l_vbuf, (void *) args->arg, - sizeof(l_vbuf)); - } - fdrop(fp, td); - return (error); - - case LINUX_VIDIOCSFBUF: - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf)); - if (error) { - fdrop(fp, td); - return (error); - } - linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf); - error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td); - fdrop(fp, td); - return (error); - - case LINUX_VIDIOCKEY: args->cmd = VIDIOCKEY; break; - case LINUX_VIDIOCGFREQ: args->cmd = VIDIOCGFREQ; break; - case LINUX_VIDIOCSFREQ: args->cmd = VIDIOCSFREQ; break; - case LINUX_VIDIOCGAUDIO: args->cmd = VIDIOCGAUDIO; break; - case LINUX_VIDIOCSAUDIO: args->cmd = VIDIOCSAUDIO; break; - case LINUX_VIDIOCSYNC: args->cmd = VIDIOCSYNC; break; - case LINUX_VIDIOCMCAPTURE: args->cmd = VIDIOCMCAPTURE; break; - case LINUX_VIDIOCGMBUF: args->cmd = VIDIOCGMBUF; break; - case LINUX_VIDIOCGUNIT: args->cmd = VIDIOCGUNIT; break; - case LINUX_VIDIOCGCAPTURE: args->cmd = VIDIOCGCAPTURE; break; - case LINUX_VIDIOCSCAPTURE: args->cmd = VIDIOCSCAPTURE; break; - case LINUX_VIDIOCSPLAYMODE: args->cmd = VIDIOCSPLAYMODE; break; - case LINUX_VIDIOCSWRITEMODE: args->cmd = VIDIOCSWRITEMODE; break; - case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break; - - case LINUX_VIDIOCSMICROCODE: - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode)); - if (error) { - fdrop(fp, td); - return (error); - } - linux_to_bsd_v4l_code(&l_vcode, &vcode); - error = fo_ioctl(fp, VIDIOCSMICROCODE, &vcode, td->td_ucred, td); - fdrop(fp, td); - return (error); - - case LINUX_VIDIOCGVBIFMT: args->cmd = VIDIOCGVBIFMT; break; - case LINUX_VIDIOCSVBIFMT: args->cmd = VIDIOCSVBIFMT; break; - default: return (ENOIOCTL); - } - - error = sys_ioctl(td, (struct ioctl_args *)args); - return (error); -} - -/* - * Special ioctl handler - */ -static int -linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args) -{ - int error; - - switch (args->cmd) { - case LINUX_SIOCGIFADDR: - args->cmd = SIOCGIFADDR; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - case LINUX_SIOCSIFADDR: - args->cmd = SIOCSIFADDR; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - case LINUX_SIOCGIFFLAGS: - args->cmd = SIOCGIFFLAGS; - error = sys_ioctl(td, (struct ioctl_args *)args); - break; - default: - error = ENOIOCTL; - } - - return (error); -} - -static int -linux_to_bsd_v4l2_standard(struct l_v4l2_standard *lvstd, struct v4l2_standard *vstd) -{ - vstd->index = lvstd->index; - vstd->id = lvstd->id; - CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name)); - memcpy(vstd->name, lvstd->name, sizeof(vstd->name)); - vstd->frameperiod = lvstd->frameperiod; - vstd->framelines = lvstd->framelines; - CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved)); - memcpy(vstd->reserved, lvstd->reserved, sizeof(vstd->reserved)); - return (0); -} - -static int -bsd_to_linux_v4l2_standard(struct v4l2_standard *vstd, struct l_v4l2_standard *lvstd) -{ - lvstd->index = vstd->index; - lvstd->id = vstd->id; - CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name)); - memcpy(lvstd->name, vstd->name, sizeof(lvstd->name)); - lvstd->frameperiod = vstd->frameperiod; - lvstd->framelines = vstd->framelines; - CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved)); - memcpy(lvstd->reserved, vstd->reserved, sizeof(lvstd->reserved)); - return (0); -} - -static int -linux_to_bsd_v4l2_buffer(struct l_v4l2_buffer *lvb, struct v4l2_buffer *vb) -{ - vb->index = lvb->index; - vb->type = lvb->type; - vb->bytesused = lvb->bytesused; - vb->flags = lvb->flags; - vb->field = lvb->field; - vb->timestamp.tv_sec = lvb->timestamp.tv_sec; - vb->timestamp.tv_usec = lvb->timestamp.tv_usec; - memcpy(&vb->timecode, &lvb->timecode, sizeof (lvb->timecode)); - vb->sequence = lvb->sequence; - vb->memory = lvb->memory; - if (lvb->memory == V4L2_MEMORY_USERPTR) - /* possible pointer size conversion */ - vb->m.userptr = (unsigned long)PTRIN(lvb->m.userptr); - else - vb->m.offset = lvb->m.offset; - vb->length = lvb->length; - vb->input = lvb->input; - vb->reserved = lvb->reserved; - return (0); -} - -static int -bsd_to_linux_v4l2_buffer(struct v4l2_buffer *vb, struct l_v4l2_buffer *lvb) -{ - lvb->index = vb->index; - lvb->type = vb->type; - lvb->bytesused = vb->bytesused; - lvb->flags = vb->flags; - lvb->field = vb->field; - lvb->timestamp.tv_sec = vb->timestamp.tv_sec; - lvb->timestamp.tv_usec = vb->timestamp.tv_usec; - memcpy(&lvb->timecode, &vb->timecode, sizeof (vb->timecode)); - lvb->sequence = vb->sequence; - lvb->memory = vb->memory; - if (vb->memory == V4L2_MEMORY_USERPTR) - /* possible pointer size conversion */ - lvb->m.userptr = PTROUT(vb->m.userptr); - else - lvb->m.offset = vb->m.offset; - lvb->length = vb->length; - lvb->input = vb->input; - lvb->reserved = vb->reserved; - return (0); -} - -static int -linux_to_bsd_v4l2_format(struct l_v4l2_format *lvf, struct v4l2_format *vf) -{ - vf->type = lvf->type; - if (lvf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY -#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY - || lvf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY -#endif - ) - /* - * XXX TODO - needs 32 -> 64 bit conversion: - * (unused by webcams?) - */ - return (EINVAL); - memcpy(&vf->fmt, &lvf->fmt, sizeof(vf->fmt)); - return (0); -} - -static int -bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf) -{ - lvf->type = vf->type; - if (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY -#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY - || vf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY -#endif - ) - /* - * XXX TODO - needs 32 -> 64 bit conversion: - * (unused by webcams?) - */ - return (EINVAL); - memcpy(&lvf->fmt, &vf->fmt, sizeof(vf->fmt)); - return (0); -} -static int -linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - int error; - struct v4l2_format vformat; - struct l_v4l2_format l_vformat; - struct v4l2_standard vstd; - struct l_v4l2_standard l_vstd; - struct l_v4l2_buffer l_vbuf; - struct v4l2_buffer vbuf; - struct v4l2_input vinp; - - switch (args->cmd & 0xffff) { - case LINUX_VIDIOC_RESERVED: - case LINUX_VIDIOC_LOG_STATUS: - if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID) - return (ENOIOCTL); - args->cmd = (args->cmd & 0xffff) | IOC_VOID; - break; - - case LINUX_VIDIOC_OVERLAY: - case LINUX_VIDIOC_STREAMON: - case LINUX_VIDIOC_STREAMOFF: - case LINUX_VIDIOC_S_STD: - case LINUX_VIDIOC_S_TUNER: - case LINUX_VIDIOC_S_AUDIO: - case LINUX_VIDIOC_S_AUDOUT: - case LINUX_VIDIOC_S_MODULATOR: - case LINUX_VIDIOC_S_FREQUENCY: - case LINUX_VIDIOC_S_CROP: - case LINUX_VIDIOC_S_JPEGCOMP: - case LINUX_VIDIOC_S_PRIORITY: - case LINUX_VIDIOC_DBG_S_REGISTER: - case LINUX_VIDIOC_S_HW_FREQ_SEEK: - case LINUX_VIDIOC_SUBSCRIBE_EVENT: - case LINUX_VIDIOC_UNSUBSCRIBE_EVENT: - args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN; - break; - - case LINUX_VIDIOC_QUERYCAP: - case LINUX_VIDIOC_G_STD: - case LINUX_VIDIOC_G_AUDIO: - case LINUX_VIDIOC_G_INPUT: - case LINUX_VIDIOC_G_OUTPUT: - case LINUX_VIDIOC_G_AUDOUT: - case LINUX_VIDIOC_G_JPEGCOMP: - case LINUX_VIDIOC_QUERYSTD: - case LINUX_VIDIOC_G_PRIORITY: - case LINUX_VIDIOC_QUERY_DV_PRESET: - args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT; - break; - - case LINUX_VIDIOC_ENUM_FMT: - case LINUX_VIDIOC_REQBUFS: - case LINUX_VIDIOC_G_PARM: - case LINUX_VIDIOC_S_PARM: - case LINUX_VIDIOC_G_CTRL: - case LINUX_VIDIOC_S_CTRL: - case LINUX_VIDIOC_G_TUNER: - case LINUX_VIDIOC_QUERYCTRL: - case LINUX_VIDIOC_QUERYMENU: - case LINUX_VIDIOC_S_INPUT: - case LINUX_VIDIOC_S_OUTPUT: - case LINUX_VIDIOC_ENUMOUTPUT: - case LINUX_VIDIOC_G_MODULATOR: - case LINUX_VIDIOC_G_FREQUENCY: - case LINUX_VIDIOC_CROPCAP: - case LINUX_VIDIOC_G_CROP: - case LINUX_VIDIOC_ENUMAUDIO: - case LINUX_VIDIOC_ENUMAUDOUT: - case LINUX_VIDIOC_G_SLICED_VBI_CAP: -#ifdef VIDIOC_ENUM_FRAMESIZES - case LINUX_VIDIOC_ENUM_FRAMESIZES: - case LINUX_VIDIOC_ENUM_FRAMEINTERVALS: - case LINUX_VIDIOC_ENCODER_CMD: - case LINUX_VIDIOC_TRY_ENCODER_CMD: -#endif - case LINUX_VIDIOC_DBG_G_REGISTER: - case LINUX_VIDIOC_DBG_G_CHIP_IDENT: - case LINUX_VIDIOC_ENUM_DV_PRESETS: - case LINUX_VIDIOC_S_DV_PRESET: - case LINUX_VIDIOC_G_DV_PRESET: - case LINUX_VIDIOC_S_DV_TIMINGS: - case LINUX_VIDIOC_G_DV_TIMINGS: - args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT; - break; - - case LINUX_VIDIOC_G_FMT: - case LINUX_VIDIOC_S_FMT: - case LINUX_VIDIOC_TRY_FMT: - error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat)); - if (error) - return (error); - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error) - return (error); - if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0) - error = EINVAL; - else if ((args->cmd & 0xffff) == LINUX_VIDIOC_G_FMT) - error = fo_ioctl(fp, VIDIOC_G_FMT, &vformat, - td->td_ucred, td); - else if ((args->cmd & 0xffff) == LINUX_VIDIOC_S_FMT) - error = fo_ioctl(fp, VIDIOC_S_FMT, &vformat, - td->td_ucred, td); - else - error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat, - td->td_ucred, td); - bsd_to_linux_v4l2_format(&vformat, &l_vformat); - if (error == 0) - error = copyout(&l_vformat, (void *)args->arg, - sizeof(l_vformat)); - fdrop(fp, td); - return (error); - - case LINUX_VIDIOC_ENUMSTD: - error = copyin((void *)args->arg, &l_vstd, sizeof(l_vstd)); - if (error) - return (error); - linux_to_bsd_v4l2_standard(&l_vstd, &vstd); - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error) - return (error); - error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd, - td->td_ucred, td); - if (error) { - fdrop(fp, td); - return (error); - } - bsd_to_linux_v4l2_standard(&vstd, &l_vstd); - error = copyout(&l_vstd, (void *)args->arg, sizeof(l_vstd)); - fdrop(fp, td); - return (error); - - case LINUX_VIDIOC_ENUMINPUT: - /* - * The Linux struct l_v4l2_input differs only in size, - * it has no padding at the end. - */ - error = copyin((void *)args->arg, &vinp, - sizeof(struct l_v4l2_input)); - if (error != 0) - return (error); - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp, - td->td_ucred, td); - if (error) { - fdrop(fp, td); - return (error); - } - error = copyout(&vinp, (void *)args->arg, - sizeof(struct l_v4l2_input)); - fdrop(fp, td); - return (error); - - case LINUX_VIDIOC_QUERYBUF: - case LINUX_VIDIOC_QBUF: - case LINUX_VIDIOC_DQBUF: - error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf)); - if (error) - return (error); - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error) - return (error); - linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf); - if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF) - error = fo_ioctl(fp, VIDIOC_QUERYBUF, &vbuf, - td->td_ucred, td); - else if ((args->cmd & 0xffff) == LINUX_VIDIOC_QBUF) - error = fo_ioctl(fp, VIDIOC_QBUF, &vbuf, - td->td_ucred, td); - else - error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf, - td->td_ucred, td); - bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf); - if (error == 0) - error = copyout(&l_vbuf, (void *)args->arg, - sizeof(l_vbuf)); - fdrop(fp, td); - return (error); - - /* - * XXX TODO - these need 32 -> 64 bit conversion: - * (are any of them needed for webcams?) - */ - case LINUX_VIDIOC_G_FBUF: - case LINUX_VIDIOC_S_FBUF: - - case LINUX_VIDIOC_G_EXT_CTRLS: - case LINUX_VIDIOC_S_EXT_CTRLS: - case LINUX_VIDIOC_TRY_EXT_CTRLS: - - case LINUX_VIDIOC_DQEVENT: - - default: return (ENOIOCTL); - } - - error = sys_ioctl(td, (struct ioctl_args *)args); - return (error); -} - -/* - * Support for emulators/linux-libusb. This port uses FBSD_LUSB* macros - * instead of USB* ones. This lets us to provide correct values for cmd. - * 0xffffffe0 -- 0xffffffff range seemed to be the least collision-prone. - */ -static int -linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args) -{ - int error; - - error = 0; - switch (args->cmd) { - case FBSD_LUSB_DEVICEENUMERATE: - args->cmd = USB_DEVICEENUMERATE; - break; - case FBSD_LUSB_DEV_QUIRK_ADD: - args->cmd = USB_DEV_QUIRK_ADD; - break; - case FBSD_LUSB_DEV_QUIRK_GET: - args->cmd = USB_DEV_QUIRK_GET; - break; - case FBSD_LUSB_DEV_QUIRK_REMOVE: - args->cmd = USB_DEV_QUIRK_REMOVE; - break; - case FBSD_LUSB_DO_REQUEST: - args->cmd = USB_DO_REQUEST; - break; - case FBSD_LUSB_FS_CLEAR_STALL_SYNC: - args->cmd = USB_FS_CLEAR_STALL_SYNC; - break; - case FBSD_LUSB_FS_CLOSE: - args->cmd = USB_FS_CLOSE; - break; - case FBSD_LUSB_FS_COMPLETE: - args->cmd = USB_FS_COMPLETE; - break; - case FBSD_LUSB_FS_INIT: - args->cmd = USB_FS_INIT; - break; - case FBSD_LUSB_FS_OPEN: - args->cmd = USB_FS_OPEN; - break; - case FBSD_LUSB_FS_START: - args->cmd = USB_FS_START; - break; - case FBSD_LUSB_FS_STOP: - args->cmd = USB_FS_STOP; - break; - case FBSD_LUSB_FS_UNINIT: - args->cmd = USB_FS_UNINIT; - break; - case FBSD_LUSB_GET_CONFIG: - args->cmd = USB_GET_CONFIG; - break; - case FBSD_LUSB_GET_DEVICEINFO: - args->cmd = USB_GET_DEVICEINFO; - break; - case FBSD_LUSB_GET_DEVICE_DESC: - args->cmd = USB_GET_DEVICE_DESC; - break; - case FBSD_LUSB_GET_FULL_DESC: - args->cmd = USB_GET_FULL_DESC; - break; - case FBSD_LUSB_GET_IFACE_DRIVER: - args->cmd = USB_GET_IFACE_DRIVER; - break; - case FBSD_LUSB_GET_PLUGTIME: - args->cmd = USB_GET_PLUGTIME; - break; - case FBSD_LUSB_GET_POWER_MODE: - args->cmd = USB_GET_POWER_MODE; - break; - case FBSD_LUSB_GET_REPORT_DESC: - args->cmd = USB_GET_REPORT_DESC; - break; - case FBSD_LUSB_GET_REPORT_ID: - args->cmd = USB_GET_REPORT_ID; - break; - case FBSD_LUSB_GET_TEMPLATE: - args->cmd = USB_GET_TEMPLATE; - break; - case FBSD_LUSB_IFACE_DRIVER_ACTIVE: - args->cmd = USB_IFACE_DRIVER_ACTIVE; - break; - case FBSD_LUSB_IFACE_DRIVER_DETACH: - args->cmd = USB_IFACE_DRIVER_DETACH; - break; - case FBSD_LUSB_QUIRK_NAME_GET: - args->cmd = USB_QUIRK_NAME_GET; - break; - case FBSD_LUSB_READ_DIR: - args->cmd = USB_READ_DIR; - break; - case FBSD_LUSB_SET_ALTINTERFACE: - args->cmd = USB_SET_ALTINTERFACE; - break; - case FBSD_LUSB_SET_CONFIG: - args->cmd = USB_SET_CONFIG; - break; - case FBSD_LUSB_SET_IMMED: - args->cmd = USB_SET_IMMED; - break; - case FBSD_LUSB_SET_POWER_MODE: - args->cmd = USB_SET_POWER_MODE; - break; - case FBSD_LUSB_SET_TEMPLATE: - args->cmd = USB_SET_TEMPLATE; - break; - case FBSD_LUSB_FS_OPEN_STREAM: - args->cmd = USB_FS_OPEN_STREAM; - break; - case FBSD_LUSB_GET_DEV_PORT_PATH: - args->cmd = USB_GET_DEV_PORT_PATH; - break; - case FBSD_LUSB_GET_POWER_USAGE: - args->cmd = USB_GET_POWER_USAGE; - break; - case FBSD_LUSB_DEVICESTATS: - args->cmd = USB_DEVICESTATS; - break; - default: - error = ENOIOCTL; - } - if (error != ENOIOCTL) - error = sys_ioctl(td, (struct ioctl_args *)args); - return (error); -} - -/* - * Some evdev ioctls must be translated. - * - EVIOCGMTSLOTS is a IOC_READ ioctl on Linux although it has input data - * (must be IOC_INOUT on FreeBSD). - * - On Linux, EVIOCGRAB, EVIOCREVOKE and EVIOCRMFF are defined as _IOW with - * an int argument. You don't pass an int pointer to the ioctl(), however, - * but just the int directly. On FreeBSD, they are defined as _IOWINT for - * this to work. - */ -static int -linux_ioctl_evdev(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - clockid_t clock; - int error; - - args->cmd = SETDIR(args->cmd); - - switch (args->cmd) { - case (EVIOCGRAB & ~IOC_DIRMASK) | IOC_IN: - args->cmd = EVIOCGRAB; - break; - case (EVIOCREVOKE & ~IOC_DIRMASK) | IOC_IN: - args->cmd = EVIOCREVOKE; - break; - case (EVIOCRMFF & ~IOC_DIRMASK) | IOC_IN: - args->cmd = EVIOCRMFF; - break; - case EVIOCSCLOCKID: { - error = copyin(PTRIN(args->arg), &clock, sizeof(clock)); - if (error != 0) - return (error); - if (clock & ~(LINUX_IOCTL_EVDEV_CLK)) - return (EINVAL); - error = linux_to_native_clockid(&clock, clock); - if (error != 0) - return (error); - - error = fget(td, args->fd, - &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - - error = fo_ioctl(fp, EVIOCSCLOCKID, &clock, td->td_ucred, td); - fdrop(fp, td); - return (error); - } - default: - break; - } - - if (IOCBASECMD(args->cmd) == - ((EVIOCGMTSLOTS(0) & ~IOC_DIRMASK) | IOC_OUT)) - args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT; - - return (sys_ioctl(td, (struct ioctl_args *)args)); -} - -static int -linux_ioctl_kcov(struct thread *td, struct linux_ioctl_args *args) -{ - int error; - - error = 0; - switch (args->cmd & 0xffff) { - case LINUX_KCOV_INIT_TRACE: - args->cmd = KIOSETBUFSIZE; - break; - case LINUX_KCOV_ENABLE: - args->cmd = KIOENABLE; - if (args->arg == 0) - args->arg = KCOV_MODE_TRACE_PC; - else if (args->arg == 1) - args->arg = KCOV_MODE_TRACE_CMP; - else - error = EINVAL; - break; - case LINUX_KCOV_DISABLE: - args->cmd = KIODISABLE; - break; - default: - error = ENOTTY; - break; - } - - if (error == 0) - error = sys_ioctl(td, (struct ioctl_args *)args); - return (error); -} - -#ifndef COMPAT_LINUX32 -static int -linux_ioctl_nvme(struct thread *td, struct linux_ioctl_args *args) -{ - - /* - * The NVMe drivers for namespace and controller implement these - * commands using their native format. All the others are not - * implemented yet. - */ - switch (args->cmd & 0xffff) { - case LINUX_NVME_IOCTL_ID: - args->cmd = NVME_IOCTL_ID; - break; - case LINUX_NVME_IOCTL_RESET: - args->cmd = NVME_IOCTL_RESET; - break; - case LINUX_NVME_IOCTL_ADMIN_CMD: - args->cmd = NVME_IOCTL_ADMIN_CMD; - break; - case LINUX_NVME_IOCTL_IO_CMD: - args->cmd = NVME_IOCTL_IO_CMD; - break; - default: - return (ENODEV); - } - return (sys_ioctl(td, (struct ioctl_args *)args)); -} -#endif - -/* - * main ioctl syscall function - */ - -static int -linux_ioctl_fallback(struct thread *td, struct linux_ioctl_args *args) -{ - struct file *fp; - struct linux_ioctl_handler_element *he; - int error, cmd; - - error = fget(td, args->fd, &cap_ioctl_rights, &fp); - if (error != 0) - return (error); - if ((fp->f_flag & (FREAD|FWRITE)) == 0) { - fdrop(fp, td); - return (EBADF); - } - - /* Iterate over the ioctl handlers */ - cmd = args->cmd & 0xffff; - sx_slock(&linux_ioctl_sx); - mtx_lock(&Giant); -#ifdef COMPAT_LINUX32 - TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { - if (cmd >= he->low && cmd <= he->high) { - error = (*he->func)(td, args); - if (error != ENOIOCTL) { - mtx_unlock(&Giant); - sx_sunlock(&linux_ioctl_sx); - fdrop(fp, td); - return (error); - } - } - } -#endif - TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { - if (cmd >= he->low && cmd <= he->high) { - error = (*he->func)(td, args); - if (error != ENOIOCTL) { - mtx_unlock(&Giant); - sx_sunlock(&linux_ioctl_sx); - fdrop(fp, td); - return (error); - } - } - } - mtx_unlock(&Giant); - sx_sunlock(&linux_ioctl_sx); - fdrop(fp, td); - - switch (args->cmd & 0xffff) { - case LINUX_BTRFS_IOC_CLONE: - case LINUX_F2FS_IOC_GET_FEATURES: - case LINUX_FS_IOC_FIEMAP: - return (ENOTSUP); - - default: - linux_msg(td, "%s fd=%d, cmd=0x%x ('%c',%d) is not implemented", - __func__, args->fd, args->cmd, - (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff)); - break; - } - - return (EINVAL); -} - -int -linux_ioctl(struct thread *td, struct linux_ioctl_args *args) -{ - struct linux_ioctl_handler *handler; - int error, cmd, i; - - cmd = args->cmd & 0xffff; - - /* - * array of ioctls known at compilation time. Elides a lot of work on - * each call compared to the list variant. Everything frequently used - * should be moved here. - * - * Arguably the magic creating the list should create an array instead. - * - * For now just a linear scan. - */ - for (i = 0; i < nitems(linux_ioctls); i++) { - handler = &linux_ioctls[i]; - if (cmd >= handler->low && cmd <= handler->high) { - error = (*handler->func)(td, args); - if (error != ENOIOCTL) { - return (error); - } - } - } - return (linux_ioctl_fallback(td, args)); -} - -int -linux_ioctl_register_handler(struct linux_ioctl_handler *h) -{ - struct linux_ioctl_handler_element *he, *cur; - - if (h == NULL || h->func == NULL) - return (EINVAL); - - /* - * Reuse the element if the handler is already on the list, otherwise - * create a new element. - */ - sx_xlock(&linux_ioctl_sx); - TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { - if (he->func == h->func) - break; - } - if (he == NULL) { - he = malloc(sizeof(*he), - M_LINUX, M_WAITOK); - he->func = h->func; - } else - TAILQ_REMOVE(&linux_ioctl_handlers, he, list); - - /* Initialize range information. */ - he->low = h->low; - he->high = h->high; - he->span = h->high - h->low + 1; - - /* Add the element to the list, sorted on span. */ - TAILQ_FOREACH(cur, &linux_ioctl_handlers, list) { - if (cur->span > he->span) { - TAILQ_INSERT_BEFORE(cur, he, list); - sx_xunlock(&linux_ioctl_sx); - return (0); - } - } - TAILQ_INSERT_TAIL(&linux_ioctl_handlers, he, list); - sx_xunlock(&linux_ioctl_sx); - - return (0); -} - -int -linux_ioctl_unregister_handler(struct linux_ioctl_handler *h) -{ - struct linux_ioctl_handler_element *he; - - if (h == NULL || h->func == NULL) - return (EINVAL); - - sx_xlock(&linux_ioctl_sx); - TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { - if (he->func == h->func) { - TAILQ_REMOVE(&linux_ioctl_handlers, he, list); - sx_xunlock(&linux_ioctl_sx); - free(he, M_LINUX); - return (0); - } - } - sx_xunlock(&linux_ioctl_sx); - - return (EINVAL); -} - -#ifdef COMPAT_LINUX32 -int -linux32_ioctl_register_handler(struct linux_ioctl_handler *h) -{ - struct linux_ioctl_handler_element *he, *cur; - - if (h == NULL || h->func == NULL) - return (EINVAL); - - /* - * Reuse the element if the handler is already on the list, otherwise - * create a new element. - */ - sx_xlock(&linux_ioctl_sx); - TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { - if (he->func == h->func) - break; - } - if (he == NULL) { - he = malloc(sizeof(*he), M_LINUX, M_WAITOK); - he->func = h->func; - } else - TAILQ_REMOVE(&linux32_ioctl_handlers, he, list); - - /* Initialize range information. */ - he->low = h->low; - he->high = h->high; - he->span = h->high - h->low + 1; - - /* Add the element to the list, sorted on span. */ - TAILQ_FOREACH(cur, &linux32_ioctl_handlers, list) { - if (cur->span > he->span) { - TAILQ_INSERT_BEFORE(cur, he, list); - sx_xunlock(&linux_ioctl_sx); - return (0); - } - } - TAILQ_INSERT_TAIL(&linux32_ioctl_handlers, he, list); - sx_xunlock(&linux_ioctl_sx); - - return (0); -} - -int -linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h) -{ - struct linux_ioctl_handler_element *he; - - if (h == NULL || h->func == NULL) - return (EINVAL); - - sx_xlock(&linux_ioctl_sx); - TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { - if (he->func == h->func) { - TAILQ_REMOVE(&linux32_ioctl_handlers, he, list); - sx_xunlock(&linux_ioctl_sx); - free(he, M_LINUX); - return (0); - } - } - sx_xunlock(&linux_ioctl_sx); - - return (EINVAL); -} -#endif +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#define DEFINE_LINUX_IOCTL_SET(shortname, SHORTNAME) \ +static linux_ioctl_function_t linux_ioctl_ ## shortname; \ +static struct linux_ioctl_handler shortname ## _handler = { \ + .func = linux_ioctl_ ## shortname, \ + .low = LINUX_IOCTL_ ## SHORTNAME ## _MIN, \ + .high = LINUX_IOCTL_ ## SHORTNAME ## _MAX, \ +}; \ +DATA_SET(linux_ioctl_handler_set, shortname ## _handler) + +DEFINE_LINUX_IOCTL_SET(cdrom, CDROM); +DEFINE_LINUX_IOCTL_SET(vfat, VFAT); +DEFINE_LINUX_IOCTL_SET(console, CONSOLE); +DEFINE_LINUX_IOCTL_SET(hdio, HDIO); +DEFINE_LINUX_IOCTL_SET(disk, DISK); +DEFINE_LINUX_IOCTL_SET(socket, SOCKET); +DEFINE_LINUX_IOCTL_SET(sound, SOUND); +DEFINE_LINUX_IOCTL_SET(termio, TERMIO); +DEFINE_LINUX_IOCTL_SET(private, PRIVATE); +DEFINE_LINUX_IOCTL_SET(drm, DRM); +DEFINE_LINUX_IOCTL_SET(sg, SG); +DEFINE_LINUX_IOCTL_SET(v4l, VIDEO); +DEFINE_LINUX_IOCTL_SET(v4l2, VIDEO2); +DEFINE_LINUX_IOCTL_SET(fbsd_usb, FBSD_LUSB); +DEFINE_LINUX_IOCTL_SET(evdev, EVDEV); +DEFINE_LINUX_IOCTL_SET(kcov, KCOV); +#ifndef COMPAT_LINUX32 +DEFINE_LINUX_IOCTL_SET(nvme, NVME); +#endif + +#undef DEFINE_LINUX_IOCTL_SET + +static int linux_ioctl_special(struct thread *, struct linux_ioctl_args *); + +/* + * Keep sorted by low. + */ +static struct linux_ioctl_handler linux_ioctls[] = { + { .func = linux_ioctl_termio, .low = LINUX_IOCTL_TERMIO_MIN, + .high = LINUX_IOCTL_TERMIO_MAX }, +}; + +#ifdef __i386__ +static TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers = + TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers); +static struct sx linux_ioctl_sx; +SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers"); +#else +extern TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers; +extern struct sx linux_ioctl_sx; +#endif +#ifdef COMPAT_LINUX32 +static TAILQ_HEAD(, linux_ioctl_handler_element) linux32_ioctl_handlers = + TAILQ_HEAD_INITIALIZER(linux32_ioctl_handlers); +#endif + +/* + * hdio related ioctls for VMWare support + */ + +struct linux_hd_geometry { + uint8_t heads; + uint8_t sectors; + uint16_t cylinders; + uint32_t start; +}; + +struct linux_hd_big_geometry { + uint8_t heads; + uint8_t sectors; + uint32_t cylinders; + uint32_t start; +}; + +static int +linux_ioctl_forward_to_sys(struct thread *td, struct linux_ioctl_args *args) +{ + struct ioctl_args bargs = { + .fd = args->fd, + .com = args->cmd, + .data = LINUX_USER_CAP_UNBOUND(args->arg) + }; + + return sys_ioctl(td, &bargs); +} + +static int +linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + u_int sectorsize, fwcylinders, fwheads, fwsectors; + off_t mediasize, bytespercyl; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + switch (args->cmd & 0xffff) { + case LINUX_HDIO_GET_GEO: + case LINUX_HDIO_GET_GEO_BIG: + error = fo_ioctl(fp, DIOCGMEDIASIZE, + (caddr_t)&mediasize, td->td_ucred, td); + if (!error) + error = fo_ioctl(fp, DIOCGSECTORSIZE, + (caddr_t)§orsize, td->td_ucred, td); + if (!error) + error = fo_ioctl(fp, DIOCGFWHEADS, + (caddr_t)&fwheads, td->td_ucred, td); + if (!error) + error = fo_ioctl(fp, DIOCGFWSECTORS, + (caddr_t)&fwsectors, td->td_ucred, td); + /* + * XXX: DIOCGFIRSTOFFSET is not yet implemented, so + * so pretend that GEOM always says 0. This is NOT VALID + * for slices or partitions, only the per-disk raw devices. + */ + + fdrop(fp, td); + if (error) + return (error); + /* + * 1. Calculate the number of bytes in a cylinder, + * given the firmware's notion of heads and sectors + * per cylinder. + * 2. Calculate the number of cylinders, given the total + * size of the media. + * All internal calculations should have 64-bit precision. + */ + bytespercyl = (off_t) sectorsize * fwheads * fwsectors; + fwcylinders = mediasize / bytespercyl; + + if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) { + struct linux_hd_geometry hdg; + + hdg.cylinders = fwcylinders; + hdg.heads = fwheads; + hdg.sectors = fwsectors; + hdg.start = 0; + error = copyout(&hdg, LINUX_USER_CAP(args->arg, sizeof(hdg)), sizeof(hdg)); + } else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) { + struct linux_hd_big_geometry hdbg; + + memset(&hdbg, 0, sizeof(hdbg)); + hdbg.cylinders = fwcylinders; + hdbg.heads = fwheads; + hdbg.sectors = fwsectors; + hdbg.start = 0; + error = copyout(&hdbg, LINUX_USER_CAP(args->arg, sizeof(hdbg)), sizeof(hdbg)); + } + return (error); + break; + default: + /* XXX */ + linux_msg(td, + "%s fd=%d, cmd=0x%x ('%c',%d) is not implemented", + __func__, args->fd, args->cmd, + (int)(args->cmd & 0xff00) >> 8, + (int)(args->cmd & 0xff)); + break; + } + fdrop(fp, td); + return (ENOIOCTL); +} + +static int +linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + u_int sectorsize, psectorsize; + uint64_t blksize64; + off_t mediasize, stripesize; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + switch (args->cmd & 0xffff) { + case LINUX_BLKGETSIZE: + error = fo_ioctl(fp, DIOCGSECTORSIZE, + (caddr_t)§orsize, td->td_ucred, td); + if (!error) + error = fo_ioctl(fp, DIOCGMEDIASIZE, + (caddr_t)&mediasize, td->td_ucred, td); + fdrop(fp, td); + if (error) + return (error); + sectorsize = mediasize / sectorsize; + /* + * XXX: How do we know we return the right size of integer ? + */ + return (copyout(§orsize, LINUX_USER_CAP(args->arg, sizeof(sectorsize)), + sizeof(sectorsize))); + break; + case LINUX_BLKGETSIZE64: + error = fo_ioctl(fp, DIOCGMEDIASIZE, + (caddr_t)&mediasize, td->td_ucred, td); + fdrop(fp, td); + if (error) + return (error); + blksize64 = mediasize; + return (copyout(&blksize64, LINUX_USER_CAP(args->arg, sizeof(blksize64)), + sizeof(blksize64))); + case LINUX_BLKSSZGET: + error = fo_ioctl(fp, DIOCGSECTORSIZE, + (caddr_t)§orsize, td->td_ucred, td); + fdrop(fp, td); + if (error) + return (error); + return (copyout(§orsize, LINUX_USER_CAP(args->arg, sizeof(sectorsize)), + sizeof(sectorsize))); + break; + case LINUX_BLKPBSZGET: + error = fo_ioctl(fp, DIOCGSTRIPESIZE, + (caddr_t)&stripesize, td->td_ucred, td); + if (error != 0) { + fdrop(fp, td); + return (error); + } + if (stripesize > 0 && stripesize <= 4096) { + psectorsize = stripesize; + } else { + error = fo_ioctl(fp, DIOCGSECTORSIZE, + (caddr_t)§orsize, td->td_ucred, td); + if (error != 0) { + fdrop(fp, td); + return (error); + } + psectorsize = sectorsize; + } + fdrop(fp, td); + return (copyout(&psectorsize, LINUX_USER_CAP(args->arg, sizeof(psectorsize)), + sizeof(psectorsize))); + } + fdrop(fp, td); + return (ENOIOCTL); +} + +/* + * termio related ioctls + */ + +struct linux_termio { + unsigned short c_iflag; + unsigned short c_oflag; + unsigned short c_cflag; + unsigned short c_lflag; + unsigned char c_line; + unsigned char c_cc[LINUX_NCC]; +}; + +struct linux_termios { + unsigned int c_iflag; + unsigned int c_oflag; + unsigned int c_cflag; + unsigned int c_lflag; + unsigned char c_line; + unsigned char c_cc[LINUX_NCCS]; +}; + +struct linux_winsize { + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; + +struct speedtab { + int sp_speed; /* Speed. */ + int sp_code; /* Code. */ +}; + +static struct speedtab sptab[] = { + { B0, LINUX_B0 }, { B50, LINUX_B50 }, + { B75, LINUX_B75 }, { B110, LINUX_B110 }, + { B134, LINUX_B134 }, { B150, LINUX_B150 }, + { B200, LINUX_B200 }, { B300, LINUX_B300 }, + { B600, LINUX_B600 }, { B1200, LINUX_B1200 }, + { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 }, + { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 }, + { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 }, + { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 }, + {-1, -1 } +}; + +struct linux_serial_struct { + int type; + int line; + int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char reserved_char[2]; + int hub6; + unsigned short closing_wait; + unsigned short closing_wait2; + int reserved[4]; +}; + +static int +linux_to_bsd_speed(int code, struct speedtab *table) +{ + for ( ; table->sp_code != -1; table++) + if (table->sp_code == code) + return (table->sp_speed); + return (-1); +} + +static int +bsd_to_linux_speed(int speed, struct speedtab *table) +{ + for ( ; table->sp_speed != -1; table++) + if (table->sp_speed == speed) + return (table->sp_code); + return (-1); +} + +static void +bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios) +{ + int i; + + lios->c_iflag = 0; + if (bios->c_iflag & IGNBRK) + lios->c_iflag |= LINUX_IGNBRK; + if (bios->c_iflag & BRKINT) + lios->c_iflag |= LINUX_BRKINT; + if (bios->c_iflag & IGNPAR) + lios->c_iflag |= LINUX_IGNPAR; + if (bios->c_iflag & PARMRK) + lios->c_iflag |= LINUX_PARMRK; + if (bios->c_iflag & INPCK) + lios->c_iflag |= LINUX_INPCK; + if (bios->c_iflag & ISTRIP) + lios->c_iflag |= LINUX_ISTRIP; + if (bios->c_iflag & INLCR) + lios->c_iflag |= LINUX_INLCR; + if (bios->c_iflag & IGNCR) + lios->c_iflag |= LINUX_IGNCR; + if (bios->c_iflag & ICRNL) + lios->c_iflag |= LINUX_ICRNL; + if (bios->c_iflag & IXON) + lios->c_iflag |= LINUX_IXON; + if (bios->c_iflag & IXANY) + lios->c_iflag |= LINUX_IXANY; + if (bios->c_iflag & IXOFF) + lios->c_iflag |= LINUX_IXOFF; + if (bios->c_iflag & IMAXBEL) + lios->c_iflag |= LINUX_IMAXBEL; + + lios->c_oflag = 0; + if (bios->c_oflag & OPOST) + lios->c_oflag |= LINUX_OPOST; + if (bios->c_oflag & ONLCR) + lios->c_oflag |= LINUX_ONLCR; + if (bios->c_oflag & TAB3) + lios->c_oflag |= LINUX_XTABS; + + lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab); + lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4; + if (bios->c_cflag & CSTOPB) + lios->c_cflag |= LINUX_CSTOPB; + if (bios->c_cflag & CREAD) + lios->c_cflag |= LINUX_CREAD; + if (bios->c_cflag & PARENB) + lios->c_cflag |= LINUX_PARENB; + if (bios->c_cflag & PARODD) + lios->c_cflag |= LINUX_PARODD; + if (bios->c_cflag & HUPCL) + lios->c_cflag |= LINUX_HUPCL; + if (bios->c_cflag & CLOCAL) + lios->c_cflag |= LINUX_CLOCAL; + if (bios->c_cflag & CRTSCTS) + lios->c_cflag |= LINUX_CRTSCTS; + + lios->c_lflag = 0; + if (bios->c_lflag & ISIG) + lios->c_lflag |= LINUX_ISIG; + if (bios->c_lflag & ICANON) + lios->c_lflag |= LINUX_ICANON; + if (bios->c_lflag & ECHO) + lios->c_lflag |= LINUX_ECHO; + if (bios->c_lflag & ECHOE) + lios->c_lflag |= LINUX_ECHOE; + if (bios->c_lflag & ECHOK) + lios->c_lflag |= LINUX_ECHOK; + if (bios->c_lflag & ECHONL) + lios->c_lflag |= LINUX_ECHONL; + if (bios->c_lflag & NOFLSH) + lios->c_lflag |= LINUX_NOFLSH; + if (bios->c_lflag & TOSTOP) + lios->c_lflag |= LINUX_TOSTOP; + if (bios->c_lflag & ECHOCTL) + lios->c_lflag |= LINUX_ECHOCTL; + if (bios->c_lflag & ECHOPRT) + lios->c_lflag |= LINUX_ECHOPRT; + if (bios->c_lflag & ECHOKE) + lios->c_lflag |= LINUX_ECHOKE; + if (bios->c_lflag & FLUSHO) + lios->c_lflag |= LINUX_FLUSHO; + if (bios->c_lflag & PENDIN) + lios->c_lflag |= LINUX_PENDIN; + if (bios->c_lflag & IEXTEN) + lios->c_lflag |= LINUX_IEXTEN; + + for (i=0; ic_cc[i] = LINUX_POSIX_VDISABLE; + lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR]; + lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT]; + lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE]; + lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL]; + lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF]; + lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL]; + lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN]; + lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME]; + lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2]; + lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP]; + lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART]; + lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP]; + lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT]; + lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD]; + lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE]; + lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT]; + if (linux_preserve_vstatus) + lios->c_cc[LINUX_VSTATUS] = bios->c_cc[VSTATUS]; + + for (i=0; ic_cc[i] == _POSIX_VDISABLE) + lios->c_cc[i] = LINUX_POSIX_VDISABLE; + } + lios->c_line = 0; +} + +static void +linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios) +{ + int i; + + bios->c_iflag = 0; + if (lios->c_iflag & LINUX_IGNBRK) + bios->c_iflag |= IGNBRK; + if (lios->c_iflag & LINUX_BRKINT) + bios->c_iflag |= BRKINT; + if (lios->c_iflag & LINUX_IGNPAR) + bios->c_iflag |= IGNPAR; + if (lios->c_iflag & LINUX_PARMRK) + bios->c_iflag |= PARMRK; + if (lios->c_iflag & LINUX_INPCK) + bios->c_iflag |= INPCK; + if (lios->c_iflag & LINUX_ISTRIP) + bios->c_iflag |= ISTRIP; + if (lios->c_iflag & LINUX_INLCR) + bios->c_iflag |= INLCR; + if (lios->c_iflag & LINUX_IGNCR) + bios->c_iflag |= IGNCR; + if (lios->c_iflag & LINUX_ICRNL) + bios->c_iflag |= ICRNL; + if (lios->c_iflag & LINUX_IXON) + bios->c_iflag |= IXON; + if (lios->c_iflag & LINUX_IXANY) + bios->c_iflag |= IXANY; + if (lios->c_iflag & LINUX_IXOFF) + bios->c_iflag |= IXOFF; + if (lios->c_iflag & LINUX_IMAXBEL) + bios->c_iflag |= IMAXBEL; + + bios->c_oflag = 0; + if (lios->c_oflag & LINUX_OPOST) + bios->c_oflag |= OPOST; + if (lios->c_oflag & LINUX_ONLCR) + bios->c_oflag |= ONLCR; + if (lios->c_oflag & LINUX_XTABS) + bios->c_oflag |= TAB3; + + bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4; + if (lios->c_cflag & LINUX_CSTOPB) + bios->c_cflag |= CSTOPB; + if (lios->c_cflag & LINUX_CREAD) + bios->c_cflag |= CREAD; + if (lios->c_cflag & LINUX_PARENB) + bios->c_cflag |= PARENB; + if (lios->c_cflag & LINUX_PARODD) + bios->c_cflag |= PARODD; + if (lios->c_cflag & LINUX_HUPCL) + bios->c_cflag |= HUPCL; + if (lios->c_cflag & LINUX_CLOCAL) + bios->c_cflag |= CLOCAL; + if (lios->c_cflag & LINUX_CRTSCTS) + bios->c_cflag |= CRTSCTS; + + bios->c_lflag = 0; + if (lios->c_lflag & LINUX_ISIG) + bios->c_lflag |= ISIG; + if (lios->c_lflag & LINUX_ICANON) + bios->c_lflag |= ICANON; + if (lios->c_lflag & LINUX_ECHO) + bios->c_lflag |= ECHO; + if (lios->c_lflag & LINUX_ECHOE) + bios->c_lflag |= ECHOE; + if (lios->c_lflag & LINUX_ECHOK) + bios->c_lflag |= ECHOK; + if (lios->c_lflag & LINUX_ECHONL) + bios->c_lflag |= ECHONL; + if (lios->c_lflag & LINUX_NOFLSH) + bios->c_lflag |= NOFLSH; + if (lios->c_lflag & LINUX_TOSTOP) + bios->c_lflag |= TOSTOP; + if (lios->c_lflag & LINUX_ECHOCTL) + bios->c_lflag |= ECHOCTL; + if (lios->c_lflag & LINUX_ECHOPRT) + bios->c_lflag |= ECHOPRT; + if (lios->c_lflag & LINUX_ECHOKE) + bios->c_lflag |= ECHOKE; + if (lios->c_lflag & LINUX_FLUSHO) + bios->c_lflag |= FLUSHO; + if (lios->c_lflag & LINUX_PENDIN) + bios->c_lflag |= PENDIN; + if (lios->c_lflag & LINUX_IEXTEN) + bios->c_lflag |= IEXTEN; + + for (i=0; ic_cc[i] = _POSIX_VDISABLE; + bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR]; + bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT]; + bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE]; + bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL]; + bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF]; + bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL]; + bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN]; + bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME]; + bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2]; + bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP]; + bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART]; + bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP]; + bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT]; + bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD]; + bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE]; + bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT]; + if (linux_preserve_vstatus) + bios->c_cc[VSTATUS] = lios->c_cc[LINUX_VSTATUS]; + + for (i=0; ic_cc[i] == LINUX_POSIX_VDISABLE) + bios->c_cc[i] = _POSIX_VDISABLE; + } + + bios->c_ispeed = bios->c_ospeed = + linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab); +} + +static void +bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio) +{ + struct linux_termios lios; + + memset(lio, 0, sizeof(*lio)); + bsd_to_linux_termios(bios, &lios); + lio->c_iflag = lios.c_iflag; + lio->c_oflag = lios.c_oflag; + lio->c_cflag = lios.c_cflag; + lio->c_lflag = lios.c_lflag; + lio->c_line = lios.c_line; + memcpy(lio->c_cc, lios.c_cc, LINUX_NCC); +} + +static void +linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios) +{ + struct linux_termios lios; + int i; + + lios.c_iflag = lio->c_iflag; + lios.c_oflag = lio->c_oflag; + lios.c_cflag = lio->c_cflag; + lios.c_lflag = lio->c_lflag; + for (i=LINUX_NCC; ic_cc, LINUX_NCC); + linux_to_bsd_termios(&lios, bios); +} + +static int +linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args) +{ + struct termios bios; + struct linux_termios lios; + struct linux_termio lio; + struct file *fp; + int error; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + + switch (args->cmd & 0xffff) { + case LINUX_TCGETS: + error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred, + td); + if (error) + break; + bsd_to_linux_termios(&bios, &lios); + error = copyout(&lios, LINUX_USER_CAP(args->arg, sizeof(lios)), sizeof(lios)); + break; + + case LINUX_TCSETS: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lios)), &lios, sizeof(lios)); + if (error) + break; + linux_to_bsd_termios(&lios, &bios); + error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred, + td)); + break; + + case LINUX_TCSETSW: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lios)), &lios, sizeof(lios)); + if (error) + break; + linux_to_bsd_termios(&lios, &bios); + error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred, + td)); + break; + + case LINUX_TCSETSF: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lios)), &lios, sizeof(lios)); + if (error) + break; + linux_to_bsd_termios(&lios, &bios); + error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred, + td)); + break; + + case LINUX_TCGETA: + error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred, + td); + if (error) + break; + bsd_to_linux_termio(&bios, &lio); + error = (copyout(&lio, LINUX_USER_CAP(args->arg, sizeof(lio)), sizeof(lio))); + break; + + case LINUX_TCSETA: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lio)), &lio, sizeof(lio)); + if (error) + break; + linux_to_bsd_termio(&lio, &bios); + error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred, + td)); + break; + + case LINUX_TCSETAW: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lio)), &lio, sizeof(lio)); + if (error) + break; + linux_to_bsd_termio(&lio, &bios); + error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred, + td)); + break; + + case LINUX_TCSETAF: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lio)), &lio, sizeof(lio)); + if (error) + break; + linux_to_bsd_termio(&lio, &bios); + error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred, + td)); + break; + + case LINUX_TCSBRK: + if (args->arg != 0) { + error = (fo_ioctl(fp, TIOCDRAIN, (caddr_t)&bios, td->td_ucred, + td)); + } else { + linux_msg(td, "ioctl TCSBRK arg 0 not implemented"); + error = ENOIOCTL; + } + break; + + case LINUX_TCXONC: { + switch (args->arg) { + case LINUX_TCOOFF: + args->cmd = TIOCSTOP; + break; + case LINUX_TCOON: + args->cmd = TIOCSTART; + break; + case LINUX_TCIOFF: + case LINUX_TCION: { + int c; + struct write_args wr; + error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, + td->td_ucred, td); + if (error) + break; + fdrop(fp, td); + c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART; + c = bios.c_cc[c]; + if (c != _POSIX_VDISABLE) { + wr.fd = args->fd; + wr.buf = &c; + wr.nbyte = sizeof(c); + return (sys_write(td, &wr)); + } else + return (0); + } + default: + fdrop(fp, td); + return (EINVAL); + } + args->arg = 0; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + } + + case LINUX_TCFLSH: { + int val; + switch (args->arg) { + case LINUX_TCIFLUSH: + val = FREAD; + break; + case LINUX_TCOFLUSH: + val = FWRITE; + break; + case LINUX_TCIOFLUSH: + val = FREAD | FWRITE; + break; + default: + fdrop(fp, td); + return (EINVAL); + } + error = (fo_ioctl(fp,TIOCFLUSH,(caddr_t)&val,td->td_ucred,td)); + break; + } + + case LINUX_TIOCEXCL: + args->cmd = TIOCEXCL; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCNXCL: + args->cmd = TIOCNXCL; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCSCTTY: + args->cmd = TIOCSCTTY; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCGPGRP: + args->cmd = TIOCGPGRP; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCSPGRP: + args->cmd = TIOCSPGRP; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + /* LINUX_TIOCOUTQ */ + /* LINUX_TIOCSTI */ + + case LINUX_TIOCGWINSZ: + args->cmd = TIOCGWINSZ; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCSWINSZ: + args->cmd = TIOCSWINSZ; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCMGET: + args->cmd = TIOCMGET; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCMBIS: + args->cmd = TIOCMBIS; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCMBIC: + args->cmd = TIOCMBIC; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCMSET: + args->cmd = TIOCMSET; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + /* TIOCGSOFTCAR */ + /* TIOCSSOFTCAR */ + + case LINUX_FIONREAD: /* LINUX_TIOCINQ */ + args->cmd = FIONREAD; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + /* LINUX_TIOCLINUX */ + + case LINUX_TIOCCONS: + args->cmd = TIOCCONS; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCGSERIAL: { + struct linux_serial_struct lss; + + bzero(&lss, sizeof(lss)); + lss.type = LINUX_PORT_16550A; + lss.flags = 0; + lss.close_delay = 0; + error = copyout(&lss, LINUX_USER_CAP(args->arg, sizeof(lss)), sizeof(lss)); + break; + } + + case LINUX_TIOCSSERIAL: { + struct linux_serial_struct lss; + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lss)), &lss, sizeof(lss)); + if (error) + break; + /* XXX - It really helps to have an implementation that + * does nothing. NOT! + */ + error = 0; + break; + } + + case LINUX_TIOCPKT: + args->cmd = TIOCPKT; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_FIONBIO: + args->cmd = FIONBIO; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCNOTTY: + args->cmd = TIOCNOTTY; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCSETD: { + int line; + switch (args->arg) { + case LINUX_N_TTY: + line = TTYDISC; + break; + case LINUX_N_SLIP: + line = SLIPDISC; + break; + case LINUX_N_PPP: + line = PPPDISC; + break; + default: + fdrop(fp, td); + return (EINVAL); + } + error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td->td_ucred, + td)); + break; + } + + case LINUX_TIOCGETD: { + int linux_line; + int bsd_line = TTYDISC; + error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, + td->td_ucred, td); + if (error) + break; + switch (bsd_line) { + case TTYDISC: + linux_line = LINUX_N_TTY; + break; + case SLIPDISC: + linux_line = LINUX_N_SLIP; + break; + case PPPDISC: + linux_line = LINUX_N_PPP; + break; + default: + fdrop(fp, td); + return (EINVAL); + } + error = (copyout(&linux_line, LINUX_USER_CAP(args->arg, sizeof(int)), sizeof(int))); + break; + } + + /* LINUX_TCSBRKP */ + /* LINUX_TIOCTTYGSTRUCT */ + + case LINUX_FIONCLEX: + args->cmd = FIONCLEX; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_FIOCLEX: + args->cmd = FIOCLEX; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_FIOASYNC: + args->cmd = FIOASYNC; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + /* LINUX_TIOCSERCONFIG */ + /* LINUX_TIOCSERGWILD */ + /* LINUX_TIOCSERSWILD */ + /* LINUX_TIOCGLCKTRMIOS */ + /* LINUX_TIOCSLCKTRMIOS */ + + case LINUX_TIOCSBRK: + args->cmd = TIOCSBRK; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_TIOCCBRK: + args->cmd = TIOCCBRK; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + case LINUX_TIOCGPTN: { + int nb; + + error = fo_ioctl(fp, TIOCGPTN, (caddr_t)&nb, td->td_ucred, td); + if (!error) + error = copyout(&nb, LINUX_USER_CAP(args->arg, sizeof(int)), + sizeof(int)); + break; + } + case LINUX_TIOCGPTPEER: + linux_msg(td, "unsupported ioctl TIOCGPTPEER"); + error = ENOIOCTL; + break; + case LINUX_TIOCSPTLCK: + /* + * Our unlockpt() does nothing. Check that fd refers + * to a pseudo-terminal master device. + */ + args->cmd = TIOCPTMASTER; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + default: + error = ENOIOCTL; + break; + } + + fdrop(fp, td); + return (error); +} + +/* + * CDROM related ioctls + */ + +struct linux_cdrom_msf +{ + u_char cdmsf_min0; + u_char cdmsf_sec0; + u_char cdmsf_frame0; + u_char cdmsf_min1; + u_char cdmsf_sec1; + u_char cdmsf_frame1; +}; + +struct linux_cdrom_tochdr +{ + u_char cdth_trk0; + u_char cdth_trk1; +}; + +union linux_cdrom_addr +{ + struct { + u_char minute; + u_char second; + u_char frame; + } msf; + int lba; +}; + +struct linux_cdrom_tocentry +{ + u_char cdte_track; + u_char cdte_adr:4; + u_char cdte_ctrl:4; + u_char cdte_format; + union linux_cdrom_addr cdte_addr; + u_char cdte_datamode; +}; + +struct linux_cdrom_subchnl +{ + u_char cdsc_format; + u_char cdsc_audiostatus; + u_char cdsc_adr:4; + u_char cdsc_ctrl:4; + u_char cdsc_trk; + u_char cdsc_ind; + union linux_cdrom_addr cdsc_absaddr; + union linux_cdrom_addr cdsc_reladdr; +}; + +struct l_cdrom_read_audio { + union linux_cdrom_addr addr; + u_char addr_format; + l_int nframes; + u_char *buf; +}; + +struct l_dvd_layer { + u_char book_version:4; + u_char book_type:4; + u_char min_rate:4; + u_char disc_size:4; + u_char layer_type:4; + u_char track_path:1; + u_char nlayers:2; + u_char track_density:4; + u_char linear_density:4; + u_char bca:1; + uint32_t start_sector; + uint32_t end_sector; + uint32_t end_sector_l0; +}; + +struct l_dvd_physical { + u_char type; + u_char layer_num; + struct l_dvd_layer layer[4]; +}; + +struct l_dvd_copyright { + u_char type; + u_char layer_num; + u_char cpst; + u_char rmi; +}; + +struct l_dvd_disckey { + u_char type; + l_uint agid:2; + u_char value[2048]; +}; + +struct l_dvd_bca { + u_char type; + l_int len; + u_char value[188]; +}; + +struct l_dvd_manufact { + u_char type; + u_char layer_num; + l_int len; + u_char value[2048]; +}; + +typedef union { + u_char type; + struct l_dvd_physical physical; + struct l_dvd_copyright copyright; + struct l_dvd_disckey disckey; + struct l_dvd_bca bca; + struct l_dvd_manufact manufact; +} l_dvd_struct; + +typedef u_char l_dvd_key[5]; +typedef u_char l_dvd_challenge[10]; + +struct l_dvd_lu_send_agid { + u_char type; + l_uint agid:2; +}; + +struct l_dvd_host_send_challenge { + u_char type; + l_uint agid:2; + l_dvd_challenge chal; +}; + +struct l_dvd_send_key { + u_char type; + l_uint agid:2; + l_dvd_key key; +}; + +struct l_dvd_lu_send_challenge { + u_char type; + l_uint agid:2; + l_dvd_challenge chal; +}; + +struct l_dvd_lu_send_title_key { + u_char type; + l_uint agid:2; + l_dvd_key title_key; + l_int lba; + l_uint cpm:1; + l_uint cp_sec:1; + l_uint cgms:2; +}; + +struct l_dvd_lu_send_asf { + u_char type; + l_uint agid:2; + l_uint asf:1; +}; + +struct l_dvd_host_send_rpcstate { + u_char type; + u_char pdrc; +}; + +struct l_dvd_lu_send_rpcstate { + u_char type:2; + u_char vra:3; + u_char ucca:3; + u_char region_mask; + u_char rpc_scheme; +}; + +typedef union { + u_char type; + struct l_dvd_lu_send_agid lsa; + struct l_dvd_host_send_challenge hsc; + struct l_dvd_send_key lsk; + struct l_dvd_lu_send_challenge lsc; + struct l_dvd_send_key hsk; + struct l_dvd_lu_send_title_key lstk; + struct l_dvd_lu_send_asf lsasf; + struct l_dvd_host_send_rpcstate hrpcs; + struct l_dvd_lu_send_rpcstate lrpcs; +} l_dvd_authinfo; + +static void +bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp) +{ + if (af == CD_LBA_FORMAT) + lp->lba = bp->lba; + else { + lp->msf.minute = bp->msf.minute; + lp->msf.second = bp->msf.second; + lp->msf.frame = bp->msf.frame; + } +} + +static void +set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba) +{ + if (format == LINUX_CDROM_MSF) { + addr->msf.frame = lba % 75; + lba /= 75; + lba += 2; + addr->msf.second = lba % 60; + addr->msf.minute = lba / 60; + } else + addr->lba = lba; +} + +static int +linux_to_bsd_dvd_struct(l_dvd_struct *lp, struct dvd_struct *bp) +{ + bp->format = lp->type; + switch (bp->format) { + case DVD_STRUCT_PHYSICAL: + if (bp->layer_num >= 4) + return (EINVAL); + bp->layer_num = lp->physical.layer_num; + break; + case DVD_STRUCT_COPYRIGHT: + bp->layer_num = lp->copyright.layer_num; + break; + case DVD_STRUCT_DISCKEY: + bp->agid = lp->disckey.agid; + break; + case DVD_STRUCT_BCA: + case DVD_STRUCT_MANUFACT: + break; + default: + return (EINVAL); + } + return (0); +} + +static int +bsd_to_linux_dvd_struct(struct dvd_struct *bp, l_dvd_struct *lp) +{ + switch (bp->format) { + case DVD_STRUCT_PHYSICAL: { + struct dvd_layer *blp = (struct dvd_layer *)bp->data; + struct l_dvd_layer *llp = &lp->physical.layer[bp->layer_num]; + memset(llp, 0, sizeof(*llp)); + llp->book_version = blp->book_version; + llp->book_type = blp->book_type; + llp->min_rate = blp->max_rate; + llp->disc_size = blp->disc_size; + llp->layer_type = blp->layer_type; + llp->track_path = blp->track_path; + llp->nlayers = blp->nlayers; + llp->track_density = blp->track_density; + llp->linear_density = blp->linear_density; + llp->bca = blp->bca; + llp->start_sector = blp->start_sector; + llp->end_sector = blp->end_sector; + llp->end_sector_l0 = blp->end_sector_l0; + break; + } + case DVD_STRUCT_COPYRIGHT: + lp->copyright.cpst = bp->cpst; + lp->copyright.rmi = bp->rmi; + break; + case DVD_STRUCT_DISCKEY: + memcpy(lp->disckey.value, bp->data, sizeof(lp->disckey.value)); + break; + case DVD_STRUCT_BCA: + lp->bca.len = bp->length; + memcpy(lp->bca.value, bp->data, sizeof(lp->bca.value)); + break; + case DVD_STRUCT_MANUFACT: + lp->manufact.len = bp->length; + memcpy(lp->manufact.value, bp->data, + sizeof(lp->manufact.value)); + /* lp->manufact.layer_num is unused in Linux (redhat 7.0). */ + break; + default: + return (EINVAL); + } + return (0); +} + +static int +linux_to_bsd_dvd_authinfo(l_dvd_authinfo *lp, int *bcode, + struct dvd_authinfo *bp) +{ + switch (lp->type) { + case LINUX_DVD_LU_SEND_AGID: + *bcode = DVDIOCREPORTKEY; + bp->format = DVD_REPORT_AGID; + bp->agid = lp->lsa.agid; + break; + case LINUX_DVD_HOST_SEND_CHALLENGE: + *bcode = DVDIOCSENDKEY; + bp->format = DVD_SEND_CHALLENGE; + bp->agid = lp->hsc.agid; + memcpy(bp->keychal, lp->hsc.chal, 10); + break; + case LINUX_DVD_LU_SEND_KEY1: + *bcode = DVDIOCREPORTKEY; + bp->format = DVD_REPORT_KEY1; + bp->agid = lp->lsk.agid; + break; + case LINUX_DVD_LU_SEND_CHALLENGE: + *bcode = DVDIOCREPORTKEY; + bp->format = DVD_REPORT_CHALLENGE; + bp->agid = lp->lsc.agid; + break; + case LINUX_DVD_HOST_SEND_KEY2: + *bcode = DVDIOCSENDKEY; + bp->format = DVD_SEND_KEY2; + bp->agid = lp->hsk.agid; + memcpy(bp->keychal, lp->hsk.key, 5); + break; + case LINUX_DVD_LU_SEND_TITLE_KEY: + *bcode = DVDIOCREPORTKEY; + bp->format = DVD_REPORT_TITLE_KEY; + bp->agid = lp->lstk.agid; + bp->lba = lp->lstk.lba; + break; + case LINUX_DVD_LU_SEND_ASF: + *bcode = DVDIOCREPORTKEY; + bp->format = DVD_REPORT_ASF; + bp->agid = lp->lsasf.agid; + break; + case LINUX_DVD_INVALIDATE_AGID: + *bcode = DVDIOCREPORTKEY; + bp->format = DVD_INVALIDATE_AGID; + bp->agid = lp->lsa.agid; + break; + case LINUX_DVD_LU_SEND_RPC_STATE: + *bcode = DVDIOCREPORTKEY; + bp->format = DVD_REPORT_RPC; + break; + case LINUX_DVD_HOST_SEND_RPC_STATE: + *bcode = DVDIOCSENDKEY; + bp->format = DVD_SEND_RPC; + bp->region = lp->hrpcs.pdrc; + break; + default: + return (EINVAL); + } + return (0); +} + +static int +bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp) +{ + switch (lp->type) { + case LINUX_DVD_LU_SEND_AGID: + lp->lsa.agid = bp->agid; + break; + case LINUX_DVD_HOST_SEND_CHALLENGE: + lp->type = LINUX_DVD_LU_SEND_KEY1; + break; + case LINUX_DVD_LU_SEND_KEY1: + memcpy(lp->lsk.key, bp->keychal, sizeof(lp->lsk.key)); + break; + case LINUX_DVD_LU_SEND_CHALLENGE: + memcpy(lp->lsc.chal, bp->keychal, sizeof(lp->lsc.chal)); + break; + case LINUX_DVD_HOST_SEND_KEY2: + lp->type = LINUX_DVD_AUTH_ESTABLISHED; + break; + case LINUX_DVD_LU_SEND_TITLE_KEY: + memcpy(lp->lstk.title_key, bp->keychal, + sizeof(lp->lstk.title_key)); + lp->lstk.cpm = bp->cpm; + lp->lstk.cp_sec = bp->cp_sec; + lp->lstk.cgms = bp->cgms; + break; + case LINUX_DVD_LU_SEND_ASF: + lp->lsasf.asf = bp->asf; + break; + case LINUX_DVD_INVALIDATE_AGID: + break; + case LINUX_DVD_LU_SEND_RPC_STATE: + lp->lrpcs.type = bp->reg_type; + lp->lrpcs.vra = bp->vend_rsts; + lp->lrpcs.ucca = bp->user_rsts; + lp->lrpcs.region_mask = bp->region; + lp->lrpcs.rpc_scheme = bp->rpc_scheme; + break; + case LINUX_DVD_HOST_SEND_RPC_STATE: + break; + default: + return (EINVAL); + } + return (0); +} + +static int +linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + switch (args->cmd & 0xffff) { + case LINUX_CDROMPAUSE: + args->cmd = CDIOCPAUSE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_CDROMRESUME: + args->cmd = CDIOCRESUME; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_CDROMPLAYMSF: + args->cmd = CDIOCPLAYMSF; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_CDROMPLAYTRKIND: + args->cmd = CDIOCPLAYTRACKS; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_CDROMREADTOCHDR: { + struct ioc_toc_header th; + struct linux_cdrom_tochdr lth; + error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, + td->td_ucred, td); + if (!error) { + lth.cdth_trk0 = th.starting_track; + lth.cdth_trk1 = th.ending_track; + error = copyout(<h, LINUX_USER_CAP(args->arg, sizeof(lth)), sizeof(lth)); + } + break; + } + + case LINUX_CDROMREADTOCENTRY: { + struct linux_cdrom_tocentry lte; + struct ioc_read_toc_single_entry irtse; + + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lte)), <e, sizeof(lte)); + if (error) + break; + irtse.address_format = lte.cdte_format; + irtse.track = lte.cdte_track; + error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, + td->td_ucred, td); + if (!error) { + lte.cdte_ctrl = irtse.entry.control; + lte.cdte_adr = irtse.entry.addr_type; + bsd_to_linux_msf_lba(irtse.address_format, + &irtse.entry.addr, <e.cdte_addr); + error = copyout(<e, LINUX_USER_CAP(args->arg, sizeof(lte)), sizeof(lte)); + } + break; + } + + case LINUX_CDROMSTOP: + args->cmd = CDIOCSTOP; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_CDROMSTART: + args->cmd = CDIOCSTART; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_CDROMEJECT: + args->cmd = CDIOCEJECT; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + /* LINUX_CDROMVOLCTRL */ + + case LINUX_CDROMSUBCHNL: { + struct linux_cdrom_subchnl sc; + struct ioc_read_subchannel bsdsc; + struct cd_sub_channel_info bsdinfo; + + error = copyin(LINUX_USER_CAP(args->arg, sizeof(sc)), &sc, sizeof(sc)); + if (error) + break; + + /* + * Invoke the native ioctl and bounce the returned data through + * the userspace buffer. This works because the Linux structure + * is the same size as our structures for the subchannel header + * and position data. + */ + bsdsc.address_format = CD_LBA_FORMAT; + bsdsc.data_format = CD_CURRENT_POSITION; + bsdsc.track = 0; + bsdsc.data_len = sizeof(sc); + bsdsc.data = LINUX_USER_CAP(args->arg, sizeof(sc)); + error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, + td->td_ucred, td); + if (error) + break; + error = copyin(LINUX_USER_CAP(args->arg, sizeof(bsdinfo)), &bsdinfo, sizeof(bsdinfo)); + if (error) + break; + sc.cdsc_audiostatus = bsdinfo.header.audio_status; + sc.cdsc_adr = bsdinfo.what.position.addr_type; + sc.cdsc_ctrl = bsdinfo.what.position.control; + sc.cdsc_trk = bsdinfo.what.position.track_number; + sc.cdsc_ind = bsdinfo.what.position.index_number; + set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format, + bsdinfo.what.position.absaddr.lba); + set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format, + bsdinfo.what.position.reladdr.lba); + error = copyout(&sc, LINUX_USER_CAP(args->arg, sizeof(sc)), sizeof(sc)); + break; + } + + /* LINUX_CDROMREADMODE2 */ + /* LINUX_CDROMREADMODE1 */ + /* LINUX_CDROMREADAUDIO */ + /* LINUX_CDROMEJECT_SW */ + /* LINUX_CDROMMULTISESSION */ + /* LINUX_CDROM_GET_UPC */ + + case LINUX_CDROMRESET: + args->cmd = CDIOCRESET; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + /* LINUX_CDROMVOLREAD */ + /* LINUX_CDROMREADRAW */ + /* LINUX_CDROMREADCOOKED */ + /* LINUX_CDROMSEEK */ + /* LINUX_CDROMPLAYBLK */ + /* LINUX_CDROMREADALL */ + /* LINUX_CDROMCLOSETRAY */ + /* LINUX_CDROMLOADFROMSLOT */ + /* LINUX_CDROMGETSPINDOWN */ + /* LINUX_CDROMSETSPINDOWN */ + /* LINUX_CDROM_SET_OPTIONS */ + /* LINUX_CDROM_CLEAR_OPTIONS */ + /* LINUX_CDROM_SELECT_SPEED */ + /* LINUX_CDROM_SELECT_DISC */ + /* LINUX_CDROM_MEDIA_CHANGED */ + /* LINUX_CDROM_DRIVE_STATUS */ + /* LINUX_CDROM_DISC_STATUS */ + /* LINUX_CDROM_CHANGER_NSLOTS */ + /* LINUX_CDROM_LOCKDOOR */ + /* LINUX_CDROM_DEBUG */ + /* LINUX_CDROM_GET_CAPABILITY */ + /* LINUX_CDROMAUDIOBUFSIZ */ + + case LINUX_DVD_READ_STRUCT: { + l_dvd_struct *lds; + struct dvd_struct *bds; + + lds = malloc(sizeof(*lds), M_LINUX, M_WAITOK); + bds = malloc(sizeof(*bds), M_LINUX, M_WAITOK); + error = copyin(LINUX_USER_CAP(args->arg, sizeof(*lds)), lds, sizeof(*lds)); + if (error) + goto out; + error = linux_to_bsd_dvd_struct(lds, bds); + if (error) + goto out; + error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)bds, + td->td_ucred, td); + if (error) + goto out; + error = bsd_to_linux_dvd_struct(bds, lds); + if (error) + goto out; + error = copyout(lds, LINUX_USER_CAP(args->arg, sizeof(*lds)), sizeof(*lds)); + out: + free(bds, M_LINUX); + free(lds, M_LINUX); + break; + } + + /* LINUX_DVD_WRITE_STRUCT */ + + case LINUX_DVD_AUTH: { + l_dvd_authinfo lda; + struct dvd_authinfo bda; + int bcode; + + error = copyin(LINUX_USER_CAP(args->arg, sizeof(lda)), &lda, sizeof(lda)); + if (error) + break; + error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda); + if (error) + break; + error = fo_ioctl(fp, bcode, (caddr_t)&bda, td->td_ucred, + td); + if (error) { + if (lda.type == LINUX_DVD_HOST_SEND_KEY2) { + lda.type = LINUX_DVD_AUTH_FAILURE; + (void)copyout(&lda, LINUX_USER_CAP(args->arg, sizeof(lda)), + sizeof(lda)); + } + break; + } + error = bsd_to_linux_dvd_authinfo(&bda, &lda); + if (error) + break; + error = copyout(&lda, LINUX_USER_CAP(args->arg, sizeof(lda)), sizeof(lda)); + break; + } + + case LINUX_SCSI_GET_BUS_NUMBER: + { + struct sg_scsi_id id; + + error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id, + td->td_ucred, td); + if (error) + break; + error = copyout(&id.channel, LINUX_USER_CAP(args->arg, sizeof(int)), sizeof(int)); + break; + } + + case LINUX_SCSI_GET_IDLUN: + { + struct sg_scsi_id id; + struct scsi_idlun idl; + + error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id, + td->td_ucred, td); + if (error) + break; + idl.dev_id = (id.scsi_id & 0xff) + ((id.lun & 0xff) << 8) + + ((id.channel & 0xff) << 16) + ((id.host_no & 0xff) << 24); + idl.host_unique_id = id.host_no; + error = copyout(&idl, LINUX_USER_CAP(args->arg, sizeof(idl)), sizeof(idl)); + break; + } + + /* LINUX_CDROM_SEND_PACKET */ + /* LINUX_CDROM_NEXT_WRITABLE */ + /* LINUX_CDROM_LAST_WRITTEN */ + + default: + error = ENOIOCTL; + break; + } + + fdrop(fp, td); + return (error); +} + +static int +linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args) +{ + + return (ENOTTY); +} + +/* + * Sound related ioctls + */ + +struct linux_old_mixer_info { + char id[16]; + char name[32]; +}; + +static uint32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT }; + +#define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30]) + +static int +linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args) +{ + + switch (args->cmd & 0xffff) { + case LINUX_SOUND_MIXER_WRITE_VOLUME: + args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_BASS: + args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_TREBLE: + args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_SYNTH: + args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_PCM: + args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_SPEAKER: + args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_LINE: + args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_MIC: + args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_CD: + args->cmd = SETDIR(SOUND_MIXER_WRITE_CD); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_IMIX: + args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_ALTPCM: + args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_RECLEV: + args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_IGAIN: + args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_OGAIN: + args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_LINE1: + args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_LINE2: + args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_LINE3: + args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_MONITOR: + args->cmd = SETDIR(SOUND_MIXER_WRITE_MONITOR); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_INFO: { + /* Key on encoded length */ + switch ((args->cmd >> 16) & 0x1fff) { + case 0x005c: { /* SOUND_MIXER_INFO */ + args->cmd = SOUND_MIXER_INFO; + return (linux_ioctl_forward_to_sys(td, args)); + } + case 0x0030: { /* SOUND_OLD_MIXER_INFO */ + struct linux_old_mixer_info info; + bzero(&info, sizeof(info)); + strncpy(info.id, "OSS", sizeof(info.id) - 1); + strncpy(info.name, "FreeBSD OSS Mixer", + sizeof(info.name) - 1); + return (copyout(&info, LINUX_USER_CAP(args->arg, sizeof(info)), + sizeof(info))); + } + default: + return (ENOIOCTL); + } + break; + } + + case LINUX_OSS_GETVERSION: { + int version = linux_get_oss_version(td); + return (copyout(&version, LINUX_USER_CAP(args->arg, sizeof(int)), sizeof(int))); + } + + case LINUX_SOUND_MIXER_READ_STEREODEVS: + args->cmd = SOUND_MIXER_READ_STEREODEVS; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_READ_CAPS: + args->cmd = SOUND_MIXER_READ_CAPS; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_READ_RECMASK: + args->cmd = SOUND_MIXER_READ_RECMASK; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_READ_DEVMASK: + args->cmd = SOUND_MIXER_READ_DEVMASK; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_MIXER_WRITE_RECSRC: + args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC); + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_RESET: + args->cmd = SNDCTL_DSP_RESET; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_SYNC: + args->cmd = SNDCTL_DSP_SYNC; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_SPEED: + args->cmd = SNDCTL_DSP_SPEED; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_STEREO: + args->cmd = SNDCTL_DSP_STEREO; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */ + args->cmd = SNDCTL_DSP_GETBLKSIZE; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_SETFMT: + args->cmd = SNDCTL_DSP_SETFMT; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_PCM_WRITE_CHANNELS: + args->cmd = SOUND_PCM_WRITE_CHANNELS; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SOUND_PCM_WRITE_FILTER: + args->cmd = SOUND_PCM_WRITE_FILTER; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_POST: + args->cmd = SNDCTL_DSP_POST; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_SUBDIVIDE: + args->cmd = SNDCTL_DSP_SUBDIVIDE; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_SETFRAGMENT: + args->cmd = SNDCTL_DSP_SETFRAGMENT; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_GETFMTS: + args->cmd = SNDCTL_DSP_GETFMTS; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_GETOSPACE: + args->cmd = SNDCTL_DSP_GETOSPACE; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_GETISPACE: + args->cmd = SNDCTL_DSP_GETISPACE; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_NONBLOCK: + args->cmd = SNDCTL_DSP_NONBLOCK; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_GETCAPS: + args->cmd = SNDCTL_DSP_GETCAPS; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */ + args->cmd = SNDCTL_DSP_SETTRIGGER; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_GETIPTR: + args->cmd = SNDCTL_DSP_GETIPTR; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_GETOPTR: + args->cmd = SNDCTL_DSP_GETOPTR; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_SETDUPLEX: + args->cmd = SNDCTL_DSP_SETDUPLEX; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_DSP_GETODELAY: + args->cmd = SNDCTL_DSP_GETODELAY; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_RESET: + args->cmd = SNDCTL_SEQ_RESET; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_SYNC: + args->cmd = SNDCTL_SEQ_SYNC; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SYNTH_INFO: + args->cmd = SNDCTL_SYNTH_INFO; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_CTRLRATE: + args->cmd = SNDCTL_SEQ_CTRLRATE; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_GETOUTCOUNT: + args->cmd = SNDCTL_SEQ_GETOUTCOUNT; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_GETINCOUNT: + args->cmd = SNDCTL_SEQ_GETINCOUNT; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_PERCMODE: + args->cmd = SNDCTL_SEQ_PERCMODE; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_FM_LOAD_INSTR: + args->cmd = SNDCTL_FM_LOAD_INSTR; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_TESTMIDI: + args->cmd = SNDCTL_SEQ_TESTMIDI; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_RESETSAMPLES: + args->cmd = SNDCTL_SEQ_RESETSAMPLES; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_NRSYNTHS: + args->cmd = SNDCTL_SEQ_NRSYNTHS; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_NRMIDIS: + args->cmd = SNDCTL_SEQ_NRMIDIS; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_MIDI_INFO: + args->cmd = SNDCTL_MIDI_INFO; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SEQ_TRESHOLD: + args->cmd = SNDCTL_SEQ_TRESHOLD; + return (linux_ioctl_forward_to_sys(td, args)); + + case LINUX_SNDCTL_SYNTH_MEMAVL: + args->cmd = SNDCTL_SYNTH_MEMAVL; + return (linux_ioctl_forward_to_sys(td, args)); + } + + return (ENOIOCTL); +} + +/* + * Console related ioctls + */ + +static int +linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + switch (args->cmd & 0xffff) { + case LINUX_KIOCSOUND: + args->cmd = KIOCSOUND; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_KDMKTONE: + args->cmd = KDMKTONE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_KDGETLED: + args->cmd = KDGETLED; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_KDSETLED: + args->cmd = KDSETLED; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_KDSETMODE: + args->cmd = KDSETMODE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_KDGETMODE: + args->cmd = KDGETMODE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_KDGKBMODE: + args->cmd = KDGKBMODE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_KDSKBMODE: { + int kbdmode; + switch (args->arg) { + case LINUX_KBD_RAW: + kbdmode = K_RAW; + break; + case LINUX_KBD_XLATE: + kbdmode = K_XLATE; + break; + case LINUX_KBD_MEDIUMRAW: + kbdmode = K_RAW; + break; + default: + fdrop(fp, td); + return (EINVAL); + } + error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, + td->td_ucred, td)); + break; + } + + case LINUX_VT_OPENQRY: + args->cmd = VT_OPENQRY; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_VT_GETMODE: + args->cmd = VT_GETMODE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_VT_SETMODE: { + struct vt_mode mode; + if ((error = copyin(LINUX_USER_CAP(args->arg, sizeof(mode)), &mode, sizeof(mode)))) + break; + if (LINUX_SIG_VALID(mode.relsig)) + mode.relsig = linux_to_bsd_signal(mode.relsig); + else + mode.relsig = 0; + if (LINUX_SIG_VALID(mode.acqsig)) + mode.acqsig = linux_to_bsd_signal(mode.acqsig); + else + mode.acqsig = 0; + /* XXX. Linux ignores frsig and set it to 0. */ + mode.frsig = 0; + if ((error = copyout(&mode, LINUX_USER_CAP(args->arg, sizeof(mode)), sizeof(mode)))) + break; + args->cmd = VT_SETMODE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + } + + case LINUX_VT_GETSTATE: + args->cmd = VT_GETACTIVE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_VT_RELDISP: + args->cmd = VT_RELDISP; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_VT_ACTIVATE: + args->cmd = VT_ACTIVATE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + case LINUX_VT_WAITACTIVE: + args->cmd = VT_WAITACTIVE; + error = (linux_ioctl_forward_to_sys(td, args)); + break; + + default: + error = ENOIOCTL; + break; + } + + fdrop(fp, td); + return (error); +} + +/* + * Implement the SIOCGIFNAME ioctl + */ + +static int +linux_ioctl_ifname(struct thread *td, struct l_ifreq * __capability uifr) +{ + struct l_ifreq ifr; + int error, ret; + + error = copyin(uifr, &ifr, sizeof(ifr)); + if (error != 0) + return (error); + ret = ifname_bsd_to_linux_idx(ifr.ifr_index, ifr.ifr_name, + LINUX_IFNAMSIZ); + if (ret > 0) + return (copyout(&ifr, uifr, sizeof(ifr))); + else + return (ENODEV); +} + +/* + * Implement the SIOCGIFCONF ioctl + */ +static u_int +linux_ifconf_ifaddr_cb(void *arg, struct ifaddr *ifa, u_int count) +{ +#ifdef COMPAT_LINUX32 + struct l_ifconf *ifc; +#else + struct ifconf *ifc; +#endif + + ifc = arg; + ifc->ifc_len += sizeof(struct l_ifreq); + return (1); +} + +static int +linux_ifconf_ifnet_cb(if_t ifp, void *arg) +{ + + if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb, arg); + return (0); +} + +struct linux_ifconfig_ifaddr_cb2_s { + struct l_ifreq ifr; + struct sbuf *sb; + size_t max_len; + size_t valid_len; +}; + +static u_int +linux_ifconf_ifaddr_cb2(void *arg, struct ifaddr *ifa, u_int len) +{ + struct linux_ifconfig_ifaddr_cb2_s *cbs = arg; + struct sockaddr *sa = ifa->ifa_addr; + + cbs->ifr.ifr_addr.sa_family = LINUX_AF_INET; + memcpy(cbs->ifr.ifr_addr.sa_data, sa->sa_data, + sizeof(cbs->ifr.ifr_addr.sa_data)); + sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr)); + cbs->max_len += sizeof(cbs->ifr); + + if (sbuf_error(cbs->sb) == 0) + cbs->valid_len = sbuf_len(cbs->sb); + return (1); +} + +static int +linux_ifconf_ifnet_cb2(if_t ifp, void *arg) +{ + struct linux_ifconfig_ifaddr_cb2_s *cbs = arg; + + bzero(&cbs->ifr, sizeof(cbs->ifr)); + ifname_bsd_to_linux_ifp(ifp, cbs->ifr.ifr_name, + sizeof(cbs->ifr.ifr_name)); + + /* Walk the address list */ + if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb2, cbs); + return (0); +} + +static int +linux_ifconf(struct thread *td, struct ifconf * __capability uifc) +{ + struct linux_ifconfig_ifaddr_cb2_s cbs; + struct epoch_tracker et; +#ifdef COMPAT_LINUX32 + struct l_ifconf ifc; +#else + struct ifconf ifc; +#endif + struct sbuf *sb; + int error, full; + + error = copyin(uifc, &ifc, sizeof(ifc)); + if (error != 0) + return (error); + + /* handle the 'request buffer size' case */ + if (ifc.ifc_buf == NULL) { + ifc.ifc_len = 0; + NET_EPOCH_ENTER(et); + if_foreach(linux_ifconf_ifnet_cb, &ifc); + NET_EPOCH_EXIT(et); + return (copyout(&ifc, uifc, sizeof(ifc))); + } + if (ifc.ifc_len <= 0) + return (EINVAL); + + full = 0; + cbs.max_len = maxphys - 1; + +again: + if (ifc.ifc_len <= cbs.max_len) { + cbs.max_len = ifc.ifc_len; + full = 1; + } + cbs.sb = sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN); + cbs.max_len = 0; + cbs.valid_len = 0; + + /* Return all AF_INET addresses of all interfaces */ + NET_EPOCH_ENTER(et); + if_foreach(linux_ifconf_ifnet_cb2, &cbs); + NET_EPOCH_EXIT(et); + + if (cbs.valid_len != cbs.max_len && !full) { + sbuf_delete(sb); + goto again; + } + + ifc.ifc_len = cbs.valid_len; + sbuf_finish(sb); + error = copyout(sbuf_data(sb), ifc.ifc_buf, ifc.ifc_len); + if (error == 0) + error = copyout(&ifc, uifc, sizeof(ifc)); + sbuf_delete(sb); + + return (error); +} + +static int +linux_ioctl_socket_ifreq(struct thread *td, int fd, u_int cmd, + struct l_ifreq * __capability uifr) +{ + struct l_ifreq lifr; + struct ifreq bifr; + size_t ifrusiz; + int error, temp_flags; + + switch (cmd) { + case LINUX_SIOCGIFINDEX: + cmd = SIOCGIFINDEX; + break; + case LINUX_SIOCGIFFLAGS: + cmd = SIOCGIFFLAGS; + break; + case LINUX_SIOCGIFADDR: + cmd = SIOCGIFADDR; + break; + case LINUX_SIOCSIFADDR: + cmd = SIOCSIFADDR; + break; + case LINUX_SIOCGIFDSTADDR: + cmd = SIOCGIFDSTADDR; + break; + case LINUX_SIOCGIFBRDADDR: + cmd = SIOCGIFBRDADDR; + break; + case LINUX_SIOCGIFNETMASK: + cmd = SIOCGIFNETMASK; + break; + case LINUX_SIOCSIFNETMASK: + cmd = SIOCSIFNETMASK; + break; + case LINUX_SIOCGIFMTU: + cmd = SIOCGIFMTU; + break; + case LINUX_SIOCSIFMTU: + cmd = SIOCSIFMTU; + break; + case LINUX_SIOCGIFHWADDR: + cmd = SIOCGHWADDR; + break; + case LINUX_SIOCGIFMETRIC: + cmd = SIOCGIFMETRIC; + break; + case LINUX_SIOCSIFMETRIC: + cmd = SIOCSIFMETRIC; + break; + /* + * XXX This is slightly bogus, but these ioctls are currently + * XXX only used by the aironet (if_an) network driver. + */ + case LINUX_SIOCDEVPRIVATE: + cmd = SIOCGPRIVATE_0; + break; + case LINUX_SIOCDEVPRIVATE+1: + cmd = SIOCGPRIVATE_1; + break; + default: + LINUX_RATELIMIT_MSG_OPT2( + "ioctl_socket_ifreq fd=%d, cmd=0x%x is not implemented", + fd, cmd); + return (ENOIOCTL); + } + + error = copyin(uifr, &lifr, sizeof(lifr)); + if (error != 0) + return (error); + bzero(&bifr, sizeof(bifr)); + + /* + * The size of Linux enum ifr_ifru is bigger than + * the FreeBSD size due to the struct ifmap. + */ + ifrusiz = (sizeof(lifr) > sizeof(bifr) ? sizeof(bifr) : + sizeof(lifr)) - offsetof(struct l_ifreq, ifr_ifru); + bcopy(&lifr.ifr_ifru, &bifr.ifr_ifru, ifrusiz); + + error = ifname_linux_to_bsd(td, lifr.ifr_name, bifr.ifr_name); + if (error != 0) + return (error); + + /* Translate in values. */ + switch (cmd) { + case SIOCGIFINDEX: + bifr.ifr_index = lifr.ifr_index; + break; + case SIOCSIFADDR: + case SIOCSIFNETMASK: + bifr.ifr_addr.sa_len = sizeof(struct sockaddr); + bifr.ifr_addr.sa_family = + linux_to_bsd_domain(lifr.ifr_addr.sa_family); + break; + default: + break; + } + + error = kern_ioctl(td, fd, cmd, (caddr_t)&bifr); + if (error != 0) + return (error); + bzero(&lifr.ifr_ifru, sizeof(lifr.ifr_ifru)); + + /* Translate out values. */ + switch (cmd) { + case SIOCGIFINDEX: + lifr.ifr_index = bifr.ifr_index; + break; + case SIOCGIFFLAGS: + temp_flags = bifr.ifr_flags | (bifr.ifr_flagshigh << 16); + lifr.ifr_flags = bsd_to_linux_ifflags(temp_flags); + break; + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCGIFNETMASK: + bcopy(&bifr.ifr_addr, &lifr.ifr_addr, sizeof(bifr.ifr_addr)); + lifr.ifr_addr.sa_family = + bsd_to_linux_domain(bifr.ifr_addr.sa_family); + break; + case SIOCGHWADDR: + bcopy(&bifr.ifr_addr, &lifr.ifr_hwaddr, sizeof(bifr.ifr_addr)); + lifr.ifr_hwaddr.sa_family = LINUX_ARPHRD_ETHER; + break; + default: + bcopy(&bifr.ifr_ifru, &lifr.ifr_ifru, ifrusiz); + break; + } + + return (copyout(&lifr, uifr, sizeof(lifr))); +} + +/* + * Socket related ioctls + */ + +static int +linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error, type; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + type = fp->f_type; + fdrop(fp, td); + + CURVNET_SET(TD_TO_VNET(td)); + + if (type != DTYPE_SOCKET) { + /* not a socket - probably a tap / vmnet device */ + switch (args->cmd) { + case LINUX_SIOCGIFADDR: + case LINUX_SIOCSIFADDR: + case LINUX_SIOCGIFFLAGS: + error = linux_ioctl_special(td, args); + break; + default: + error = ENOIOCTL; + break; + } + CURVNET_RESTORE(); + return (error); + } + + switch (args->cmd) { + case LINUX_FIOSETOWN: + args->cmd = FIOSETOWN; + error = linux_ioctl_forward_to_sys(td, args); + break; + + case LINUX_SIOCSPGRP: + args->cmd = SIOCSPGRP; + error = linux_ioctl_forward_to_sys(td, args); + break; + + case LINUX_FIOGETOWN: + args->cmd = FIOGETOWN; + error = linux_ioctl_forward_to_sys(td, args); + break; + + case LINUX_SIOCGPGRP: + args->cmd = SIOCGPGRP; + error = linux_ioctl_forward_to_sys(td, args); + break; + + case LINUX_SIOCATMARK: + args->cmd = SIOCATMARK; + error = linux_ioctl_forward_to_sys(td, args); + break; + + /* LINUX_SIOCGSTAMP */ + + case LINUX_SIOCGIFNAME: + error = linux_ioctl_ifname(td, LINUX_USER_CAP(args->arg, sizeof(struct l_ifreq))); + break; + + case LINUX_SIOCGIFCONF: + error = linux_ifconf(td, LINUX_USER_CAP(args->arg, sizeof(struct ifconf))); + break; + + case LINUX_SIOCADDMULTI: + args->cmd = SIOCADDMULTI; + error = linux_ioctl_forward_to_sys(td, args); + break; + + case LINUX_SIOCDELMULTI: + args->cmd = SIOCDELMULTI; + error = linux_ioctl_forward_to_sys(td, args); + break; + + case LINUX_SIOCGIFCOUNT: + error = 0; + break; + + default: + error = linux_ioctl_socket_ifreq(td, args->fd, args->cmd, + LINUX_USER_CAP(args->arg, sizeof(struct l_ifreq))); + break; + } + + CURVNET_RESTORE(); + return (error); +} + +/* + * Device private ioctl handler + */ +static int +linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error, type; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + type = fp->f_type; + fdrop(fp, td); + if (type == DTYPE_SOCKET) + return (linux_ioctl_socket(td, args)); + return (ENOIOCTL); +} + +/* + * DRM ioctl handler (sys/dev/drm) + */ +static int +linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args) +{ + args->cmd = SETDIR(args->cmd); + return (linux_ioctl_forward_to_sys(td, args)); +} + +#ifdef COMPAT_LINUX32 +static int +linux_ioctl_sg_io(struct thread *td, struct linux_ioctl_args *args) +{ + struct sg_io_hdr io; + struct sg_io_hdr32 io32; + struct file *fp; + int error; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) { + printf("sg_linux_ioctl: fget returned %d\n", error); + return (error); + } + + if ((error = copyin(LINUX_USER_CAP(args->arg, sizeof(io32)), &io32, sizeof(io32))) != 0) + goto out; + + CP(io32, io, interface_id); + CP(io32, io, dxfer_direction); + CP(io32, io, cmd_len); + CP(io32, io, mx_sb_len); + CP(io32, io, iovec_count); + CP(io32, io, dxfer_len); + PTRIN_CP(io32, io, dxferp); + PTRIN_CP(io32, io, cmdp); + PTRIN_CP(io32, io, sbp); + CP(io32, io, timeout); + CP(io32, io, flags); + CP(io32, io, pack_id); + PTRIN_CP(io32, io, usr_ptr); + CP(io32, io, status); + CP(io32, io, masked_status); + CP(io32, io, msg_status); + CP(io32, io, sb_len_wr); + CP(io32, io, host_status); + CP(io32, io, driver_status); + CP(io32, io, resid); + CP(io32, io, duration); + CP(io32, io, info); + + if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0) + goto out; + + CP(io, io32, interface_id); + CP(io, io32, dxfer_direction); + CP(io, io32, cmd_len); + CP(io, io32, mx_sb_len); + CP(io, io32, iovec_count); + CP(io, io32, dxfer_len); + PTROUT_CP(io, io32, dxferp); + PTROUT_CP(io, io32, cmdp); + PTROUT_CP(io, io32, sbp); + CP(io, io32, timeout); + CP(io, io32, flags); + CP(io, io32, pack_id); + PTROUT_CP(io, io32, usr_ptr); + CP(io, io32, status); + CP(io, io32, masked_status); + CP(io, io32, msg_status); + CP(io, io32, sb_len_wr); + CP(io, io32, host_status); + CP(io, io32, driver_status); + CP(io, io32, resid); + CP(io, io32, duration); + CP(io, io32, info); + + error = copyout(&io32, LINUX_USER_CAP(args->arg, sizeof(io32)), sizeof(io32)); + +out: + fdrop(fp, td); + return (error); +} +#endif + +static int +linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args) +{ + + switch (args->cmd) { + case LINUX_SG_GET_VERSION_NUM: + args->cmd = SG_GET_VERSION_NUM; + break; + case LINUX_SG_SET_TIMEOUT: + args->cmd = SG_SET_TIMEOUT; + break; + case LINUX_SG_GET_TIMEOUT: + args->cmd = SG_GET_TIMEOUT; + break; + case LINUX_SG_IO: + args->cmd = SG_IO; +#ifdef COMPAT_LINUX32 + return (linux_ioctl_sg_io(td, args)); +#endif + break; + case LINUX_SG_GET_RESERVED_SIZE: + args->cmd = SG_GET_RESERVED_SIZE; + break; + case LINUX_SG_GET_SCSI_ID: + args->cmd = SG_GET_SCSI_ID; + break; + case LINUX_SG_GET_SG_TABLESIZE: + args->cmd = SG_GET_SG_TABLESIZE; + break; + default: + return (ENODEV); + } + return (linux_ioctl_forward_to_sys(td, args)); +} + +/* + * Video4Linux (V4L) ioctl handler + */ +static int +linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt) +{ + vt->tuner = lvt->tuner; + strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE); + vt->rangelow = lvt->rangelow; /* possible long size conversion */ + vt->rangehigh = lvt->rangehigh; /* possible long size conversion */ + vt->flags = lvt->flags; + vt->mode = lvt->mode; + vt->signal = lvt->signal; + return (0); +} + +static int +bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt) +{ + lvt->tuner = vt->tuner; + strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE); + lvt->rangelow = vt->rangelow; /* possible long size conversion */ + lvt->rangehigh = vt->rangehigh; /* possible long size conversion */ + lvt->flags = vt->flags; + lvt->mode = vt->mode; + lvt->signal = vt->signal; + return (0); +} + +#ifdef COMPAT_LINUX_V4L_CLIPLIST +static int +linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc) +{ + vc->x = lvc->x; + vc->y = lvc->y; + vc->width = lvc->width; + vc->height = lvc->height; + vc->next = PTRIN(lvc->next); /* possible pointer size conversion */ + return (0); +} +#endif + +static int +linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw) +{ + vw->x = lvw->x; + vw->y = lvw->y; + vw->width = lvw->width; + vw->height = lvw->height; + vw->chromakey = lvw->chromakey; + vw->flags = lvw->flags; + vw->clips = PTRIN(lvw->clips); /* possible pointer size conversion */ + vw->clipcount = lvw->clipcount; + return (0); +} + +static int +bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw) +{ + memset(lvw, 0, sizeof(*lvw)); + + lvw->x = vw->x; + lvw->y = vw->y; + lvw->width = vw->width; + lvw->height = vw->height; + lvw->chromakey = vw->chromakey; + lvw->flags = vw->flags; + lvw->clips = PTROUT(vw->clips); /* possible pointer size conversion */ + lvw->clipcount = vw->clipcount; + return (0); +} + +static int +linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb) +{ + vb->base = PTRIN(lvb->base); /* possible pointer size conversion */ + vb->height = lvb->height; + vb->width = lvb->width; + vb->depth = lvb->depth; + vb->bytesperline = lvb->bytesperline; + return (0); +} + +static int +bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb) +{ + lvb->base = PTROUT(vb->base); /* possible pointer size conversion */ + lvb->height = vb->height; + lvb->width = vb->width; + lvb->depth = vb->depth; + lvb->bytesperline = vb->bytesperline; + return (0); +} + +static int +linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc) +{ + strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE); + vc->datasize = lvc->datasize; + vc->data = PTRIN(lvc->data); /* possible pointer size conversion */ + return (0); +} + +#ifdef COMPAT_LINUX_V4L_CLIPLIST +static int +linux_v4l_clip_copy(void *lvc, struct video_clip **ppvc) +{ + int error; + struct video_clip vclip; + struct l_video_clip l_vclip; + + error = copyin(lvc, &l_vclip, sizeof(l_vclip)); + if (error) return (error); + linux_to_bsd_v4l_clip(&l_vclip, &vclip); + /* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */ + if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL) + return (ENOMEM); /* XXX: Linux has no ENOMEM here. */ + memcpy(*ppvc, &vclip, sizeof(vclip)); + (*ppvc)->next = NULL; + return (0); +} + +static int +linux_v4l_cliplist_free(struct video_window *vw) +{ + struct video_clip **ppvc; + struct video_clip **ppvc_next; + + for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) { + ppvc_next = &((*ppvc)->next); + free(*ppvc, M_LINUX); + } + vw->clips = NULL; + + return (0); +} + +static int +linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw) +{ + int error; + int clipcount; + void *plvc; + struct video_clip **ppvc; + + /* + * XXX: The cliplist is used to pass in a list of clipping + * rectangles or, if clipcount == VIDEO_CLIP_BITMAP, a + * clipping bitmap. Some Linux apps, however, appear to + * leave cliplist and clips uninitialized. In any case, + * the cliplist is not used by pwc(4), at the time of + * writing, FreeBSD's only V4L driver. When a driver + * that uses the cliplist is developed, this code may + * need re-examiniation. + */ + error = 0; + clipcount = vw->clipcount; + if (clipcount == VIDEO_CLIP_BITMAP) { + /* + * In this case, the pointer (clips) is overloaded + * to be a "void *" to a bitmap, therefore there + * is no struct video_clip to copy now. + */ + } else if (clipcount > 0 && clipcount <= 16384) { + /* + * Clips points to list of clip rectangles, so + * copy the list. + * + * XXX: Upper limit of 16384 was used here to try to + * avoid cases when clipcount and clips pointer + * are uninitialized and therefore have high random + * values, as is the case in the Linux Skype + * application. The value 16384 was chosen as that + * is what is used in the Linux stradis(4) MPEG + * decoder driver, the only place we found an + * example of cliplist use. + */ + plvc = PTRIN(lvw->clips); + vw->clips = NULL; + ppvc = &(vw->clips); + while (clipcount-- > 0) { + if (plvc == NULL) { + error = EFAULT; + break; + } else { + error = linux_v4l_clip_copy(plvc, ppvc); + if (error) { + linux_v4l_cliplist_free(vw); + break; + } + } + ppvc = &((*ppvc)->next); + plvc = PTRIN(((struct l_video_clip *) plvc)->next); + } + } else { + /* + * clipcount == 0 or negative (but not VIDEO_CLIP_BITMAP) + * Force cliplist to null. + */ + vw->clipcount = 0; + vw->clips = NULL; + } + return (error); +} +#endif + +static int +linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + struct video_tuner vtun; + struct video_window vwin; + struct video_buffer vbuf; + struct video_code vcode; + struct l_video_tuner l_vtun; + struct l_video_window l_vwin; + struct l_video_buffer l_vbuf; + struct l_video_code l_vcode; + + switch (args->cmd & 0xffff) { + case LINUX_VIDIOCGCAP: args->cmd = VIDIOCGCAP; break; + case LINUX_VIDIOCGCHAN: args->cmd = VIDIOCGCHAN; break; + case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break; + + case LINUX_VIDIOCGTUNER: + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + error = copyin(LINUX_USER_CAP(args->arg, sizeof(l_vtun)), &l_vtun, sizeof(l_vtun)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_tuner(&l_vtun, &vtun); + error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td); + if (!error) { + bsd_to_linux_v4l_tuner(&vtun, &l_vtun); + error = copyout(&l_vtun, LINUX_USER_CAP(args->arg, sizeof(l_vtun)), + sizeof(l_vtun)); + } + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCSTUNER: + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + error = copyin(LINUX_USER_CAP(args->arg, sizeof(l_vtun)), &l_vtun, sizeof(l_vtun)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_tuner(&l_vtun, &vtun); + error = fo_ioctl(fp, VIDIOCSTUNER, &vtun, td->td_ucred, td); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCGPICT: args->cmd = VIDIOCGPICT; break; + case LINUX_VIDIOCSPICT: args->cmd = VIDIOCSPICT; break; + case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break; + + case LINUX_VIDIOCGWIN: + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td); + if (!error) { + bsd_to_linux_v4l_window(&vwin, &l_vwin); + error = copyout(&l_vwin, LINUX_USER_CAP(args->arg, sizeof(l_vwin)), + sizeof(l_vwin)); + } + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCSWIN: + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + error = copyin(LINUX_USER_CAP(args->arg, sizeof(l_vwin)), &l_vwin, sizeof(l_vwin)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_window(&l_vwin, &vwin); +#ifdef COMPAT_LINUX_V4L_CLIPLIST + error = linux_v4l_cliplist_copy(&l_vwin, &vwin); + if (error) { + fdrop(fp, td); + return (error); + } +#endif + error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td); + fdrop(fp, td); +#ifdef COMPAT_LINUX_V4L_CLIPLIST + linux_v4l_cliplist_free(&vwin); +#endif + return (error); + + case LINUX_VIDIOCGFBUF: + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td); + if (!error) { + bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf); + error = copyout(&l_vbuf, LINUX_USER_CAP(args->arg, sizeof(l_vbuf)), + sizeof(l_vbuf)); + } + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCSFBUF: + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + error = copyin(LINUX_USER_CAP(args->arg, sizeof(l_vbuf)), &l_vbuf, sizeof(l_vbuf)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf); + error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCKEY: args->cmd = VIDIOCKEY; break; + case LINUX_VIDIOCGFREQ: args->cmd = VIDIOCGFREQ; break; + case LINUX_VIDIOCSFREQ: args->cmd = VIDIOCSFREQ; break; + case LINUX_VIDIOCGAUDIO: args->cmd = VIDIOCGAUDIO; break; + case LINUX_VIDIOCSAUDIO: args->cmd = VIDIOCSAUDIO; break; + case LINUX_VIDIOCSYNC: args->cmd = VIDIOCSYNC; break; + case LINUX_VIDIOCMCAPTURE: args->cmd = VIDIOCMCAPTURE; break; + case LINUX_VIDIOCGMBUF: args->cmd = VIDIOCGMBUF; break; + case LINUX_VIDIOCGUNIT: args->cmd = VIDIOCGUNIT; break; + case LINUX_VIDIOCGCAPTURE: args->cmd = VIDIOCGCAPTURE; break; + case LINUX_VIDIOCSCAPTURE: args->cmd = VIDIOCSCAPTURE; break; + case LINUX_VIDIOCSPLAYMODE: args->cmd = VIDIOCSPLAYMODE; break; + case LINUX_VIDIOCSWRITEMODE: args->cmd = VIDIOCSWRITEMODE; break; + case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break; + + case LINUX_VIDIOCSMICROCODE: + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + error = copyin(LINUX_USER_CAP(args->arg, sizeof(l_vcode)), &l_vcode, sizeof(l_vcode)); + if (error) { + fdrop(fp, td); + return (error); + } + linux_to_bsd_v4l_code(&l_vcode, &vcode); + error = fo_ioctl(fp, VIDIOCSMICROCODE, &vcode, td->td_ucred, td); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOCGVBIFMT: args->cmd = VIDIOCGVBIFMT; break; + case LINUX_VIDIOCSVBIFMT: args->cmd = VIDIOCSVBIFMT; break; + default: return (ENOIOCTL); + } + + error = linux_ioctl_forward_to_sys(td, args); + return (error); +} + +/* + * Special ioctl handler + */ +static int +linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args) +{ + int error; + + switch (args->cmd) { + case LINUX_SIOCGIFADDR: + args->cmd = SIOCGIFADDR; + error = linux_ioctl_forward_to_sys(td, args); + break; + case LINUX_SIOCSIFADDR: + args->cmd = SIOCSIFADDR; + error = linux_ioctl_forward_to_sys(td, args); + break; + case LINUX_SIOCGIFFLAGS: + args->cmd = SIOCGIFFLAGS; + error = linux_ioctl_forward_to_sys(td, args); + break; + default: + error = ENOIOCTL; + } + + return (error); +} + +static int +linux_to_bsd_v4l2_standard(struct l_v4l2_standard *lvstd, struct v4l2_standard *vstd) +{ + vstd->index = lvstd->index; + vstd->id = lvstd->id; + CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name)); + memcpy(vstd->name, lvstd->name, sizeof(vstd->name)); + vstd->frameperiod = lvstd->frameperiod; + vstd->framelines = lvstd->framelines; + CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved)); + memcpy(vstd->reserved, lvstd->reserved, sizeof(vstd->reserved)); + return (0); +} + +static int +bsd_to_linux_v4l2_standard(struct v4l2_standard *vstd, struct l_v4l2_standard *lvstd) +{ + lvstd->index = vstd->index; + lvstd->id = vstd->id; + CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name)); + memcpy(lvstd->name, vstd->name, sizeof(lvstd->name)); + lvstd->frameperiod = vstd->frameperiod; + lvstd->framelines = vstd->framelines; + CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved)); + memcpy(lvstd->reserved, vstd->reserved, sizeof(lvstd->reserved)); + return (0); +} + +static int +linux_to_bsd_v4l2_buffer(struct l_v4l2_buffer *lvb, struct v4l2_buffer *vb) +{ + vb->index = lvb->index; + vb->type = lvb->type; + vb->bytesused = lvb->bytesused; + vb->flags = lvb->flags; + vb->field = lvb->field; + vb->timestamp.tv_sec = lvb->timestamp.tv_sec; + vb->timestamp.tv_usec = lvb->timestamp.tv_usec; + memcpy(&vb->timecode, &lvb->timecode, sizeof (lvb->timecode)); + vb->sequence = lvb->sequence; + vb->memory = lvb->memory; + if (lvb->memory == V4L2_MEMORY_USERPTR) + /* possible pointer size conversion */ + vb->m.userptr = (unsigned long)PTRIN(lvb->m.userptr); + else + vb->m.offset = lvb->m.offset; + vb->length = lvb->length; + vb->input = lvb->input; + vb->reserved = lvb->reserved; + return (0); +} + +static int +bsd_to_linux_v4l2_buffer(struct v4l2_buffer *vb, struct l_v4l2_buffer *lvb) +{ + lvb->index = vb->index; + lvb->type = vb->type; + lvb->bytesused = vb->bytesused; + lvb->flags = vb->flags; + lvb->field = vb->field; + lvb->timestamp.tv_sec = vb->timestamp.tv_sec; + lvb->timestamp.tv_usec = vb->timestamp.tv_usec; + memcpy(&lvb->timecode, &vb->timecode, sizeof (vb->timecode)); + lvb->sequence = vb->sequence; + lvb->memory = vb->memory; + if (vb->memory == V4L2_MEMORY_USERPTR) + /* possible pointer size conversion */ + lvb->m.userptr = PTROUT(vb->m.userptr); + else + lvb->m.offset = vb->m.offset; + lvb->length = vb->length; + lvb->input = vb->input; + lvb->reserved = vb->reserved; + return (0); +} + +static int +linux_to_bsd_v4l2_format(struct l_v4l2_format *lvf, struct v4l2_format *vf) +{ + vf->type = lvf->type; + if (lvf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY +#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY + || lvf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY +#endif + ) + /* + * XXX TODO - needs 32 -> 64 bit conversion: + * (unused by webcams?) + */ + return (EINVAL); + memcpy(&vf->fmt, &lvf->fmt, sizeof(vf->fmt)); + return (0); +} + +static int +bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf) +{ + lvf->type = vf->type; + if (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY +#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY + || vf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY +#endif + ) + /* + * XXX TODO - needs 32 -> 64 bit conversion: + * (unused by webcams?) + */ + return (EINVAL); + memcpy(&lvf->fmt, &vf->fmt, sizeof(vf->fmt)); + return (0); +} +static int +linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + struct v4l2_format vformat; + struct l_v4l2_format l_vformat; + struct v4l2_standard vstd; + struct l_v4l2_standard l_vstd; + struct l_v4l2_buffer l_vbuf; + struct v4l2_buffer vbuf; + struct v4l2_input vinp; + + switch (args->cmd & 0xffff) { + case LINUX_VIDIOC_RESERVED: + case LINUX_VIDIOC_LOG_STATUS: + if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID) + return (ENOIOCTL); + args->cmd = (args->cmd & 0xffff) | IOC_VOID; + break; + + case LINUX_VIDIOC_OVERLAY: + case LINUX_VIDIOC_STREAMON: + case LINUX_VIDIOC_STREAMOFF: + case LINUX_VIDIOC_S_STD: + case LINUX_VIDIOC_S_TUNER: + case LINUX_VIDIOC_S_AUDIO: + case LINUX_VIDIOC_S_AUDOUT: + case LINUX_VIDIOC_S_MODULATOR: + case LINUX_VIDIOC_S_FREQUENCY: + case LINUX_VIDIOC_S_CROP: + case LINUX_VIDIOC_S_JPEGCOMP: + case LINUX_VIDIOC_S_PRIORITY: + case LINUX_VIDIOC_DBG_S_REGISTER: + case LINUX_VIDIOC_S_HW_FREQ_SEEK: + case LINUX_VIDIOC_SUBSCRIBE_EVENT: + case LINUX_VIDIOC_UNSUBSCRIBE_EVENT: + args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN; + break; + + case LINUX_VIDIOC_QUERYCAP: + case LINUX_VIDIOC_G_STD: + case LINUX_VIDIOC_G_AUDIO: + case LINUX_VIDIOC_G_INPUT: + case LINUX_VIDIOC_G_OUTPUT: + case LINUX_VIDIOC_G_AUDOUT: + case LINUX_VIDIOC_G_JPEGCOMP: + case LINUX_VIDIOC_QUERYSTD: + case LINUX_VIDIOC_G_PRIORITY: + case LINUX_VIDIOC_QUERY_DV_PRESET: + args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT; + break; + + case LINUX_VIDIOC_ENUM_FMT: + case LINUX_VIDIOC_REQBUFS: + case LINUX_VIDIOC_G_PARM: + case LINUX_VIDIOC_S_PARM: + case LINUX_VIDIOC_G_CTRL: + case LINUX_VIDIOC_S_CTRL: + case LINUX_VIDIOC_G_TUNER: + case LINUX_VIDIOC_QUERYCTRL: + case LINUX_VIDIOC_QUERYMENU: + case LINUX_VIDIOC_S_INPUT: + case LINUX_VIDIOC_S_OUTPUT: + case LINUX_VIDIOC_ENUMOUTPUT: + case LINUX_VIDIOC_G_MODULATOR: + case LINUX_VIDIOC_G_FREQUENCY: + case LINUX_VIDIOC_CROPCAP: + case LINUX_VIDIOC_G_CROP: + case LINUX_VIDIOC_ENUMAUDIO: + case LINUX_VIDIOC_ENUMAUDOUT: + case LINUX_VIDIOC_G_SLICED_VBI_CAP: +#ifdef VIDIOC_ENUM_FRAMESIZES + case LINUX_VIDIOC_ENUM_FRAMESIZES: + case LINUX_VIDIOC_ENUM_FRAMEINTERVALS: + case LINUX_VIDIOC_ENCODER_CMD: + case LINUX_VIDIOC_TRY_ENCODER_CMD: +#endif + case LINUX_VIDIOC_DBG_G_REGISTER: + case LINUX_VIDIOC_DBG_G_CHIP_IDENT: + case LINUX_VIDIOC_ENUM_DV_PRESETS: + case LINUX_VIDIOC_S_DV_PRESET: + case LINUX_VIDIOC_G_DV_PRESET: + case LINUX_VIDIOC_S_DV_TIMINGS: + case LINUX_VIDIOC_G_DV_TIMINGS: + args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT; + break; + + case LINUX_VIDIOC_G_FMT: + case LINUX_VIDIOC_S_FMT: + case LINUX_VIDIOC_TRY_FMT: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(l_vformat)), &l_vformat, sizeof(l_vformat)); + if (error) + return (error); + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error) + return (error); + if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0) + error = EINVAL; + else if ((args->cmd & 0xffff) == LINUX_VIDIOC_G_FMT) + error = fo_ioctl(fp, VIDIOC_G_FMT, &vformat, + td->td_ucred, td); + else if ((args->cmd & 0xffff) == LINUX_VIDIOC_S_FMT) + error = fo_ioctl(fp, VIDIOC_S_FMT, &vformat, + td->td_ucred, td); + else + error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat, + td->td_ucred, td); + bsd_to_linux_v4l2_format(&vformat, &l_vformat); + if (error == 0) + error = copyout(&l_vformat, LINUX_USER_CAP(args->arg, sizeof(l_vformat)), + sizeof(l_vformat)); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOC_ENUMSTD: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(l_vstd)), &l_vstd, sizeof(l_vstd)); + if (error) + return (error); + linux_to_bsd_v4l2_standard(&l_vstd, &vstd); + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error) + return (error); + error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd, + td->td_ucred, td); + if (error) { + fdrop(fp, td); + return (error); + } + bsd_to_linux_v4l2_standard(&vstd, &l_vstd); + error = copyout(&l_vstd, LINUX_USER_CAP(args->arg, sizeof(l_vstd)), sizeof(l_vstd)); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOC_ENUMINPUT: + /* + * The Linux struct l_v4l2_input differs only in size, + * it has no padding at the end. + */ + error = copyin(LINUX_USER_CAP(args->arg, sizeof(struct l_v4l2_input)), &vinp, + sizeof(struct l_v4l2_input)); + if (error != 0) + return (error); + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp, + td->td_ucred, td); + if (error) { + fdrop(fp, td); + return (error); + } + error = copyout(&vinp, LINUX_USER_CAP(args->arg, sizeof(struct l_v4l2_input)), + sizeof(struct l_v4l2_input)); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOC_QUERYBUF: + case LINUX_VIDIOC_QBUF: + case LINUX_VIDIOC_DQBUF: + error = copyin(LINUX_USER_CAP(args->arg, sizeof(l_vbuf)), &l_vbuf, sizeof(l_vbuf)); + if (error) + return (error); + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error) + return (error); + linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf); + if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF) + error = fo_ioctl(fp, VIDIOC_QUERYBUF, &vbuf, + td->td_ucred, td); + else if ((args->cmd & 0xffff) == LINUX_VIDIOC_QBUF) + error = fo_ioctl(fp, VIDIOC_QBUF, &vbuf, + td->td_ucred, td); + else + error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf, + td->td_ucred, td); + bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf); + if (error == 0) + error = copyout(&l_vbuf, LINUX_USER_CAP(args->arg, sizeof(l_vbuf)), + sizeof(l_vbuf)); + fdrop(fp, td); + return (error); + + /* + * XXX TODO - these need 32 -> 64 bit conversion: + * (are any of them needed for webcams?) + */ + case LINUX_VIDIOC_G_FBUF: + case LINUX_VIDIOC_S_FBUF: + + case LINUX_VIDIOC_G_EXT_CTRLS: + case LINUX_VIDIOC_S_EXT_CTRLS: + case LINUX_VIDIOC_TRY_EXT_CTRLS: + + case LINUX_VIDIOC_DQEVENT: + + default: return (ENOIOCTL); + } + + error = linux_ioctl_forward_to_sys(td, args); + return (error); +} + +/* + * Support for emulators/linux-libusb. This port uses FBSD_LUSB* macros + * instead of USB* ones. This lets us to provide correct values for cmd. + * 0xffffffe0 -- 0xffffffff range seemed to be the least collision-prone. + */ +static int +linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args) +{ + int error; + + error = 0; + switch (args->cmd) { + case FBSD_LUSB_DEVICEENUMERATE: + args->cmd = USB_DEVICEENUMERATE; + break; + case FBSD_LUSB_DEV_QUIRK_ADD: + args->cmd = USB_DEV_QUIRK_ADD; + break; + case FBSD_LUSB_DEV_QUIRK_GET: + args->cmd = USB_DEV_QUIRK_GET; + break; + case FBSD_LUSB_DEV_QUIRK_REMOVE: + args->cmd = USB_DEV_QUIRK_REMOVE; + break; + case FBSD_LUSB_DO_REQUEST: + args->cmd = USB_DO_REQUEST; + break; + case FBSD_LUSB_FS_CLEAR_STALL_SYNC: + args->cmd = USB_FS_CLEAR_STALL_SYNC; + break; + case FBSD_LUSB_FS_CLOSE: + args->cmd = USB_FS_CLOSE; + break; + case FBSD_LUSB_FS_COMPLETE: + args->cmd = USB_FS_COMPLETE; + break; + case FBSD_LUSB_FS_INIT: + args->cmd = USB_FS_INIT; + break; + case FBSD_LUSB_FS_OPEN: + args->cmd = USB_FS_OPEN; + break; + case FBSD_LUSB_FS_START: + args->cmd = USB_FS_START; + break; + case FBSD_LUSB_FS_STOP: + args->cmd = USB_FS_STOP; + break; + case FBSD_LUSB_FS_UNINIT: + args->cmd = USB_FS_UNINIT; + break; + case FBSD_LUSB_GET_CONFIG: + args->cmd = USB_GET_CONFIG; + break; + case FBSD_LUSB_GET_DEVICEINFO: + args->cmd = USB_GET_DEVICEINFO; + break; + case FBSD_LUSB_GET_DEVICE_DESC: + args->cmd = USB_GET_DEVICE_DESC; + break; + case FBSD_LUSB_GET_FULL_DESC: + args->cmd = USB_GET_FULL_DESC; + break; + case FBSD_LUSB_GET_IFACE_DRIVER: + args->cmd = USB_GET_IFACE_DRIVER; + break; + case FBSD_LUSB_GET_PLUGTIME: + args->cmd = USB_GET_PLUGTIME; + break; + case FBSD_LUSB_GET_POWER_MODE: + args->cmd = USB_GET_POWER_MODE; + break; + case FBSD_LUSB_GET_REPORT_DESC: + args->cmd = USB_GET_REPORT_DESC; + break; + case FBSD_LUSB_GET_REPORT_ID: + args->cmd = USB_GET_REPORT_ID; + break; + case FBSD_LUSB_GET_TEMPLATE: + args->cmd = USB_GET_TEMPLATE; + break; + case FBSD_LUSB_IFACE_DRIVER_ACTIVE: + args->cmd = USB_IFACE_DRIVER_ACTIVE; + break; + case FBSD_LUSB_IFACE_DRIVER_DETACH: + args->cmd = USB_IFACE_DRIVER_DETACH; + break; + case FBSD_LUSB_QUIRK_NAME_GET: + args->cmd = USB_QUIRK_NAME_GET; + break; + case FBSD_LUSB_READ_DIR: + args->cmd = USB_READ_DIR; + break; + case FBSD_LUSB_SET_ALTINTERFACE: + args->cmd = USB_SET_ALTINTERFACE; + break; + case FBSD_LUSB_SET_CONFIG: + args->cmd = USB_SET_CONFIG; + break; + case FBSD_LUSB_SET_IMMED: + args->cmd = USB_SET_IMMED; + break; + case FBSD_LUSB_SET_POWER_MODE: + args->cmd = USB_SET_POWER_MODE; + break; + case FBSD_LUSB_SET_TEMPLATE: + args->cmd = USB_SET_TEMPLATE; + break; + case FBSD_LUSB_FS_OPEN_STREAM: + args->cmd = USB_FS_OPEN_STREAM; + break; + case FBSD_LUSB_GET_DEV_PORT_PATH: + args->cmd = USB_GET_DEV_PORT_PATH; + break; + case FBSD_LUSB_GET_POWER_USAGE: + args->cmd = USB_GET_POWER_USAGE; + break; + case FBSD_LUSB_DEVICESTATS: + args->cmd = USB_DEVICESTATS; + break; + default: + error = ENOIOCTL; + } + if (error != ENOIOCTL) + error = linux_ioctl_forward_to_sys(td, args); + return (error); +} + +/* + * Some evdev ioctls must be translated. + * - EVIOCGMTSLOTS is a IOC_READ ioctl on Linux although it has input data + * (must be IOC_INOUT on FreeBSD). + * - On Linux, EVIOCGRAB, EVIOCREVOKE and EVIOCRMFF are defined as _IOW with + * an int argument. You don't pass an int pointer to the ioctl(), however, + * but just the int directly. On FreeBSD, they are defined as _IOWINT for + * this to work. + */ +static int +linux_ioctl_evdev(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + clockid_t clock; + int error; + + args->cmd = SETDIR(args->cmd); + + switch (args->cmd) { + case (EVIOCGRAB & ~IOC_DIRMASK) | IOC_IN: + args->cmd = EVIOCGRAB; + break; + case (EVIOCREVOKE & ~IOC_DIRMASK) | IOC_IN: + args->cmd = EVIOCREVOKE; + break; + case (EVIOCRMFF & ~IOC_DIRMASK) | IOC_IN: + args->cmd = EVIOCRMFF; + break; + case EVIOCSCLOCKID: { + error = copyin(LINUX_USER_CAP(args->arg, sizeof(clock)), &clock, sizeof(clock)); + if (error != 0) + return (error); + if (clock & ~(LINUX_IOCTL_EVDEV_CLK)) + return (EINVAL); + error = linux_to_native_clockid(&clock, clock); + if (error != 0) + return (error); + + error = fget(td, args->fd, + &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + + error = fo_ioctl(fp, EVIOCSCLOCKID, &clock, td->td_ucred, td); + fdrop(fp, td); + return (error); + } + default: + break; + } + + if (IOCBASECMD(args->cmd) == + ((EVIOCGMTSLOTS(0) & ~IOC_DIRMASK) | IOC_OUT)) + args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT; + + return (linux_ioctl_forward_to_sys(td, args)); +} + +static int +linux_ioctl_kcov(struct thread *td, struct linux_ioctl_args *args) +{ + int error; + + error = 0; + switch (args->cmd & 0xffff) { + case LINUX_KCOV_INIT_TRACE: + args->cmd = KIOSETBUFSIZE; + break; + case LINUX_KCOV_ENABLE: + args->cmd = KIOENABLE; + if (args->arg == 0) + args->arg = KCOV_MODE_TRACE_PC; + else if (args->arg == 1) + args->arg = KCOV_MODE_TRACE_CMP; + else + error = EINVAL; + break; + case LINUX_KCOV_DISABLE: + args->cmd = KIODISABLE; + break; + default: + error = ENOTTY; + break; + } + + if (error == 0) + error = linux_ioctl_forward_to_sys(td, args); + return (error); +} + +#ifndef COMPAT_LINUX32 +static int +linux_ioctl_nvme(struct thread *td, struct linux_ioctl_args *args) +{ + + /* + * The NVMe drivers for namespace and controller implement these + * commands using their native format. All the others are not + * implemented yet. + */ + switch (args->cmd & 0xffff) { + case LINUX_NVME_IOCTL_ID: + args->cmd = NVME_IOCTL_ID; + break; + case LINUX_NVME_IOCTL_RESET: + args->cmd = NVME_IOCTL_RESET; + break; + case LINUX_NVME_IOCTL_ADMIN_CMD: + args->cmd = NVME_IOCTL_ADMIN_CMD; + break; + case LINUX_NVME_IOCTL_IO_CMD: + args->cmd = NVME_IOCTL_IO_CMD; + break; + default: + return (ENODEV); + } + return (linux_ioctl_forward_to_sys(td, args)); +} +#endif + +/* + * main ioctl syscall function + */ + +static int +linux_ioctl_fallback(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + struct linux_ioctl_handler_element *he; + int error, cmd; + + error = fget(td, args->fd, &cap_ioctl_rights, &fp); + if (error != 0) + return (error); + if ((fp->f_flag & (FREAD|FWRITE)) == 0) { + fdrop(fp, td); + return (EBADF); + } + + /* Iterate over the ioctl handlers */ + cmd = args->cmd & 0xffff; + sx_slock(&linux_ioctl_sx); + mtx_lock(&Giant); +#ifdef COMPAT_LINUX32 + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { + if (cmd >= he->low && cmd <= he->high) { + error = (*he->func)(td, args); + if (error != ENOIOCTL) { + mtx_unlock(&Giant); + sx_sunlock(&linux_ioctl_sx); + fdrop(fp, td); + return (error); + } + } + } +#endif + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { + if (cmd >= he->low && cmd <= he->high) { + error = (*he->func)(td, args); + if (error != ENOIOCTL) { + mtx_unlock(&Giant); + sx_sunlock(&linux_ioctl_sx); + fdrop(fp, td); + return (error); + } + } + } + mtx_unlock(&Giant); + sx_sunlock(&linux_ioctl_sx); + fdrop(fp, td); + + switch (args->cmd & 0xffff) { + case LINUX_BTRFS_IOC_CLONE: + case LINUX_F2FS_IOC_GET_FEATURES: + case LINUX_FS_IOC_FIEMAP: + return (ENOTSUP); + + default: + linux_msg(td, "%s fd=%d, cmd=0x%x ('%c',%d) is not implemented", + __func__, args->fd, args->cmd, + (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff)); + break; + } + + return (EINVAL); +} + +int +linux_ioctl(struct thread *td, struct linux_ioctl_args *args) +{ + struct linux_ioctl_handler *handler; + int error, cmd, i; + + cmd = args->cmd & 0xffff; + + /* + * array of ioctls known at compilation time. Elides a lot of work on + * each call compared to the list variant. Everything frequently used + * should be moved here. + * + * Arguably the magic creating the list should create an array instead. + * + * For now just a linear scan. + */ + for (i = 0; i < nitems(linux_ioctls); i++) { + handler = &linux_ioctls[i]; + if (cmd >= handler->low && cmd <= handler->high) { + error = (*handler->func)(td, args); + if (error != ENOIOCTL) { + return (error); + } + } + } + return (linux_ioctl_fallback(td, args)); +} + +int +linux_ioctl_register_handler(struct linux_ioctl_handler *h) +{ + struct linux_ioctl_handler_element *he, *cur; + + if (h == NULL || h->func == NULL) + return (EINVAL); + + /* + * Reuse the element if the handler is already on the list, otherwise + * create a new element. + */ + sx_xlock(&linux_ioctl_sx); + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { + if (he->func == h->func) + break; + } + if (he == NULL) { + he = malloc(sizeof(*he), + M_LINUX, M_WAITOK); + he->func = h->func; + } else + TAILQ_REMOVE(&linux_ioctl_handlers, he, list); + + /* Initialize range information. */ + he->low = h->low; + he->high = h->high; + he->span = h->high - h->low + 1; + + /* Add the element to the list, sorted on span. */ + TAILQ_FOREACH(cur, &linux_ioctl_handlers, list) { + if (cur->span > he->span) { + TAILQ_INSERT_BEFORE(cur, he, list); + sx_xunlock(&linux_ioctl_sx); + return (0); + } + } + TAILQ_INSERT_TAIL(&linux_ioctl_handlers, he, list); + sx_xunlock(&linux_ioctl_sx); + + return (0); +} + +int +linux_ioctl_unregister_handler(struct linux_ioctl_handler *h) +{ + struct linux_ioctl_handler_element *he; + + if (h == NULL || h->func == NULL) + return (EINVAL); + + sx_xlock(&linux_ioctl_sx); + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) { + if (he->func == h->func) { + TAILQ_REMOVE(&linux_ioctl_handlers, he, list); + sx_xunlock(&linux_ioctl_sx); + free(he, M_LINUX); + return (0); + } + } + sx_xunlock(&linux_ioctl_sx); + + return (EINVAL); +} + +#ifdef COMPAT_LINUX32 +int +linux32_ioctl_register_handler(struct linux_ioctl_handler *h) +{ + struct linux_ioctl_handler_element *he, *cur; + + if (h == NULL || h->func == NULL) + return (EINVAL); + + /* + * Reuse the element if the handler is already on the list, otherwise + * create a new element. + */ + sx_xlock(&linux_ioctl_sx); + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { + if (he->func == h->func) + break; + } + if (he == NULL) { + he = malloc(sizeof(*he), M_LINUX, M_WAITOK); + he->func = h->func; + } else + TAILQ_REMOVE(&linux32_ioctl_handlers, he, list); + + /* Initialize range information. */ + he->low = h->low; + he->high = h->high; + he->span = h->high - h->low + 1; + + /* Add the element to the list, sorted on span. */ + TAILQ_FOREACH(cur, &linux32_ioctl_handlers, list) { + if (cur->span > he->span) { + TAILQ_INSERT_BEFORE(cur, he, list); + sx_xunlock(&linux_ioctl_sx); + return (0); + } + } + TAILQ_INSERT_TAIL(&linux32_ioctl_handlers, he, list); + sx_xunlock(&linux_ioctl_sx); + + return (0); +} + +int +linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h) +{ + struct linux_ioctl_handler_element *he; + + if (h == NULL || h->func == NULL) + return (EINVAL); + + sx_xlock(&linux_ioctl_sx); + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) { + if (he->func == h->func) { + TAILQ_REMOVE(&linux32_ioctl_handlers, he, list); + sx_xunlock(&linux_ioctl_sx); + free(he, M_LINUX); + return (0); + } + } + sx_xunlock(&linux_ioctl_sx); + + return (EINVAL); +} +#endif diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h index 4ef6d4f40830..252493706d04 100644 --- a/sys/compat/linux/linux_ioctl.h +++ b/sys/compat/linux/linux_ioctl.h @@ -1,825 +1,825 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 1999 Marcel Moolenaar - * 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. - */ - -#ifndef _LINUX_IOCTL_H_ -#define _LINUX_IOCTL_H_ - -/* - * ioctl - * - * XXX comments in Linux' indicate these - * could be arch-dependant... - */ -#define LINUX_IOC_VOID 0 -#define LINUX_IOC_IN 0x40000000 -#define LINUX_IOC_OUT 0x80000000 -#define LINUX_IOC_INOUT (LINUX_IOC_IN|LINUX_IOC_OUT) - -/* - * disk - */ -#define LINUX_BLKROSET 0x125d -#define LINUX_BLKROGET 0x125e -#define LINUX_BLKRRPART 0x125f -#define LINUX_BLKGETSIZE 0x1260 -#define LINUX_BLKFLSBUF 0x1261 -#define LINUX_BLKRASET 0x1262 -#define LINUX_BLKRAGET 0x1263 -#define LINUX_BLKFRASET 0x1264 -#define LINUX_BLKFRAGET 0x1265 -#define LINUX_BLKSECTSET 0x1266 -#define LINUX_BLKSECTGET 0x1267 -#define LINUX_BLKSSZGET 0x1268 -#define LINUX_BLKGETSIZE64 0x1272 -#define LINUX_BLKPBSZGET 0x127b - -#define LINUX_IOCTL_DISK_MIN LINUX_BLKROSET -#define LINUX_IOCTL_DISK_MAX LINUX_BLKPBSZGET - -/* - * hdio - */ -#define LINUX_HDIO_GET_GEO 0x0301 -#define LINUX_HDIO_GET_IDENTITY 0x030D /* not yet implemented */ -#define LINUX_HDIO_GET_GEO_BIG 0x0330 - -#define LINUX_IOCTL_HDIO_MIN LINUX_HDIO_GET_GEO -#define LINUX_IOCTL_HDIO_MAX LINUX_HDIO_GET_GEO_BIG - -/* - * cdrom - */ -#define LINUX_CDROMPAUSE 0x5301 -#define LINUX_CDROMRESUME 0x5302 -#define LINUX_CDROMPLAYMSF 0x5303 -#define LINUX_CDROMPLAYTRKIND 0x5304 -#define LINUX_CDROMREADTOCHDR 0x5305 -#define LINUX_CDROMREADTOCENTRY 0x5306 -#define LINUX_CDROMSTOP 0x5307 -#define LINUX_CDROMSTART 0x5308 -#define LINUX_CDROMEJECT 0x5309 -#define LINUX_CDROMVOLCTRL 0x530a -#define LINUX_CDROMSUBCHNL 0x530b -#define LINUX_CDROMREADMODE2 0x530c -#define LINUX_CDROMREADMODE1 0x530d -#define LINUX_CDROMREADAUDIO 0x530e -#define LINUX_CDROMEJECT_SW 0x530f -#define LINUX_CDROMMULTISESSION 0x5310 -#define LINUX_CDROM_GET_UPC 0x5311 -#define LINUX_CDROMRESET 0x5312 -#define LINUX_CDROMVOLREAD 0x5313 -#define LINUX_CDROMREADRAW 0x5314 -#define LINUX_CDROMREADCOOKED 0x5315 -#define LINUX_CDROMSEEK 0x5316 -#define LINUX_CDROMPLAYBLK 0x5317 -#define LINUX_CDROMREADALL 0x5318 -#define LINUX_CDROMCLOSETRAY 0x5319 -#define LINUX_CDROMLOADFROMSLOT 0x531a -#define LINUX_CDROMGETSPINDOWN 0x531d -#define LINUX_CDROMSETSPINDOWN 0x531e -#define LINUX_CDROM_SET_OPTIONS 0x5320 -#define LINUX_CDROM_CLEAR_OPTIONS 0x5321 -#define LINUX_CDROM_SELECT_SPEED 0x5322 -#define LINUX_CDROM_SELECT_DISC 0x5323 -#define LINUX_CDROM_MEDIA_CHANGED 0x5325 -#define LINUX_CDROM_DRIVE_STATUS 0x5326 -#define LINUX_CDROM_DISC_STATUS 0x5327 -#define LINUX_CDROM_CHANGER_NSLOTS 0x5328 -#define LINUX_CDROM_LOCKDOOR 0x5329 -#define LINUX_CDROM_DEBUG 0x5330 -#define LINUX_CDROM_GET_CAPABILITY 0x5331 -#define LINUX_CDROMAUDIOBUFSIZ 0x5382 -#define LINUX_SCSI_GET_IDLUN 0x5382 -#define LINUX_SCSI_GET_BUS_NUMBER 0x5386 -#define LINUX_DVD_READ_STRUCT 0x5390 -#define LINUX_DVD_WRITE_STRUCT 0x5391 -#define LINUX_DVD_AUTH 0x5392 -#define LINUX_CDROM_SEND_PACKET 0x5393 -#define LINUX_CDROM_NEXT_WRITABLE 0x5394 -#define LINUX_CDROM_LAST_WRITTEN 0x5395 - -#define LINUX_IOCTL_CDROM_MIN LINUX_CDROMPAUSE -#define LINUX_IOCTL_CDROM_MAX LINUX_CDROM_LAST_WRITTEN - -#define LINUX_CDROM_LBA 0x01 -#define LINUX_CDROM_MSF 0x02 - -#define LINUX_DVD_LU_SEND_AGID 0 -#define LINUX_DVD_HOST_SEND_CHALLENGE 1 -#define LINUX_DVD_LU_SEND_KEY1 2 -#define LINUX_DVD_LU_SEND_CHALLENGE 3 -#define LINUX_DVD_HOST_SEND_KEY2 4 -#define LINUX_DVD_AUTH_ESTABLISHED 5 -#define LINUX_DVD_AUTH_FAILURE 6 -#define LINUX_DVD_LU_SEND_TITLE_KEY 7 -#define LINUX_DVD_LU_SEND_ASF 8 -#define LINUX_DVD_INVALIDATE_AGID 9 -#define LINUX_DVD_LU_SEND_RPC_STATE 10 -#define LINUX_DVD_HOST_SEND_RPC_STATE 11 - -/* - * SG - */ -#define LINUX_SG_SET_TIMEOUT 0x2201 -#define LINUX_SG_GET_TIMEOUT 0x2202 -#define LINUX_SG_EMULATED_HOST 0x2203 -#define LINUX_SG_SET_TRANSFORM 0x2204 -#define LINUX_SG_GET_TRANSFORM 0x2205 -#define LINUX_SG_GET_COMMAND_Q 0x2270 -#define LINUX_SG_SET_COMMAND_Q 0x2271 -#define LINUX_SG_SET_RESERVED_SIZE 0x2275 -#define LINUX_SG_GET_RESERVED_SIZE 0x2272 -#define LINUX_SG_GET_SCSI_ID 0x2276 -#define LINUX_SG_SET_FORCE_LOW_DMA 0x2279 -#define LINUX_SG_GET_LOW_DMA 0x227a -#define LINUX_SG_SET_FORCE_PACK_ID 0x227b -#define LINUX_SG_GET_PACK_ID 0x227c -#define LINUX_SG_GET_NUM_WAITING 0x227d -#define LINUX_SG_SET_DEBUG 0x227e -#define LINUX_SG_GET_SG_TABLESIZE 0x227f -#define LINUX_SG_GET_VERSION_NUM 0x2282 -#define LINUX_SG_NEXT_CMD_LEN 0x2283 -#define LINUX_SG_SCSI_RESET 0x2284 -#define LINUX_SG_IO 0x2285 -#define LINUX_SG_GET_REQUEST_TABLE 0x2286 -#define LINUX_SG_SET_KEEP_ORPHAN 0x2287 -#define LINUX_SG_GET_KEEP_ORPHAN 0x2288 -#define LINUX_SG_GET_ACCESS_COUNT 0x2289 - -#define LINUX_IOCTL_SG_MIN 0x2200 -#define LINUX_IOCTL_SG_MAX 0x22ff - -/* - * VFAT - */ -#define LINUX_VFAT_READDIR_BOTH 0x7201 - -#define LINUX_IOCTL_VFAT_MIN LINUX_VFAT_READDIR_BOTH -#define LINUX_IOCTL_VFAT_MAX LINUX_VFAT_READDIR_BOTH - -/* - * console - */ -#define LINUX_KIOCSOUND 0x4B2F -#define LINUX_KDMKTONE 0x4B30 -#define LINUX_KDGETLED 0x4B31 -#define LINUX_KDSETLED 0x4B32 -#define LINUX_KDSETMODE 0x4B3A -#define LINUX_KDGETMODE 0x4B3B -#define LINUX_KDGKBMODE 0x4B44 -#define LINUX_KDSKBMODE 0x4B45 -#define LINUX_VT_OPENQRY 0x5600 -#define LINUX_VT_GETMODE 0x5601 -#define LINUX_VT_SETMODE 0x5602 -#define LINUX_VT_GETSTATE 0x5603 -#define LINUX_VT_RELDISP 0x5605 -#define LINUX_VT_ACTIVATE 0x5606 -#define LINUX_VT_WAITACTIVE 0x5607 - -#define LINUX_IOCTL_CONSOLE_MIN LINUX_KIOCSOUND -#define LINUX_IOCTL_CONSOLE_MAX LINUX_VT_WAITACTIVE - -#define LINUX_LED_SCR 0x01 -#define LINUX_LED_NUM 0x02 -#define LINUX_LED_CAP 0x04 - -#define LINUX_KD_TEXT 0x0 -#define LINUX_KD_GRAPHICS 0x1 -#define LINUX_KD_TEXT0 0x2 -#define LINUX_KD_TEXT1 0x3 - -#define LINUX_KBD_RAW 0 -#define LINUX_KBD_XLATE 1 -#define LINUX_KBD_MEDIUMRAW 2 - -/* - * socket - */ -#define LINUX_FIOSETOWN 0x8901 -#define LINUX_SIOCSPGRP 0x8902 -#define LINUX_FIOGETOWN 0x8903 -#define LINUX_SIOCGPGRP 0x8904 -#define LINUX_SIOCATMARK 0x8905 -#define LINUX_SIOCGSTAMP 0x8906 -#define LINUX_SIOCGIFNAME 0x8910 -#define LINUX_SIOCGIFCONF 0x8912 -#define LINUX_SIOCGIFFLAGS 0x8913 -#define LINUX_SIOCGIFADDR 0x8915 -#define LINUX_SIOCSIFADDR 0x8916 -#define LINUX_SIOCGIFDSTADDR 0x8917 -#define LINUX_SIOCGIFBRDADDR 0x8919 -#define LINUX_SIOCGIFNETMASK 0x891b -#define LINUX_SIOCSIFNETMASK 0x891c -#define LINUX_SIOCGIFMETRIC 0x891d -#define LINUX_SIOCSIFMETRIC 0x891e -#define LINUX_SIOCGIFMTU 0x8921 -#define LINUX_SIOCSIFMTU 0x8922 -#define LINUX_SIOCSIFNAME 0x8923 -#define LINUX_SIOCSIFHWADDR 0x8924 -#define LINUX_SIOCGIFHWADDR 0x8927 -#define LINUX_SIOCADDMULTI 0x8931 -#define LINUX_SIOCDELMULTI 0x8932 -#define LINUX_SIOCGIFINDEX 0x8933 -#define LINUX_SIOGIFINDEX LINUX_SIOCGIFINDEX -#define LINUX_SIOCGIFCOUNT 0x8938 - -#define LINUX_IOCTL_SOCKET_MIN LINUX_FIOSETOWN -#define LINUX_IOCTL_SOCKET_MAX LINUX_SIOCGIFCOUNT - -/* - * Device private ioctl calls - */ -#define LINUX_SIOCDEVPRIVATE 0x89F0 /* to 89FF */ -#define LINUX_IOCTL_PRIVATE_MIN LINUX_SIOCDEVPRIVATE -#define LINUX_IOCTL_PRIVATE_MAX LINUX_SIOCDEVPRIVATE+0xf - -/* - * sound - */ -#define LINUX_SOUND_MIXER_WRITE_VOLUME 0x4d00 -#define LINUX_SOUND_MIXER_WRITE_BASS 0x4d01 -#define LINUX_SOUND_MIXER_WRITE_TREBLE 0x4d02 -#define LINUX_SOUND_MIXER_WRITE_SYNTH 0x4d03 -#define LINUX_SOUND_MIXER_WRITE_PCM 0x4d04 -#define LINUX_SOUND_MIXER_WRITE_SPEAKER 0x4d05 -#define LINUX_SOUND_MIXER_WRITE_LINE 0x4d06 -#define LINUX_SOUND_MIXER_WRITE_MIC 0x4d07 -#define LINUX_SOUND_MIXER_WRITE_CD 0x4d08 -#define LINUX_SOUND_MIXER_WRITE_IMIX 0x4d09 -#define LINUX_SOUND_MIXER_WRITE_ALTPCM 0x4d0A -#define LINUX_SOUND_MIXER_WRITE_RECLEV 0x4d0B -#define LINUX_SOUND_MIXER_WRITE_IGAIN 0x4d0C -#define LINUX_SOUND_MIXER_WRITE_OGAIN 0x4d0D -#define LINUX_SOUND_MIXER_WRITE_LINE1 0x4d0E -#define LINUX_SOUND_MIXER_WRITE_LINE2 0x4d0F -#define LINUX_SOUND_MIXER_WRITE_LINE3 0x4d10 -#define LINUX_SOUND_MIXER_WRITE_MONITOR 0x4d18 -#define LINUX_SOUND_MIXER_INFO 0x4d65 -#define LINUX_OSS_GETVERSION 0x4d76 -#define LINUX_SOUND_MIXER_READ_STEREODEVS 0x4dfb -#define LINUX_SOUND_MIXER_READ_CAPS 0x4dfc -#define LINUX_SOUND_MIXER_READ_RECMASK 0x4dfd -#define LINUX_SOUND_MIXER_READ_DEVMASK 0x4dfe -#define LINUX_SOUND_MIXER_WRITE_RECSRC 0x4dff -#define LINUX_SNDCTL_DSP_RESET 0x5000 -#define LINUX_SNDCTL_DSP_SYNC 0x5001 -#define LINUX_SNDCTL_DSP_SPEED 0x5002 -#define LINUX_SNDCTL_DSP_STEREO 0x5003 -#define LINUX_SNDCTL_DSP_GETBLKSIZE 0x5004 -#define LINUX_SNDCTL_DSP_SETBLKSIZE LINUX_SNDCTL_DSP_GETBLKSIZE -#define LINUX_SNDCTL_DSP_SETFMT 0x5005 -#define LINUX_SOUND_PCM_WRITE_CHANNELS 0x5006 -#define LINUX_SOUND_PCM_WRITE_FILTER 0x5007 -#define LINUX_SNDCTL_DSP_POST 0x5008 -#define LINUX_SNDCTL_DSP_SUBDIVIDE 0x5009 -#define LINUX_SNDCTL_DSP_SETFRAGMENT 0x500A -#define LINUX_SNDCTL_DSP_GETFMTS 0x500B -#define LINUX_SNDCTL_DSP_GETOSPACE 0x500C -#define LINUX_SNDCTL_DSP_GETISPACE 0x500D -#define LINUX_SNDCTL_DSP_NONBLOCK 0x500E -#define LINUX_SNDCTL_DSP_GETCAPS 0x500F -#define LINUX_SNDCTL_DSP_GETTRIGGER 0x5010 -#define LINUX_SNDCTL_DSP_SETTRIGGER LINUX_SNDCTL_DSP_GETTRIGGER -#define LINUX_SNDCTL_DSP_GETIPTR 0x5011 -#define LINUX_SNDCTL_DSP_GETOPTR 0x5012 -#define LINUX_SNDCTL_DSP_SETDUPLEX 0x5016 -#define LINUX_SNDCTL_DSP_GETODELAY 0x5017 -#define LINUX_SNDCTL_SEQ_RESET 0x5100 -#define LINUX_SNDCTL_SEQ_SYNC 0x5101 -#define LINUX_SNDCTL_SYNTH_INFO 0x5102 -#define LINUX_SNDCTL_SEQ_CTRLRATE 0x5103 -#define LINUX_SNDCTL_SEQ_GETOUTCOUNT 0x5104 -#define LINUX_SNDCTL_SEQ_GETINCOUNT 0x5105 -#define LINUX_SNDCTL_SEQ_PERCMODE 0x5106 -#define LINUX_SNDCTL_FM_LOAD_INSTR 0x5107 -#define LINUX_SNDCTL_SEQ_TESTMIDI 0x5108 -#define LINUX_SNDCTL_SEQ_RESETSAMPLES 0x5109 -#define LINUX_SNDCTL_SEQ_NRSYNTHS 0x510A -#define LINUX_SNDCTL_SEQ_NRMIDIS 0x510B -#define LINUX_SNDCTL_MIDI_INFO 0x510C -#define LINUX_SNDCTL_SEQ_TRESHOLD 0x510D -#define LINUX_SNDCTL_SYNTH_MEMAVL 0x510E - -#define LINUX_IOCTL_SOUND_MIN LINUX_SOUND_MIXER_WRITE_VOLUME -#define LINUX_IOCTL_SOUND_MAX LINUX_SNDCTL_SYNTH_MEMAVL - -/* - * termio - */ -#define LINUX_TCGETS 0x5401 -#define LINUX_TCSETS 0x5402 -#define LINUX_TCSETSW 0x5403 -#define LINUX_TCSETSF 0x5404 -#define LINUX_TCGETA 0x5405 -#define LINUX_TCSETA 0x5406 -#define LINUX_TCSETAW 0x5407 -#define LINUX_TCSETAF 0x5408 -#define LINUX_TCSBRK 0x5409 -#define LINUX_TCXONC 0x540A -#define LINUX_TCFLSH 0x540B - -#define LINUX_TIOCEXCL 0x540C -#define LINUX_TIOCNXCL 0x540D -#define LINUX_TIOCSCTTY 0x540E - -#define LINUX_TIOCGPGRP 0x540F -#define LINUX_TIOCSPGRP 0x5410 - -#define LINUX_TIOCOUTQ 0x5411 -#define LINUX_TIOCSTI 0x5412 - -#define LINUX_TIOCGWINSZ 0x5413 -#define LINUX_TIOCSWINSZ 0x5414 - -#define LINUX_TIOCMGET 0x5415 -#define LINUX_TIOCMBIS 0x5416 -#define LINUX_TIOCMBIC 0x5417 -#define LINUX_TIOCMSET 0x5418 -#define LINUX_TIOCGSOFTCAR 0x5419 -#define LINUX_TIOCSSOFTCAR 0x541A - -#define LINUX_FIONREAD 0x541B - -#define LINUX_TIOCINQ FIONREAD -#define LINUX_TIOCLINUX 0x541C -#define LINUX_TIOCCONS 0x541D -#define LINUX_TIOCGSERIAL 0x541E -#define LINUX_TIOCSSERIAL 0x541F -#define LINUX_TIOCPKT 0x5420 - -#define LINUX_FIONBIO 0x5421 - -#define LINUX_TIOCNOTTY 0x5422 -#define LINUX_TIOCSETD 0x5423 -#define LINUX_TIOCGETD 0x5424 -#define LINUX_TCSBRKP 0x5425 -#define LINUX_TIOCTTYGSTRUCT 0x5426 - -#define LINUX_TIOCSBRK 0x5427 -#define LINUX_TIOCCBRK 0x5428 - -#define LINUX_TIOCGPTN 0x5430 -#define LINUX_TIOCSPTLCK 0x5431 - -#define LINUX_TIOCGPTPEER 0x5441 - -#define LINUX_FIONCLEX 0x5450 -#define LINUX_FIOCLEX 0x5451 -#define LINUX_FIOASYNC 0x5452 - -#define LINUX_TIOCSERCONFIG 0x5453 -#define LINUX_TIOCSERGWILD 0x5454 -#define LINUX_TIOCSERSWILD 0x5455 -#define LINUX_TIOCGLCKTRMIOS 0x5456 -#define LINUX_TIOCSLCKTRMIOS 0x5457 - -#define LINUX_IOCTL_TERMIO_MIN LINUX_TCGETS -#define LINUX_IOCTL_TERMIO_MAX LINUX_TIOCSLCKTRMIOS - -/* arguments for tcflow() and LINUX_TCXONC */ -#define LINUX_TCOOFF 0 -#define LINUX_TCOON 1 -#define LINUX_TCIOFF 2 -#define LINUX_TCION 3 - -/* arguments for tcflush() and LINUX_TCFLSH */ -#define LINUX_TCIFLUSH 0 -#define LINUX_TCOFLUSH 1 -#define LINUX_TCIOFLUSH 2 - -/* line disciplines */ -#define LINUX_N_TTY 0 -#define LINUX_N_SLIP 1 -#define LINUX_N_MOUSE 2 -#define LINUX_N_PPP 3 - -/* Linux termio c_cc values */ -#define LINUX_VINTR 0 -#define LINUX_VQUIT 1 -#define LINUX_VERASE 2 -#define LINUX_VKILL 3 -#define LINUX_VEOF 4 -#define LINUX_VTIME 5 -#define LINUX_VMIN 6 -#define LINUX_VSWTC 7 -#define LINUX_NCC 8 - -/* Linux termios c_cc values */ -/* In addition to the termio values */ -#define LINUX_VSTART 8 -#define LINUX_VSTOP 9 -#define LINUX_VSUSP 10 -#define LINUX_VEOL 11 -#define LINUX_VREPRINT 12 -#define LINUX_VDISCARD 13 -#define LINUX_VWERASE 14 -#define LINUX_VLNEXT 15 -#define LINUX_VEOL2 16 -#define LINUX_VSTATUS 18 -#define LINUX_NCCS 19 - -#define LINUX_POSIX_VDISABLE '\0' - -/* Linux c_iflag masks */ -#define LINUX_IGNBRK 0x0000001 -#define LINUX_BRKINT 0x0000002 -#define LINUX_IGNPAR 0x0000004 -#define LINUX_PARMRK 0x0000008 -#define LINUX_INPCK 0x0000010 -#define LINUX_ISTRIP 0x0000020 -#define LINUX_INLCR 0x0000040 -#define LINUX_IGNCR 0x0000080 -#define LINUX_ICRNL 0x0000100 - -#define LINUX_IUCLC 0x0000200 -#define LINUX_IXON 0x0000400 -#define LINUX_IXANY 0x0000800 -#define LINUX_IXOFF 0x0001000 - -#define LINUX_IMAXBEL 0x0002000 - -/* Linux c_oflag masks */ -#define LINUX_OPOST 0x0000001 - -#define LINUX_OLCUC 0x0000002 -#define LINUX_ONLCR 0x0000004 - -#define LINUX_OCRNL 0x0000008 -#define LINUX_ONOCR 0x0000010 -#define LINUX_ONLRET 0x0000020 -#define LINUX_OFILL 0x0000040 -#define LINUX_OFDEL 0x0000080 - -#define LINUX_NLDLY 0x0000100 -#define LINUX_NL0 0x0000000 -#define LINUX_NL1 0x0000100 -#define LINUX_CRDLY 0x0000600 -#define LINUX_CR0 0x0000000 -#define LINUX_CR1 0x0000200 -#define LINUX_CR2 0x0000400 -#define LINUX_CR3 0x0000600 -#define LINUX_TABDLY 0x0001800 -#define LINUX_TAB0 0x0000000 -#define LINUX_TAB1 0x0000800 -#define LINUX_TAB2 0x0001000 -#define LINUX_TAB3 0x0001800 -#define LINUX_XTABS 0x0001800 -#define LINUX_BSDLY 0x0002000 -#define LINUX_BS0 0x0000000 -#define LINUX_BS1 0x0002000 -#define LINUX_VTDLY 0x0004000 -#define LINUX_VT0 0x0000000 -#define LINUX_VT1 0x0004000 -#define LINUX_FFDLY 0x0008000 -#define LINUX_FF0 0x0000000 -#define LINUX_FF1 0x0008000 - -#define LINUX_CBAUD 0x0000100f - -#define LINUX_B0 0x00000000 -#define LINUX_B50 0x00000001 -#define LINUX_B75 0x00000002 -#define LINUX_B110 0x00000003 -#define LINUX_B134 0x00000004 -#define LINUX_B150 0x00000005 -#define LINUX_B200 0x00000006 -#define LINUX_B300 0x00000007 -#define LINUX_B600 0x00000008 -#define LINUX_B1200 0x00000009 -#define LINUX_B1800 0x0000000a -#define LINUX_B2400 0x0000000b -#define LINUX_B4800 0x0000000c -#define LINUX_B9600 0x0000000d -#define LINUX_B19200 0x0000000e -#define LINUX_B38400 0x0000000f -#define LINUX_EXTA LINUX_B19200 -#define LINUX_EXTB LINUX_B38400 - -#define LINUX_CBAUDEX 0x00001000 -#define LINUX_B57600 0x00001001 -#define LINUX_B115200 0x00001002 - -#define LINUX_CSIZE 0x00000030 -#define LINUX_CS5 0x00000000 -#define LINUX_CS6 0x00000010 -#define LINUX_CS7 0x00000020 -#define LINUX_CS8 0x00000030 -#define LINUX_CSTOPB 0x00000040 -#define LINUX_CREAD 0x00000080 -#define LINUX_PARENB 0x00000100 -#define LINUX_PARODD 0x00000200 -#define LINUX_HUPCL 0x00000400 -#define LINUX_CLOCAL 0x00000800 - -#define LINUX_CRTSCTS 0x80000000 - -/* Linux c_lflag masks */ -#define LINUX_ISIG 0x00000001 -#define LINUX_ICANON 0x00000002 -#define LINUX_XCASE 0x00000004 -#define LINUX_ECHO 0x00000008 -#define LINUX_ECHOE 0x00000010 -#define LINUX_ECHOK 0x00000020 -#define LINUX_ECHONL 0x00000040 -#define LINUX_NOFLSH 0x00000080 -#define LINUX_TOSTOP 0x00000100 -#define LINUX_ECHOCTL 0x00000200 -#define LINUX_ECHOPRT 0x00000400 -#define LINUX_ECHOKE 0x00000800 -#define LINUX_FLUSHO 0x00001000 -#define LINUX_PENDIN 0x00002000 -#define LINUX_IEXTEN 0x00008000 - -/* serial_struct values for TIOC[GS]SERIAL ioctls */ -#define LINUX_ASYNC_CLOSING_WAIT_INF 0 -#define LINUX_ASYNC_CLOSING_WAIT_NONE 65535 - -#define LINUX_PORT_UNKNOWN 0 -#define LINUX_PORT_8250 1 -#define LINUX_PORT_16450 2 -#define LINUX_PORT_16550 3 -#define LINUX_PORT_16550A 4 -#define LINUX_PORT_CIRRUS 5 -#define LINUX_PORT_16650 6 - -#define LINUX_PORT_MAX 6 - -#define LINUX_ASYNC_HUP_NOTIFY 0x0001 -#define LINUX_ASYNC_FOURPORT 0x0002 -#define LINUX_ASYNC_SAK 0x0004 -#define LINUX_ASYNC_SPLIT_TERMIOS 0x0008 -#define LINUX_ASYNC_SPD_MASK 0x0030 -#define LINUX_ASYNC_SPD_HI 0x0010 -#define LINUX_ASYNC_SPD_VHI 0x0020 -#define LINUX_ASYNC_SPD_CUST 0x0030 -#define LINUX_ASYNC_SKIP_TEST 0x0040 -#define LINUX_ASYNC_AUTO_IRQ 0x0080 -#define LINUX_ASYNC_SESSION_LOCKOUT 0x0100 -#define LINUX_ASYNC_PGRP_LOCKOUT 0x0200 -#define LINUX_ASYNC_CALLOUT_NOHUP 0x0400 -#define LINUX_ASYNC_FLAGS 0x0FFF - -#define LINUX_IOCTL_DRM_MIN 0x6400 -#define LINUX_IOCTL_DRM_MAX 0x64ff - -/* - * video - */ -#define LINUX_VIDIOCGCAP 0x7601 -#define LINUX_VIDIOCGCHAN 0x7602 -#define LINUX_VIDIOCSCHAN 0x7603 -#define LINUX_VIDIOCGTUNER 0x7604 -#define LINUX_VIDIOCSTUNER 0x7605 -#define LINUX_VIDIOCGPICT 0x7606 -#define LINUX_VIDIOCSPICT 0x7607 -#define LINUX_VIDIOCCAPTURE 0x7608 -#define LINUX_VIDIOCGWIN 0x7609 -#define LINUX_VIDIOCSWIN 0x760a -#define LINUX_VIDIOCGFBUF 0x760b -#define LINUX_VIDIOCSFBUF 0x760c -#define LINUX_VIDIOCKEY 0x760d -#define LINUX_VIDIOCGFREQ 0x760e -#define LINUX_VIDIOCSFREQ 0x760f -#define LINUX_VIDIOCGAUDIO 0x7610 -#define LINUX_VIDIOCSAUDIO 0x7611 -#define LINUX_VIDIOCSYNC 0x7623 -#define LINUX_VIDIOCMCAPTURE 0x7613 -#define LINUX_VIDIOCGMBUF 0x7614 -#define LINUX_VIDIOCGUNIT 0x7615 -#define LINUX_VIDIOCGCAPTURE 0x7616 -#define LINUX_VIDIOCSCAPTURE 0x7617 -#define LINUX_VIDIOCSPLAYMODE 0x7618 -#define LINUX_VIDIOCSWRITEMODE 0x7619 -#define LINUX_VIDIOCGPLAYINFO 0x761a -#define LINUX_VIDIOCSMICROCODE 0x761b -#define LINUX_VIDIOCGVBIFMT 0x761c -#define LINUX_VIDIOCSVBIFMT 0x761d - -#define LINUX_IOCTL_VIDEO_MIN LINUX_VIDIOCGCAP -#define LINUX_IOCTL_VIDEO_MAX LINUX_VIDIOCSVBIFMT - -/* videodev2 aka V4L2 */ - -#define LINUX_VIDIOC_QUERYCAP 0x5600 /* 0x80685600 */ -#define LINUX_VIDIOC_RESERVED 0x5601 /* 0x00005601 */ -#define LINUX_VIDIOC_ENUM_FMT 0x5602 /* 0xc0405602 */ -#define LINUX_VIDIOC_G_FMT 0x5604 /* 0xc0cc5604 */ -#define LINUX_VIDIOC_S_FMT 0x5605 /* 0xc0cc5605 */ -#define LINUX_VIDIOC_REQBUFS 0x5608 /* 0xc0145608 */ -#define LINUX_VIDIOC_QUERYBUF 0x5609 /* 0xc0445609 */ -#define LINUX_VIDIOC_G_FBUF 0x560a /* 0x802c560a */ -#define LINUX_VIDIOC_S_FBUF 0x560b /* 0x402c560b */ -#define LINUX_VIDIOC_OVERLAY 0x560e /* 0x4004560e */ -#define LINUX_VIDIOC_QBUF 0x560f /* 0xc044560f */ -#define LINUX_VIDIOC_DQBUF 0x5611 /* 0xc0445611 */ -#define LINUX_VIDIOC_STREAMON 0x5612 /* 0x40045612 */ -#define LINUX_VIDIOC_STREAMOFF 0x5613 /* 0x40045613 */ -#define LINUX_VIDIOC_G_PARM 0x5615 /* 0xc0cc5615 */ -#define LINUX_VIDIOC_S_PARM 0x5616 /* 0xc0cc5616 */ -#define LINUX_VIDIOC_G_STD 0x5617 /* 0x80085617 */ -#define LINUX_VIDIOC_S_STD 0x5618 /* 0x40085618 */ -#define LINUX_VIDIOC_ENUMSTD 0x5619 /* 0xc0405619 */ -#define LINUX_VIDIOC_ENUMINPUT 0x561a /* 0xc04c561a */ -#define LINUX_VIDIOC_G_CTRL 0x561b /* 0xc008561b */ -#define LINUX_VIDIOC_S_CTRL 0x561c /* 0xc008561c */ -#define LINUX_VIDIOC_G_TUNER 0x561d /* 0xc054561d */ -#define LINUX_VIDIOC_S_TUNER 0x561e /* 0x4054561e */ -#define LINUX_VIDIOC_G_AUDIO 0x5621 /* 0x80345621 */ -#define LINUX_VIDIOC_S_AUDIO 0x5622 /* 0x40345622 */ -#define LINUX_VIDIOC_QUERYCTRL 0x5624 /* 0xc0445624 */ -#define LINUX_VIDIOC_QUERYMENU 0x5625 /* 0xc02c5625 */ -#define LINUX_VIDIOC_G_INPUT 0x5626 /* 0x80045626 */ -#define LINUX_VIDIOC_S_INPUT 0x5627 /* 0xc0045627 */ -#define LINUX_VIDIOC_G_OUTPUT 0x562e /* 0x8004562e */ -#define LINUX_VIDIOC_S_OUTPUT 0x562f /* 0xc004562f */ -#define LINUX_VIDIOC_ENUMOUTPUT 0x5630 /* 0xc0485630 */ -#define LINUX_VIDIOC_G_AUDOUT 0x5631 /* 0x80345631 */ -#define LINUX_VIDIOC_S_AUDOUT 0x5632 /* 0x40345632 */ -#define LINUX_VIDIOC_G_MODULATOR 0x5636 /* 0xc0445636 */ -#define LINUX_VIDIOC_S_MODULATOR 0x5637 /* 0x40445637 */ -#define LINUX_VIDIOC_G_FREQUENCY 0x5638 /* 0xc02c5638 */ -#define LINUX_VIDIOC_S_FREQUENCY 0x5639 /* 0x402c5639 */ -#define LINUX_VIDIOC_CROPCAP 0x563a /* 0xc02c563a */ -#define LINUX_VIDIOC_G_CROP 0x563b /* 0xc014563b */ -#define LINUX_VIDIOC_S_CROP 0x563c /* 0x4014563c */ -#define LINUX_VIDIOC_G_JPEGCOMP 0x563d /* 0x808c563d */ -#define LINUX_VIDIOC_S_JPEGCOMP 0x563e /* 0x408c563e */ -#define LINUX_VIDIOC_QUERYSTD 0x563f /* 0x8008563f */ -#define LINUX_VIDIOC_TRY_FMT 0x5640 /* 0xc0cc5640 */ -#define LINUX_VIDIOC_ENUMAUDIO 0x5641 /* 0xc0345641 */ -#define LINUX_VIDIOC_ENUMAUDOUT 0x5642 /* 0xc0345642 */ -#define LINUX_VIDIOC_G_PRIORITY 0x5643 /* 0x80045643 */ -#define LINUX_VIDIOC_S_PRIORITY 0x5644 /* 0x40045644 */ -#define LINUX_VIDIOC_G_SLICED_VBI_CAP 0x5645 /* 0xc0745645 */ -#define LINUX_VIDIOC_LOG_STATUS 0x5646 /* 0x00005646 */ -#define LINUX_VIDIOC_G_EXT_CTRLS 0x5647 /* 0xc0185647 */ -#define LINUX_VIDIOC_S_EXT_CTRLS 0x5648 /* 0xc0185648 */ -#define LINUX_VIDIOC_TRY_EXT_CTRLS 0x5649 /* 0xc0185649 */ -#define LINUX_VIDIOC_ENUM_FRAMESIZES 0x564a /* 0xc02c564a */ -#define LINUX_VIDIOC_ENUM_FRAMEINTERVALS 0x564b /* 0xc034564b */ -#define LINUX_VIDIOC_G_ENC_INDEX 0x564c /* 0x8818564c */ -#define LINUX_VIDIOC_ENCODER_CMD 0x564d /* 0xc028564d */ -#define LINUX_VIDIOC_TRY_ENCODER_CMD 0x564e /* 0xc028564e */ -#define LINUX_VIDIOC_DBG_S_REGISTER 0x564f /* 0x4038564f */ -#define LINUX_VIDIOC_DBG_G_REGISTER 0x5650 /* 0xc0385650 */ -#define LINUX_VIDIOC_DBG_G_CHIP_IDENT 0x5651 /* 0xc02c5651 */ -#define LINUX_VIDIOC_S_HW_FREQ_SEEK 0x5652 /* 0x40305652 */ -#define LINUX_VIDIOC_ENUM_DV_PRESETS 0x5653 /* 0xc0405653 */ -#define LINUX_VIDIOC_S_DV_PRESET 0x5654 /* 0xc0145654 */ -#define LINUX_VIDIOC_G_DV_PRESET 0x5655 /* 0xc0145655 */ -#define LINUX_VIDIOC_QUERY_DV_PRESET 0x5656 /* 0x80145656 */ -#define LINUX_VIDIOC_S_DV_TIMINGS 0x5657 /* 0xc0845657 */ -#define LINUX_VIDIOC_G_DV_TIMINGS 0x5658 /* 0xc0845658 */ -#define LINUX_VIDIOC_DQEVENT 0x5659 /* 0x80785659 */ -#define LINUX_VIDIOC_SUBSCRIBE_EVENT 0x565a /* 0x4020565a */ -#define LINUX_VIDIOC_UNSUBSCRIBE_EVENT 0x565b /* 0x4020565b */ - -#define LINUX_VIDIOC_OVERLAY_OLD 0x560e /* 0xc004560e */ -#define LINUX_VIDIOC_S_PARM_OLD 0x5616 /* 0x40cc5616 */ -#define LINUX_VIDIOC_S_CTRL_OLD 0x561c /* 0x4008561c */ -#define LINUX_VIDIOC_G_AUDIO_OLD 0x5621 /* 0xc0345621 */ -#define LINUX_VIDIOC_G_AUDOUT_OLD 0x5631 /* 0xc0345631 */ -#define LINUX_VIDIOC_CROPCAP_OLD 0x563a /* 0x802c563a */ - -#define LINUX_IOCTL_VIDEO2_MIN LINUX_VIDIOC_QUERYCAP -#define LINUX_IOCTL_VIDEO2_MAX LINUX_VIDIOC_UNSUBSCRIBE_EVENT - -#define LINUX_F2FS_IOC_GET_FEATURES 0xf50c /* 0x8004f50c */ - -#define LINUX_IOCTL_F2FS_MIN 0xf500 -#define LINUX_IOCTL_F2FS_MAX LINUX_F2FS_IOC_GET_FEATURES - -/* - * Our libusb(8) calls emulated within linux(4). - */ -#define FBSD_LUSB_DEVICEENUMERATE 0xffff -#define FBSD_LUSB_DEV_QUIRK_ADD 0xfffe -#define FBSD_LUSB_DEV_QUIRK_GET 0xfffd -#define FBSD_LUSB_DEV_QUIRK_REMOVE 0xfffc -#define FBSD_LUSB_DO_REQUEST 0xfffb -#define FBSD_LUSB_FS_CLEAR_STALL_SYNC 0xfffa -#define FBSD_LUSB_FS_CLOSE 0xfff9 -#define FBSD_LUSB_FS_COMPLETE 0xfff8 -#define FBSD_LUSB_FS_INIT 0xfff7 -#define FBSD_LUSB_FS_OPEN 0xfff6 -#define FBSD_LUSB_FS_START 0xfff5 -#define FBSD_LUSB_FS_STOP 0xfff4 -#define FBSD_LUSB_FS_UNINIT 0xfff3 -#define FBSD_LUSB_GET_CONFIG 0xfff2 -#define FBSD_LUSB_GET_DEVICEINFO 0xfff1 -#define FBSD_LUSB_GET_DEVICE_DESC 0xfff0 -#define FBSD_LUSB_GET_FULL_DESC 0xffef -#define FBSD_LUSB_GET_IFACE_DRIVER 0xffee -#define FBSD_LUSB_GET_PLUGTIME 0xffed -#define FBSD_LUSB_GET_POWER_MODE 0xffec -#define FBSD_LUSB_GET_REPORT_DESC 0xffeb -#define FBSD_LUSB_GET_REPORT_ID 0xffea -#define FBSD_LUSB_GET_TEMPLATE 0xffe9 -#define FBSD_LUSB_IFACE_DRIVER_ACTIVE 0xffe8 -#define FBSD_LUSB_IFACE_DRIVER_DETACH 0xffe7 -#define FBSD_LUSB_QUIRK_NAME_GET 0xffe6 -#define FBSD_LUSB_READ_DIR 0xffe5 -#define FBSD_LUSB_SET_ALTINTERFACE 0xffe4 -#define FBSD_LUSB_SET_CONFIG 0xffe3 -#define FBSD_LUSB_SET_IMMED 0xffe2 -#define FBSD_LUSB_SET_POWER_MODE 0xffe1 -#define FBSD_LUSB_SET_TEMPLATE 0xffe0 -#define FBSD_LUSB_FS_OPEN_STREAM 0xffdf -#define FBSD_LUSB_GET_DEV_PORT_PATH 0xffde -#define FBSD_LUSB_GET_POWER_USAGE 0xffdd -#define FBSD_LUSB_DEVICESTATS 0xffdc - -#define LINUX_IOCTL_FBSD_LUSB_MAX 0xffff -#define LINUX_IOCTL_FBSD_LUSB_MIN 0xffdc - -/* - * Linux btrfs clone operation - */ -#define LINUX_BTRFS_IOC_CLONE 0x9409 /* 0x40049409 */ -#define LINUX_FS_IOC_FIEMAP 0x660b - -/* - * Linux evdev ioctl min and max - */ -#define LINUX_IOCTL_EVDEV_MIN 0x4500 -#define LINUX_IOCTL_EVDEV_MAX 0x45ff -#define LINUX_IOCTL_EVDEV_CLK LINUX_CLOCK_REALTIME | \ - LINUX_CLOCK_MONOTONIC |LINUX_CLOCK_BOOTTIME - -/* - * kcov(4) shims - */ -#define LINUX_IOCTL_KCOV_MIN 0x6300 -#define LINUX_IOCTL_KCOV_MAX 0x63ff -#define LINUX_KCOV_INIT_TRACE 0x6301 -#define LINUX_KCOV_ENABLE 0x6364 -#define LINUX_KCOV_DISABLE 0x6365 -#define LINUX_KCOV_REMOTE_ENABLE 0x6366 - -/* - * NVMe IOCTLs defined by Linux - */ -#define LINUX_NVME_IOCTL_ID 0x4e40 -#define LINUX_NVME_IOCTL_ADMIN_CMD 0x4e41 -#define LINUX_NVME_IOCTL_SUBMIT_IO 0x4e42 -#define LINUX_NVME_IOCTL_IO_CMD 0x4e43 -#define LINUX_NVME_IOCTL_RESET 0x4e44 -#define LINUX_NVME_IOCTL_SUBSYS_RESET 0x4e45 -#define LINUX_NVME_IOCTL_RESCAN 0x4e46 - -#define LINUX_IOCTL_NVME_MIN LINUX_NVME_IOCTL_ID -#define LINUX_IOCTL_NVME_MAX LINUX_NVME_IOCTL_RESCAN - -/* - * Pluggable ioctl handlers - */ -struct linux_ioctl_args; -struct thread; - -typedef int linux_ioctl_function_t(struct thread *, struct linux_ioctl_args *); - -struct linux_ioctl_handler { - linux_ioctl_function_t *func; - int low, high; -}; - -struct linux_ioctl_handler_element -{ - TAILQ_ENTRY(linux_ioctl_handler_element) list; - int (*func)(struct thread *, struct linux_ioctl_args *); - int low, high, span; -}; - -int linux_ioctl_register_handler(struct linux_ioctl_handler *h); -int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h); -#ifdef COMPAT_LINUX32 -int linux32_ioctl_register_handler(struct linux_ioctl_handler *h); -int linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h); -#endif - -#endif /* !_LINUX_IOCTL_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 Marcel Moolenaar + * 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. + */ + +#ifndef _LINUX_IOCTL_H_ +#define _LINUX_IOCTL_H_ + +/* + * ioctl + * + * XXX comments in Linux' indicate these + * could be arch-dependant... + */ +#define LINUX_IOC_VOID 0 +#define LINUX_IOC_IN 0x40000000 +#define LINUX_IOC_OUT 0x80000000 +#define LINUX_IOC_INOUT (LINUX_IOC_IN|LINUX_IOC_OUT) + +/* + * disk + */ +#define LINUX_BLKROSET 0x125d +#define LINUX_BLKROGET 0x125e +#define LINUX_BLKRRPART 0x125f +#define LINUX_BLKGETSIZE 0x1260 +#define LINUX_BLKFLSBUF 0x1261 +#define LINUX_BLKRASET 0x1262 +#define LINUX_BLKRAGET 0x1263 +#define LINUX_BLKFRASET 0x1264 +#define LINUX_BLKFRAGET 0x1265 +#define LINUX_BLKSECTSET 0x1266 +#define LINUX_BLKSECTGET 0x1267 +#define LINUX_BLKSSZGET 0x1268 +#define LINUX_BLKGETSIZE64 0x1272 +#define LINUX_BLKPBSZGET 0x127b + +#define LINUX_IOCTL_DISK_MIN LINUX_BLKROSET +#define LINUX_IOCTL_DISK_MAX LINUX_BLKPBSZGET + +/* + * hdio + */ +#define LINUX_HDIO_GET_GEO 0x0301 +#define LINUX_HDIO_GET_IDENTITY 0x030D /* not yet implemented */ +#define LINUX_HDIO_GET_GEO_BIG 0x0330 + +#define LINUX_IOCTL_HDIO_MIN LINUX_HDIO_GET_GEO +#define LINUX_IOCTL_HDIO_MAX LINUX_HDIO_GET_GEO_BIG + +/* + * cdrom + */ +#define LINUX_CDROMPAUSE 0x5301 +#define LINUX_CDROMRESUME 0x5302 +#define LINUX_CDROMPLAYMSF 0x5303 +#define LINUX_CDROMPLAYTRKIND 0x5304 +#define LINUX_CDROMREADTOCHDR 0x5305 +#define LINUX_CDROMREADTOCENTRY 0x5306 +#define LINUX_CDROMSTOP 0x5307 +#define LINUX_CDROMSTART 0x5308 +#define LINUX_CDROMEJECT 0x5309 +#define LINUX_CDROMVOLCTRL 0x530a +#define LINUX_CDROMSUBCHNL 0x530b +#define LINUX_CDROMREADMODE2 0x530c +#define LINUX_CDROMREADMODE1 0x530d +#define LINUX_CDROMREADAUDIO 0x530e +#define LINUX_CDROMEJECT_SW 0x530f +#define LINUX_CDROMMULTISESSION 0x5310 +#define LINUX_CDROM_GET_UPC 0x5311 +#define LINUX_CDROMRESET 0x5312 +#define LINUX_CDROMVOLREAD 0x5313 +#define LINUX_CDROMREADRAW 0x5314 +#define LINUX_CDROMREADCOOKED 0x5315 +#define LINUX_CDROMSEEK 0x5316 +#define LINUX_CDROMPLAYBLK 0x5317 +#define LINUX_CDROMREADALL 0x5318 +#define LINUX_CDROMCLOSETRAY 0x5319 +#define LINUX_CDROMLOADFROMSLOT 0x531a +#define LINUX_CDROMGETSPINDOWN 0x531d +#define LINUX_CDROMSETSPINDOWN 0x531e +#define LINUX_CDROM_SET_OPTIONS 0x5320 +#define LINUX_CDROM_CLEAR_OPTIONS 0x5321 +#define LINUX_CDROM_SELECT_SPEED 0x5322 +#define LINUX_CDROM_SELECT_DISC 0x5323 +#define LINUX_CDROM_MEDIA_CHANGED 0x5325 +#define LINUX_CDROM_DRIVE_STATUS 0x5326 +#define LINUX_CDROM_DISC_STATUS 0x5327 +#define LINUX_CDROM_CHANGER_NSLOTS 0x5328 +#define LINUX_CDROM_LOCKDOOR 0x5329 +#define LINUX_CDROM_DEBUG 0x5330 +#define LINUX_CDROM_GET_CAPABILITY 0x5331 +#define LINUX_CDROMAUDIOBUFSIZ 0x5382 +#define LINUX_SCSI_GET_IDLUN 0x5382 +#define LINUX_SCSI_GET_BUS_NUMBER 0x5386 +#define LINUX_DVD_READ_STRUCT 0x5390 +#define LINUX_DVD_WRITE_STRUCT 0x5391 +#define LINUX_DVD_AUTH 0x5392 +#define LINUX_CDROM_SEND_PACKET 0x5393 +#define LINUX_CDROM_NEXT_WRITABLE 0x5394 +#define LINUX_CDROM_LAST_WRITTEN 0x5395 + +#define LINUX_IOCTL_CDROM_MIN LINUX_CDROMPAUSE +#define LINUX_IOCTL_CDROM_MAX LINUX_CDROM_LAST_WRITTEN + +#define LINUX_CDROM_LBA 0x01 +#define LINUX_CDROM_MSF 0x02 + +#define LINUX_DVD_LU_SEND_AGID 0 +#define LINUX_DVD_HOST_SEND_CHALLENGE 1 +#define LINUX_DVD_LU_SEND_KEY1 2 +#define LINUX_DVD_LU_SEND_CHALLENGE 3 +#define LINUX_DVD_HOST_SEND_KEY2 4 +#define LINUX_DVD_AUTH_ESTABLISHED 5 +#define LINUX_DVD_AUTH_FAILURE 6 +#define LINUX_DVD_LU_SEND_TITLE_KEY 7 +#define LINUX_DVD_LU_SEND_ASF 8 +#define LINUX_DVD_INVALIDATE_AGID 9 +#define LINUX_DVD_LU_SEND_RPC_STATE 10 +#define LINUX_DVD_HOST_SEND_RPC_STATE 11 + +/* + * SG + */ +#define LINUX_SG_SET_TIMEOUT 0x2201 +#define LINUX_SG_GET_TIMEOUT 0x2202 +#define LINUX_SG_EMULATED_HOST 0x2203 +#define LINUX_SG_SET_TRANSFORM 0x2204 +#define LINUX_SG_GET_TRANSFORM 0x2205 +#define LINUX_SG_GET_COMMAND_Q 0x2270 +#define LINUX_SG_SET_COMMAND_Q 0x2271 +#define LINUX_SG_SET_RESERVED_SIZE 0x2275 +#define LINUX_SG_GET_RESERVED_SIZE 0x2272 +#define LINUX_SG_GET_SCSI_ID 0x2276 +#define LINUX_SG_SET_FORCE_LOW_DMA 0x2279 +#define LINUX_SG_GET_LOW_DMA 0x227a +#define LINUX_SG_SET_FORCE_PACK_ID 0x227b +#define LINUX_SG_GET_PACK_ID 0x227c +#define LINUX_SG_GET_NUM_WAITING 0x227d +#define LINUX_SG_SET_DEBUG 0x227e +#define LINUX_SG_GET_SG_TABLESIZE 0x227f +#define LINUX_SG_GET_VERSION_NUM 0x2282 +#define LINUX_SG_NEXT_CMD_LEN 0x2283 +#define LINUX_SG_SCSI_RESET 0x2284 +#define LINUX_SG_IO 0x2285 +#define LINUX_SG_GET_REQUEST_TABLE 0x2286 +#define LINUX_SG_SET_KEEP_ORPHAN 0x2287 +#define LINUX_SG_GET_KEEP_ORPHAN 0x2288 +#define LINUX_SG_GET_ACCESS_COUNT 0x2289 + +#define LINUX_IOCTL_SG_MIN 0x2200 +#define LINUX_IOCTL_SG_MAX 0x22ff + +/* + * VFAT + */ +#define LINUX_VFAT_READDIR_BOTH 0x7201 + +#define LINUX_IOCTL_VFAT_MIN LINUX_VFAT_READDIR_BOTH +#define LINUX_IOCTL_VFAT_MAX LINUX_VFAT_READDIR_BOTH + +/* + * console + */ +#define LINUX_KIOCSOUND 0x4B2F +#define LINUX_KDMKTONE 0x4B30 +#define LINUX_KDGETLED 0x4B31 +#define LINUX_KDSETLED 0x4B32 +#define LINUX_KDSETMODE 0x4B3A +#define LINUX_KDGETMODE 0x4B3B +#define LINUX_KDGKBMODE 0x4B44 +#define LINUX_KDSKBMODE 0x4B45 +#define LINUX_VT_OPENQRY 0x5600 +#define LINUX_VT_GETMODE 0x5601 +#define LINUX_VT_SETMODE 0x5602 +#define LINUX_VT_GETSTATE 0x5603 +#define LINUX_VT_RELDISP 0x5605 +#define LINUX_VT_ACTIVATE 0x5606 +#define LINUX_VT_WAITACTIVE 0x5607 + +#define LINUX_IOCTL_CONSOLE_MIN LINUX_KIOCSOUND +#define LINUX_IOCTL_CONSOLE_MAX LINUX_VT_WAITACTIVE + +#define LINUX_LED_SCR 0x01 +#define LINUX_LED_NUM 0x02 +#define LINUX_LED_CAP 0x04 + +#define LINUX_KD_TEXT 0x0 +#define LINUX_KD_GRAPHICS 0x1 +#define LINUX_KD_TEXT0 0x2 +#define LINUX_KD_TEXT1 0x3 + +#define LINUX_KBD_RAW 0 +#define LINUX_KBD_XLATE 1 +#define LINUX_KBD_MEDIUMRAW 2 + +/* + * socket + */ +#define LINUX_FIOSETOWN 0x8901 +#define LINUX_SIOCSPGRP 0x8902 +#define LINUX_FIOGETOWN 0x8903 +#define LINUX_SIOCGPGRP 0x8904 +#define LINUX_SIOCATMARK 0x8905 +#define LINUX_SIOCGSTAMP 0x8906 +#define LINUX_SIOCGIFNAME 0x8910 +#define LINUX_SIOCGIFCONF 0x8912 +#define LINUX_SIOCGIFFLAGS 0x8913 +#define LINUX_SIOCGIFADDR 0x8915 +#define LINUX_SIOCSIFADDR 0x8916 +#define LINUX_SIOCGIFDSTADDR 0x8917 +#define LINUX_SIOCGIFBRDADDR 0x8919 +#define LINUX_SIOCGIFNETMASK 0x891b +#define LINUX_SIOCSIFNETMASK 0x891c +#define LINUX_SIOCGIFMETRIC 0x891d +#define LINUX_SIOCSIFMETRIC 0x891e +#define LINUX_SIOCGIFMTU 0x8921 +#define LINUX_SIOCSIFMTU 0x8922 +#define LINUX_SIOCSIFNAME 0x8923 +#define LINUX_SIOCSIFHWADDR 0x8924 +#define LINUX_SIOCGIFHWADDR 0x8927 +#define LINUX_SIOCADDMULTI 0x8931 +#define LINUX_SIOCDELMULTI 0x8932 +#define LINUX_SIOCGIFINDEX 0x8933 +#define LINUX_SIOGIFINDEX LINUX_SIOCGIFINDEX +#define LINUX_SIOCGIFCOUNT 0x8938 + +#define LINUX_IOCTL_SOCKET_MIN LINUX_FIOSETOWN +#define LINUX_IOCTL_SOCKET_MAX LINUX_SIOCGIFCOUNT + +/* + * Device private ioctl calls + */ +#define LINUX_SIOCDEVPRIVATE 0x89F0 /* to 89FF */ +#define LINUX_IOCTL_PRIVATE_MIN LINUX_SIOCDEVPRIVATE +#define LINUX_IOCTL_PRIVATE_MAX LINUX_SIOCDEVPRIVATE+0xf + +/* + * sound + */ +#define LINUX_SOUND_MIXER_WRITE_VOLUME 0x4d00 +#define LINUX_SOUND_MIXER_WRITE_BASS 0x4d01 +#define LINUX_SOUND_MIXER_WRITE_TREBLE 0x4d02 +#define LINUX_SOUND_MIXER_WRITE_SYNTH 0x4d03 +#define LINUX_SOUND_MIXER_WRITE_PCM 0x4d04 +#define LINUX_SOUND_MIXER_WRITE_SPEAKER 0x4d05 +#define LINUX_SOUND_MIXER_WRITE_LINE 0x4d06 +#define LINUX_SOUND_MIXER_WRITE_MIC 0x4d07 +#define LINUX_SOUND_MIXER_WRITE_CD 0x4d08 +#define LINUX_SOUND_MIXER_WRITE_IMIX 0x4d09 +#define LINUX_SOUND_MIXER_WRITE_ALTPCM 0x4d0A +#define LINUX_SOUND_MIXER_WRITE_RECLEV 0x4d0B +#define LINUX_SOUND_MIXER_WRITE_IGAIN 0x4d0C +#define LINUX_SOUND_MIXER_WRITE_OGAIN 0x4d0D +#define LINUX_SOUND_MIXER_WRITE_LINE1 0x4d0E +#define LINUX_SOUND_MIXER_WRITE_LINE2 0x4d0F +#define LINUX_SOUND_MIXER_WRITE_LINE3 0x4d10 +#define LINUX_SOUND_MIXER_WRITE_MONITOR 0x4d18 +#define LINUX_SOUND_MIXER_INFO 0x4d65 +#define LINUX_OSS_GETVERSION 0x4d76 +#define LINUX_SOUND_MIXER_READ_STEREODEVS 0x4dfb +#define LINUX_SOUND_MIXER_READ_CAPS 0x4dfc +#define LINUX_SOUND_MIXER_READ_RECMASK 0x4dfd +#define LINUX_SOUND_MIXER_READ_DEVMASK 0x4dfe +#define LINUX_SOUND_MIXER_WRITE_RECSRC 0x4dff +#define LINUX_SNDCTL_DSP_RESET 0x5000 +#define LINUX_SNDCTL_DSP_SYNC 0x5001 +#define LINUX_SNDCTL_DSP_SPEED 0x5002 +#define LINUX_SNDCTL_DSP_STEREO 0x5003 +#define LINUX_SNDCTL_DSP_GETBLKSIZE 0x5004 +#define LINUX_SNDCTL_DSP_SETBLKSIZE LINUX_SNDCTL_DSP_GETBLKSIZE +#define LINUX_SNDCTL_DSP_SETFMT 0x5005 +#define LINUX_SOUND_PCM_WRITE_CHANNELS 0x5006 +#define LINUX_SOUND_PCM_WRITE_FILTER 0x5007 +#define LINUX_SNDCTL_DSP_POST 0x5008 +#define LINUX_SNDCTL_DSP_SUBDIVIDE 0x5009 +#define LINUX_SNDCTL_DSP_SETFRAGMENT 0x500A +#define LINUX_SNDCTL_DSP_GETFMTS 0x500B +#define LINUX_SNDCTL_DSP_GETOSPACE 0x500C +#define LINUX_SNDCTL_DSP_GETISPACE 0x500D +#define LINUX_SNDCTL_DSP_NONBLOCK 0x500E +#define LINUX_SNDCTL_DSP_GETCAPS 0x500F +#define LINUX_SNDCTL_DSP_GETTRIGGER 0x5010 +#define LINUX_SNDCTL_DSP_SETTRIGGER LINUX_SNDCTL_DSP_GETTRIGGER +#define LINUX_SNDCTL_DSP_GETIPTR 0x5011 +#define LINUX_SNDCTL_DSP_GETOPTR 0x5012 +#define LINUX_SNDCTL_DSP_SETDUPLEX 0x5016 +#define LINUX_SNDCTL_DSP_GETODELAY 0x5017 +#define LINUX_SNDCTL_SEQ_RESET 0x5100 +#define LINUX_SNDCTL_SEQ_SYNC 0x5101 +#define LINUX_SNDCTL_SYNTH_INFO 0x5102 +#define LINUX_SNDCTL_SEQ_CTRLRATE 0x5103 +#define LINUX_SNDCTL_SEQ_GETOUTCOUNT 0x5104 +#define LINUX_SNDCTL_SEQ_GETINCOUNT 0x5105 +#define LINUX_SNDCTL_SEQ_PERCMODE 0x5106 +#define LINUX_SNDCTL_FM_LOAD_INSTR 0x5107 +#define LINUX_SNDCTL_SEQ_TESTMIDI 0x5108 +#define LINUX_SNDCTL_SEQ_RESETSAMPLES 0x5109 +#define LINUX_SNDCTL_SEQ_NRSYNTHS 0x510A +#define LINUX_SNDCTL_SEQ_NRMIDIS 0x510B +#define LINUX_SNDCTL_MIDI_INFO 0x510C +#define LINUX_SNDCTL_SEQ_TRESHOLD 0x510D +#define LINUX_SNDCTL_SYNTH_MEMAVL 0x510E + +#define LINUX_IOCTL_SOUND_MIN LINUX_SOUND_MIXER_WRITE_VOLUME +#define LINUX_IOCTL_SOUND_MAX LINUX_SNDCTL_SYNTH_MEMAVL + +/* + * termio + */ +#define LINUX_TCGETS 0x5401 +#define LINUX_TCSETS 0x5402 +#define LINUX_TCSETSW 0x5403 +#define LINUX_TCSETSF 0x5404 +#define LINUX_TCGETA 0x5405 +#define LINUX_TCSETA 0x5406 +#define LINUX_TCSETAW 0x5407 +#define LINUX_TCSETAF 0x5408 +#define LINUX_TCSBRK 0x5409 +#define LINUX_TCXONC 0x540A +#define LINUX_TCFLSH 0x540B + +#define LINUX_TIOCEXCL 0x540C +#define LINUX_TIOCNXCL 0x540D +#define LINUX_TIOCSCTTY 0x540E + +#define LINUX_TIOCGPGRP 0x540F +#define LINUX_TIOCSPGRP 0x5410 + +#define LINUX_TIOCOUTQ 0x5411 +#define LINUX_TIOCSTI 0x5412 + +#define LINUX_TIOCGWINSZ 0x5413 +#define LINUX_TIOCSWINSZ 0x5414 + +#define LINUX_TIOCMGET 0x5415 +#define LINUX_TIOCMBIS 0x5416 +#define LINUX_TIOCMBIC 0x5417 +#define LINUX_TIOCMSET 0x5418 +#define LINUX_TIOCGSOFTCAR 0x5419 +#define LINUX_TIOCSSOFTCAR 0x541A + +#define LINUX_FIONREAD 0x541B + +#define LINUX_TIOCINQ FIONREAD +#define LINUX_TIOCLINUX 0x541C +#define LINUX_TIOCCONS 0x541D +#define LINUX_TIOCGSERIAL 0x541E +#define LINUX_TIOCSSERIAL 0x541F +#define LINUX_TIOCPKT 0x5420 + +#define LINUX_FIONBIO 0x5421 + +#define LINUX_TIOCNOTTY 0x5422 +#define LINUX_TIOCSETD 0x5423 +#define LINUX_TIOCGETD 0x5424 +#define LINUX_TCSBRKP 0x5425 +#define LINUX_TIOCTTYGSTRUCT 0x5426 + +#define LINUX_TIOCSBRK 0x5427 +#define LINUX_TIOCCBRK 0x5428 + +#define LINUX_TIOCGPTN 0x5430 +#define LINUX_TIOCSPTLCK 0x5431 + +#define LINUX_TIOCGPTPEER 0x5441 + +#define LINUX_FIONCLEX 0x5450 +#define LINUX_FIOCLEX 0x5451 +#define LINUX_FIOASYNC 0x5452 + +#define LINUX_TIOCSERCONFIG 0x5453 +#define LINUX_TIOCSERGWILD 0x5454 +#define LINUX_TIOCSERSWILD 0x5455 +#define LINUX_TIOCGLCKTRMIOS 0x5456 +#define LINUX_TIOCSLCKTRMIOS 0x5457 + +#define LINUX_IOCTL_TERMIO_MIN LINUX_TCGETS +#define LINUX_IOCTL_TERMIO_MAX LINUX_TIOCSLCKTRMIOS + +/* arguments for tcflow() and LINUX_TCXONC */ +#define LINUX_TCOOFF 0 +#define LINUX_TCOON 1 +#define LINUX_TCIOFF 2 +#define LINUX_TCION 3 + +/* arguments for tcflush() and LINUX_TCFLSH */ +#define LINUX_TCIFLUSH 0 +#define LINUX_TCOFLUSH 1 +#define LINUX_TCIOFLUSH 2 + +/* line disciplines */ +#define LINUX_N_TTY 0 +#define LINUX_N_SLIP 1 +#define LINUX_N_MOUSE 2 +#define LINUX_N_PPP 3 + +/* Linux termio c_cc values */ +#define LINUX_VINTR 0 +#define LINUX_VQUIT 1 +#define LINUX_VERASE 2 +#define LINUX_VKILL 3 +#define LINUX_VEOF 4 +#define LINUX_VTIME 5 +#define LINUX_VMIN 6 +#define LINUX_VSWTC 7 +#define LINUX_NCC 8 + +/* Linux termios c_cc values */ +/* In addition to the termio values */ +#define LINUX_VSTART 8 +#define LINUX_VSTOP 9 +#define LINUX_VSUSP 10 +#define LINUX_VEOL 11 +#define LINUX_VREPRINT 12 +#define LINUX_VDISCARD 13 +#define LINUX_VWERASE 14 +#define LINUX_VLNEXT 15 +#define LINUX_VEOL2 16 +#define LINUX_VSTATUS 18 +#define LINUX_NCCS 19 + +#define LINUX_POSIX_VDISABLE '\0' + +/* Linux c_iflag masks */ +#define LINUX_IGNBRK 0x0000001 +#define LINUX_BRKINT 0x0000002 +#define LINUX_IGNPAR 0x0000004 +#define LINUX_PARMRK 0x0000008 +#define LINUX_INPCK 0x0000010 +#define LINUX_ISTRIP 0x0000020 +#define LINUX_INLCR 0x0000040 +#define LINUX_IGNCR 0x0000080 +#define LINUX_ICRNL 0x0000100 + +#define LINUX_IUCLC 0x0000200 +#define LINUX_IXON 0x0000400 +#define LINUX_IXANY 0x0000800 +#define LINUX_IXOFF 0x0001000 + +#define LINUX_IMAXBEL 0x0002000 + +/* Linux c_oflag masks */ +#define LINUX_OPOST 0x0000001 + +#define LINUX_OLCUC 0x0000002 +#define LINUX_ONLCR 0x0000004 + +#define LINUX_OCRNL 0x0000008 +#define LINUX_ONOCR 0x0000010 +#define LINUX_ONLRET 0x0000020 +#define LINUX_OFILL 0x0000040 +#define LINUX_OFDEL 0x0000080 + +#define LINUX_NLDLY 0x0000100 +#define LINUX_NL0 0x0000000 +#define LINUX_NL1 0x0000100 +#define LINUX_CRDLY 0x0000600 +#define LINUX_CR0 0x0000000 +#define LINUX_CR1 0x0000200 +#define LINUX_CR2 0x0000400 +#define LINUX_CR3 0x0000600 +#define LINUX_TABDLY 0x0001800 +#define LINUX_TAB0 0x0000000 +#define LINUX_TAB1 0x0000800 +#define LINUX_TAB2 0x0001000 +#define LINUX_TAB3 0x0001800 +#define LINUX_XTABS 0x0001800 +#define LINUX_BSDLY 0x0002000 +#define LINUX_BS0 0x0000000 +#define LINUX_BS1 0x0002000 +#define LINUX_VTDLY 0x0004000 +#define LINUX_VT0 0x0000000 +#define LINUX_VT1 0x0004000 +#define LINUX_FFDLY 0x0008000 +#define LINUX_FF0 0x0000000 +#define LINUX_FF1 0x0008000 + +#define LINUX_CBAUD 0x0000100f + +#define LINUX_B0 0x00000000 +#define LINUX_B50 0x00000001 +#define LINUX_B75 0x00000002 +#define LINUX_B110 0x00000003 +#define LINUX_B134 0x00000004 +#define LINUX_B150 0x00000005 +#define LINUX_B200 0x00000006 +#define LINUX_B300 0x00000007 +#define LINUX_B600 0x00000008 +#define LINUX_B1200 0x00000009 +#define LINUX_B1800 0x0000000a +#define LINUX_B2400 0x0000000b +#define LINUX_B4800 0x0000000c +#define LINUX_B9600 0x0000000d +#define LINUX_B19200 0x0000000e +#define LINUX_B38400 0x0000000f +#define LINUX_EXTA LINUX_B19200 +#define LINUX_EXTB LINUX_B38400 + +#define LINUX_CBAUDEX 0x00001000 +#define LINUX_B57600 0x00001001 +#define LINUX_B115200 0x00001002 + +#define LINUX_CSIZE 0x00000030 +#define LINUX_CS5 0x00000000 +#define LINUX_CS6 0x00000010 +#define LINUX_CS7 0x00000020 +#define LINUX_CS8 0x00000030 +#define LINUX_CSTOPB 0x00000040 +#define LINUX_CREAD 0x00000080 +#define LINUX_PARENB 0x00000100 +#define LINUX_PARODD 0x00000200 +#define LINUX_HUPCL 0x00000400 +#define LINUX_CLOCAL 0x00000800 + +#define LINUX_CRTSCTS 0x80000000 + +/* Linux c_lflag masks */ +#define LINUX_ISIG 0x00000001 +#define LINUX_ICANON 0x00000002 +#define LINUX_XCASE 0x00000004 +#define LINUX_ECHO 0x00000008 +#define LINUX_ECHOE 0x00000010 +#define LINUX_ECHOK 0x00000020 +#define LINUX_ECHONL 0x00000040 +#define LINUX_NOFLSH 0x00000080 +#define LINUX_TOSTOP 0x00000100 +#define LINUX_ECHOCTL 0x00000200 +#define LINUX_ECHOPRT 0x00000400 +#define LINUX_ECHOKE 0x00000800 +#define LINUX_FLUSHO 0x00001000 +#define LINUX_PENDIN 0x00002000 +#define LINUX_IEXTEN 0x00008000 + +/* serial_struct values for TIOC[GS]SERIAL ioctls */ +#define LINUX_ASYNC_CLOSING_WAIT_INF 0 +#define LINUX_ASYNC_CLOSING_WAIT_NONE 65535 + +#define LINUX_PORT_UNKNOWN 0 +#define LINUX_PORT_8250 1 +#define LINUX_PORT_16450 2 +#define LINUX_PORT_16550 3 +#define LINUX_PORT_16550A 4 +#define LINUX_PORT_CIRRUS 5 +#define LINUX_PORT_16650 6 + +#define LINUX_PORT_MAX 6 + +#define LINUX_ASYNC_HUP_NOTIFY 0x0001 +#define LINUX_ASYNC_FOURPORT 0x0002 +#define LINUX_ASYNC_SAK 0x0004 +#define LINUX_ASYNC_SPLIT_TERMIOS 0x0008 +#define LINUX_ASYNC_SPD_MASK 0x0030 +#define LINUX_ASYNC_SPD_HI 0x0010 +#define LINUX_ASYNC_SPD_VHI 0x0020 +#define LINUX_ASYNC_SPD_CUST 0x0030 +#define LINUX_ASYNC_SKIP_TEST 0x0040 +#define LINUX_ASYNC_AUTO_IRQ 0x0080 +#define LINUX_ASYNC_SESSION_LOCKOUT 0x0100 +#define LINUX_ASYNC_PGRP_LOCKOUT 0x0200 +#define LINUX_ASYNC_CALLOUT_NOHUP 0x0400 +#define LINUX_ASYNC_FLAGS 0x0FFF + +#define LINUX_IOCTL_DRM_MIN 0x6400 +#define LINUX_IOCTL_DRM_MAX 0x64ff + +/* + * video + */ +#define LINUX_VIDIOCGCAP 0x7601 +#define LINUX_VIDIOCGCHAN 0x7602 +#define LINUX_VIDIOCSCHAN 0x7603 +#define LINUX_VIDIOCGTUNER 0x7604 +#define LINUX_VIDIOCSTUNER 0x7605 +#define LINUX_VIDIOCGPICT 0x7606 +#define LINUX_VIDIOCSPICT 0x7607 +#define LINUX_VIDIOCCAPTURE 0x7608 +#define LINUX_VIDIOCGWIN 0x7609 +#define LINUX_VIDIOCSWIN 0x760a +#define LINUX_VIDIOCGFBUF 0x760b +#define LINUX_VIDIOCSFBUF 0x760c +#define LINUX_VIDIOCKEY 0x760d +#define LINUX_VIDIOCGFREQ 0x760e +#define LINUX_VIDIOCSFREQ 0x760f +#define LINUX_VIDIOCGAUDIO 0x7610 +#define LINUX_VIDIOCSAUDIO 0x7611 +#define LINUX_VIDIOCSYNC 0x7623 +#define LINUX_VIDIOCMCAPTURE 0x7613 +#define LINUX_VIDIOCGMBUF 0x7614 +#define LINUX_VIDIOCGUNIT 0x7615 +#define LINUX_VIDIOCGCAPTURE 0x7616 +#define LINUX_VIDIOCSCAPTURE 0x7617 +#define LINUX_VIDIOCSPLAYMODE 0x7618 +#define LINUX_VIDIOCSWRITEMODE 0x7619 +#define LINUX_VIDIOCGPLAYINFO 0x761a +#define LINUX_VIDIOCSMICROCODE 0x761b +#define LINUX_VIDIOCGVBIFMT 0x761c +#define LINUX_VIDIOCSVBIFMT 0x761d + +#define LINUX_IOCTL_VIDEO_MIN LINUX_VIDIOCGCAP +#define LINUX_IOCTL_VIDEO_MAX LINUX_VIDIOCSVBIFMT + +/* videodev2 aka V4L2 */ + +#define LINUX_VIDIOC_QUERYCAP 0x5600 /* 0x80685600 */ +#define LINUX_VIDIOC_RESERVED 0x5601 /* 0x00005601 */ +#define LINUX_VIDIOC_ENUM_FMT 0x5602 /* 0xc0405602 */ +#define LINUX_VIDIOC_G_FMT 0x5604 /* 0xc0cc5604 */ +#define LINUX_VIDIOC_S_FMT 0x5605 /* 0xc0cc5605 */ +#define LINUX_VIDIOC_REQBUFS 0x5608 /* 0xc0145608 */ +#define LINUX_VIDIOC_QUERYBUF 0x5609 /* 0xc0445609 */ +#define LINUX_VIDIOC_G_FBUF 0x560a /* 0x802c560a */ +#define LINUX_VIDIOC_S_FBUF 0x560b /* 0x402c560b */ +#define LINUX_VIDIOC_OVERLAY 0x560e /* 0x4004560e */ +#define LINUX_VIDIOC_QBUF 0x560f /* 0xc044560f */ +#define LINUX_VIDIOC_DQBUF 0x5611 /* 0xc0445611 */ +#define LINUX_VIDIOC_STREAMON 0x5612 /* 0x40045612 */ +#define LINUX_VIDIOC_STREAMOFF 0x5613 /* 0x40045613 */ +#define LINUX_VIDIOC_G_PARM 0x5615 /* 0xc0cc5615 */ +#define LINUX_VIDIOC_S_PARM 0x5616 /* 0xc0cc5616 */ +#define LINUX_VIDIOC_G_STD 0x5617 /* 0x80085617 */ +#define LINUX_VIDIOC_S_STD 0x5618 /* 0x40085618 */ +#define LINUX_VIDIOC_ENUMSTD 0x5619 /* 0xc0405619 */ +#define LINUX_VIDIOC_ENUMINPUT 0x561a /* 0xc04c561a */ +#define LINUX_VIDIOC_G_CTRL 0x561b /* 0xc008561b */ +#define LINUX_VIDIOC_S_CTRL 0x561c /* 0xc008561c */ +#define LINUX_VIDIOC_G_TUNER 0x561d /* 0xc054561d */ +#define LINUX_VIDIOC_S_TUNER 0x561e /* 0x4054561e */ +#define LINUX_VIDIOC_G_AUDIO 0x5621 /* 0x80345621 */ +#define LINUX_VIDIOC_S_AUDIO 0x5622 /* 0x40345622 */ +#define LINUX_VIDIOC_QUERYCTRL 0x5624 /* 0xc0445624 */ +#define LINUX_VIDIOC_QUERYMENU 0x5625 /* 0xc02c5625 */ +#define LINUX_VIDIOC_G_INPUT 0x5626 /* 0x80045626 */ +#define LINUX_VIDIOC_S_INPUT 0x5627 /* 0xc0045627 */ +#define LINUX_VIDIOC_G_OUTPUT 0x562e /* 0x8004562e */ +#define LINUX_VIDIOC_S_OUTPUT 0x562f /* 0xc004562f */ +#define LINUX_VIDIOC_ENUMOUTPUT 0x5630 /* 0xc0485630 */ +#define LINUX_VIDIOC_G_AUDOUT 0x5631 /* 0x80345631 */ +#define LINUX_VIDIOC_S_AUDOUT 0x5632 /* 0x40345632 */ +#define LINUX_VIDIOC_G_MODULATOR 0x5636 /* 0xc0445636 */ +#define LINUX_VIDIOC_S_MODULATOR 0x5637 /* 0x40445637 */ +#define LINUX_VIDIOC_G_FREQUENCY 0x5638 /* 0xc02c5638 */ +#define LINUX_VIDIOC_S_FREQUENCY 0x5639 /* 0x402c5639 */ +#define LINUX_VIDIOC_CROPCAP 0x563a /* 0xc02c563a */ +#define LINUX_VIDIOC_G_CROP 0x563b /* 0xc014563b */ +#define LINUX_VIDIOC_S_CROP 0x563c /* 0x4014563c */ +#define LINUX_VIDIOC_G_JPEGCOMP 0x563d /* 0x808c563d */ +#define LINUX_VIDIOC_S_JPEGCOMP 0x563e /* 0x408c563e */ +#define LINUX_VIDIOC_QUERYSTD 0x563f /* 0x8008563f */ +#define LINUX_VIDIOC_TRY_FMT 0x5640 /* 0xc0cc5640 */ +#define LINUX_VIDIOC_ENUMAUDIO 0x5641 /* 0xc0345641 */ +#define LINUX_VIDIOC_ENUMAUDOUT 0x5642 /* 0xc0345642 */ +#define LINUX_VIDIOC_G_PRIORITY 0x5643 /* 0x80045643 */ +#define LINUX_VIDIOC_S_PRIORITY 0x5644 /* 0x40045644 */ +#define LINUX_VIDIOC_G_SLICED_VBI_CAP 0x5645 /* 0xc0745645 */ +#define LINUX_VIDIOC_LOG_STATUS 0x5646 /* 0x00005646 */ +#define LINUX_VIDIOC_G_EXT_CTRLS 0x5647 /* 0xc0185647 */ +#define LINUX_VIDIOC_S_EXT_CTRLS 0x5648 /* 0xc0185648 */ +#define LINUX_VIDIOC_TRY_EXT_CTRLS 0x5649 /* 0xc0185649 */ +#define LINUX_VIDIOC_ENUM_FRAMESIZES 0x564a /* 0xc02c564a */ +#define LINUX_VIDIOC_ENUM_FRAMEINTERVALS 0x564b /* 0xc034564b */ +#define LINUX_VIDIOC_G_ENC_INDEX 0x564c /* 0x8818564c */ +#define LINUX_VIDIOC_ENCODER_CMD 0x564d /* 0xc028564d */ +#define LINUX_VIDIOC_TRY_ENCODER_CMD 0x564e /* 0xc028564e */ +#define LINUX_VIDIOC_DBG_S_REGISTER 0x564f /* 0x4038564f */ +#define LINUX_VIDIOC_DBG_G_REGISTER 0x5650 /* 0xc0385650 */ +#define LINUX_VIDIOC_DBG_G_CHIP_IDENT 0x5651 /* 0xc02c5651 */ +#define LINUX_VIDIOC_S_HW_FREQ_SEEK 0x5652 /* 0x40305652 */ +#define LINUX_VIDIOC_ENUM_DV_PRESETS 0x5653 /* 0xc0405653 */ +#define LINUX_VIDIOC_S_DV_PRESET 0x5654 /* 0xc0145654 */ +#define LINUX_VIDIOC_G_DV_PRESET 0x5655 /* 0xc0145655 */ +#define LINUX_VIDIOC_QUERY_DV_PRESET 0x5656 /* 0x80145656 */ +#define LINUX_VIDIOC_S_DV_TIMINGS 0x5657 /* 0xc0845657 */ +#define LINUX_VIDIOC_G_DV_TIMINGS 0x5658 /* 0xc0845658 */ +#define LINUX_VIDIOC_DQEVENT 0x5659 /* 0x80785659 */ +#define LINUX_VIDIOC_SUBSCRIBE_EVENT 0x565a /* 0x4020565a */ +#define LINUX_VIDIOC_UNSUBSCRIBE_EVENT 0x565b /* 0x4020565b */ + +#define LINUX_VIDIOC_OVERLAY_OLD 0x560e /* 0xc004560e */ +#define LINUX_VIDIOC_S_PARM_OLD 0x5616 /* 0x40cc5616 */ +#define LINUX_VIDIOC_S_CTRL_OLD 0x561c /* 0x4008561c */ +#define LINUX_VIDIOC_G_AUDIO_OLD 0x5621 /* 0xc0345621 */ +#define LINUX_VIDIOC_G_AUDOUT_OLD 0x5631 /* 0xc0345631 */ +#define LINUX_VIDIOC_CROPCAP_OLD 0x563a /* 0x802c563a */ + +#define LINUX_IOCTL_VIDEO2_MIN LINUX_VIDIOC_QUERYCAP +#define LINUX_IOCTL_VIDEO2_MAX LINUX_VIDIOC_UNSUBSCRIBE_EVENT + +#define LINUX_F2FS_IOC_GET_FEATURES 0xf50c /* 0x8004f50c */ + +#define LINUX_IOCTL_F2FS_MIN 0xf500 +#define LINUX_IOCTL_F2FS_MAX LINUX_F2FS_IOC_GET_FEATURES + +/* + * Our libusb(8) calls emulated within linux(4). + */ +#define FBSD_LUSB_DEVICEENUMERATE 0xffff +#define FBSD_LUSB_DEV_QUIRK_ADD 0xfffe +#define FBSD_LUSB_DEV_QUIRK_GET 0xfffd +#define FBSD_LUSB_DEV_QUIRK_REMOVE 0xfffc +#define FBSD_LUSB_DO_REQUEST 0xfffb +#define FBSD_LUSB_FS_CLEAR_STALL_SYNC 0xfffa +#define FBSD_LUSB_FS_CLOSE 0xfff9 +#define FBSD_LUSB_FS_COMPLETE 0xfff8 +#define FBSD_LUSB_FS_INIT 0xfff7 +#define FBSD_LUSB_FS_OPEN 0xfff6 +#define FBSD_LUSB_FS_START 0xfff5 +#define FBSD_LUSB_FS_STOP 0xfff4 +#define FBSD_LUSB_FS_UNINIT 0xfff3 +#define FBSD_LUSB_GET_CONFIG 0xfff2 +#define FBSD_LUSB_GET_DEVICEINFO 0xfff1 +#define FBSD_LUSB_GET_DEVICE_DESC 0xfff0 +#define FBSD_LUSB_GET_FULL_DESC 0xffef +#define FBSD_LUSB_GET_IFACE_DRIVER 0xffee +#define FBSD_LUSB_GET_PLUGTIME 0xffed +#define FBSD_LUSB_GET_POWER_MODE 0xffec +#define FBSD_LUSB_GET_REPORT_DESC 0xffeb +#define FBSD_LUSB_GET_REPORT_ID 0xffea +#define FBSD_LUSB_GET_TEMPLATE 0xffe9 +#define FBSD_LUSB_IFACE_DRIVER_ACTIVE 0xffe8 +#define FBSD_LUSB_IFACE_DRIVER_DETACH 0xffe7 +#define FBSD_LUSB_QUIRK_NAME_GET 0xffe6 +#define FBSD_LUSB_READ_DIR 0xffe5 +#define FBSD_LUSB_SET_ALTINTERFACE 0xffe4 +#define FBSD_LUSB_SET_CONFIG 0xffe3 +#define FBSD_LUSB_SET_IMMED 0xffe2 +#define FBSD_LUSB_SET_POWER_MODE 0xffe1 +#define FBSD_LUSB_SET_TEMPLATE 0xffe0 +#define FBSD_LUSB_FS_OPEN_STREAM 0xffdf +#define FBSD_LUSB_GET_DEV_PORT_PATH 0xffde +#define FBSD_LUSB_GET_POWER_USAGE 0xffdd +#define FBSD_LUSB_DEVICESTATS 0xffdc + +#define LINUX_IOCTL_FBSD_LUSB_MAX 0xffff +#define LINUX_IOCTL_FBSD_LUSB_MIN 0xffdc + +/* + * Linux btrfs clone operation + */ +#define LINUX_BTRFS_IOC_CLONE 0x9409 /* 0x40049409 */ +#define LINUX_FS_IOC_FIEMAP 0x660b + +/* + * Linux evdev ioctl min and max + */ +#define LINUX_IOCTL_EVDEV_MIN 0x4500 +#define LINUX_IOCTL_EVDEV_MAX 0x45ff +#define LINUX_IOCTL_EVDEV_CLK LINUX_CLOCK_REALTIME | \ + LINUX_CLOCK_MONOTONIC |LINUX_CLOCK_BOOTTIME + +/* + * kcov(4) shims + */ +#define LINUX_IOCTL_KCOV_MIN 0x6300 +#define LINUX_IOCTL_KCOV_MAX 0x63ff +#define LINUX_KCOV_INIT_TRACE 0x6301 +#define LINUX_KCOV_ENABLE 0x6364 +#define LINUX_KCOV_DISABLE 0x6365 +#define LINUX_KCOV_REMOTE_ENABLE 0x6366 + +/* + * NVMe IOCTLs defined by Linux + */ +#define LINUX_NVME_IOCTL_ID 0x4e40 +#define LINUX_NVME_IOCTL_ADMIN_CMD 0x4e41 +#define LINUX_NVME_IOCTL_SUBMIT_IO 0x4e42 +#define LINUX_NVME_IOCTL_IO_CMD 0x4e43 +#define LINUX_NVME_IOCTL_RESET 0x4e44 +#define LINUX_NVME_IOCTL_SUBSYS_RESET 0x4e45 +#define LINUX_NVME_IOCTL_RESCAN 0x4e46 + +#define LINUX_IOCTL_NVME_MIN LINUX_NVME_IOCTL_ID +#define LINUX_IOCTL_NVME_MAX LINUX_NVME_IOCTL_RESCAN + +/* + * Pluggable ioctl handlers + */ +struct linux_ioctl_args; +struct thread; + +typedef int linux_ioctl_function_t(struct thread *, struct linux_ioctl_args *); + +struct linux_ioctl_handler { + linux_ioctl_function_t *func; + int low, high; +}; + +struct linux_ioctl_handler_element +{ + TAILQ_ENTRY(linux_ioctl_handler_element) list; + int (*func)(struct thread *, struct linux_ioctl_args *); + int low, high, span; +}; + +int linux_ioctl_register_handler(struct linux_ioctl_handler *h); +int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h); +#ifdef COMPAT_LINUX32 +int linux32_ioctl_register_handler(struct linux_ioctl_handler *h); +int linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h); +#endif + +#endif /* !_LINUX_IOCTL_H_ */ diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c index 81c46535f102..e4baf1d36199 100644 --- a/sys/compat/linux/linux_ipc.c +++ b/sys/compat/linux/linux_ipc.c @@ -1,925 +1,941 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif -#include -#include -#include -#include - -/* - * old, pre 2.4 kernel - */ -struct l_ipc_perm { - l_key_t key; - l_uid16_t uid; - l_gid16_t gid; - l_uid16_t cuid; - l_gid16_t cgid; - l_ushort mode; - l_ushort seq; -}; - -struct l_seminfo { - l_int semmap; - l_int semmni; - l_int semmns; - l_int semmnu; - l_int semmsl; - l_int semopm; - l_int semume; - l_int semusz; - l_int semvmx; - l_int semaem; -}; - -struct l_shminfo { - l_int shmmax; - l_int shmmin; - l_int shmmni; - l_int shmseg; - l_int shmall; -}; - -struct l_shm_info { - l_int used_ids; - l_ulong shm_tot; /* total allocated shm */ - l_ulong shm_rss; /* total resident shm */ - l_ulong shm_swp; /* total swapped shm */ - l_ulong swap_attempts; - l_ulong swap_successes; -}; - -struct l_msginfo { - l_int msgpool; - l_int msgmap; - l_int msgmax; - l_int msgmnb; - l_int msgmni; - l_int msgssz; - l_int msgtql; - l_ushort msgseg; -}; - -static void -bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo64 *lpp) -{ - - lpp->shmmax = bpp->shmmax; - lpp->shmmin = bpp->shmmin; - lpp->shmmni = bpp->shmmni; - lpp->shmseg = bpp->shmseg; - lpp->shmall = bpp->shmall; -} - -static void -bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp) -{ - - lpp->used_ids = bpp->used_ids; - lpp->shm_tot = bpp->shm_tot; - lpp->shm_rss = bpp->shm_rss; - lpp->shm_swp = bpp->shm_swp; - lpp->swap_attempts = bpp->swap_attempts; - lpp->swap_successes = bpp->swap_successes; -} - -static void -linux_to_bsd_ipc_perm(struct l_ipc64_perm *lpp, struct ipc_perm *bpp) -{ - - bpp->key = lpp->key; - bpp->uid = lpp->uid; - bpp->gid = lpp->gid; - bpp->cuid = lpp->cuid; - bpp->cgid = lpp->cgid; - bpp->mode = lpp->mode; - bpp->seq = lpp->seq; -} - -static void -bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc64_perm *lpp) -{ - - lpp->key = bpp->key; - lpp->uid = bpp->uid; - lpp->gid = bpp->gid; - lpp->cuid = bpp->cuid; - lpp->cgid = bpp->cgid; - lpp->mode = bpp->mode & (S_IRWXU|S_IRWXG|S_IRWXO); - lpp->seq = bpp->seq; -} - -struct l_msqid_ds { - struct l_ipc_perm msg_perm; - l_uintptr_t msg_first; /* first message on queue,unused */ - l_uintptr_t msg_last; /* last message in queue,unused */ - l_time_t msg_stime; /* last msgsnd time */ - l_time_t msg_rtime; /* last msgrcv time */ - l_time_t msg_ctime; /* last change time */ - l_ulong msg_lcbytes; /* Reuse junk fields for 32 bit */ - l_ulong msg_lqbytes; /* ditto */ - l_ushort msg_cbytes; /* current number of bytes on queue */ - l_ushort msg_qnum; /* number of messages in queue */ - l_ushort msg_qbytes; /* max number of bytes on queue */ - l_pid_t msg_lspid; /* pid of last msgsnd */ - l_pid_t msg_lrpid; /* last receive pid */ -}; - -struct l_semid_ds { - struct l_ipc_perm sem_perm; - l_time_t sem_otime; - l_time_t sem_ctime; - l_uintptr_t sem_base; - l_uintptr_t sem_pending; - l_uintptr_t sem_pending_last; - l_uintptr_t undo; - l_ushort sem_nsems; -}; - -struct l_shmid_ds { - struct l_ipc_perm shm_perm; - l_int shm_segsz; - l_time_t shm_atime; - l_time_t shm_dtime; - l_time_t shm_ctime; - l_ushort shm_cpid; - l_ushort shm_lpid; - l_short shm_nattch; - l_ushort private1; - l_uintptr_t private2; - l_uintptr_t private3; -}; - -static void -linux_to_bsd_semid_ds(struct l_semid64_ds *lsp, struct semid_ds *bsp) -{ - - linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); - bsp->sem_otime = lsp->sem_otime; - bsp->sem_ctime = lsp->sem_ctime; - bsp->sem_nsems = lsp->sem_nsems; -} - -static void -bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid64_ds *lsp) -{ - - bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); - lsp->sem_otime = bsp->sem_otime; - lsp->sem_ctime = bsp->sem_ctime; - lsp->sem_nsems = bsp->sem_nsems; -} - -static void -linux_to_bsd_shmid_ds(struct l_shmid64_ds *lsp, struct shmid_ds *bsp) -{ - - linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); - bsp->shm_segsz = lsp->shm_segsz; - bsp->shm_lpid = lsp->shm_lpid; - bsp->shm_cpid = lsp->shm_cpid; - bsp->shm_nattch = lsp->shm_nattch; - bsp->shm_atime = lsp->shm_atime; - bsp->shm_dtime = lsp->shm_dtime; - bsp->shm_ctime = lsp->shm_ctime; -} - -static void -bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid64_ds *lsp) -{ - - bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); - lsp->shm_segsz = bsp->shm_segsz; - lsp->shm_lpid = bsp->shm_lpid; - lsp->shm_cpid = bsp->shm_cpid; - lsp->shm_nattch = bsp->shm_nattch; - lsp->shm_atime = bsp->shm_atime; - lsp->shm_dtime = bsp->shm_dtime; - lsp->shm_ctime = bsp->shm_ctime; -} - -static void -linux_to_bsd_msqid_ds(struct l_msqid64_ds *lsp, struct msqid_ds *bsp) -{ - - linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm); - bsp->msg_cbytes = lsp->msg_cbytes; - bsp->msg_qnum = lsp->msg_qnum; - bsp->msg_qbytes = lsp->msg_qbytes; - bsp->msg_lspid = lsp->msg_lspid; - bsp->msg_lrpid = lsp->msg_lrpid; - bsp->msg_stime = lsp->msg_stime; - bsp->msg_rtime = lsp->msg_rtime; - bsp->msg_ctime = lsp->msg_ctime; -} - -static void -bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid64_ds *lsp) -{ - - bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm); - lsp->msg_cbytes = bsp->msg_cbytes; - lsp->msg_qnum = bsp->msg_qnum; - lsp->msg_qbytes = bsp->msg_qbytes; - lsp->msg_lspid = bsp->msg_lspid; - lsp->msg_lrpid = bsp->msg_lrpid; - lsp->msg_stime = bsp->msg_stime; - lsp->msg_rtime = bsp->msg_rtime; - lsp->msg_ctime = bsp->msg_ctime; -} - -static int -linux_ipc64_perm_to_ipc_perm(struct l_ipc64_perm *in, struct l_ipc_perm *out) -{ - - out->key = in->key; - out->uid = in->uid; - out->gid = in->gid; - out->cuid = in->cuid; - out->cgid = in->cgid; - out->mode = in->mode; - out->seq = in->seq; - - /* Linux does not check overflow */ - if (out->uid != in->uid || out->gid != in->gid || - out->cuid != in->cuid || out->cgid != in->cgid || - out->mode != in->mode) - return (EOVERFLOW); - else - return (0); -} - -static int -linux_msqid_pullup(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr) -{ - struct l_msqid_ds linux_msqid; - int error; - - if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) - return (copyin(uaddr, linux_msqid64, sizeof(*linux_msqid64))); - - error = copyin(uaddr, &linux_msqid, sizeof(linux_msqid)); - if (error != 0) - return (error); - - bzero(linux_msqid64, sizeof(*linux_msqid64)); - linux_msqid64->msg_perm.uid = linux_msqid.msg_perm.uid; - linux_msqid64->msg_perm.gid = linux_msqid.msg_perm.gid; - linux_msqid64->msg_perm.mode = linux_msqid.msg_perm.mode; - if (linux_msqid.msg_qbytes == 0) - linux_msqid64->msg_qbytes = linux_msqid.msg_lqbytes; - else - linux_msqid64->msg_qbytes = linux_msqid.msg_qbytes; - return (0); -} - -static int -linux_msqid_pushdown(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr) -{ - struct l_msqid_ds linux_msqid; - int error; - - if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) - return (copyout(linux_msqid64, uaddr, sizeof(*linux_msqid64))); - - bzero(&linux_msqid, sizeof(linux_msqid)); - error = linux_ipc64_perm_to_ipc_perm(&linux_msqid64->msg_perm, - &linux_msqid.msg_perm); - if (error != 0) - return (error); - - linux_msqid.msg_stime = linux_msqid64->msg_stime; - linux_msqid.msg_rtime = linux_msqid64->msg_rtime; - linux_msqid.msg_ctime = linux_msqid64->msg_ctime; - - if (linux_msqid64->msg_cbytes > USHRT_MAX) - linux_msqid.msg_cbytes = USHRT_MAX; - else - linux_msqid.msg_cbytes = linux_msqid64->msg_cbytes; - linux_msqid.msg_lcbytes = linux_msqid64->msg_cbytes; - if (linux_msqid64->msg_qnum > USHRT_MAX) - linux_msqid.msg_qnum = USHRT_MAX; - else - linux_msqid.msg_qnum = linux_msqid64->msg_qnum; - if (linux_msqid64->msg_qbytes > USHRT_MAX) - linux_msqid.msg_qbytes = USHRT_MAX; - else - linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes; - linux_msqid.msg_lqbytes = linux_msqid64->msg_qbytes; - linux_msqid.msg_lspid = linux_msqid64->msg_lspid; - linux_msqid.msg_lrpid = linux_msqid64->msg_lrpid; - - /* Linux does not check overflow */ - if (linux_msqid.msg_stime != linux_msqid64->msg_stime || - linux_msqid.msg_rtime != linux_msqid64->msg_rtime || - linux_msqid.msg_ctime != linux_msqid64->msg_ctime) - return (EOVERFLOW); - return (copyout(&linux_msqid, uaddr, sizeof(linux_msqid))); -} - -static int -linux_semid_pullup(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr) -{ - struct l_semid_ds linux_semid; - int error; - - if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) - return (copyin(uaddr, linux_semid64, sizeof(*linux_semid64))); - error = copyin(uaddr, &linux_semid, sizeof(linux_semid)); - if (error != 0) - return (error); - - bzero(linux_semid64, sizeof(*linux_semid64)); - linux_semid64->sem_perm.uid = linux_semid.sem_perm.uid; - linux_semid64->sem_perm.gid = linux_semid.sem_perm.gid; - linux_semid64->sem_perm.mode = linux_semid.sem_perm.mode; - return (0); -} - -static int -linux_semid_pushdown(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr) -{ - struct l_semid_ds linux_semid; - int error; - - if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) - return (copyout(linux_semid64, uaddr, sizeof(*linux_semid64))); - - bzero(&linux_semid, sizeof(linux_semid)); - error = linux_ipc64_perm_to_ipc_perm(&linux_semid64->sem_perm, - &linux_semid.sem_perm); - if (error != 0) - return (error); - - linux_semid.sem_otime = linux_semid64->sem_otime; - linux_semid.sem_ctime = linux_semid64->sem_ctime; - linux_semid.sem_nsems = linux_semid64->sem_nsems; - - /* Linux does not check overflow */ - if (linux_semid.sem_otime != linux_semid64->sem_otime || - linux_semid.sem_ctime != linux_semid64->sem_ctime || - linux_semid.sem_nsems != linux_semid64->sem_nsems) - return (EOVERFLOW); - return (copyout(&linux_semid, uaddr, sizeof(linux_semid))); -} - -static int -linux_shmid_pullup(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr) -{ - struct l_shmid_ds linux_shmid; - int error; - - if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) - return (copyin(uaddr, linux_shmid64, sizeof(*linux_shmid64))); - - error = copyin(uaddr, &linux_shmid, sizeof(linux_shmid)); - if (error != 0) - return (error); - - bzero(linux_shmid64, sizeof(*linux_shmid64)); - linux_shmid64->shm_perm.uid = linux_shmid.shm_perm.uid; - linux_shmid64->shm_perm.gid = linux_shmid.shm_perm.gid; - linux_shmid64->shm_perm.mode = linux_shmid.shm_perm.mode; - return (0); -} - -static int -linux_shmid_pushdown(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr) -{ - struct l_shmid_ds linux_shmid; - int error; - - if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) - return (copyout(linux_shmid64, uaddr, sizeof(*linux_shmid64))); - - bzero(&linux_shmid, sizeof(linux_shmid)); - error = linux_ipc64_perm_to_ipc_perm(&linux_shmid64->shm_perm, - &linux_shmid.shm_perm); - if (error != 0) - return (error); - - linux_shmid.shm_segsz = linux_shmid64->shm_segsz; - linux_shmid.shm_atime = linux_shmid64->shm_atime; - linux_shmid.shm_dtime = linux_shmid64->shm_dtime; - linux_shmid.shm_ctime = linux_shmid64->shm_ctime; - linux_shmid.shm_cpid = linux_shmid64->shm_cpid; - linux_shmid.shm_lpid = linux_shmid64->shm_lpid; - linux_shmid.shm_nattch = linux_shmid64->shm_nattch; - - /* Linux does not check overflow */ - if (linux_shmid.shm_segsz != linux_shmid64->shm_segsz || - linux_shmid.shm_atime != linux_shmid64->shm_atime || - linux_shmid.shm_dtime != linux_shmid64->shm_dtime || - linux_shmid.shm_ctime != linux_shmid64->shm_ctime || - linux_shmid.shm_cpid != linux_shmid64->shm_cpid || - linux_shmid.shm_lpid != linux_shmid64->shm_lpid || - linux_shmid.shm_nattch != linux_shmid64->shm_nattch) - return (EOVERFLOW); - return (copyout(&linux_shmid, uaddr, sizeof(linux_shmid))); -} - -static int -linux_shminfo_pushdown(l_int ver, struct l_shminfo64 *linux_shminfo64, - caddr_t uaddr) -{ - struct l_shminfo linux_shminfo; - - if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) - return (copyout(linux_shminfo64, uaddr, - sizeof(*linux_shminfo64))); - - bzero(&linux_shminfo, sizeof(linux_shminfo)); - linux_shminfo.shmmax = linux_shminfo64->shmmax; - linux_shminfo.shmmin = linux_shminfo64->shmmin; - linux_shminfo.shmmni = linux_shminfo64->shmmni; - linux_shminfo.shmseg = linux_shminfo64->shmseg; - linux_shminfo.shmall = linux_shminfo64->shmall; - return (copyout(&linux_shminfo, uaddr, sizeof(linux_shminfo))); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_semtimedop_time64(struct thread *td, struct linux_semtimedop_time64_args *args) -{ - struct timespec ts, *tsa; - int error; - - if (args->timeout) { - error = linux_get_timespec64(&ts, args->timeout); - if (error != 0) - return (error); - tsa = &ts; - } else - tsa = NULL; - - return (kern_semop(td, args->semid, PTRIN(args->tsops), - args->nsops, tsa)); -} -#endif /* __i386__) || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_semtimedop(struct thread *td, struct linux_semtimedop_args *args) -{ - struct timespec ts, *tsa; - int error; - - if (args->timeout) { - error = linux_get_timespec(&ts, args->timeout); - if (error != 0) - return (error); - tsa = &ts; - } else - tsa = NULL; - - return (kern_semop(td, args->semid, PTRIN(args->tsops), - args->nsops, tsa)); -} - -int -linux_semget(struct thread *td, struct linux_semget_args *args) -{ - struct semget_args bsd_args = { - .key = args->key, - .nsems = args->nsems, - .semflg = args->semflg - }; - - if (args->nsems < 0) - return (EINVAL); - return (sys_semget(td, &bsd_args)); -} - -int -linux_semctl(struct thread *td, struct linux_semctl_args *args) -{ - struct l_semid64_ds linux_semid64; - struct l_seminfo linux_seminfo; - struct semid_ds semid; - union semun semun; - register_t rval; - int cmd, error; - - memset(&linux_seminfo, 0, sizeof(linux_seminfo)); - memset(&linux_semid64, 0, sizeof(linux_semid64)); - - switch (args->cmd & ~LINUX_IPC_64) { - case LINUX_IPC_RMID: - cmd = IPC_RMID; - break; - case LINUX_GETNCNT: - cmd = GETNCNT; - break; - case LINUX_GETPID: - cmd = GETPID; - break; - case LINUX_GETVAL: - cmd = GETVAL; - break; - case LINUX_GETZCNT: - cmd = GETZCNT; - break; - case LINUX_SETVAL: - cmd = SETVAL; - semun.val = args->arg.val; - break; - case LINUX_IPC_SET: - cmd = IPC_SET; - error = linux_semid_pullup(args->cmd & LINUX_IPC_64, - &linux_semid64, PTRIN(args->arg.buf)); - if (error != 0) - return (error); - linux_to_bsd_semid_ds(&linux_semid64, &semid); - semun.buf = &semid; - return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, - td->td_retval)); - case LINUX_IPC_STAT: - cmd = IPC_STAT; - semun.buf = &semid; - error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, - &rval); - if (error != 0) - return (error); - bsd_to_linux_semid_ds(&semid, &linux_semid64); - return (linux_semid_pushdown(args->cmd & LINUX_IPC_64, - &linux_semid64, PTRIN(args->arg.buf))); - case LINUX_SEM_STAT: - cmd = SEM_STAT; - semun.buf = &semid; - error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, - &rval); - if (error != 0) - return (error); - bsd_to_linux_semid_ds(&semid, &linux_semid64); - error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, - &linux_semid64, PTRIN(args->arg.buf)); - if (error == 0) - td->td_retval[0] = rval; - return (error); - case LINUX_IPC_INFO: - case LINUX_SEM_INFO: - bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) - - sizeof(linux_seminfo.semmap) ); - /* - * Linux does not use the semmap field but populates it with - * the defined value from SEMMAP, which really is redefined to - * SEMMNS, which they define as SEMMNI * SEMMSL. Try to - * simulate this returning our dynamic semmns value. - */ - linux_seminfo.semmap = linux_seminfo.semmns; -/* XXX BSD equivalent? -#define used_semids 10 -#define used_sems 10 - linux_seminfo.semusz = used_semids; - linux_seminfo.semaem = used_sems; -*/ - error = copyout(&linux_seminfo, - PTRIN(args->arg.buf), sizeof(linux_seminfo)); - if (error != 0) - return (error); - /* - * TODO: Linux return the last assigned id, not the semmni. - */ - td->td_retval[0] = seminfo.semmni; - return (0); - case LINUX_GETALL: - cmd = GETALL; - semun.array = __USER_CAP_UNBOUND(PTRIN(args->arg.array)); - break; - case LINUX_SETALL: - cmd = SETALL; - semun.array = __USER_CAP_UNBOUND(PTRIN(args->arg.array)); - break; - default: - linux_msg(td, "ipc type %d is not implemented", - args->cmd & ~LINUX_IPC_64); - return (EINVAL); - } - return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, - td->td_retval)); -} - -int -linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) -{ - const void *msgp; - long mtype; - l_long lmtype; - int error; - - if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) - return (EINVAL); - msgp = PTRIN(args->msgp); - if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0) - return (error); - mtype = (long)lmtype; - return (kern_msgsnd(td, args->msqid, - PTR2CAP((const char *)msgp) + sizeof(lmtype), - args->msgsz, args->msgflg, mtype)); -} - -int -linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) -{ - void *msgp; - long mtype; - l_long lmtype; - int error; - - if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) - return (EINVAL); - msgp = PTRIN(args->msgp); - if ((error = kern_msgrcv(td, args->msqid, - PTR2CAP((char *)msgp) + sizeof(lmtype), args->msgsz, - args->msgtyp, args->msgflg, &mtype)) != 0) - return (error); - lmtype = (l_long)mtype; - return (copyout(&lmtype, msgp, sizeof(lmtype))); -} - -int -linux_msgget(struct thread *td, struct linux_msgget_args *args) -{ - struct msgget_args bsd_args = { - .key = args->key, - .msgflg = args->msgflg - }; - - return (sys_msgget(td, &bsd_args)); -} - -int -linux_msgctl(struct thread *td, struct linux_msgctl_args *args) -{ - int error, bsd_cmd; - struct l_msqid64_ds linux_msqid64; - struct msqid_ds bsd_msqid; - - memset(&linux_msqid64, 0, sizeof(linux_msqid64)); - - bsd_cmd = args->cmd & ~LINUX_IPC_64; - switch (bsd_cmd) { - case LINUX_IPC_INFO: - case LINUX_MSG_INFO: { - struct l_msginfo linux_msginfo; - - memset(&linux_msginfo, 0, sizeof(linux_msginfo)); - /* - * XXX MSG_INFO uses the same data structure but returns different - * dynamic counters in msgpool, msgmap, and msgtql fields. - */ - linux_msginfo.msgpool = (long)msginfo.msgmni * - (long)msginfo.msgmnb / 1024L; /* XXX MSG_INFO. */ - linux_msginfo.msgmap = msginfo.msgmnb; /* XXX MSG_INFO. */ - linux_msginfo.msgmax = msginfo.msgmax; - linux_msginfo.msgmnb = msginfo.msgmnb; - linux_msginfo.msgmni = msginfo.msgmni; - linux_msginfo.msgssz = msginfo.msgssz; - linux_msginfo.msgtql = msginfo.msgtql; /* XXX MSG_INFO. */ - linux_msginfo.msgseg = msginfo.msgseg; - error = copyout(&linux_msginfo, PTRIN(args->buf), - sizeof(linux_msginfo)); - if (error == 0) - td->td_retval[0] = msginfo.msgmni; /* XXX */ - - return (error); - } - - /* - * TODO: implement this - * case LINUX_MSG_STAT: - */ - case LINUX_IPC_STAT: - /* NOTHING */ - break; - - case LINUX_IPC_SET: - error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, - &linux_msqid64, PTRIN(args->buf)); - if (error != 0) - return (error); - linux_to_bsd_msqid_ds(&linux_msqid64, &bsd_msqid); - break; - - case LINUX_IPC_RMID: - /* NOTHING */ - break; - - default: - return (EINVAL); - break; - } - - error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid); - if (error != 0) { - if (bsd_cmd == LINUX_IPC_RMID && error == EACCES) - return (EPERM); - if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL) - return (error); - } - - if (bsd_cmd == LINUX_IPC_STAT) { - bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid64); - return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, - &linux_msqid64, PTRIN(args->buf))); - } - - return (0); -} - -int -linux_shmat(struct thread *td, struct linux_shmat_args *args) -{ - struct shmat_args bsd_args = { - .shmid = args->shmid, - .shmaddr = PTRIN(args->shmaddr), - .shmflg = args->shmflg - }; - - return (sys_shmat(td, &bsd_args)); -} - -int -linux_shmdt(struct thread *td, struct linux_shmdt_args *args) -{ - struct shmdt_args bsd_args = { - .shmaddr = PTRIN(args->shmaddr) - }; - - return (sys_shmdt(td, &bsd_args)); -} - -int -linux_shmget(struct thread *td, struct linux_shmget_args *args) -{ - struct shmget_args bsd_args = { - .key = args->key, - .size = args->size, - .shmflg = args->shmflg - }; - - return (sys_shmget(td, &bsd_args)); -} - -int -linux_shmctl(struct thread *td, struct linux_shmctl_args *args) -{ - struct l_shmid64_ds linux_shmid64; - struct l_shminfo64 linux_shminfo64; - struct l_shm_info linux_shm_info; - struct shmid_ds bsd_shmid; - int error; - - memset(&linux_shm_info, 0, sizeof(linux_shm_info)); - memset(&linux_shmid64, 0, sizeof(linux_shmid64)); - memset(&linux_shminfo64, 0, sizeof(linux_shminfo64)); - - switch (args->cmd & ~LINUX_IPC_64) { - case LINUX_IPC_INFO: { - struct shminfo bsd_shminfo; - - /* Perform shmctl wanting removed segments lookup */ - error = kern_shmctl(td, args->shmid, IPC_INFO, - (void *)&bsd_shminfo, NULL); - if (error != 0) - return (error); - - bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo64); - - return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, - &linux_shminfo64, PTRIN(args->buf))); - } - - case LINUX_SHM_INFO: { - struct shm_info bsd_shm_info; - - /* Perform shmctl wanting removed segments lookup */ - error = kern_shmctl(td, args->shmid, SHM_INFO, - (void *)&bsd_shm_info, NULL); - if (error != 0) - return (error); - - bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info); - - return (copyout(&linux_shm_info, PTRIN(args->buf), - sizeof(struct l_shm_info))); - } - - case LINUX_IPC_STAT: - /* Perform shmctl wanting removed segments lookup */ - error = kern_shmctl(td, args->shmid, IPC_STAT, - (void *)&bsd_shmid, NULL); - if (error != 0) - return (error); - - bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64); - - return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, - &linux_shmid64, PTRIN(args->buf))); - - case LINUX_SHM_STAT: - /* Perform shmctl wanting removed segments lookup */ - error = kern_shmctl(td, args->shmid, IPC_STAT, - (void *)&bsd_shmid, NULL); - if (error != 0) - return (error); - - bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64); - - return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, - &linux_shmid64, PTRIN(args->buf))); - - case LINUX_IPC_SET: - error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, - &linux_shmid64, PTRIN(args->buf)); - if (error != 0) - return (error); - - linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid); - - /* Perform shmctl wanting removed segments lookup */ - return (kern_shmctl(td, args->shmid, IPC_SET, - (void *)&bsd_shmid, NULL)); - - case LINUX_IPC_RMID: { - void *buf; - - if (args->buf == 0) - buf = NULL; - else { - error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, - &linux_shmid64, PTRIN(args->buf)); - if (error != 0) - return (error); - linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid); - buf = (void *)&bsd_shmid; - } - return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL)); - } - - case LINUX_SHM_LOCK: - /* FALLTHROUGH */ - case LINUX_SHM_UNLOCK: - /* FALLTHROUGH */ - default: - linux_msg(td, "ipc type %d not implemented", - args->cmd & ~LINUX_IPC_64); - return (EINVAL); - } -} - -MODULE_DEPEND(linux, sysvmsg, 1, 1, 1); -MODULE_DEPEND(linux, sysvsem, 1, 1, 1); -MODULE_DEPEND(linux, sysvshm, 1, 1, 1); -// CHERI CHANGES START -// { -// "updated": 20230509, -// "target_type": "kernel", -// "changes": [ -// "integer_provenance", -// "user_capabilities" -// ] -// } -// CHERI CHANGES END +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include + +/* + * old, pre 2.4 kernel + */ +struct l_ipc_perm { + l_key_t key; + l_uid16_t uid; + l_gid16_t gid; + l_uid16_t cuid; + l_gid16_t cgid; + l_ushort mode; + l_ushort seq; +}; + +struct l_seminfo { + l_int semmap; + l_int semmni; + l_int semmns; + l_int semmnu; + l_int semmsl; + l_int semopm; + l_int semume; + l_int semusz; + l_int semvmx; + l_int semaem; +}; + +struct l_shminfo { + l_int shmmax; + l_int shmmin; + l_int shmmni; + l_int shmseg; + l_int shmall; +}; + +struct l_shm_info { + l_int used_ids; + l_ulong shm_tot; /* total allocated shm */ + l_ulong shm_rss; /* total resident shm */ + l_ulong shm_swp; /* total swapped shm */ + l_ulong swap_attempts; + l_ulong swap_successes; +}; + +struct l_msginfo { + l_int msgpool; + l_int msgmap; + l_int msgmax; + l_int msgmnb; + l_int msgmni; + l_int msgssz; + l_int msgtql; + l_ushort msgseg; +}; + +static void +bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo64 *lpp) +{ + + lpp->shmmax = bpp->shmmax; + lpp->shmmin = bpp->shmmin; + lpp->shmmni = bpp->shmmni; + lpp->shmseg = bpp->shmseg; + lpp->shmall = bpp->shmall; +} + +static void +bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp) +{ + + lpp->used_ids = bpp->used_ids; + lpp->shm_tot = bpp->shm_tot; + lpp->shm_rss = bpp->shm_rss; + lpp->shm_swp = bpp->shm_swp; + lpp->swap_attempts = bpp->swap_attempts; + lpp->swap_successes = bpp->swap_successes; +} + +static void +linux_to_bsd_ipc_perm(struct l_ipc64_perm *lpp, struct ipc_perm *bpp) +{ + + bpp->key = lpp->key; + bpp->uid = lpp->uid; + bpp->gid = lpp->gid; + bpp->cuid = lpp->cuid; + bpp->cgid = lpp->cgid; + bpp->mode = lpp->mode; + bpp->seq = lpp->seq; +} + +static void +bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc64_perm *lpp) +{ + + lpp->key = bpp->key; + lpp->uid = bpp->uid; + lpp->gid = bpp->gid; + lpp->cuid = bpp->cuid; + lpp->cgid = bpp->cgid; + lpp->mode = bpp->mode & (S_IRWXU|S_IRWXG|S_IRWXO); + lpp->seq = bpp->seq; +} + +struct l_msqid_ds { + struct l_ipc_perm msg_perm; + l_uintptr_t msg_first; /* first message on queue,unused */ + l_uintptr_t msg_last; /* last message in queue,unused */ + l_time_t msg_stime; /* last msgsnd time */ + l_time_t msg_rtime; /* last msgrcv time */ + l_time_t msg_ctime; /* last change time */ + l_ulong msg_lcbytes; /* Reuse junk fields for 32 bit */ + l_ulong msg_lqbytes; /* ditto */ + l_ushort msg_cbytes; /* current number of bytes on queue */ + l_ushort msg_qnum; /* number of messages in queue */ + l_ushort msg_qbytes; /* max number of bytes on queue */ + l_pid_t msg_lspid; /* pid of last msgsnd */ + l_pid_t msg_lrpid; /* last receive pid */ +}; + +struct l_semid_ds { + struct l_ipc_perm sem_perm; + l_time_t sem_otime; + l_time_t sem_ctime; + l_uintptr_t sem_base; + l_uintptr_t sem_pending; + l_uintptr_t sem_pending_last; + l_uintptr_t undo; + l_ushort sem_nsems; +}; + +struct l_shmid_ds { + struct l_ipc_perm shm_perm; + l_int shm_segsz; + l_time_t shm_atime; + l_time_t shm_dtime; + l_time_t shm_ctime; + l_ushort shm_cpid; + l_ushort shm_lpid; + l_short shm_nattch; + l_ushort private1; + l_uintptr_t private2; + l_uintptr_t private3; +}; + +static void +linux_to_bsd_semid_ds(struct l_semid64_ds *lsp, struct semid_ds *bsp) +{ + + linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); + bsp->sem_otime = lsp->sem_otime; + bsp->sem_ctime = lsp->sem_ctime; + bsp->sem_nsems = lsp->sem_nsems; +} + +static void +bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid64_ds *lsp) +{ + + bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); + lsp->sem_otime = bsp->sem_otime; + lsp->sem_ctime = bsp->sem_ctime; + lsp->sem_nsems = bsp->sem_nsems; +} + +static void +linux_to_bsd_shmid_ds(struct l_shmid64_ds *lsp, struct shmid_ds *bsp) +{ + + linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); + bsp->shm_segsz = lsp->shm_segsz; + bsp->shm_lpid = lsp->shm_lpid; + bsp->shm_cpid = lsp->shm_cpid; + bsp->shm_nattch = lsp->shm_nattch; + bsp->shm_atime = lsp->shm_atime; + bsp->shm_dtime = lsp->shm_dtime; + bsp->shm_ctime = lsp->shm_ctime; +} + +static void +bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid64_ds *lsp) +{ + + bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); + lsp->shm_segsz = bsp->shm_segsz; + lsp->shm_lpid = bsp->shm_lpid; + lsp->shm_cpid = bsp->shm_cpid; + lsp->shm_nattch = bsp->shm_nattch; + lsp->shm_atime = bsp->shm_atime; + lsp->shm_dtime = bsp->shm_dtime; + lsp->shm_ctime = bsp->shm_ctime; +} + +static void +linux_to_bsd_msqid_ds(struct l_msqid64_ds *lsp, struct msqid_ds *bsp) +{ + + linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm); + bsp->msg_cbytes = lsp->msg_cbytes; + bsp->msg_qnum = lsp->msg_qnum; + bsp->msg_qbytes = lsp->msg_qbytes; + bsp->msg_lspid = lsp->msg_lspid; + bsp->msg_lrpid = lsp->msg_lrpid; + bsp->msg_stime = lsp->msg_stime; + bsp->msg_rtime = lsp->msg_rtime; + bsp->msg_ctime = lsp->msg_ctime; +} + +static void +bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid64_ds *lsp) +{ + + bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm); + lsp->msg_cbytes = bsp->msg_cbytes; + lsp->msg_qnum = bsp->msg_qnum; + lsp->msg_qbytes = bsp->msg_qbytes; + lsp->msg_lspid = bsp->msg_lspid; + lsp->msg_lrpid = bsp->msg_lrpid; + lsp->msg_stime = bsp->msg_stime; + lsp->msg_rtime = bsp->msg_rtime; + lsp->msg_ctime = bsp->msg_ctime; +} + +static int +linux_ipc64_perm_to_ipc_perm(struct l_ipc64_perm *in, struct l_ipc_perm *out) +{ + + out->key = in->key; + out->uid = in->uid; + out->gid = in->gid; + out->cuid = in->cuid; + out->cgid = in->cgid; + out->mode = in->mode; + out->seq = in->seq; + + /* Linux does not check overflow */ + if (out->uid != in->uid || out->gid != in->gid || + out->cuid != in->cuid || out->cgid != in->cgid || + out->mode != in->mode) + return (EOVERFLOW); + else + return (0); +} + +static int +linux_msqid_pullup(l_int ver, struct l_msqid64_ds *linux_msqid64, void * __linuxcap uaddr) +{ + struct l_msqid_ds linux_msqid; + int error; + + if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) + return (copyin(LINUX_USER_CAP(uaddr, sizeof(*linux_msqid64)), linux_msqid64, sizeof(*linux_msqid64))); + + error = copyin(LINUX_USER_CAP(uaddr, sizeof(linux_msqid)), &linux_msqid, sizeof(linux_msqid)); + if (error != 0) + return (error); + + bzero(linux_msqid64, sizeof(*linux_msqid64)); + linux_msqid64->msg_perm.uid = linux_msqid.msg_perm.uid; + linux_msqid64->msg_perm.gid = linux_msqid.msg_perm.gid; + linux_msqid64->msg_perm.mode = linux_msqid.msg_perm.mode; + if (linux_msqid.msg_qbytes == 0) + linux_msqid64->msg_qbytes = linux_msqid.msg_lqbytes; + else + linux_msqid64->msg_qbytes = linux_msqid.msg_qbytes; + return (0); +} + +static int +linux_msqid_pushdown(l_int ver, struct l_msqid64_ds *linux_msqid64, void * __linuxcap uaddr) +{ + struct l_msqid_ds linux_msqid; + int error; + + if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) + return (copyout(linux_msqid64, LINUX_USER_CAP(uaddr, sizeof(*linux_msqid64)), sizeof(*linux_msqid64))); + + bzero(&linux_msqid, sizeof(linux_msqid)); + error = linux_ipc64_perm_to_ipc_perm(&linux_msqid64->msg_perm, + &linux_msqid.msg_perm); + if (error != 0) + return (error); + + linux_msqid.msg_stime = linux_msqid64->msg_stime; + linux_msqid.msg_rtime = linux_msqid64->msg_rtime; + linux_msqid.msg_ctime = linux_msqid64->msg_ctime; + + if (linux_msqid64->msg_cbytes > USHRT_MAX) + linux_msqid.msg_cbytes = USHRT_MAX; + else + linux_msqid.msg_cbytes = linux_msqid64->msg_cbytes; + linux_msqid.msg_lcbytes = linux_msqid64->msg_cbytes; + if (linux_msqid64->msg_qnum > USHRT_MAX) + linux_msqid.msg_qnum = USHRT_MAX; + else + linux_msqid.msg_qnum = linux_msqid64->msg_qnum; + if (linux_msqid64->msg_qbytes > USHRT_MAX) + linux_msqid.msg_qbytes = USHRT_MAX; + else + linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes; + linux_msqid.msg_lqbytes = linux_msqid64->msg_qbytes; + linux_msqid.msg_lspid = linux_msqid64->msg_lspid; + linux_msqid.msg_lrpid = linux_msqid64->msg_lrpid; + + /* Linux does not check overflow */ + if (linux_msqid.msg_stime != linux_msqid64->msg_stime || + linux_msqid.msg_rtime != linux_msqid64->msg_rtime || + linux_msqid.msg_ctime != linux_msqid64->msg_ctime) + return (EOVERFLOW); + return (copyout(&linux_msqid, LINUX_USER_CAP(uaddr, sizeof(linux_msqid)), sizeof(linux_msqid))); +} + +static int +linux_semid_pullup(l_int ver, struct l_semid64_ds *linux_semid64, void * __linuxcap uaddr) +{ + struct l_semid_ds linux_semid; + int error; + + if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) + return (copyin(LINUX_USER_CAP(uaddr, sizeof(*linux_semid64)), linux_semid64, sizeof(*linux_semid64))); + error = copyin(LINUX_USER_CAP(uaddr, sizeof(linux_semid)), &linux_semid, sizeof(linux_semid)); + if (error != 0) + return (error); + + bzero(linux_semid64, sizeof(*linux_semid64)); + linux_semid64->sem_perm.uid = linux_semid.sem_perm.uid; + linux_semid64->sem_perm.gid = linux_semid.sem_perm.gid; + linux_semid64->sem_perm.mode = linux_semid.sem_perm.mode; + return (0); +} + +static int +linux_semid_pushdown(l_int ver, struct l_semid64_ds *linux_semid64, void * __linuxcap uaddr) +{ + struct l_semid_ds linux_semid; + int error; + + if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) + return (copyout(linux_semid64, LINUX_USER_CAP(uaddr, sizeof(*linux_semid64)), sizeof(*linux_semid64))); + + bzero(&linux_semid, sizeof(linux_semid)); + error = linux_ipc64_perm_to_ipc_perm(&linux_semid64->sem_perm, + &linux_semid.sem_perm); + if (error != 0) + return (error); + + linux_semid.sem_otime = linux_semid64->sem_otime; + linux_semid.sem_ctime = linux_semid64->sem_ctime; + linux_semid.sem_nsems = linux_semid64->sem_nsems; + + /* Linux does not check overflow */ + if (linux_semid.sem_otime != linux_semid64->sem_otime || + linux_semid.sem_ctime != linux_semid64->sem_ctime || + linux_semid.sem_nsems != linux_semid64->sem_nsems) + return (EOVERFLOW); + return (copyout(&linux_semid, LINUX_USER_CAP(uaddr, sizeof(linux_semid)), sizeof(linux_semid))); +} + +static int +linux_shmid_pullup(l_int ver, struct l_shmid64_ds *linux_shmid64, void * __linuxcap uaddr) +{ + struct l_shmid_ds linux_shmid; + int error; + + if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) + return (copyin(LINUX_USER_CAP(uaddr, sizeof(*linux_shmid64)), linux_shmid64, sizeof(*linux_shmid64))); + + error = copyin(LINUX_USER_CAP(uaddr, sizeof(linux_shmid)), &linux_shmid, sizeof(linux_shmid)); + if (error != 0) + return (error); + + bzero(linux_shmid64, sizeof(*linux_shmid64)); + linux_shmid64->shm_perm.uid = linux_shmid.shm_perm.uid; + linux_shmid64->shm_perm.gid = linux_shmid.shm_perm.gid; + linux_shmid64->shm_perm.mode = linux_shmid.shm_perm.mode; + return (0); +} + +static int +linux_shmid_pushdown(l_int ver, struct l_shmid64_ds *linux_shmid64, void * __linuxcap uaddr) +{ + struct l_shmid_ds linux_shmid; + int error; + + if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) + return (copyout(linux_shmid64, LINUX_USER_CAP(uaddr, sizeof(*linux_shmid64)), sizeof(*linux_shmid64))); + + bzero(&linux_shmid, sizeof(linux_shmid)); + error = linux_ipc64_perm_to_ipc_perm(&linux_shmid64->shm_perm, + &linux_shmid.shm_perm); + if (error != 0) + return (error); + + linux_shmid.shm_segsz = linux_shmid64->shm_segsz; + linux_shmid.shm_atime = linux_shmid64->shm_atime; + linux_shmid.shm_dtime = linux_shmid64->shm_dtime; + linux_shmid.shm_ctime = linux_shmid64->shm_ctime; + linux_shmid.shm_cpid = linux_shmid64->shm_cpid; + linux_shmid.shm_lpid = linux_shmid64->shm_lpid; + linux_shmid.shm_nattch = linux_shmid64->shm_nattch; + + /* Linux does not check overflow */ + if (linux_shmid.shm_segsz != linux_shmid64->shm_segsz || + linux_shmid.shm_atime != linux_shmid64->shm_atime || + linux_shmid.shm_dtime != linux_shmid64->shm_dtime || + linux_shmid.shm_ctime != linux_shmid64->shm_ctime || + linux_shmid.shm_cpid != linux_shmid64->shm_cpid || + linux_shmid.shm_lpid != linux_shmid64->shm_lpid || + linux_shmid.shm_nattch != linux_shmid64->shm_nattch) + return (EOVERFLOW); + return (copyout(&linux_shmid, LINUX_USER_CAP(uaddr, sizeof(linux_shmid)), sizeof(linux_shmid))); +} + +static int +linux_shminfo_pushdown(l_int ver, struct l_shminfo64 *linux_shminfo64, + void * __linuxcap uaddr) +{ + struct l_shminfo linux_shminfo; + + if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) + return (copyout(linux_shminfo64, LINUX_USER_CAP(uaddr, sizeof(*linux_shminfo64)), + sizeof(*linux_shminfo64))); + + bzero(&linux_shminfo, sizeof(linux_shminfo)); + linux_shminfo.shmmax = linux_shminfo64->shmmax; + linux_shminfo.shmmin = linux_shminfo64->shmmin; + linux_shminfo.shmmni = linux_shminfo64->shmmni; + linux_shminfo.shmseg = linux_shminfo64->shmseg; + linux_shminfo.shmall = linux_shminfo64->shmall; + return (copyout(&linux_shminfo, LINUX_USER_CAP(uaddr, sizeof(linux_shminfo)), sizeof(linux_shminfo))); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_semtimedop_time64(struct thread *td, struct linux_semtimedop_time64_args *args) +{ + struct timespec ts, *tsa; + int error; + + if (args->timeout) { + error = linux_get_timespec64(&ts, args->timeout); + if (error != 0) + return (error); + tsa = &ts; + } else + tsa = NULL; + + return (kern_semop(td, args->semid, PTRIN(args->tsops), + args->nsops, tsa)); +} +#endif /* __i386__) || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_semtimedop(struct thread *td, struct linux_semtimedop_args *args) +{ + struct timespec ts, *tsa; + int error; + + if (args->timeout) { + error = linux_get_timespec(&ts, args->timeout); + if (error != 0) + return (error); + tsa = &ts; + } else + tsa = NULL; + + return (kern_semop(td, args->semid, LINUX_USER_CAP(args->tsops, sizeof(struct sembuf) * args->nsops), + args->nsops, tsa)); +} + +int +linux_semop(struct thread *td, struct linux_semop_args *args) +{ + + struct semop_args bargs = { + .semid = args->semid, + .sops = LINUX_USER_CAP_ARRAY(args->sops, args->nsops), + .nsops = args->nsops + }; + + return (sys_semop(td, &bargs)); +} + +int +linux_semget(struct thread *td, struct linux_semget_args *args) +{ + struct semget_args bsd_args = { + .key = args->key, + .nsems = args->nsems, + .semflg = args->semflg + }; + + if (args->nsems < 0) + return (EINVAL); + return (sys_semget(td, &bsd_args)); +} + +int +linux_semctl(struct thread *td, struct linux_semctl_args *args) +{ + struct l_semid64_ds linux_semid64; + struct l_seminfo linux_seminfo; + struct semid_ds semid; + union semun semun; + register_t rval; + int cmd, error; + + memset(&linux_seminfo, 0, sizeof(linux_seminfo)); + memset(&linux_semid64, 0, sizeof(linux_semid64)); + + switch (args->cmd & ~LINUX_IPC_64) { + case LINUX_IPC_RMID: + cmd = IPC_RMID; + break; + case LINUX_GETNCNT: + cmd = GETNCNT; + break; + case LINUX_GETPID: + cmd = GETPID; + break; + case LINUX_GETVAL: + cmd = GETVAL; + break; + case LINUX_GETZCNT: + cmd = GETZCNT; + break; + case LINUX_SETVAL: + cmd = SETVAL; + semun.val = args->arg.val; + break; + case LINUX_IPC_SET: + cmd = IPC_SET; + error = linux_semid_pullup(args->cmd & LINUX_IPC_64, + &linux_semid64, (void * __linuxcap)(linuxcap_t)(args->arg.buf)); + if (error != 0) + return (error); + linux_to_bsd_semid_ds(&linux_semid64, &semid); + semun.buf = &semid; + return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, + (register_t *)td->td_retval)); + case LINUX_IPC_STAT: + cmd = IPC_STAT; + semun.buf = &semid; + error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, + &rval); + if (error != 0) + return (error); + bsd_to_linux_semid_ds(&semid, &linux_semid64); + return (linux_semid_pushdown(args->cmd & LINUX_IPC_64, + &linux_semid64, (void * __linuxcap)(linuxcap_t)(args->arg.buf))); + case LINUX_SEM_STAT: + cmd = SEM_STAT; + semun.buf = &semid; + error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, + &rval); + if (error != 0) + return (error); + bsd_to_linux_semid_ds(&semid, &linux_semid64); + error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, + &linux_semid64, (void * __linuxcap)(linuxcap_t)(args->arg.buf)); + if (error == 0) + td->td_retval[0] = rval; + return (error); + case LINUX_IPC_INFO: + case LINUX_SEM_INFO: + bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) - + sizeof(linux_seminfo.semmap) ); + /* + * Linux does not use the semmap field but populates it with + * the defined value from SEMMAP, which really is redefined to + * SEMMNS, which they define as SEMMNI * SEMMSL. Try to + * simulate this returning our dynamic semmns value. + */ + linux_seminfo.semmap = linux_seminfo.semmns; +/* XXX BSD equivalent? +#define used_semids 10 +#define used_sems 10 + linux_seminfo.semusz = used_semids; + linux_seminfo.semaem = used_sems; +*/ + error = copyout(&linux_seminfo, + LINUX_USER_CAP(args->arg.buf, sizeof(linux_seminfo)), sizeof(linux_seminfo)); + if (error != 0) + return (error); + /* + * TODO: Linux return the last assigned id, not the semmni. + */ + td->td_retval[0] = seminfo.semmni; + return (0); + case LINUX_GETALL: + cmd = GETALL; + semun.array = LINUX_USER_CAP_UNBOUND(args->arg.array); + break; + case LINUX_SETALL: + cmd = SETALL; + semun.array = LINUX_USER_CAP_UNBOUND(args->arg.array); + break; + default: + linux_msg(td, "ipc type %d is not implemented", + args->cmd & ~LINUX_IPC_64); + return (EINVAL); + } + return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, + (register_t *)td->td_retval)); +} + +int +linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) +{ + const void * __capability msgp; + long mtype; + l_long lmtype; + int error; + + if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) + return (EINVAL); + msgp = LINUX_USER_CAP(args->msgp, sizeof(lmtype) + args->msgsz); + if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0) + return (error); + mtype = (long)lmtype; + return (kern_msgsnd(td, args->msqid, + (const char * __capability)msgp + sizeof(lmtype), + args->msgsz, args->msgflg, mtype)); +} + +int +linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) +{ + void * __capability msgp; + long mtype; + l_long lmtype; + int error; + + if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) + return (EINVAL); + msgp = LINUX_USER_CAP(args->msgp, sizeof(lmtype) + args->msgsz); + if ((error = kern_msgrcv(td, args->msqid, + (char * __capability)msgp + sizeof(lmtype), args->msgsz, + args->msgtyp, args->msgflg, &mtype)) != 0) + return (error); + lmtype = (l_long)mtype; + return (copyout(&lmtype, msgp, sizeof(lmtype))); +} + +int +linux_msgget(struct thread *td, struct linux_msgget_args *args) +{ + struct msgget_args bsd_args = { + .key = args->key, + .msgflg = args->msgflg + }; + + return (sys_msgget(td, &bsd_args)); +} + +int +linux_msgctl(struct thread *td, struct linux_msgctl_args *args) +{ + int error, bsd_cmd; + struct l_msqid64_ds linux_msqid64; + struct msqid_ds bsd_msqid; + + memset(&linux_msqid64, 0, sizeof(linux_msqid64)); + + bsd_cmd = args->cmd & ~LINUX_IPC_64; + switch (bsd_cmd) { + case LINUX_IPC_INFO: + case LINUX_MSG_INFO: { + struct l_msginfo linux_msginfo; + + memset(&linux_msginfo, 0, sizeof(linux_msginfo)); + /* + * XXX MSG_INFO uses the same data structure but returns different + * dynamic counters in msgpool, msgmap, and msgtql fields. + */ + linux_msginfo.msgpool = (long)msginfo.msgmni * + (long)msginfo.msgmnb / 1024L; /* XXX MSG_INFO. */ + linux_msginfo.msgmap = msginfo.msgmnb; /* XXX MSG_INFO. */ + linux_msginfo.msgmax = msginfo.msgmax; + linux_msginfo.msgmnb = msginfo.msgmnb; + linux_msginfo.msgmni = msginfo.msgmni; + linux_msginfo.msgssz = msginfo.msgssz; + linux_msginfo.msgtql = msginfo.msgtql; /* XXX MSG_INFO. */ + linux_msginfo.msgseg = msginfo.msgseg; + error = copyout(&linux_msginfo, LINUX_USER_CAP(args->buf, sizeof(linux_msginfo)), + sizeof(linux_msginfo)); + if (error == 0) + td->td_retval[0] = msginfo.msgmni; /* XXX */ + + return (error); + } + + /* + * TODO: implement this + * case LINUX_MSG_STAT: + */ + case LINUX_IPC_STAT: + /* NOTHING */ + break; + + case LINUX_IPC_SET: + error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, + &linux_msqid64, (void * __linuxcap)(args->buf)); + if (error != 0) + return (error); + linux_to_bsd_msqid_ds(&linux_msqid64, &bsd_msqid); + break; + + case LINUX_IPC_RMID: + /* NOTHING */ + break; + + default: + return (EINVAL); + break; + } + + error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid); + if (error != 0) { + if (bsd_cmd == LINUX_IPC_RMID && error == EACCES) + return (EPERM); + if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL) + return (error); + } + + if (bsd_cmd == LINUX_IPC_STAT) { + bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid64); + return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, + &linux_msqid64, (void * __linuxcap)(args->buf))); + } + + return (0); +} + +int +linux_shmat(struct thread *td, struct linux_shmat_args *args) +{ + struct shmat_args bsd_args = { + .shmid = args->shmid, + .shmaddr = LINUX_USER_CAP_UNBOUND(args->shmaddr), + .shmflg = args->shmflg + }; + + return (sys_shmat(td, &bsd_args)); +} + +int +linux_shmdt(struct thread *td, struct linux_shmdt_args *args) +{ + struct shmdt_args bsd_args = { + .shmaddr = LINUX_USER_CAP_UNBOUND(args->shmaddr) + }; + + return (sys_shmdt(td, &bsd_args)); +} + +int +linux_shmget(struct thread *td, struct linux_shmget_args *args) +{ + struct shmget_args bsd_args = { + .key = args->key, + .size = args->size, + .shmflg = args->shmflg + }; + + return (sys_shmget(td, &bsd_args)); +} + +int +linux_shmctl(struct thread *td, struct linux_shmctl_args *args) +{ + struct l_shmid64_ds linux_shmid64; + struct l_shminfo64 linux_shminfo64; + struct l_shm_info linux_shm_info; + struct shmid_ds bsd_shmid; + int error; + + memset(&linux_shm_info, 0, sizeof(linux_shm_info)); + memset(&linux_shmid64, 0, sizeof(linux_shmid64)); + memset(&linux_shminfo64, 0, sizeof(linux_shminfo64)); + + switch (args->cmd & ~LINUX_IPC_64) { + case LINUX_IPC_INFO: { + struct shminfo bsd_shminfo; + + /* Perform shmctl wanting removed segments lookup */ + error = kern_shmctl(td, args->shmid, IPC_INFO, + (void *)&bsd_shminfo, NULL); + if (error != 0) + return (error); + + bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo64); + + return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, + &linux_shminfo64, (void * __linuxcap)(args->buf))); + } + + case LINUX_SHM_INFO: { + struct shm_info bsd_shm_info; + + /* Perform shmctl wanting removed segments lookup */ + error = kern_shmctl(td, args->shmid, SHM_INFO, + (void *)&bsd_shm_info, NULL); + if (error != 0) + return (error); + + bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info); + + return (copyout(&linux_shm_info, LINUX_USER_CAP(args->buf, sizeof(struct l_shm_info)), + sizeof(struct l_shm_info))); + } + + case LINUX_IPC_STAT: + /* Perform shmctl wanting removed segments lookup */ + error = kern_shmctl(td, args->shmid, IPC_STAT, + (void *)&bsd_shmid, NULL); + if (error != 0) + return (error); + + bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64); + + return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, + &linux_shmid64, (void * __linuxcap)(args->buf))); + + case LINUX_SHM_STAT: + /* Perform shmctl wanting removed segments lookup */ + error = kern_shmctl(td, args->shmid, IPC_STAT, + (void *)&bsd_shmid, NULL); + if (error != 0) + return (error); + + bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64); + + return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, + &linux_shmid64, (void * __linuxcap)(args->buf))); + + case LINUX_IPC_SET: + error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, + &linux_shmid64, (void * __linuxcap)(args->buf)); + if (error != 0) + return (error); + + linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid); + + /* Perform shmctl wanting removed segments lookup */ + return (kern_shmctl(td, args->shmid, IPC_SET, + (void *)&bsd_shmid, NULL)); + + case LINUX_IPC_RMID: { + void *buf; + + if (args->buf == 0) + buf = NULL; + else { + error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, + &linux_shmid64, (void * __linuxcap)(args->buf)); + if (error != 0) + return (error); + linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid); + buf = (void *)&bsd_shmid; + } + return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL)); + } + + case LINUX_SHM_LOCK: + /* FALLTHROUGH */ + case LINUX_SHM_UNLOCK: + /* FALLTHROUGH */ + default: + linux_msg(td, "ipc type %d not implemented", + args->cmd & ~LINUX_IPC_64); + return (EINVAL); + } +} + +MODULE_DEPEND(linux, sysvmsg, 1, 1, 1); +MODULE_DEPEND(linux, sysvsem, 1, 1, 1); +MODULE_DEPEND(linux, sysvshm, 1, 1, 1); +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "kernel", +// "changes": [ +// "integer_provenance", +// "user_capabilities" +// ] +// } +// CHERI CHANGES END diff --git a/sys/compat/linux/linux_ipc.h b/sys/compat/linux/linux_ipc.h index c7a512516444..13b01dc545b5 100644 --- a/sys/compat/linux/linux_ipc.h +++ b/sys/compat/linux/linux_ipc.h @@ -1,96 +1,96 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2000 Marcel Moolenaar - * 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. - */ - -#ifndef _LINUX_IPC_H_ -#define _LINUX_IPC_H_ - -/* - * SystemV IPC defines - */ -#define LINUX_SEMOP 1 -#define LINUX_SEMGET 2 -#define LINUX_SEMCTL 3 -#define LINUX_SEMTIMEDOP 4 -#define LINUX_MSGSND 11 -#define LINUX_MSGRCV 12 -#define LINUX_MSGGET 13 -#define LINUX_MSGCTL 14 -#define LINUX_SHMAT 21 -#define LINUX_SHMDT 22 -#define LINUX_SHMGET 23 -#define LINUX_SHMCTL 24 - -#define LINUX_IPC_RMID 0 -#define LINUX_IPC_SET 1 -#define LINUX_IPC_STAT 2 -#define LINUX_IPC_INFO 3 - -#define LINUX_MSG_INFO 12 - -#define LINUX_SHM_LOCK 11 -#define LINUX_SHM_UNLOCK 12 -#define LINUX_SHM_STAT 13 -#define LINUX_SHM_INFO 14 - -#define LINUX_SHM_RDONLY 0x1000 -#define LINUX_SHM_RND 0x2000 -#define LINUX_SHM_REMAP 0x4000 - -/* semctl commands */ -#define LINUX_GETPID 11 -#define LINUX_GETVAL 12 -#define LINUX_GETALL 13 -#define LINUX_GETNCNT 14 -#define LINUX_GETZCNT 15 -#define LINUX_SETVAL 16 -#define LINUX_SETALL 17 -#define LINUX_SEM_STAT 18 -#define LINUX_SEM_INFO 19 - -/* - * Version flags for semctl, msgctl, and shmctl commands - * These are passed as bitflags or-ed with the actual command - */ -#define LINUX_IPC_OLD 0 /* Old version (no 32-bit UID support on many - architectures) */ -#define LINUX_IPC_64 0x0100 /* New version (support 32-bit UIDs, bigger - message sizes, etc. */ - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -struct linux_semtimedop_args -{ - l_int semid; - struct sembuf *tsops; - l_uint nsops; - struct l_timespec *timeout; -}; - -int linux_semtimedop(struct thread *, struct linux_semtimedop_args *); -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -#endif /* _LINUX_IPC_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2000 Marcel Moolenaar + * 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. + */ + +#ifndef _LINUX_IPC_H_ +#define _LINUX_IPC_H_ + +/* + * SystemV IPC defines + */ +#define LINUX_SEMOP 1 +#define LINUX_SEMGET 2 +#define LINUX_SEMCTL 3 +#define LINUX_SEMTIMEDOP 4 +#define LINUX_MSGSND 11 +#define LINUX_MSGRCV 12 +#define LINUX_MSGGET 13 +#define LINUX_MSGCTL 14 +#define LINUX_SHMAT 21 +#define LINUX_SHMDT 22 +#define LINUX_SHMGET 23 +#define LINUX_SHMCTL 24 + +#define LINUX_IPC_RMID 0 +#define LINUX_IPC_SET 1 +#define LINUX_IPC_STAT 2 +#define LINUX_IPC_INFO 3 + +#define LINUX_MSG_INFO 12 + +#define LINUX_SHM_LOCK 11 +#define LINUX_SHM_UNLOCK 12 +#define LINUX_SHM_STAT 13 +#define LINUX_SHM_INFO 14 + +#define LINUX_SHM_RDONLY 0x1000 +#define LINUX_SHM_RND 0x2000 +#define LINUX_SHM_REMAP 0x4000 + +/* semctl commands */ +#define LINUX_GETPID 11 +#define LINUX_GETVAL 12 +#define LINUX_GETALL 13 +#define LINUX_GETNCNT 14 +#define LINUX_GETZCNT 15 +#define LINUX_SETVAL 16 +#define LINUX_SETALL 17 +#define LINUX_SEM_STAT 18 +#define LINUX_SEM_INFO 19 + +/* + * Version flags for semctl, msgctl, and shmctl commands + * These are passed as bitflags or-ed with the actual command + */ +#define LINUX_IPC_OLD 0 /* Old version (no 32-bit UID support on many + architectures) */ +#define LINUX_IPC_64 0x0100 /* New version (support 32-bit UIDs, bigger + message sizes, etc. */ + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +struct linux_semtimedop_args +{ + l_int semid; + struct sembuf *tsops; + l_uint nsops; + struct l_timespec *timeout; +}; + +int linux_semtimedop(struct thread *, struct linux_semtimedop_args *); +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +#endif /* _LINUX_IPC_H_ */ diff --git a/sys/compat/linux/linux_ipc64.h b/sys/compat/linux/linux_ipc64.h index e3834b909bfc..a1c9658b7ffb 100644 --- a/sys/compat/linux/linux_ipc64.h +++ b/sys/compat/linux/linux_ipc64.h @@ -1,160 +1,160 @@ -/*- - * Copyright (c) 2002 Maxim Sobolev - * 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 - * in this position and unchanged. - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - */ - -#ifndef _LINUX_IPC64_H_ -#define _LINUX_IPC64_H_ - -/* - * The generic ipc64_perm structure. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 32-bit mode_t on architectures that only had 16 bit - * - 32-bit seq - * - 2 miscellaneous 32-bit values - */ -struct l_ipc64_perm -{ - l_key_t key; - l_uid_t uid; - l_gid_t gid; - l_uid_t cuid; - l_gid_t cgid; - l_mode_t mode; - /* pad if mode_t is ushort: */ - unsigned char __pad1[sizeof(l_int) - sizeof(l_mode_t)]; - l_ushort seq; - l_ushort __pad2; - l_ulong __unused1; - l_ulong __unused2; -}; - -/* - * The generic msqid64_ds structure fro x86 architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct l_msqid64_ds { - struct l_ipc64_perm msg_perm; - l_time_t msg_stime; /* last msgsnd time */ -#if !defined(__LP64__) || defined(COMPAT_LINUX32) - l_ulong __unused1; -#endif - l_time_t msg_rtime; /* last msgrcv time */ -#if !defined(__LP64__) || defined(COMPAT_LINUX32) - l_ulong __unused2; -#endif - l_time_t msg_ctime; /* last change time */ -#if !defined(__LP64__) || defined(COMPAT_LINUX32) - l_ulong __unused3; -#endif - l_ulong msg_cbytes; /* current number of bytes on queue */ - l_ulong msg_qnum; /* number of messages in queue */ - l_ulong msg_qbytes; /* max number of bytes on queue */ - l_pid_t msg_lspid; /* pid of last msgsnd */ - l_pid_t msg_lrpid; /* last receive pid */ - l_ulong __unused4; - l_ulong __unused5; -}; - -/* - * The generic semid64_ds structure for x86 architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct l_semid64_ds { - struct l_ipc64_perm sem_perm; /* permissions */ - l_time_t sem_otime; /* last semop time */ -#if defined(__amd64__) || defined(__i386__) - l_ulong __unused1; -#endif - l_time_t sem_ctime; /* last change time */ -#if defined(__amd64__) || defined(__i386__) - l_ulong __unused2; -#endif - l_ulong sem_nsems; /* no. of semaphores in array */ - l_ulong __unused3; - l_ulong __unused4; -}; - -/* - * The generic shmid64_ds structure for x86 architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct l_shmid64_ds { - struct l_ipc64_perm shm_perm; /* operation perms */ - l_size_t shm_segsz; /* size of segment (bytes) */ - l_time_t shm_atime; /* last attach time */ -#if !defined(__LP64__) || defined(COMPAT_LINUX32) - l_ulong __unused1; -#endif - l_time_t shm_dtime; /* last detach time */ -#if !defined(__LP64__) || defined(COMPAT_LINUX32) - l_ulong __unused2; -#endif - l_time_t shm_ctime; /* last change time */ -#if !defined(__LP64__) || defined(COMPAT_LINUX32) - l_ulong __unused3; -#endif - l_pid_t shm_cpid; /* pid of creator */ - l_pid_t shm_lpid; /* pid of last operator */ - l_ulong shm_nattch; /* no. of current attaches */ - l_ulong __unused4; - l_ulong __unused5; -}; - -struct l_shminfo64 { - l_ulong shmmax; - l_ulong shmmin; - l_ulong shmmni; - l_ulong shmseg; - l_ulong shmall; - l_ulong __unused1; - l_ulong __unused2; - l_ulong __unused3; - l_ulong __unused4; -}; - -#endif /* !LINUX_IPC64_H_ */ +/*- + * Copyright (c) 2002 Maxim Sobolev + * 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 + * in this position and unchanged. + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#ifndef _LINUX_IPC64_H_ +#define _LINUX_IPC64_H_ + +/* + * The generic ipc64_perm structure. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit mode_t on architectures that only had 16 bit + * - 32-bit seq + * - 2 miscellaneous 32-bit values + */ +struct l_ipc64_perm +{ + l_key_t key; + l_uid_t uid; + l_gid_t gid; + l_uid_t cuid; + l_gid_t cgid; + l_mode_t mode; + /* pad if mode_t is ushort: */ + unsigned char __pad1[sizeof(l_int) - sizeof(l_mode_t)]; + l_ushort seq; + l_ushort __pad2; + l_ulong __unused1; + l_ulong __unused2; +}; + +/* + * The generic msqid64_ds structure fro x86 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct l_msqid64_ds { + struct l_ipc64_perm msg_perm; + l_time_t msg_stime; /* last msgsnd time */ +#if !defined(__LP64__) || defined(COMPAT_LINUX32) + l_ulong __unused1; +#endif + l_time_t msg_rtime; /* last msgrcv time */ +#if !defined(__LP64__) || defined(COMPAT_LINUX32) + l_ulong __unused2; +#endif + l_time_t msg_ctime; /* last change time */ +#if !defined(__LP64__) || defined(COMPAT_LINUX32) + l_ulong __unused3; +#endif + l_ulong msg_cbytes; /* current number of bytes on queue */ + l_ulong msg_qnum; /* number of messages in queue */ + l_ulong msg_qbytes; /* max number of bytes on queue */ + l_pid_t msg_lspid; /* pid of last msgsnd */ + l_pid_t msg_lrpid; /* last receive pid */ + l_ulong __unused4; + l_ulong __unused5; +}; + +/* + * The generic semid64_ds structure for x86 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct l_semid64_ds { + struct l_ipc64_perm sem_perm; /* permissions */ + l_time_t sem_otime; /* last semop time */ +#if defined(__amd64__) || defined(__i386__) + l_ulong __unused1; +#endif + l_time_t sem_ctime; /* last change time */ +#if defined(__amd64__) || defined(__i386__) + l_ulong __unused2; +#endif + l_ulong sem_nsems; /* no. of semaphores in array */ + l_ulong __unused3; + l_ulong __unused4; +}; + +/* + * The generic shmid64_ds structure for x86 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct l_shmid64_ds { + struct l_ipc64_perm shm_perm; /* operation perms */ + l_size_t shm_segsz; /* size of segment (bytes) */ + l_time_t shm_atime; /* last attach time */ +#if !defined(__LP64__) || defined(COMPAT_LINUX32) + l_ulong __unused1; +#endif + l_time_t shm_dtime; /* last detach time */ +#if !defined(__LP64__) || defined(COMPAT_LINUX32) + l_ulong __unused2; +#endif + l_time_t shm_ctime; /* last change time */ +#if !defined(__LP64__) || defined(COMPAT_LINUX32) + l_ulong __unused3; +#endif + l_pid_t shm_cpid; /* pid of creator */ + l_pid_t shm_lpid; /* pid of last operator */ + l_ulong shm_nattch; /* no. of current attaches */ + l_ulong __unused4; + l_ulong __unused5; +}; + +struct l_shminfo64 { + l_ulong shmmax; + l_ulong shmmin; + l_ulong shmmni; + l_ulong shmseg; + l_ulong shmall; + l_ulong __unused1; + l_ulong __unused2; + l_ulong __unused3; + l_ulong __unused4; +}; + +#endif /* !LINUX_IPC64_H_ */ diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c index 9e1c4ed9df57..65e3573315c6 100644 --- a/sys/compat/linux/linux_mib.c +++ b/sys/compat/linux/linux_mib.c @@ -1,580 +1,580 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 1999 Marcel Moolenaar - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include - -struct linux_prison { - char pr_osname[LINUX_MAX_UTSNAME]; - char pr_osrelease[LINUX_MAX_UTSNAME]; - int pr_oss_version; - int pr_osrel; -}; - -static struct linux_prison lprison0 = { - .pr_osname = "Linux", - .pr_osrelease = LINUX_VERSION_STR, - .pr_oss_version = 0x030600, - .pr_osrel = LINUX_VERSION_CODE -}; - -static unsigned linux_osd_jail_slot; - -SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, - "Linux mode"); - -int linux_debug = 3; -SYSCTL_INT(_compat_linux, OID_AUTO, debug, CTLFLAG_RWTUN, - &linux_debug, 0, "Log warnings from linux(4); or 0 to disable"); - -int linux_default_openfiles = 1024; -SYSCTL_INT(_compat_linux, OID_AUTO, default_openfiles, CTLFLAG_RWTUN, - &linux_default_openfiles, 0, - "Default soft openfiles resource limit, or -1 for unlimited"); - -int linux_default_stacksize = 8 * 1024 * 1024; -SYSCTL_INT(_compat_linux, OID_AUTO, default_stacksize, CTLFLAG_RWTUN, - &linux_default_stacksize, 0, - "Default soft stack size resource limit, or -1 for unlimited"); - -int linux_dummy_rlimits = 0; -SYSCTL_INT(_compat_linux, OID_AUTO, dummy_rlimits, CTLFLAG_RWTUN, - &linux_dummy_rlimits, 0, - "Return dummy values for unsupported Linux-specific rlimits"); - -int linux_ignore_ip_recverr = 1; -SYSCTL_INT(_compat_linux, OID_AUTO, ignore_ip_recverr, CTLFLAG_RWTUN, - &linux_ignore_ip_recverr, 0, "Ignore enabling IP_RECVERR"); - -int linux_preserve_vstatus = 1; -SYSCTL_INT(_compat_linux, OID_AUTO, preserve_vstatus, CTLFLAG_RWTUN, - &linux_preserve_vstatus, 0, "Preserve VSTATUS termios(4) flag"); - -bool linux_map_sched_prio = true; -SYSCTL_BOOL(_compat_linux, OID_AUTO, map_sched_prio, CTLFLAG_RDTUN, - &linux_map_sched_prio, 0, "Map scheduler priorities to Linux priorities " - "(not POSIX compliant)"); - -static bool linux_setid_allowed = true; -SYSCTL_BOOL(_compat_linux, OID_AUTO, setid_allowed, CTLFLAG_RWTUN, - &linux_setid_allowed, 0, - "Allow setuid/setgid on execve of Linux binary"); - -int -linux_setid_allowed_query(struct thread *td __unused, - struct image_params *imgp __unused) -{ - return (linux_setid_allowed); -} - -static int linux_set_osname(struct thread *td, char *osname); -static int linux_set_osrelease(struct thread *td, char *osrelease); -static int linux_set_oss_version(struct thread *td, int oss_version); - -static int -linux_sysctl_osname(SYSCTL_HANDLER_ARGS) -{ - char osname[LINUX_MAX_UTSNAME]; - int error; - - linux_get_osname(req->td, osname); - error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); - if (error != 0 || req->newptr == NULL) - return (error); - error = linux_set_osname(req->td, osname); - - return (error); -} - -SYSCTL_PROC(_compat_linux, OID_AUTO, osname, - CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, - 0, 0, linux_sysctl_osname, "A", - "Linux kernel OS name"); - -static int -linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS) -{ - char osrelease[LINUX_MAX_UTSNAME]; - int error; - - linux_get_osrelease(req->td, osrelease); - error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); - if (error != 0 || req->newptr == NULL) - return (error); - error = linux_set_osrelease(req->td, osrelease); - - return (error); -} - -SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease, - CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, - 0, 0, linux_sysctl_osrelease, "A", - "Linux kernel OS release"); - -static int -linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS) -{ - int oss_version; - int error; - - oss_version = linux_get_oss_version(req->td); - error = sysctl_handle_int(oidp, &oss_version, 0, req); - if (error != 0 || req->newptr == NULL) - return (error); - error = linux_set_oss_version(req->td, oss_version); - - return (error); -} - -SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, - 0, 0, linux_sysctl_oss_version, "I", - "Linux OSS version"); - -/* - * Map the osrelease into integer - */ -static int -linux_map_osrel(char *osrelease, int *osrel) -{ - char *sep, *eosrelease; - int len, v0, v1, v2, v; - - len = strlen(osrelease); - eosrelease = osrelease + len; - v0 = strtol(osrelease, &sep, 10); - if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') - return (EINVAL); - osrelease = sep + 1; - v1 = strtol(osrelease, &sep, 10); - if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') - return (EINVAL); - osrelease = sep + 1; - v2 = strtol(osrelease, &sep, 10); - if (osrelease == sep || - (sep != eosrelease && (sep + 1 >= eosrelease || *sep != '-'))) - return (EINVAL); - - v = LINUX_KERNVER(v0, v1, v2); - if (v < LINUX_KERNVER(1, 0, 0)) - return (EINVAL); - - if (osrel != NULL) - *osrel = v; - - return (0); -} - -/* - * Find a prison with Linux info. - * Return the Linux info and the (locked) prison. - */ -static struct linux_prison * -linux_find_prison(struct prison *spr, struct prison **prp) -{ - struct prison *pr; - struct linux_prison *lpr; - - for (pr = spr;; pr = pr->pr_parent) { - mtx_lock(&pr->pr_mtx); - lpr = (pr == &prison0) - ? &lprison0 - : osd_jail_get(pr, linux_osd_jail_slot); - if (lpr != NULL) - break; - mtx_unlock(&pr->pr_mtx); - } - *prp = pr; - - return (lpr); -} - -/* - * Ensure a prison has its own Linux info. If lprp is non-null, point it to - * the Linux info and lock the prison. - */ -static void -linux_alloc_prison(struct prison *pr, struct linux_prison **lprp) -{ - struct prison *ppr; - struct linux_prison *lpr, *nlpr; - void **rsv; - - /* If this prison already has Linux info, return that. */ - lpr = linux_find_prison(pr, &ppr); - if (ppr == pr) - goto done; - /* - * Allocate a new info record. Then check again, in case something - * changed during the allocation. - */ - mtx_unlock(&ppr->pr_mtx); - nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK); - rsv = osd_reserve(linux_osd_jail_slot); - lpr = linux_find_prison(pr, &ppr); - if (ppr == pr) { - free(nlpr, M_PRISON); - osd_free_reserved(rsv); - goto done; - } - /* Inherit the initial values from the ancestor. */ - mtx_lock(&pr->pr_mtx); - (void)osd_jail_set_reserved(pr, linux_osd_jail_slot, rsv, nlpr); - bcopy(lpr, nlpr, sizeof(*lpr)); - lpr = nlpr; - mtx_unlock(&ppr->pr_mtx); - done: - if (lprp != NULL) - *lprp = lpr; - else - mtx_unlock(&pr->pr_mtx); -} - -/* - * Jail OSD methods for Linux prison data. - */ -static int -linux_prison_create(void *obj, void *data) -{ - struct prison *pr = obj; - struct vfsoptlist *opts = data; - int jsys; - - if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 && - jsys == JAIL_SYS_INHERIT) - return (0); - /* - * Inherit a prison's initial values from its parent - * (different from JAIL_SYS_INHERIT which also inherits changes). - */ - linux_alloc_prison(pr, NULL); - return (0); -} - -static int -linux_prison_check(void *obj __unused, void *data) -{ - struct vfsoptlist *opts = data; - char *osname, *osrelease; - int error, jsys, len, oss_version; - - /* Check that the parameters are correct. */ - error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); - if (error != ENOENT) { - if (error != 0) - return (error); - if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) - return (EINVAL); - } - error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); - if (error != ENOENT) { - if (error != 0) - return (error); - if (len == 0 || osname[len - 1] != '\0') - return (EINVAL); - if (len > LINUX_MAX_UTSNAME) { - vfs_opterror(opts, "linux.osname too long"); - return (ENAMETOOLONG); - } - } - error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); - if (error != ENOENT) { - if (error != 0) - return (error); - if (len == 0 || osrelease[len - 1] != '\0') - return (EINVAL); - if (len > LINUX_MAX_UTSNAME) { - vfs_opterror(opts, "linux.osrelease too long"); - return (ENAMETOOLONG); - } - error = linux_map_osrel(osrelease, NULL); - if (error != 0) { - vfs_opterror(opts, "linux.osrelease format error"); - return (error); - } - } - error = vfs_copyopt(opts, "linux.oss_version", &oss_version, - sizeof(oss_version)); - - if (error == ENOENT) - error = 0; - return (error); -} - -static int -linux_prison_set(void *obj, void *data) -{ - struct linux_prison *lpr; - struct prison *pr = obj; - struct vfsoptlist *opts = data; - char *osname, *osrelease; - int error, gotversion, jsys, len, oss_version; - - /* Set the parameters, which should be correct. */ - error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); - if (error == ENOENT) - jsys = -1; - error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); - if (error == ENOENT) - osname = NULL; - else - jsys = JAIL_SYS_NEW; - error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); - if (error == ENOENT) - osrelease = NULL; - else - jsys = JAIL_SYS_NEW; - error = vfs_copyopt(opts, "linux.oss_version", &oss_version, - sizeof(oss_version)); - if (error == ENOENT) - gotversion = 0; - else { - gotversion = 1; - jsys = JAIL_SYS_NEW; - } - switch (jsys) { - case JAIL_SYS_INHERIT: - /* "linux=inherit": inherit the parent's Linux info. */ - mtx_lock(&pr->pr_mtx); - osd_jail_del(pr, linux_osd_jail_slot); - mtx_unlock(&pr->pr_mtx); - break; - case JAIL_SYS_NEW: - /* - * "linux=new" or "linux.*": - * the prison gets its own Linux info. - */ - linux_alloc_prison(pr, &lpr); - if (osrelease) { - (void)linux_map_osrel(osrelease, &lpr->pr_osrel); - strlcpy(lpr->pr_osrelease, osrelease, - LINUX_MAX_UTSNAME); - } - if (osname) - strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); - if (gotversion) - lpr->pr_oss_version = oss_version; - mtx_unlock(&pr->pr_mtx); - } - - return (0); -} - -SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters"); -SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME, - "Jail Linux kernel OS name"); -SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME, - "Jail Linux kernel OS release"); -SYSCTL_JAIL_PARAM(_linux, oss_version, CTLTYPE_INT | CTLFLAG_RW, - "I", "Jail Linux OSS version"); - -static int -linux_prison_get(void *obj, void *data) -{ - struct linux_prison *lpr; - struct prison *ppr; - struct prison *pr = obj; - struct vfsoptlist *opts = data; - int error, i; - - static int version0; - - /* See if this prison is the one with the Linux info. */ - lpr = linux_find_prison(pr, &ppr); - i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; - error = vfs_setopt(opts, "linux", &i, sizeof(i)); - if (error != 0 && error != ENOENT) - goto done; - if (i) { - error = vfs_setopts(opts, "linux.osname", lpr->pr_osname); - if (error != 0 && error != ENOENT) - goto done; - error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease); - if (error != 0 && error != ENOENT) - goto done; - error = vfs_setopt(opts, "linux.oss_version", - &lpr->pr_oss_version, sizeof(lpr->pr_oss_version)); - if (error != 0 && error != ENOENT) - goto done; - } else { - /* - * If this prison is inheriting its Linux info, report - * empty/zero parameters. - */ - error = vfs_setopts(opts, "linux.osname", ""); - if (error != 0 && error != ENOENT) - goto done; - error = vfs_setopts(opts, "linux.osrelease", ""); - if (error != 0 && error != ENOENT) - goto done; - error = vfs_setopt(opts, "linux.oss_version", &version0, - sizeof(lpr->pr_oss_version)); - if (error != 0 && error != ENOENT) - goto done; - } - error = 0; - - done: - mtx_unlock(&ppr->pr_mtx); - - return (error); -} - -static void -linux_prison_destructor(void *data) -{ - - free(data, M_PRISON); -} - -void -linux_osd_jail_register(void) -{ - struct prison *pr; - osd_method_t methods[PR_MAXMETHOD] = { - [PR_METHOD_CREATE] = linux_prison_create, - [PR_METHOD_GET] = linux_prison_get, - [PR_METHOD_SET] = linux_prison_set, - [PR_METHOD_CHECK] = linux_prison_check - }; - - linux_osd_jail_slot = - osd_jail_register(linux_prison_destructor, methods); - /* Copy the system Linux info to any current prisons. */ - sx_slock(&allprison_lock); - TAILQ_FOREACH(pr, &allprison, pr_list) - linux_alloc_prison(pr, NULL); - sx_sunlock(&allprison_lock); -} - -void -linux_osd_jail_deregister(void) -{ - - osd_jail_deregister(linux_osd_jail_slot); -} - -void -linux_get_osname(struct thread *td, char *dst) -{ - struct prison *pr; - struct linux_prison *lpr; - - lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); - bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); - mtx_unlock(&pr->pr_mtx); -} - -static int -linux_set_osname(struct thread *td, char *osname) -{ - struct prison *pr; - struct linux_prison *lpr; - - lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); - strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); - mtx_unlock(&pr->pr_mtx); - - return (0); -} - -void -linux_get_osrelease(struct thread *td, char *dst) -{ - struct prison *pr; - struct linux_prison *lpr; - - lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); - bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME); - mtx_unlock(&pr->pr_mtx); -} - -int -linux_kernver(struct thread *td) -{ - struct prison *pr; - struct linux_prison *lpr; - int osrel; - - lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); - osrel = lpr->pr_osrel; - mtx_unlock(&pr->pr_mtx); - - return (osrel); -} - -static int -linux_set_osrelease(struct thread *td, char *osrelease) -{ - struct prison *pr; - struct linux_prison *lpr; - int error; - - lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); - error = linux_map_osrel(osrelease, &lpr->pr_osrel); - if (error == 0) - strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME); - mtx_unlock(&pr->pr_mtx); - - return (error); -} - -int -linux_get_oss_version(struct thread *td) -{ - struct prison *pr; - struct linux_prison *lpr; - int version; - - lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); - version = lpr->pr_oss_version; - mtx_unlock(&pr->pr_mtx); - - return (version); -} - -static int -linux_set_oss_version(struct thread *td, int oss_version) -{ - struct prison *pr; - struct linux_prison *lpr; - - lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); - lpr->pr_oss_version = oss_version; - mtx_unlock(&pr->pr_mtx); - - return (0); -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 Marcel Moolenaar + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +struct linux_prison { + char pr_osname[LINUX_MAX_UTSNAME]; + char pr_osrelease[LINUX_MAX_UTSNAME]; + int pr_oss_version; + int pr_osrel; +}; + +static struct linux_prison lprison0 = { + .pr_osname = "Linux", + .pr_osrelease = LINUX_VERSION_STR, + .pr_oss_version = 0x030600, + .pr_osrel = LINUX_VERSION_CODE +}; + +static unsigned linux_osd_jail_slot; + +SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, + "Linux mode"); + +int linux_debug = 3; +SYSCTL_INT(_compat_linux, OID_AUTO, debug, CTLFLAG_RWTUN, + &linux_debug, 0, "Log warnings from linux(4); or 0 to disable"); + +int linux_default_openfiles = 1024; +SYSCTL_INT(_compat_linux, OID_AUTO, default_openfiles, CTLFLAG_RWTUN, + &linux_default_openfiles, 0, + "Default soft openfiles resource limit, or -1 for unlimited"); + +int linux_default_stacksize = 8 * 1024 * 1024; +SYSCTL_INT(_compat_linux, OID_AUTO, default_stacksize, CTLFLAG_RWTUN, + &linux_default_stacksize, 0, + "Default soft stack size resource limit, or -1 for unlimited"); + +int linux_dummy_rlimits = 0; +SYSCTL_INT(_compat_linux, OID_AUTO, dummy_rlimits, CTLFLAG_RWTUN, + &linux_dummy_rlimits, 0, + "Return dummy values for unsupported Linux-specific rlimits"); + +int linux_ignore_ip_recverr = 1; +SYSCTL_INT(_compat_linux, OID_AUTO, ignore_ip_recverr, CTLFLAG_RWTUN, + &linux_ignore_ip_recverr, 0, "Ignore enabling IP_RECVERR"); + +int linux_preserve_vstatus = 1; +SYSCTL_INT(_compat_linux, OID_AUTO, preserve_vstatus, CTLFLAG_RWTUN, + &linux_preserve_vstatus, 0, "Preserve VSTATUS termios(4) flag"); + +bool linux_map_sched_prio = true; +SYSCTL_BOOL(_compat_linux, OID_AUTO, map_sched_prio, CTLFLAG_RDTUN, + &linux_map_sched_prio, 0, "Map scheduler priorities to Linux priorities " + "(not POSIX compliant)"); + +static bool linux_setid_allowed = true; +SYSCTL_BOOL(_compat_linux, OID_AUTO, setid_allowed, CTLFLAG_RWTUN, + &linux_setid_allowed, 0, + "Allow setuid/setgid on execve of Linux binary"); + +int +linux_setid_allowed_query(struct thread *td __unused, + struct image_params *imgp __unused) +{ + return (linux_setid_allowed); +} + +static int linux_set_osname(struct thread *td, char *osname); +static int linux_set_osrelease(struct thread *td, char *osrelease); +static int linux_set_oss_version(struct thread *td, int oss_version); + +static int +linux_sysctl_osname(SYSCTL_HANDLER_ARGS) +{ + char osname[LINUX_MAX_UTSNAME]; + int error; + + linux_get_osname(req->td, osname); + error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); + if (error != 0 || req->newptr == NULL) + return (error); + error = linux_set_osname(req->td, osname); + + return (error); +} + +SYSCTL_PROC(_compat_linux, OID_AUTO, osname, + CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, + 0, 0, linux_sysctl_osname, "A", + "Linux kernel OS name"); + +static int +linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS) +{ + char osrelease[LINUX_MAX_UTSNAME]; + int error; + + linux_get_osrelease(req->td, osrelease); + error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); + if (error != 0 || req->newptr == NULL) + return (error); + error = linux_set_osrelease(req->td, osrelease); + + return (error); +} + +SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease, + CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, + 0, 0, linux_sysctl_osrelease, "A", + "Linux kernel OS release"); + +static int +linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS) +{ + int oss_version; + int error; + + oss_version = linux_get_oss_version(req->td); + error = sysctl_handle_int(oidp, &oss_version, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + error = linux_set_oss_version(req->td, oss_version); + + return (error); +} + +SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, + 0, 0, linux_sysctl_oss_version, "I", + "Linux OSS version"); + +/* + * Map the osrelease into integer + */ +static int +linux_map_osrel(char *osrelease, int *osrel) +{ + char *sep, *eosrelease; + int len, v0, v1, v2, v; + + len = strlen(osrelease); + eosrelease = osrelease + len; + v0 = strtol(osrelease, &sep, 10); + if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') + return (EINVAL); + osrelease = sep + 1; + v1 = strtol(osrelease, &sep, 10); + if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') + return (EINVAL); + osrelease = sep + 1; + v2 = strtol(osrelease, &sep, 10); + if (osrelease == sep || + (sep != eosrelease && (sep + 1 >= eosrelease || *sep != '-'))) + return (EINVAL); + + v = LINUX_KERNVER(v0, v1, v2); + if (v < LINUX_KERNVER(1, 0, 0)) + return (EINVAL); + + if (osrel != NULL) + *osrel = v; + + return (0); +} + +/* + * Find a prison with Linux info. + * Return the Linux info and the (locked) prison. + */ +static struct linux_prison * +linux_find_prison(struct prison *spr, struct prison **prp) +{ + struct prison *pr; + struct linux_prison *lpr; + + for (pr = spr;; pr = pr->pr_parent) { + mtx_lock(&pr->pr_mtx); + lpr = (pr == &prison0) + ? &lprison0 + : osd_jail_get(pr, linux_osd_jail_slot); + if (lpr != NULL) + break; + mtx_unlock(&pr->pr_mtx); + } + *prp = pr; + + return (lpr); +} + +/* + * Ensure a prison has its own Linux info. If lprp is non-null, point it to + * the Linux info and lock the prison. + */ +static void +linux_alloc_prison(struct prison *pr, struct linux_prison **lprp) +{ + struct prison *ppr; + struct linux_prison *lpr, *nlpr; + void **rsv; + + /* If this prison already has Linux info, return that. */ + lpr = linux_find_prison(pr, &ppr); + if (ppr == pr) + goto done; + /* + * Allocate a new info record. Then check again, in case something + * changed during the allocation. + */ + mtx_unlock(&ppr->pr_mtx); + nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK); + rsv = osd_reserve(linux_osd_jail_slot); + lpr = linux_find_prison(pr, &ppr); + if (ppr == pr) { + free(nlpr, M_PRISON); + osd_free_reserved(rsv); + goto done; + } + /* Inherit the initial values from the ancestor. */ + mtx_lock(&pr->pr_mtx); + (void)osd_jail_set_reserved(pr, linux_osd_jail_slot, rsv, nlpr); + bcopy(lpr, nlpr, sizeof(*lpr)); + lpr = nlpr; + mtx_unlock(&ppr->pr_mtx); + done: + if (lprp != NULL) + *lprp = lpr; + else + mtx_unlock(&pr->pr_mtx); +} + +/* + * Jail OSD methods for Linux prison data. + */ +static int +linux_prison_create(void *obj, void *data) +{ + struct prison *pr = obj; + struct vfsoptlist *opts = data; + int jsys; + + if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 && + jsys == JAIL_SYS_INHERIT) + return (0); + /* + * Inherit a prison's initial values from its parent + * (different from JAIL_SYS_INHERIT which also inherits changes). + */ + linux_alloc_prison(pr, NULL); + return (0); +} + +static int +linux_prison_check(void *obj __unused, void *data) +{ + struct vfsoptlist *opts = data; + char *osname, *osrelease; + int error, jsys, len, oss_version; + + /* Check that the parameters are correct. */ + error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error != ENOENT) { + if (error != 0) + return (error); + if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) + return (EINVAL); + } + error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); + if (error != ENOENT) { + if (error != 0) + return (error); + if (len == 0 || osname[len - 1] != '\0') + return (EINVAL); + if (len > LINUX_MAX_UTSNAME) { + vfs_opterror(opts, "linux.osname too long"); + return (ENAMETOOLONG); + } + } + error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); + if (error != ENOENT) { + if (error != 0) + return (error); + if (len == 0 || osrelease[len - 1] != '\0') + return (EINVAL); + if (len > LINUX_MAX_UTSNAME) { + vfs_opterror(opts, "linux.osrelease too long"); + return (ENAMETOOLONG); + } + error = linux_map_osrel(osrelease, NULL); + if (error != 0) { + vfs_opterror(opts, "linux.osrelease format error"); + return (error); + } + } + error = vfs_copyopt(opts, "linux.oss_version", &oss_version, + sizeof(oss_version)); + + if (error == ENOENT) + error = 0; + return (error); +} + +static int +linux_prison_set(void *obj, void *data) +{ + struct linux_prison *lpr; + struct prison *pr = obj; + struct vfsoptlist *opts = data; + char *osname, *osrelease; + int error, gotversion, jsys, len, oss_version; + + /* Set the parameters, which should be correct. */ + error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error == ENOENT) + jsys = -1; + error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); + if (error == ENOENT) + osname = NULL; + else + jsys = JAIL_SYS_NEW; + error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); + if (error == ENOENT) + osrelease = NULL; + else + jsys = JAIL_SYS_NEW; + error = vfs_copyopt(opts, "linux.oss_version", &oss_version, + sizeof(oss_version)); + if (error == ENOENT) + gotversion = 0; + else { + gotversion = 1; + jsys = JAIL_SYS_NEW; + } + switch (jsys) { + case JAIL_SYS_INHERIT: + /* "linux=inherit": inherit the parent's Linux info. */ + mtx_lock(&pr->pr_mtx); + osd_jail_del(pr, linux_osd_jail_slot); + mtx_unlock(&pr->pr_mtx); + break; + case JAIL_SYS_NEW: + /* + * "linux=new" or "linux.*": + * the prison gets its own Linux info. + */ + linux_alloc_prison(pr, &lpr); + if (osrelease) { + (void)linux_map_osrel(osrelease, &lpr->pr_osrel); + strlcpy(lpr->pr_osrelease, osrelease, + LINUX_MAX_UTSNAME); + } + if (osname) + strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); + if (gotversion) + lpr->pr_oss_version = oss_version; + mtx_unlock(&pr->pr_mtx); + } + + return (0); +} + +SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters"); +SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME, + "Jail Linux kernel OS name"); +SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME, + "Jail Linux kernel OS release"); +SYSCTL_JAIL_PARAM(_linux, oss_version, CTLTYPE_INT | CTLFLAG_RW, + "I", "Jail Linux OSS version"); + +static int +linux_prison_get(void *obj, void *data) +{ + struct linux_prison *lpr; + struct prison *ppr; + struct prison *pr = obj; + struct vfsoptlist *opts = data; + int error, i; + + static int version0; + + /* See if this prison is the one with the Linux info. */ + lpr = linux_find_prison(pr, &ppr); + i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; + error = vfs_setopt(opts, "linux", &i, sizeof(i)); + if (error != 0 && error != ENOENT) + goto done; + if (i) { + error = vfs_setopts(opts, "linux.osname", lpr->pr_osname); + if (error != 0 && error != ENOENT) + goto done; + error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease); + if (error != 0 && error != ENOENT) + goto done; + error = vfs_setopt(opts, "linux.oss_version", + &lpr->pr_oss_version, sizeof(lpr->pr_oss_version)); + if (error != 0 && error != ENOENT) + goto done; + } else { + /* + * If this prison is inheriting its Linux info, report + * empty/zero parameters. + */ + error = vfs_setopts(opts, "linux.osname", ""); + if (error != 0 && error != ENOENT) + goto done; + error = vfs_setopts(opts, "linux.osrelease", ""); + if (error != 0 && error != ENOENT) + goto done; + error = vfs_setopt(opts, "linux.oss_version", &version0, + sizeof(lpr->pr_oss_version)); + if (error != 0 && error != ENOENT) + goto done; + } + error = 0; + + done: + mtx_unlock(&ppr->pr_mtx); + + return (error); +} + +static void +linux_prison_destructor(void *data) +{ + + free(data, M_PRISON); +} + +void +linux_osd_jail_register(void) +{ + struct prison *pr; + osd_method_t methods[PR_MAXMETHOD] = { + [PR_METHOD_CREATE] = linux_prison_create, + [PR_METHOD_GET] = linux_prison_get, + [PR_METHOD_SET] = linux_prison_set, + [PR_METHOD_CHECK] = linux_prison_check + }; + + linux_osd_jail_slot = + osd_jail_register(linux_prison_destructor, methods); + /* Copy the system Linux info to any current prisons. */ + sx_slock(&allprison_lock); + TAILQ_FOREACH(pr, &allprison, pr_list) + linux_alloc_prison(pr, NULL); + sx_sunlock(&allprison_lock); +} + +void +linux_osd_jail_deregister(void) +{ + + osd_jail_deregister(linux_osd_jail_slot); +} + +void +linux_get_osname(struct thread *td, char *dst) +{ + struct prison *pr; + struct linux_prison *lpr; + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); + mtx_unlock(&pr->pr_mtx); +} + +static int +linux_set_osname(struct thread *td, char *osname) +{ + struct prison *pr; + struct linux_prison *lpr; + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); + mtx_unlock(&pr->pr_mtx); + + return (0); +} + +void +linux_get_osrelease(struct thread *td, char *dst) +{ + struct prison *pr; + struct linux_prison *lpr; + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME); + mtx_unlock(&pr->pr_mtx); +} + +int +linux_kernver(struct thread *td) +{ + struct prison *pr; + struct linux_prison *lpr; + int osrel; + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + osrel = lpr->pr_osrel; + mtx_unlock(&pr->pr_mtx); + + return (osrel); +} + +static int +linux_set_osrelease(struct thread *td, char *osrelease) +{ + struct prison *pr; + struct linux_prison *lpr; + int error; + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + error = linux_map_osrel(osrelease, &lpr->pr_osrel); + if (error == 0) + strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME); + mtx_unlock(&pr->pr_mtx); + + return (error); +} + +int +linux_get_oss_version(struct thread *td) +{ + struct prison *pr; + struct linux_prison *lpr; + int version; + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + version = lpr->pr_oss_version; + mtx_unlock(&pr->pr_mtx); + + return (version); +} + +static int +linux_set_oss_version(struct thread *td, int oss_version) +{ + struct prison *pr; + struct linux_prison *lpr; + + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); + lpr->pr_oss_version = oss_version; + mtx_unlock(&pr->pr_mtx); + + return (0); +} diff --git a/sys/compat/linux/linux_mib.h b/sys/compat/linux/linux_mib.h index 1372f4a0f5cf..b8073d4f3c6c 100644 --- a/sys/compat/linux/linux_mib.h +++ b/sys/compat/linux/linux_mib.h @@ -1,68 +1,68 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 1999 Marcel Moolenaar - * 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. - */ - -#ifndef _LINUX_MIB_H_ -#define _LINUX_MIB_H_ - -#ifdef SYSCTL_DECL -SYSCTL_DECL(_compat_linux); -#endif - -void linux_osd_jail_register(void); -void linux_osd_jail_deregister(void); - -void linux_get_osname(struct thread *td, char *dst); - -void linux_get_osrelease(struct thread *td, char *dst); - -int linux_get_oss_version(struct thread *td); - -int linux_kernver(struct thread *td); - -#define LINUX_KVERSION 5 -#define LINUX_KPATCHLEVEL 15 -#define LINUX_KSUBLEVEL 0 - -#define LINUX_KERNVER(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -#define LINUX_VERSION_CODE LINUX_KERNVER(LINUX_KVERSION, \ - LINUX_KPATCHLEVEL, LINUX_KSUBLEVEL) -#define LINUX_KERNVERSTR(x) #x -#define LINUX_XKERNVERSTR(x) LINUX_KERNVERSTR(x) -#define LINUX_VERSION_STR LINUX_XKERNVERSTR(LINUX_KVERSION.LINUX_KPATCHLEVEL.LINUX_KSUBLEVEL) - -extern int linux_default_openfiles; -extern int linux_default_stacksize; -extern int linux_dummy_rlimits; -extern int linux_ignore_ip_recverr; -extern int linux_preserve_vstatus; -extern bool linux_map_sched_prio; - -struct image_params; -int linux_setid_allowed_query(struct thread *td, struct image_params *imgp); - -#endif /* _LINUX_MIB_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 Marcel Moolenaar + * 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. + */ + +#ifndef _LINUX_MIB_H_ +#define _LINUX_MIB_H_ + +#ifdef SYSCTL_DECL +SYSCTL_DECL(_compat_linux); +#endif + +void linux_osd_jail_register(void); +void linux_osd_jail_deregister(void); + +void linux_get_osname(struct thread *td, char *dst); + +void linux_get_osrelease(struct thread *td, char *dst); + +int linux_get_oss_version(struct thread *td); + +int linux_kernver(struct thread *td); + +#define LINUX_KVERSION 5 +#define LINUX_KPATCHLEVEL 15 +#define LINUX_KSUBLEVEL 0 + +#define LINUX_KERNVER(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#define LINUX_VERSION_CODE LINUX_KERNVER(LINUX_KVERSION, \ + LINUX_KPATCHLEVEL, LINUX_KSUBLEVEL) +#define LINUX_KERNVERSTR(x) #x +#define LINUX_XKERNVERSTR(x) LINUX_KERNVERSTR(x) +#define LINUX_VERSION_STR LINUX_XKERNVERSTR(LINUX_KVERSION.LINUX_KPATCHLEVEL.LINUX_KSUBLEVEL) + +extern int linux_default_openfiles; +extern int linux_default_stacksize; +extern int linux_dummy_rlimits; +extern int linux_ignore_ip_recverr; +extern int linux_preserve_vstatus; +extern bool linux_map_sched_prio; + +struct image_params; +int linux_setid_allowed_query(struct thread *td, struct image_params *imgp); + +#endif /* _LINUX_MIB_H_ */ diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index c12ab879757a..1217efc55cdc 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1,3141 +1,3373 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2002 Doug Rabson - * 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 - * in this position and unchanged. - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 -#else -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int stclohz; /* Statistics clock frequency */ - -static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { - RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, - RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, - RLIMIT_MEMLOCK, RLIMIT_AS -}; - -struct l_sysinfo { - l_long uptime; /* Seconds since boot */ - l_ulong loads[3]; /* 1, 5, and 15 minute load averages */ -#define LINUX_SYSINFO_LOADS_SCALE 65536 - l_ulong totalram; /* Total usable main memory size */ - l_ulong freeram; /* Available memory size */ - l_ulong sharedram; /* Amount of shared memory */ - l_ulong bufferram; /* Memory used by buffers */ - l_ulong totalswap; /* Total swap space size */ - l_ulong freeswap; /* swap space still available */ - l_ushort procs; /* Number of current processes */ - l_ushort pads; - l_ulong totalhigh; - l_ulong freehigh; - l_uint mem_unit; - char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */ -}; - -struct l_pselect6arg { - l_uintptr_t ss; - l_size_t ss_len; -}; - -static int linux_utimensat_lts_to_ts(struct l_timespec *, - struct timespec *); -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -static int linux_utimensat_lts64_to_ts(struct l_timespec64 *, - struct timespec *); -#endif -static int linux_common_utimensat(struct thread *, int, - const char *, struct timespec *, int); -static int linux_common_pselect6(struct thread *, l_int, - l_fd_set *, l_fd_set *, l_fd_set *, - struct timespec *, l_uintptr_t *); -static int linux_common_ppoll(struct thread *, struct pollfd *, - uint32_t, struct timespec *, l_sigset_t *, - l_size_t); -static int linux_pollin(struct thread *, struct pollfd *, - struct pollfd *, u_int); -static int linux_pollout(struct thread *, struct pollfd *, - struct pollfd *, u_int); - -int -linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) -{ - struct l_sysinfo sysinfo; - int i, j; - struct timespec ts; - - bzero(&sysinfo, sizeof(sysinfo)); - getnanouptime(&ts); - if (ts.tv_nsec != 0) - ts.tv_sec++; - sysinfo.uptime = ts.tv_sec; - - /* Use the information from the mib to get our load averages */ - for (i = 0; i < 3; i++) - sysinfo.loads[i] = averunnable.ldavg[i] * - LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale; - - sysinfo.totalram = physmem * PAGE_SIZE; - sysinfo.freeram = (u_long)vm_free_count() * PAGE_SIZE; - - /* - * sharedram counts pages allocated to named, swap-backed objects such - * as shared memory segments and tmpfs files. There is no cheap way to - * compute this, so just leave the field unpopulated. Linux itself only - * started setting this field in the 3.x timeframe. - */ - sysinfo.sharedram = 0; - sysinfo.bufferram = 0; - - swap_pager_status(&i, &j); - sysinfo.totalswap = i * PAGE_SIZE; - sysinfo.freeswap = (i - j) * PAGE_SIZE; - - sysinfo.procs = nprocs; - - /* - * Platforms supported by the emulation layer do not have a notion of - * high memory. - */ - sysinfo.totalhigh = 0; - sysinfo.freehigh = 0; - - sysinfo.mem_unit = 1; - - return (copyout(&sysinfo, args->info, sizeof(sysinfo))); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_alarm(struct thread *td, struct linux_alarm_args *args) -{ - struct itimerval it, old_it; - u_int secs; - int error __diagused; - - secs = args->secs; - /* - * Linux alarm() is always successful. Limit secs to INT32_MAX / 2 - * to match kern_setitimer()'s limit to avoid error from it. - * - * XXX. Linux limit secs to INT_MAX on 32 and does not limit on 64-bit - * platforms. - */ - if (secs > INT32_MAX / 2) - secs = INT32_MAX / 2; - - it.it_value.tv_sec = secs; - it.it_value.tv_usec = 0; - timevalclear(&it.it_interval); - error = kern_setitimer(td, ITIMER_REAL, &it, &old_it); - KASSERT(error == 0, ("kern_setitimer returns %d", error)); - - if ((old_it.it_value.tv_sec == 0 && old_it.it_value.tv_usec > 0) || - old_it.it_value.tv_usec >= 500000) - old_it.it_value.tv_sec++; - td->td_retval[0] = old_it.it_value.tv_sec; - return (0); -} -#endif - -int -linux_brk(struct thread *td, struct linux_brk_args *args) -{ - struct vmspace *vm = td->td_proc->p_vmspace; - uintptr_t new, old; - - old = (uintptr_t)vm->vm_daddr + ctob(vm->vm_dsize); - new = (uintptr_t)args->dsend; - if ((caddr_t)new > vm->vm_daddr && !kern_break(td, &new)) - td->td_retval[0] = (register_t)new; - else - td->td_retval[0] = (register_t)old; - - return (0); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_select(struct thread *td, struct linux_select_args *args) -{ - l_timeval ltv; - struct timeval tv0, tv1, utv, *tvp; - int error; - - /* - * Store current time for computation of the amount of - * time left. - */ - if (args->timeout) { - if ((error = copyin(args->timeout, <v, sizeof(ltv)))) - goto select_out; - utv.tv_sec = ltv.tv_sec; - utv.tv_usec = ltv.tv_usec; - - if (itimerfix(&utv)) { - /* - * The timeval was invalid. Convert it to something - * valid that will act as it does under Linux. - */ - utv.tv_sec += utv.tv_usec / 1000000; - utv.tv_usec %= 1000000; - if (utv.tv_usec < 0) { - utv.tv_sec -= 1; - utv.tv_usec += 1000000; - } - if (utv.tv_sec < 0) - timevalclear(&utv); - } - microtime(&tv0); - tvp = &utv; - } else - tvp = NULL; - - error = kern_select(td, args->nfds, __USER_CAP_UNBOUND(args->readfds), - __USER_CAP_UNBOUND(args->writefds), - __USER_CAP_UNBOUND(args->exceptfds), tvp, LINUX_NFDBITS); - if (error) - goto select_out; - - if (args->timeout) { - if (td->td_retval[0]) { - /* - * Compute how much time was left of the timeout, - * by subtracting the current time and the time - * before we started the call, and subtracting - * that result from the user-supplied value. - */ - microtime(&tv1); - timevalsub(&tv1, &tv0); - timevalsub(&utv, &tv1); - if (utv.tv_sec < 0) - timevalclear(&utv); - } else - timevalclear(&utv); - ltv.tv_sec = utv.tv_sec; - ltv.tv_usec = utv.tv_usec; - if ((error = copyout(<v, args->timeout, sizeof(ltv)))) - goto select_out; - } - -select_out: - return (error); -} -#endif - -int -linux_mremap(struct thread *td, struct linux_mremap_args *args) -{ - uintptr_t addr; - size_t len; - int error = 0; - - if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) { - td->td_retval[0] = 0; - return (EINVAL); - } - - /* - * Check for the page alignment. - * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK. - */ - if (args->addr & PAGE_MASK) { - td->td_retval[0] = 0; - return (EINVAL); - } - - args->new_len = round_page(args->new_len); - args->old_len = round_page(args->old_len); - - if (args->new_len > args->old_len) { - td->td_retval[0] = 0; - return (ENOMEM); - } - - if (args->new_len < args->old_len) { - addr = args->addr + args->new_len; - len = args->old_len - args->new_len; - error = kern_munmap(td, addr, len); - } - - td->td_retval[0] = error ? 0 : (uintptr_t)args->addr; - return (error); -} - -#define LINUX_MS_ASYNC 0x0001 -#define LINUX_MS_INVALIDATE 0x0002 -#define LINUX_MS_SYNC 0x0004 - -int -linux_msync(struct thread *td, struct linux_msync_args *args) -{ - - return (kern_msync(td, args->addr, args->len, - args->fl & ~LINUX_MS_SYNC)); -} - -int -linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) -{ - - return (linux_mprotect_common(td, PTROUT(uap->addr), uap->len, - uap->prot)); -} - -int -linux_madvise(struct thread *td, struct linux_madvise_args *uap) -{ - - return (linux_madvise_common(td, PTROUT(uap->addr), uap->len, - uap->behav)); -} - -int -linux_mmap2(struct thread *td, struct linux_mmap2_args *uap) -{ -#if defined(LINUX_ARCHWANT_MMAP2PGOFF) - /* - * For architectures with sizeof (off_t) < sizeof (loff_t) mmap is - * implemented with mmap2 syscall and the offset is represented in - * multiples of page size. - */ - return (linux_mmap_common(td, PTROUT(uap->addr), uap->len, uap->prot, - uap->flags, uap->fd, (uint64_t)(uint32_t)uap->pgoff * PAGE_SIZE)); -#else - return (linux_mmap_common(td, PTROUT(uap->addr), uap->len, uap->prot, - uap->flags, uap->fd, uap->pgoff)); -#endif -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_time(struct thread *td, struct linux_time_args *args) -{ - struct timeval tv; - l_time_t tm; - int error; - - microtime(&tv); - tm = tv.tv_sec; - if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm)))) - return (error); - td->td_retval[0] = tm; - return (0); -} -#endif - -struct l_times_argv { - l_clock_t tms_utime; - l_clock_t tms_stime; - l_clock_t tms_cutime; - l_clock_t tms_cstime; -}; - -/* - * Glibc versions prior to 2.2.1 always use hard-coded CLK_TCK value. - * Since 2.2.1 Glibc uses value exported from kernel via AT_CLKTCK - * auxiliary vector entry. - */ -#define CLK_TCK 100 - -#define CONVOTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) -#define CONVNTCK(r) (r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz)) - -#define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER(2,4,0) ? \ - CONVNTCK(r) : CONVOTCK(r)) - -int -linux_times(struct thread *td, struct linux_times_args *args) -{ - struct timeval tv, utime, stime, cutime, cstime; - struct l_times_argv tms; - struct proc *p; - int error; - - if (args->buf != NULL) { - p = td->td_proc; - PROC_LOCK(p); - PROC_STATLOCK(p); - calcru(p, &utime, &stime); - PROC_STATUNLOCK(p); - calccru(p, &cutime, &cstime); - PROC_UNLOCK(p); - - tms.tms_utime = CONVTCK(utime); - tms.tms_stime = CONVTCK(stime); - - tms.tms_cutime = CONVTCK(cutime); - tms.tms_cstime = CONVTCK(cstime); - - if ((error = copyout(&tms, args->buf, sizeof(tms)))) - return (error); - } - - microuptime(&tv); - td->td_retval[0] = (int)CONVTCK(tv); - return (0); -} - -int -linux_newuname(struct thread *td, struct linux_newuname_args *args) -{ - struct l_new_utsname utsname; - char osname[LINUX_MAX_UTSNAME]; - char osrelease[LINUX_MAX_UTSNAME]; - char *p; - - linux_get_osname(td, osname); - linux_get_osrelease(td, osrelease); - - bzero(&utsname, sizeof(utsname)); - strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME); - getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME); - getcreddomainname(td->td_ucred, utsname.domainname, LINUX_MAX_UTSNAME); - strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME); - strlcpy(utsname.version, version, LINUX_MAX_UTSNAME); - for (p = utsname.version; *p != '\0'; ++p) - if (*p == '\n') { - *p = '\0'; - break; - } -#if defined(__amd64__) - /* - * On amd64, Linux uname(2) needs to return "x86_64" - * for both 64-bit and 32-bit applications. On 32-bit, - * the string returned by getauxval(AT_PLATFORM) needs - * to remain "i686", though. - */ -#if defined(COMPAT_LINUX32) - if (linux32_emulate_i386) - strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME); - else -#endif - strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME); -#elif defined(__aarch64__) - strlcpy(utsname.machine, "aarch64", LINUX_MAX_UTSNAME); -#elif defined(__i386__) - strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME); -#endif - - return (copyout(&utsname, args->buf, sizeof(utsname))); -} - -struct l_utimbuf { - l_time_t l_actime; - l_time_t l_modtime; -}; - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_utime(struct thread *td, struct linux_utime_args *args) -{ - struct timeval tv[2], *tvp; - struct l_utimbuf lut; - int error; - - if (args->times) { - if ((error = copyin(args->times, &lut, sizeof lut)) != 0) - return (error); - tv[0].tv_sec = lut.l_actime; - tv[0].tv_usec = 0; - tv[1].tv_sec = lut.l_modtime; - tv[1].tv_usec = 0; - tvp = tv; - } else - tvp = NULL; - - return (kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE, - tvp, UIO_SYSSPACE)); -} -#endif - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_utimes(struct thread *td, struct linux_utimes_args *args) -{ - l_timeval ltv[2]; - struct timeval tv[2], *tvp = NULL; - int error; - - if (args->tptr != NULL) { - if ((error = copyin(args->tptr, ltv, sizeof ltv)) != 0) - return (error); - tv[0].tv_sec = ltv[0].tv_sec; - tv[0].tv_usec = ltv[0].tv_usec; - tv[1].tv_sec = ltv[1].tv_sec; - tv[1].tv_usec = ltv[1].tv_usec; - tvp = tv; - } - - return (kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE, - tvp, UIO_SYSSPACE)); -} -#endif - -static int -linux_utimensat_lts_to_ts(struct l_timespec *l_times, struct timespec *times) -{ - - if (l_times->tv_nsec != LINUX_UTIME_OMIT && - l_times->tv_nsec != LINUX_UTIME_NOW && - (l_times->tv_nsec < 0 || l_times->tv_nsec > 999999999)) - return (EINVAL); - - times->tv_sec = l_times->tv_sec; - switch (l_times->tv_nsec) - { - case LINUX_UTIME_OMIT: - times->tv_nsec = UTIME_OMIT; - break; - case LINUX_UTIME_NOW: - times->tv_nsec = UTIME_NOW; - break; - default: - times->tv_nsec = l_times->tv_nsec; - } - - return (0); -} - -static int -linux_common_utimensat(struct thread *td, int ldfd, const char *pathname, - struct timespec *timesp, int lflags) -{ - int dfd, flags = 0; - - dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd; - - if (lflags & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH)) - return (EINVAL); - - if (timesp != NULL) { - /* This breaks POSIX, but is what the Linux kernel does - * _on purpose_ (documented in the man page for utimensat(2)), - * so we must follow that behaviour. */ - if (timesp[0].tv_nsec == UTIME_OMIT && - timesp[1].tv_nsec == UTIME_OMIT) - return (0); - } - - if (lflags & LINUX_AT_SYMLINK_NOFOLLOW) - flags |= AT_SYMLINK_NOFOLLOW; - if (lflags & LINUX_AT_EMPTY_PATH) - flags |= AT_EMPTY_PATH; - - if (pathname != NULL) - return (kern_utimensat(td, dfd, pathname, - UIO_USERSPACE, timesp, UIO_SYSSPACE, flags)); - - if (lflags != 0) - return (EINVAL); - - return (kern_futimens(td, dfd, timesp, UIO_SYSSPACE)); -} - -int -linux_utimensat(struct thread *td, struct linux_utimensat_args *args) -{ - struct l_timespec l_times[2]; - struct timespec times[2], *timesp; - int error; - - if (args->times != NULL) { - error = copyin(args->times, l_times, sizeof(l_times)); - if (error != 0) - return (error); - - error = linux_utimensat_lts_to_ts(&l_times[0], ×[0]); - if (error != 0) - return (error); - error = linux_utimensat_lts_to_ts(&l_times[1], ×[1]); - if (error != 0) - return (error); - timesp = times; - } else - timesp = NULL; - - return (linux_common_utimensat(td, args->dfd, args->pathname, - timesp, args->flags)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -static int -linux_utimensat_lts64_to_ts(struct l_timespec64 *l_times, struct timespec *times) -{ - - /* Zero out the padding in compat mode. */ - l_times->tv_nsec &= 0xFFFFFFFFUL; - - if (l_times->tv_nsec != LINUX_UTIME_OMIT && - l_times->tv_nsec != LINUX_UTIME_NOW && - (l_times->tv_nsec < 0 || l_times->tv_nsec > 999999999)) - return (EINVAL); - - times->tv_sec = l_times->tv_sec; - switch (l_times->tv_nsec) - { - case LINUX_UTIME_OMIT: - times->tv_nsec = UTIME_OMIT; - break; - case LINUX_UTIME_NOW: - times->tv_nsec = UTIME_NOW; - break; - default: - times->tv_nsec = l_times->tv_nsec; - } - - return (0); -} - -int -linux_utimensat_time64(struct thread *td, struct linux_utimensat_time64_args *args) -{ - struct l_timespec64 l_times[2]; - struct timespec times[2], *timesp; - int error; - - if (args->times64 != NULL) { - error = copyin(args->times64, l_times, sizeof(l_times)); - if (error != 0) - return (error); - - error = linux_utimensat_lts64_to_ts(&l_times[0], ×[0]); - if (error != 0) - return (error); - error = linux_utimensat_lts64_to_ts(&l_times[1], ×[1]); - if (error != 0) - return (error); - timesp = times; - } else - timesp = NULL; - - return (linux_common_utimensat(td, args->dfd, args->pathname, - timesp, args->flags)); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_futimesat(struct thread *td, struct linux_futimesat_args *args) -{ - l_timeval ltv[2]; - struct timeval tv[2], *tvp = NULL; - int error, dfd; - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - - if (args->utimes != NULL) { - if ((error = copyin(args->utimes, ltv, sizeof ltv)) != 0) - return (error); - tv[0].tv_sec = ltv[0].tv_sec; - tv[0].tv_usec = ltv[0].tv_usec; - tv[1].tv_sec = ltv[1].tv_sec; - tv[1].tv_usec = ltv[1].tv_usec; - tvp = tv; - } - - return (kern_utimesat(td, dfd, args->filename, UIO_USERSPACE, - tvp, UIO_SYSSPACE)); -} -#endif - -static int -linux_common_wait(struct thread *td, idtype_t idtype, int id, int *statusp, - int options, void *rup, l_siginfo_t *infop) -{ - l_siginfo_t lsi; - siginfo_t siginfo; - struct __wrusage wru; - int error, status, tmpstat, sig; - - error = kern_wait6(td, idtype, id, &status, options, - rup != NULL ? &wru : NULL, &siginfo); - - if (error == 0 && statusp) { - tmpstat = status & 0xffff; - if (WIFSIGNALED(tmpstat)) { - tmpstat = (tmpstat & 0xffffff80) | - bsd_to_linux_signal(WTERMSIG(tmpstat)); - } else if (WIFSTOPPED(tmpstat)) { - tmpstat = (tmpstat & 0xffff00ff) | - (bsd_to_linux_signal(WSTOPSIG(tmpstat)) << 8); -#if defined(__aarch64__) || (defined(__amd64__) && !defined(COMPAT_LINUX32)) - if (WSTOPSIG(status) == SIGTRAP) { - tmpstat = linux_ptrace_status(td, - siginfo.si_pid, tmpstat); - } -#endif - } else if (WIFCONTINUED(tmpstat)) { - tmpstat = 0xffff; - } - error = copyout(&tmpstat, statusp, sizeof(int)); - } - if (error == 0 && rup != NULL) - error = linux_copyout_rusage(&wru.wru_self, rup); - if (error == 0 && infop != NULL && td->td_retval[0] != 0) { - sig = bsd_to_linux_signal(siginfo.si_signo); - siginfo_to_lsiginfo(&siginfo, &lsi, sig); - error = copyout(&lsi, infop, sizeof(lsi)); - } - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_waitpid(struct thread *td, struct linux_waitpid_args *args) -{ - struct linux_wait4_args wait4_args = { - .pid = args->pid, - .status = args->status, - .options = args->options, - .rusage = NULL, - }; - - return (linux_wait4(td, &wait4_args)); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_wait4(struct thread *td, struct linux_wait4_args *args) -{ - struct proc *p; - int options, id, idtype; - - if (args->options & ~(LINUX_WUNTRACED | LINUX_WNOHANG | - LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL)) - return (EINVAL); - - /* -INT_MIN is not defined. */ - if (args->pid == INT_MIN) - return (ESRCH); - - options = 0; - linux_to_bsd_waitopts(args->options, &options); - - /* - * For backward compatibility we implicitly add flags WEXITED - * and WTRAPPED here. - */ - options |= WEXITED | WTRAPPED; - - if (args->pid == WAIT_ANY) { - idtype = P_ALL; - id = 0; - } else if (args->pid < 0) { - idtype = P_PGID; - id = (id_t)-args->pid; - } else if (args->pid == 0) { - idtype = P_PGID; - p = td->td_proc; - PROC_LOCK(p); - id = p->p_pgid; - PROC_UNLOCK(p); - } else { - idtype = P_PID; - id = (id_t)args->pid; - } - - return (linux_common_wait(td, idtype, id, args->status, options, - args->rusage, NULL)); -} - -int -linux_waitid(struct thread *td, struct linux_waitid_args *args) -{ - idtype_t idtype; - int error, options; - struct proc *p; - pid_t id; - - if (args->options & ~(LINUX_WNOHANG | LINUX_WNOWAIT | LINUX_WEXITED | - LINUX_WSTOPPED | LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL)) - return (EINVAL); - - options = 0; - linux_to_bsd_waitopts(args->options, &options); - - id = args->id; - switch (args->idtype) { - case LINUX_P_ALL: - idtype = P_ALL; - break; - case LINUX_P_PID: - if (args->id <= 0) - return (EINVAL); - idtype = P_PID; - break; - case LINUX_P_PGID: - if (linux_kernver(td) >= LINUX_KERNVER(5,4,0) && args->id == 0) { - p = td->td_proc; - PROC_LOCK(p); - id = p->p_pgid; - PROC_UNLOCK(p); - } else if (args->id <= 0) - return (EINVAL); - idtype = P_PGID; - break; - case LINUX_P_PIDFD: - LINUX_RATELIMIT_MSG("unsupported waitid P_PIDFD idtype"); - return (ENOSYS); - default: - return (EINVAL); - } - - error = linux_common_wait(td, idtype, id, NULL, options, - args->rusage, args->info); - td->td_retval[0] = 0; - - return (error); -} - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_mknod(struct thread *td, struct linux_mknod_args *args) -{ - int error; - - switch (args->mode & S_IFMT) { - case S_IFIFO: - case S_IFSOCK: - error = kern_mkfifoat(td, AT_FDCWD, args->path, UIO_USERSPACE, - args->mode); - break; - - case S_IFCHR: - case S_IFBLK: - error = kern_mknodat(td, AT_FDCWD, args->path, UIO_USERSPACE, - args->mode, linux_decode_dev(args->dev)); - break; - - case S_IFDIR: - error = EPERM; - break; - - case 0: - args->mode |= S_IFREG; - /* FALLTHROUGH */ - case S_IFREG: - error = kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE, - O_WRONLY | O_CREAT | O_TRUNC, args->mode); - if (error == 0) - kern_close(td, td->td_retval[0]); - break; - - default: - error = EINVAL; - break; - } - return (error); -} -#endif - -int -linux_mknodat(struct thread *td, struct linux_mknodat_args *args) -{ - int error, dfd; - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - - switch (args->mode & S_IFMT) { - case S_IFIFO: - case S_IFSOCK: - error = kern_mkfifoat(td, dfd, args->filename, UIO_USERSPACE, - args->mode); - break; - - case S_IFCHR: - case S_IFBLK: - error = kern_mknodat(td, dfd, args->filename, UIO_USERSPACE, - args->mode, linux_decode_dev(args->dev)); - break; - - case S_IFDIR: - error = EPERM; - break; - - case 0: - args->mode |= S_IFREG; - /* FALLTHROUGH */ - case S_IFREG: - error = kern_openat(td, dfd, args->filename, UIO_USERSPACE, - O_WRONLY | O_CREAT | O_TRUNC, args->mode); - if (error == 0) - kern_close(td, td->td_retval[0]); - break; - - default: - error = EINVAL; - break; - } - return (error); -} - -/* - * UGH! This is just about the dumbest idea I've ever heard!! - */ -int -linux_personality(struct thread *td, struct linux_personality_args *args) -{ - struct linux_pemuldata *pem; - struct proc *p = td->td_proc; - uint32_t old; - - PROC_LOCK(p); - pem = pem_find(p); - old = pem->persona; - if (args->per != 0xffffffff) - pem->persona = args->per; - PROC_UNLOCK(p); - - td->td_retval[0] = old; - return (0); -} - -struct l_itimerval { - l_timeval it_interval; - l_timeval it_value; -}; - -#define B2L_ITIMERVAL(bip, lip) \ - (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \ - (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \ - (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \ - (bip)->it_value.tv_usec = (lip)->it_value.tv_usec; - -int -linux_setitimer(struct thread *td, struct linux_setitimer_args *uap) -{ - int error; - struct l_itimerval ls; - struct itimerval aitv, oitv; - - if (uap->itv == NULL) { - uap->itv = uap->oitv; - return (linux_getitimer(td, (struct linux_getitimer_args *)uap)); - } - - error = copyin(uap->itv, &ls, sizeof(ls)); - if (error != 0) - return (error); - B2L_ITIMERVAL(&aitv, &ls); - error = kern_setitimer(td, uap->which, &aitv, &oitv); - if (error != 0 || uap->oitv == NULL) - return (error); - B2L_ITIMERVAL(&ls, &oitv); - - return (copyout(&ls, uap->oitv, sizeof(ls))); -} - -int -linux_getitimer(struct thread *td, struct linux_getitimer_args *uap) -{ - int error; - struct l_itimerval ls; - struct itimerval aitv; - - error = kern_getitimer(td, uap->which, &aitv); - if (error != 0) - return (error); - B2L_ITIMERVAL(&ls, &aitv); - return (copyout(&ls, uap->itv, sizeof(ls))); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_nice(struct thread *td, struct linux_nice_args *args) -{ - - return (kern_setpriority(td, PRIO_PROCESS, 0, args->inc)); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_setgroups(struct thread *td, struct linux_setgroups_args *args) -{ - struct ucred *newcred, *oldcred; - l_gid_t *linux_gidset; - gid_t *bsd_gidset; - int ngrp, error; - struct proc *p; - - ngrp = args->gidsetsize; - if (ngrp < 0 || ngrp >= ngroups_max + 1) - return (EINVAL); - linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); - error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); - if (error) - goto out; - newcred = crget(); - crextend(newcred, ngrp + 1); - p = td->td_proc; - PROC_LOCK(p); - oldcred = p->p_ucred; - crcopy(newcred, oldcred); - - /* - * cr_groups[0] holds egid. Setting the whole set from - * the supplied set will cause egid to be changed too. - * Keep cr_groups[0] unchanged to prevent that. - */ - - if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) { - PROC_UNLOCK(p); - crfree(newcred); - goto out; - } - - if (ngrp > 0) { - newcred->cr_ngroups = ngrp + 1; - - bsd_gidset = newcred->cr_groups; - ngrp--; - while (ngrp >= 0) { - bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; - ngrp--; - } - } else - newcred->cr_ngroups = 1; - - setsugid(p); - proc_set_cred(p, newcred); - PROC_UNLOCK(p); - crfree(oldcred); - error = 0; -out: - free(linux_gidset, M_LINUX); - return (error); -} - -int -linux_getgroups(struct thread *td, struct linux_getgroups_args *args) -{ - struct ucred *cred; - l_gid_t *linux_gidset; - gid_t *bsd_gidset; - int bsd_gidsetsz, ngrp, error; - - cred = td->td_ucred; - bsd_gidset = cred->cr_groups; - bsd_gidsetsz = cred->cr_ngroups - 1; - - /* - * cr_groups[0] holds egid. Returning the whole set - * here will cause a duplicate. Exclude cr_groups[0] - * to prevent that. - */ - - if ((ngrp = args->gidsetsize) == 0) { - td->td_retval[0] = bsd_gidsetsz; - return (0); - } - - if (ngrp < bsd_gidsetsz) - return (EINVAL); - - ngrp = 0; - linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), - M_LINUX, M_WAITOK); - while (ngrp < bsd_gidsetsz) { - linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; - ngrp++; - } - - error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t)); - free(linux_gidset, M_LINUX); - if (error) - return (error); - - td->td_retval[0] = ngrp; - return (0); -} - -static bool -linux_get_dummy_limit(struct thread *td, l_uint resource, struct rlimit *rlim) -{ - ssize_t size; - int res, error; - - if (linux_dummy_rlimits == 0) - return (false); - - switch (resource) { - case LINUX_RLIMIT_LOCKS: - case LINUX_RLIMIT_RTTIME: - rlim->rlim_cur = LINUX_RLIM_INFINITY; - rlim->rlim_max = LINUX_RLIM_INFINITY; - return (true); - case LINUX_RLIMIT_NICE: - case LINUX_RLIMIT_RTPRIO: - rlim->rlim_cur = 0; - rlim->rlim_max = 0; - return (true); - case LINUX_RLIMIT_SIGPENDING: - error = kernel_sysctlbyname(td, - "kern.sigqueue.max_pending_per_proc", - &res, &size, 0, 0, 0, 0); - if (error != 0) - return (false); - rlim->rlim_cur = res; - rlim->rlim_max = res; - return (true); - case LINUX_RLIMIT_MSGQUEUE: - error = kernel_sysctlbyname(td, - "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0); - if (error != 0) - return (false); - rlim->rlim_cur = res; - rlim->rlim_max = res; - return (true); - default: - return (false); - } -} - -int -linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) -{ - struct rlimit bsd_rlim; - struct l_rlimit rlim; - u_int which; - int error; - - if (args->resource >= LINUX_RLIM_NLIMITS) - return (EINVAL); - - which = linux_to_bsd_resource[args->resource]; - if (which == -1) - return (EINVAL); - - error = copyin(args->rlim, &rlim, sizeof(rlim)); - if (error) - return (error); - - bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur; - bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max; - return (kern_setrlimit(td, which, &bsd_rlim)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) -{ - struct l_rlimit rlim; - struct rlimit bsd_rlim; - u_int which; - - if (linux_get_dummy_limit(td, args->resource, &bsd_rlim)) { - rlim.rlim_cur = bsd_rlim.rlim_cur; - rlim.rlim_max = bsd_rlim.rlim_max; - return (copyout(&rlim, args->rlim, sizeof(rlim))); - } - - if (args->resource >= LINUX_RLIM_NLIMITS) - return (EINVAL); - - which = linux_to_bsd_resource[args->resource]; - if (which == -1) - return (EINVAL); - - lim_rlimit(td, which, &bsd_rlim); - -#ifdef COMPAT_LINUX32 - rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur; - if (rlim.rlim_cur == UINT_MAX) - rlim.rlim_cur = INT_MAX; - rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max; - if (rlim.rlim_max == UINT_MAX) - rlim.rlim_max = INT_MAX; -#else - rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur; - if (rlim.rlim_cur == ULONG_MAX) - rlim.rlim_cur = LONG_MAX; - rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max; - if (rlim.rlim_max == ULONG_MAX) - rlim.rlim_max = LONG_MAX; -#endif - return (copyout(&rlim, args->rlim, sizeof(rlim))); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) -{ - struct l_rlimit rlim; - struct rlimit bsd_rlim; - u_int which; - - if (linux_get_dummy_limit(td, args->resource, &bsd_rlim)) { - rlim.rlim_cur = bsd_rlim.rlim_cur; - rlim.rlim_max = bsd_rlim.rlim_max; - return (copyout(&rlim, args->rlim, sizeof(rlim))); - } - - if (args->resource >= LINUX_RLIM_NLIMITS) - return (EINVAL); - - which = linux_to_bsd_resource[args->resource]; - if (which == -1) - return (EINVAL); - - lim_rlimit(td, which, &bsd_rlim); - - rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur; - rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max; - return (copyout(&rlim, args->rlim, sizeof(rlim))); -} - -int -linux_sched_setscheduler(struct thread *td, - struct linux_sched_setscheduler_args *args) -{ - struct sched_param sched_param; - struct thread *tdt; - int error, policy; - - switch (args->policy) { - case LINUX_SCHED_OTHER: - policy = SCHED_OTHER; - break; - case LINUX_SCHED_FIFO: - policy = SCHED_FIFO; - break; - case LINUX_SCHED_RR: - policy = SCHED_RR; - break; - default: - return (EINVAL); - } - - error = copyin(args->param, &sched_param, sizeof(sched_param)); - if (error) - return (error); - - if (linux_map_sched_prio) { - switch (policy) { - case SCHED_OTHER: - if (sched_param.sched_priority != 0) - return (EINVAL); - - sched_param.sched_priority = - PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; - break; - case SCHED_FIFO: - case SCHED_RR: - if (sched_param.sched_priority < 1 || - sched_param.sched_priority >= LINUX_MAX_RT_PRIO) - return (EINVAL); - - /* - * Map [1, LINUX_MAX_RT_PRIO - 1] to - * [0, RTP_PRIO_MAX - RTP_PRIO_MIN] (rounding down). - */ - sched_param.sched_priority = - (sched_param.sched_priority - 1) * - (RTP_PRIO_MAX - RTP_PRIO_MIN + 1) / - (LINUX_MAX_RT_PRIO - 1); - break; - } - } - - tdt = linux_tdfind(td, args->pid, -1); - if (tdt == NULL) - return (ESRCH); - - error = kern_sched_setscheduler(td, tdt, policy, &sched_param); - PROC_UNLOCK(tdt->td_proc); - return (error); -} - -int -linux_sched_getscheduler(struct thread *td, - struct linux_sched_getscheduler_args *args) -{ - struct thread *tdt; - int error, policy; - - tdt = linux_tdfind(td, args->pid, -1); - if (tdt == NULL) - return (ESRCH); - - error = kern_sched_getscheduler(td, tdt, &policy); - PROC_UNLOCK(tdt->td_proc); - - switch (policy) { - case SCHED_OTHER: - td->td_retval[0] = LINUX_SCHED_OTHER; - break; - case SCHED_FIFO: - td->td_retval[0] = LINUX_SCHED_FIFO; - break; - case SCHED_RR: - td->td_retval[0] = LINUX_SCHED_RR; - break; - } - return (error); -} - -int -linux_sched_get_priority_max(struct thread *td, - struct linux_sched_get_priority_max_args *args) -{ - struct sched_get_priority_max_args bsd; - - if (linux_map_sched_prio) { - switch (args->policy) { - case LINUX_SCHED_OTHER: - td->td_retval[0] = 0; - return (0); - case LINUX_SCHED_FIFO: - case LINUX_SCHED_RR: - td->td_retval[0] = LINUX_MAX_RT_PRIO - 1; - return (0); - default: - return (EINVAL); - } - } - - switch (args->policy) { - case LINUX_SCHED_OTHER: - bsd.policy = SCHED_OTHER; - break; - case LINUX_SCHED_FIFO: - bsd.policy = SCHED_FIFO; - break; - case LINUX_SCHED_RR: - bsd.policy = SCHED_RR; - break; - default: - return (EINVAL); - } - return (sys_sched_get_priority_max(td, &bsd)); -} - -int -linux_sched_get_priority_min(struct thread *td, - struct linux_sched_get_priority_min_args *args) -{ - struct sched_get_priority_min_args bsd; - - if (linux_map_sched_prio) { - switch (args->policy) { - case LINUX_SCHED_OTHER: - td->td_retval[0] = 0; - return (0); - case LINUX_SCHED_FIFO: - case LINUX_SCHED_RR: - td->td_retval[0] = 1; - return (0); - default: - return (EINVAL); - } - } - - switch (args->policy) { - case LINUX_SCHED_OTHER: - bsd.policy = SCHED_OTHER; - break; - case LINUX_SCHED_FIFO: - bsd.policy = SCHED_FIFO; - break; - case LINUX_SCHED_RR: - bsd.policy = SCHED_RR; - break; - default: - return (EINVAL); - } - return (sys_sched_get_priority_min(td, &bsd)); -} - -#define REBOOT_CAD_ON 0x89abcdef -#define REBOOT_CAD_OFF 0 -#define REBOOT_HALT 0xcdef0123 -#define REBOOT_RESTART 0x01234567 -#define REBOOT_RESTART2 0xA1B2C3D4 -#define REBOOT_POWEROFF 0x4321FEDC -#define REBOOT_MAGIC1 0xfee1dead -#define REBOOT_MAGIC2 0x28121969 -#define REBOOT_MAGIC2A 0x05121996 -#define REBOOT_MAGIC2B 0x16041998 - -int -linux_reboot(struct thread *td, struct linux_reboot_args *args) -{ - struct reboot_args bsd_args; - - if (args->magic1 != REBOOT_MAGIC1) - return (EINVAL); - - switch (args->magic2) { - case REBOOT_MAGIC2: - case REBOOT_MAGIC2A: - case REBOOT_MAGIC2B: - break; - default: - return (EINVAL); - } - - switch (args->cmd) { - case REBOOT_CAD_ON: - case REBOOT_CAD_OFF: - return (priv_check(td, PRIV_REBOOT)); - case REBOOT_HALT: - bsd_args.opt = RB_HALT; - break; - case REBOOT_RESTART: - case REBOOT_RESTART2: - bsd_args.opt = 0; - break; - case REBOOT_POWEROFF: - bsd_args.opt = RB_POWEROFF; - break; - default: - return (EINVAL); - } - return (sys_reboot(td, &bsd_args)); -} - -int -linux_getpid(struct thread *td, struct linux_getpid_args *args) -{ - - td->td_retval[0] = td->td_proc->p_pid; - - return (0); -} - -int -linux_gettid(struct thread *td, struct linux_gettid_args *args) -{ - struct linux_emuldata *em; - - em = em_find(td); - KASSERT(em != NULL, ("gettid: emuldata not found.\n")); - - td->td_retval[0] = em->em_tid; - - return (0); -} - -int -linux_getppid(struct thread *td, struct linux_getppid_args *args) -{ - - td->td_retval[0] = kern_getppid(td); - return (0); -} - -int -linux_getgid(struct thread *td, struct linux_getgid_args *args) -{ - - td->td_retval[0] = td->td_ucred->cr_rgid; - return (0); -} - -int -linux_getuid(struct thread *td, struct linux_getuid_args *args) -{ - - td->td_retval[0] = td->td_ucred->cr_ruid; - return (0); -} - -int -linux_getsid(struct thread *td, struct linux_getsid_args *args) -{ - - return (kern_getsid(td, args->pid)); -} - -int -linux_getpriority(struct thread *td, struct linux_getpriority_args *args) -{ - int error; - - error = kern_getpriority(td, args->which, args->who); - td->td_retval[0] = 20 - td->td_retval[0]; - return (error); -} - -int -linux_sethostname(struct thread *td, struct linux_sethostname_args *args) -{ - int name[2]; - - name[0] = CTL_KERN; - name[1] = KERN_HOSTNAME; - return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname, - args->len, 0, 0)); -} - -int -linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args) -{ - int name[2]; - - name[0] = CTL_KERN; - name[1] = KERN_NISDOMAINNAME; - return (userland_sysctl(td, name, 2, 0, 0, 0, args->name, - args->len, 0, 0)); -} - -int -linux_exit_group(struct thread *td, struct linux_exit_group_args *args) -{ - - LINUX_CTR2(exit_group, "thread(%d) (%d)", td->td_tid, - args->error_code); - - /* - * XXX: we should send a signal to the parent if - * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?) - * as it doesnt occur often. - */ - exit1(td, args->error_code, 0); - /* NOTREACHED */ -} - -#define _LINUX_CAPABILITY_VERSION_1 0x19980330 -#define _LINUX_CAPABILITY_VERSION_2 0x20071026 -#define _LINUX_CAPABILITY_VERSION_3 0x20080522 - -struct l_user_cap_header { - l_int version; - l_int pid; -}; - -struct l_user_cap_data { - l_int effective; - l_int permitted; - l_int inheritable; -}; - -int -linux_capget(struct thread *td, struct linux_capget_args *uap) -{ - struct l_user_cap_header luch; - struct l_user_cap_data lucd[2]; - int error, u32s; - - if (uap->hdrp == NULL) - return (EFAULT); - - error = copyin(uap->hdrp, &luch, sizeof(luch)); - if (error != 0) - return (error); - - switch (luch.version) { - case _LINUX_CAPABILITY_VERSION_1: - u32s = 1; - break; - case _LINUX_CAPABILITY_VERSION_2: - case _LINUX_CAPABILITY_VERSION_3: - u32s = 2; - break; - default: - luch.version = _LINUX_CAPABILITY_VERSION_1; - error = copyout(&luch, uap->hdrp, sizeof(luch)); - if (error) - return (error); - return (EINVAL); - } - - if (luch.pid) - return (EPERM); - - if (uap->datap) { - /* - * The current implementation doesn't support setting - * a capability (it's essentially a stub) so indicate - * that no capabilities are currently set or available - * to request. - */ - memset(&lucd, 0, u32s * sizeof(lucd[0])); - error = copyout(&lucd, uap->datap, u32s * sizeof(lucd[0])); - } - - return (error); -} - -int -linux_capset(struct thread *td, struct linux_capset_args *uap) -{ - struct l_user_cap_header luch; - struct l_user_cap_data lucd[2]; - int error, i, u32s; - - if (uap->hdrp == NULL || uap->datap == NULL) - return (EFAULT); - - error = copyin(uap->hdrp, &luch, sizeof(luch)); - if (error != 0) - return (error); - - switch (luch.version) { - case _LINUX_CAPABILITY_VERSION_1: - u32s = 1; - break; - case _LINUX_CAPABILITY_VERSION_2: - case _LINUX_CAPABILITY_VERSION_3: - u32s = 2; - break; - default: - luch.version = _LINUX_CAPABILITY_VERSION_1; - error = copyout(&luch, uap->hdrp, sizeof(luch)); - if (error) - return (error); - return (EINVAL); - } - - if (luch.pid) - return (EPERM); - - error = copyin(uap->datap, &lucd, u32s * sizeof(lucd[0])); - if (error != 0) - return (error); - - /* We currently don't support setting any capabilities. */ - for (i = 0; i < u32s; i++) { - if (lucd[i].effective || lucd[i].permitted || - lucd[i].inheritable) { - linux_msg(td, - "capset[%d] effective=0x%x, permitted=0x%x, " - "inheritable=0x%x is not implemented", i, - (int)lucd[i].effective, (int)lucd[i].permitted, - (int)lucd[i].inheritable); - return (EPERM); - } - } - - return (0); -} - -int -linux_prctl(struct thread *td, struct linux_prctl_args *args) -{ - int error = 0, max_size, arg; - struct proc *p = td->td_proc; - char comm[LINUX_MAX_COMM_LEN]; - int pdeath_signal, trace_state; - - switch (args->option) { - case LINUX_PR_SET_PDEATHSIG: - if (!LINUX_SIG_VALID(args->arg2)) - return (EINVAL); - pdeath_signal = linux_to_bsd_signal(args->arg2); - return (kern_procctl(td, P_PID, 0, PROC_PDEATHSIG_CTL, - &pdeath_signal)); - case LINUX_PR_GET_PDEATHSIG: - error = kern_procctl(td, P_PID, 0, PROC_PDEATHSIG_STATUS, - &pdeath_signal); - if (error != 0) - return (error); - pdeath_signal = bsd_to_linux_signal(pdeath_signal); - return (copyout(&pdeath_signal, - (void *)(register_t)args->arg2, - sizeof(pdeath_signal))); - /* - * In Linux, this flag controls if set[gu]id processes can coredump. - * There are additional semantics imposed on processes that cannot - * coredump: - * - Such processes can not be ptraced. - * - There are some semantics around ownership of process-related files - * in the /proc namespace. - * - * In FreeBSD, we can (and by default, do) disable setuid coredump - * system-wide with 'sugid_coredump.' We control tracability on a - * per-process basis with the procctl PROC_TRACE (=> P2_NOTRACE flag). - * By happy coincidence, P2_NOTRACE also prevents coredumping. So the - * procctl is roughly analogous to Linux's DUMPABLE. - * - * So, proxy these knobs to the corresponding PROC_TRACE setting. - */ - case LINUX_PR_GET_DUMPABLE: - error = kern_procctl(td, P_PID, p->p_pid, PROC_TRACE_STATUS, - &trace_state); - if (error != 0) - return (error); - td->td_retval[0] = (trace_state != -1); - return (0); - case LINUX_PR_SET_DUMPABLE: - /* - * It is only valid for userspace to set one of these two - * flags, and only one at a time. - */ - switch (args->arg2) { - case LINUX_SUID_DUMP_DISABLE: - trace_state = PROC_TRACE_CTL_DISABLE_EXEC; - break; - case LINUX_SUID_DUMP_USER: - trace_state = PROC_TRACE_CTL_ENABLE; - break; - default: - return (EINVAL); - } - return (kern_procctl(td, P_PID, p->p_pid, PROC_TRACE_CTL, - &trace_state)); - case LINUX_PR_GET_KEEPCAPS: - /* - * Indicate that we always clear the effective and - * permitted capability sets when the user id becomes - * non-zero (actually the capability sets are simply - * always zero in the current implementation). - */ - td->td_retval[0] = 0; - break; - case LINUX_PR_SET_KEEPCAPS: - /* - * Ignore requests to keep the effective and permitted - * capability sets when the user id becomes non-zero. - */ - break; - case LINUX_PR_SET_NAME: - /* - * To be on the safe side we need to make sure to not - * overflow the size a Linux program expects. We already - * do this here in the copyin, so that we don't need to - * check on copyout. - */ - max_size = MIN(sizeof(comm), sizeof(p->p_comm)); - error = copyinstr((void *)(register_t)args->arg2, comm, - max_size, NULL); - - /* Linux silently truncates the name if it is too long. */ - if (error == ENAMETOOLONG) { - /* - * XXX: copyinstr() isn't documented to populate the - * array completely, so do a copyin() to be on the - * safe side. This should be changed in case - * copyinstr() is changed to guarantee this. - */ - error = copyin((void *)(register_t)args->arg2, comm, - max_size - 1); - comm[max_size - 1] = '\0'; - } - if (error) - return (error); - - PROC_LOCK(p); - strlcpy(p->p_comm, comm, sizeof(p->p_comm)); - PROC_UNLOCK(p); - break; - case LINUX_PR_GET_NAME: - PROC_LOCK(p); - strlcpy(comm, p->p_comm, sizeof(comm)); - PROC_UNLOCK(p); - error = copyout(comm, (void *)(register_t)args->arg2, - strlen(comm) + 1); - break; - case LINUX_PR_GET_SECCOMP: - case LINUX_PR_SET_SECCOMP: - /* - * Same as returned by Linux without CONFIG_SECCOMP enabled. - */ - error = EINVAL; - break; - case LINUX_PR_CAPBSET_READ: -#if 0 - /* - * This makes too much noise with Ubuntu Focal. - */ - linux_msg(td, "unsupported prctl PR_CAPBSET_READ %d", - (int)args->arg2); -#endif - error = EINVAL; - break; - case LINUX_PR_SET_CHILD_SUBREAPER: - if (args->arg2 == 0) { - return (kern_procctl(td, P_PID, 0, PROC_REAP_RELEASE, - NULL)); - } - - return (kern_procctl(td, P_PID, 0, PROC_REAP_ACQUIRE, - NULL)); - case LINUX_PR_SET_NO_NEW_PRIVS: - arg = args->arg2 == 1 ? - PROC_NO_NEW_PRIVS_ENABLE : PROC_NO_NEW_PRIVS_DISABLE; - error = kern_procctl(td, P_PID, p->p_pid, - PROC_NO_NEW_PRIVS_CTL, &arg); - break; - case LINUX_PR_SET_PTRACER: - linux_msg(td, "unsupported prctl PR_SET_PTRACER"); - error = EINVAL; - break; - default: - linux_msg(td, "unsupported prctl option %d", args->option); - error = EINVAL; - break; - } - - return (error); -} - -int -linux_sched_setparam(struct thread *td, - struct linux_sched_setparam_args *uap) -{ - struct sched_param sched_param; - struct thread *tdt; - int error, policy; - - error = copyin(uap->param, &sched_param, sizeof(sched_param)); - if (error) - return (error); - - tdt = linux_tdfind(td, uap->pid, -1); - if (tdt == NULL) - return (ESRCH); - - if (linux_map_sched_prio) { - error = kern_sched_getscheduler(td, tdt, &policy); - if (error) - goto out; - - switch (policy) { - case SCHED_OTHER: - if (sched_param.sched_priority != 0) { - error = EINVAL; - goto out; - } - sched_param.sched_priority = - PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; - break; - case SCHED_FIFO: - case SCHED_RR: - if (sched_param.sched_priority < 1 || - sched_param.sched_priority >= LINUX_MAX_RT_PRIO) { - error = EINVAL; - goto out; - } - /* - * Map [1, LINUX_MAX_RT_PRIO - 1] to - * [0, RTP_PRIO_MAX - RTP_PRIO_MIN] (rounding down). - */ - sched_param.sched_priority = - (sched_param.sched_priority - 1) * - (RTP_PRIO_MAX - RTP_PRIO_MIN + 1) / - (LINUX_MAX_RT_PRIO - 1); - break; - } - } - - error = kern_sched_setparam(td, tdt, &sched_param); -out: PROC_UNLOCK(tdt->td_proc); - return (error); -} - -int -linux_sched_getparam(struct thread *td, - struct linux_sched_getparam_args *uap) -{ - struct sched_param sched_param; - struct thread *tdt; - int error, policy; - - tdt = linux_tdfind(td, uap->pid, -1); - if (tdt == NULL) - return (ESRCH); - - error = kern_sched_getparam(td, tdt, &sched_param); - if (error) { - PROC_UNLOCK(tdt->td_proc); - return (error); - } - - if (linux_map_sched_prio) { - error = kern_sched_getscheduler(td, tdt, &policy); - PROC_UNLOCK(tdt->td_proc); - if (error) - return (error); - - switch (policy) { - case SCHED_OTHER: - sched_param.sched_priority = 0; - break; - case SCHED_FIFO: - case SCHED_RR: - /* - * Map [0, RTP_PRIO_MAX - RTP_PRIO_MIN] to - * [1, LINUX_MAX_RT_PRIO - 1] (rounding up). - */ - sched_param.sched_priority = - (sched_param.sched_priority * - (LINUX_MAX_RT_PRIO - 1) + - (RTP_PRIO_MAX - RTP_PRIO_MIN - 1)) / - (RTP_PRIO_MAX - RTP_PRIO_MIN) + 1; - break; - } - } else - PROC_UNLOCK(tdt->td_proc); - - error = copyout(&sched_param, uap->param, sizeof(sched_param)); - return (error); -} - -/* - * Get affinity of a process. - */ -int -linux_sched_getaffinity(struct thread *td, - struct linux_sched_getaffinity_args *args) -{ - struct thread *tdt; - cpuset_t *mask; - size_t size; - int error; - id_t tid; - - tdt = linux_tdfind(td, args->pid, -1); - if (tdt == NULL) - return (ESRCH); - tid = tdt->td_tid; - PROC_UNLOCK(tdt->td_proc); - - mask = malloc(sizeof(cpuset_t), M_LINUX, M_WAITOK | M_ZERO); - size = min(args->len, sizeof(cpuset_t)); - error = kern_cpuset_getaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, - tid, size, mask); - if (error == ERANGE) - error = EINVAL; - if (error == 0) - error = copyout(mask, args->user_mask_ptr, size); - if (error == 0) - td->td_retval[0] = size; - free(mask, M_LINUX); - return (error); -} - -/* - * Set affinity of a process. - */ -int -linux_sched_setaffinity(struct thread *td, - struct linux_sched_setaffinity_args *args) -{ - struct thread *tdt; - cpuset_t *mask; - int cpu, error; - size_t len; - id_t tid; - - tdt = linux_tdfind(td, args->pid, -1); - if (tdt == NULL) - return (ESRCH); - tid = tdt->td_tid; - PROC_UNLOCK(tdt->td_proc); - - len = min(args->len, sizeof(cpuset_t)); - mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO); - error = copyin(args->user_mask_ptr, mask, len); - if (error != 0) - goto out; - /* Linux ignore high bits */ - CPU_FOREACH_ISSET(cpu, mask) - if (cpu > mp_maxid) - CPU_CLR(cpu, mask); - - error = kern_cpuset_setaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, - tid, mask); - if (error == EDEADLK) - error = EINVAL; -out: - free(mask, M_TEMP); - return (error); -} - -struct linux_rlimit64 { - uint64_t rlim_cur; - uint64_t rlim_max; -}; - -int -linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) -{ - struct rlimit rlim, nrlim; - struct linux_rlimit64 lrlim; - struct proc *p; - u_int which; - int flags; - int error; - - if (args->new == NULL && args->old != NULL) { - if (linux_get_dummy_limit(td, args->resource, &rlim)) { - lrlim.rlim_cur = rlim.rlim_cur; - lrlim.rlim_max = rlim.rlim_max; - return (copyout(&lrlim, args->old, sizeof(lrlim))); - } - } - - if (args->resource >= LINUX_RLIM_NLIMITS) - return (EINVAL); - - which = linux_to_bsd_resource[args->resource]; - if (which == -1) - return (EINVAL); - - if (args->new != NULL) { - /* - * Note. Unlike FreeBSD where rlim is signed 64-bit Linux - * rlim is unsigned 64-bit. FreeBSD treats negative limits - * as INFINITY so we do not need a conversion even. - */ - error = copyin(args->new, &nrlim, sizeof(nrlim)); - if (error != 0) - return (error); - } - - flags = PGET_HOLD | PGET_NOTWEXIT; - if (args->new != NULL) - flags |= PGET_CANDEBUG; - else - flags |= PGET_CANSEE; - if (args->pid == 0) { - p = td->td_proc; - PHOLD(p); - } else { - error = pget(args->pid, flags, &p); - if (error != 0) - return (error); - } - if (args->old != NULL) { - PROC_LOCK(p); - lim_rlimit_proc(p, which, &rlim); - PROC_UNLOCK(p); - if (rlim.rlim_cur == RLIM_INFINITY) - lrlim.rlim_cur = LINUX_RLIM_INFINITY; - else - lrlim.rlim_cur = rlim.rlim_cur; - if (rlim.rlim_max == RLIM_INFINITY) - lrlim.rlim_max = LINUX_RLIM_INFINITY; - else - lrlim.rlim_max = rlim.rlim_max; - error = copyout(&lrlim, args->old, sizeof(lrlim)); - if (error != 0) - goto out; - } - - if (args->new != NULL) - error = kern_proc_setrlimit(td, p, which, &nrlim); - - out: - PRELE(p); - return (error); -} - -int -linux_pselect6(struct thread *td, struct linux_pselect6_args *args) -{ - struct timespec ts, *tsp; - int error; - - if (args->tsp != NULL) { - error = linux_get_timespec(&ts, args->tsp); - if (error != 0) - return (error); - tsp = &ts; - } else - tsp = NULL; - - error = linux_common_pselect6(td, args->nfds, args->readfds, - args->writefds, args->exceptfds, tsp, args->sig); - - if (args->tsp != NULL) - linux_put_timespec(&ts, args->tsp); - return (error); -} - -static int -linux_common_pselect6(struct thread *td, l_int nfds, l_fd_set *readfds, - l_fd_set *writefds, l_fd_set *exceptfds, struct timespec *tsp, - l_uintptr_t *sig) -{ - struct timeval utv, tv0, tv1, *tvp; - struct l_pselect6arg lpse6; - sigset_t *ssp; - sigset_t ss; - int error; - - ssp = NULL; - if (sig != NULL) { - error = copyin(sig, &lpse6, sizeof(lpse6)); - if (error != 0) - return (error); - error = linux_copyin_sigset(td, PTRIN(lpse6.ss), - lpse6.ss_len, &ss, &ssp); - if (error != 0) - return (error); - } else - ssp = NULL; - - /* - * Currently glibc changes nanosecond number to microsecond. - * This mean losing precision but for now it is hardly seen. - */ - if (tsp != NULL) { - TIMESPEC_TO_TIMEVAL(&utv, tsp); - if (itimerfix(&utv)) - return (EINVAL); - - microtime(&tv0); - tvp = &utv; - } else - tvp = NULL; - - error = kern_pselect(td, nfds, __USER_CAP_UNBOUND(readfds), - __USER_CAP_UNBOUND(writefds), - __USER_CAP_UNBOUND(exceptfds), tvp, ssp, LINUX_NFDBITS); - - if (tsp != NULL) { - /* - * Compute how much time was left of the timeout, - * by subtracting the current time and the time - * before we started the call, and subtracting - * that result from the user-supplied value. - */ - microtime(&tv1); - timevalsub(&tv1, &tv0); - timevalsub(&utv, &tv1); - if (utv.tv_sec < 0) - timevalclear(&utv); - TIMEVAL_TO_TIMESPEC(&utv, tsp); - } - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_pselect6_time64(struct thread *td, - struct linux_pselect6_time64_args *args) -{ - struct timespec ts, *tsp; - int error; - - if (args->tsp != NULL) { - error = linux_get_timespec64(&ts, args->tsp); - if (error != 0) - return (error); - tsp = &ts; - } else - tsp = NULL; - - error = linux_common_pselect6(td, args->nfds, args->readfds, - args->writefds, args->exceptfds, tsp, args->sig); - - if (args->tsp != NULL) - linux_put_timespec64(&ts, args->tsp); - return (error); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_ppoll(struct thread *td, struct linux_ppoll_args *args) -{ - struct timespec uts, *tsp; - int error; - - if (args->tsp != NULL) { - error = linux_get_timespec(&uts, args->tsp); - if (error != 0) - return (error); - tsp = &uts; - } else - tsp = NULL; - - error = linux_common_ppoll(td, args->fds, args->nfds, tsp, - args->sset, args->ssize); - if (error == 0 && args->tsp != NULL) - error = linux_put_timespec(&uts, args->tsp); - return (error); -} - -static int -linux_common_ppoll(struct thread *td, struct pollfd *fds, uint32_t nfds, - struct timespec *tsp, l_sigset_t *sset, l_size_t ssize) -{ - struct timespec ts0, ts1; - struct pollfd stackfds[32]; - struct pollfd *kfds; - sigset_t *ssp; - sigset_t ss; - int error; - - if (kern_poll_maxfds(nfds)) - return (EINVAL); - if (sset != NULL) { - error = linux_copyin_sigset(td, sset, ssize, &ss, &ssp); - if (error != 0) - return (error); - } else - ssp = NULL; - if (tsp != NULL) - nanotime(&ts0); - - if (nfds > nitems(stackfds)) - kfds = mallocarray(nfds, sizeof(*kfds), M_TEMP, M_WAITOK); - else - kfds = stackfds; - error = linux_pollin(td, kfds, fds, nfds); - if (error != 0) - goto out; - - error = kern_poll_kfds(td, kfds, nfds, tsp, ssp); - if (error == 0) - error = linux_pollout(td, kfds, fds, nfds); - - if (error == 0 && tsp != NULL) { - if (td->td_retval[0]) { - nanotime(&ts1); - timespecsub(&ts1, &ts0, &ts1); - timespecsub(tsp, &ts1, tsp); - if (tsp->tv_sec < 0) - timespecclear(tsp); - } else - timespecclear(tsp); - } - -out: - if (nfds > nitems(stackfds)) - free(kfds, M_TEMP); - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_ppoll_time64(struct thread *td, struct linux_ppoll_time64_args *args) -{ - struct timespec uts, *tsp; - int error; - - if (args->tsp != NULL) { - error = linux_get_timespec64(&uts, args->tsp); - if (error != 0) - return (error); - tsp = &uts; - } else - tsp = NULL; - error = linux_common_ppoll(td, args->fds, args->nfds, tsp, - args->sset, args->ssize); - if (error == 0 && args->tsp != NULL) - error = linux_put_timespec64(&uts, args->tsp); - return (error); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -static int -linux_pollin(struct thread *td, struct pollfd *fds, struct pollfd *ufds, u_int nfd) -{ - int error; - u_int i; - - error = copyin(ufds, fds, nfd * sizeof(*fds)); - if (error != 0) - return (error); - - for (i = 0; i < nfd; i++) { - if (fds->events != 0) - linux_to_bsd_poll_events(td, fds->fd, - fds->events, &fds->events); - fds++; - } - return (0); -} - -static int -linux_pollout(struct thread *td, struct pollfd *fds, struct pollfd *ufds, u_int nfd) -{ - int error = 0; - u_int i, n = 0; - - for (i = 0; i < nfd; i++) { - if (fds->revents != 0) { - bsd_to_linux_poll_events(fds->revents, - &fds->revents); - n++; - } - error = copyout(&fds->revents, &ufds->revents, - sizeof(ufds->revents)); - if (error) - return (error); - fds++; - ufds++; - } - td->td_retval[0] = n; - return (0); -} - -static int -linux_sched_rr_get_interval_common(struct thread *td, pid_t pid, - struct timespec *ts) -{ - struct thread *tdt; - int error; - - /* - * According to man in case the invalid pid specified - * EINVAL should be returned. - */ - if (pid < 0) - return (EINVAL); - - tdt = linux_tdfind(td, pid, -1); - if (tdt == NULL) - return (ESRCH); - - error = kern_sched_rr_get_interval_td(td, tdt, ts); - PROC_UNLOCK(tdt->td_proc); - return (error); -} - -int -linux_sched_rr_get_interval(struct thread *td, - struct linux_sched_rr_get_interval_args *uap) -{ - struct timespec ts; - int error; - - error = linux_sched_rr_get_interval_common(td, uap->pid, &ts); - if (error != 0) - return (error); - return (linux_put_timespec(&ts, uap->interval)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_sched_rr_get_interval_time64(struct thread *td, - struct linux_sched_rr_get_interval_time64_args *uap) -{ - struct timespec ts; - int error; - - error = linux_sched_rr_get_interval_common(td, uap->pid, &ts); - if (error != 0) - return (error); - return (linux_put_timespec64(&ts, uap->interval)); -} -#endif - -/* - * In case when the Linux thread is the initial thread in - * the thread group thread id is equal to the process id. - * Glibc depends on this magic (assert in pthread_getattr_np.c). - */ -struct thread * -linux_tdfind(struct thread *td, lwpid_t tid, pid_t pid) -{ - struct linux_emuldata *em; - struct thread *tdt; - struct proc *p; - - tdt = NULL; - if (tid == 0 || tid == td->td_tid) { - if (pid != -1 && td->td_proc->p_pid != pid) - return (NULL); - PROC_LOCK(td->td_proc); - return (td); - } else if (tid > PID_MAX) - return (tdfind(tid, pid)); - - /* - * Initial thread where the tid equal to the pid. - */ - p = pfind(tid); - if (p != NULL) { - if (SV_PROC_ABI(p) != SV_ABI_LINUX || - (pid != -1 && tid != pid)) { - /* - * p is not a Linuxulator process. - */ - PROC_UNLOCK(p); - return (NULL); - } - FOREACH_THREAD_IN_PROC(p, tdt) { - em = em_find(tdt); - if (tid == em->em_tid) - return (tdt); - } - PROC_UNLOCK(p); - } - return (NULL); -} - -void -linux_to_bsd_waitopts(int options, int *bsdopts) -{ - - if (options & LINUX_WNOHANG) - *bsdopts |= WNOHANG; - if (options & LINUX_WUNTRACED) - *bsdopts |= WUNTRACED; - if (options & LINUX_WEXITED) - *bsdopts |= WEXITED; - if (options & LINUX_WCONTINUED) - *bsdopts |= WCONTINUED; - if (options & LINUX_WNOWAIT) - *bsdopts |= WNOWAIT; - - if (options & __WCLONE) - *bsdopts |= WLINUXCLONE; -} - -int -linux_getrandom(struct thread *td, struct linux_getrandom_args *args) -{ - struct uio uio; - struct iovec iov; - int error; - - if (args->flags & ~(LINUX_GRND_NONBLOCK|LINUX_GRND_RANDOM)) - return (EINVAL); - if (args->count > INT_MAX) - args->count = INT_MAX; - - IOVEC_INIT(&iov, args->buf, args->count); - - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_resid = iov.iov_len; - uio.uio_segflg = UIO_USERSPACE; - uio.uio_rw = UIO_READ; - uio.uio_td = td; - - error = read_random_uio(&uio, args->flags & LINUX_GRND_NONBLOCK); - if (error == 0) - td->td_retval[0] = args->count - uio.uio_resid; - return (error); -} - -int -linux_mincore(struct thread *td, struct linux_mincore_args *args) -{ - - /* Needs to be page-aligned */ - if (args->start & PAGE_MASK) - return (EINVAL); - return (kern_mincore(td, args->start, args->len, - __USER_CAP(args->vec, args->len))); -} - -#define SYSLOG_TAG "<6>" - -int -linux_syslog(struct thread *td, struct linux_syslog_args *args) -{ - char buf[128], *src, *dst; - u_int seq; - int buflen, error; - - if (args->type != LINUX_SYSLOG_ACTION_READ_ALL) { - linux_msg(td, "syslog unsupported type 0x%x", args->type); - return (EINVAL); - } - - if (args->len < 6) { - td->td_retval[0] = 0; - return (0); - } - - error = priv_check(td, PRIV_MSGBUF); - if (error) - return (error); - - mtx_lock(&msgbuf_lock); - msgbuf_peekbytes(msgbufp, NULL, 0, &seq); - mtx_unlock(&msgbuf_lock); - - dst = args->buf; - error = copyout(&SYSLOG_TAG, dst, sizeof(SYSLOG_TAG)); - /* The -1 is to skip the trailing '\0'. */ - dst += sizeof(SYSLOG_TAG) - 1; - - while (error == 0) { - mtx_lock(&msgbuf_lock); - buflen = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq); - mtx_unlock(&msgbuf_lock); - - if (buflen == 0) - break; - - for (src = buf; src < buf + buflen && error == 0; src++) { - if (*src == '\0') - continue; - - if (dst >= args->buf + args->len) - goto out; - - error = copyout(src, dst, 1); - dst++; - - if (*src == '\n' && *(src + 1) != '<' && - dst + sizeof(SYSLOG_TAG) < args->buf + args->len) { - error = copyout(&SYSLOG_TAG, - dst, sizeof(SYSLOG_TAG)); - dst += sizeof(SYSLOG_TAG) - 1; - } - } - } -out: - td->td_retval[0] = dst - args->buf; - return (error); -} - -int -linux_getcpu(struct thread *td, struct linux_getcpu_args *args) -{ - int cpu, error, node; - - cpu = td->td_oncpu; /* Make sure it doesn't change during copyout(9) */ - error = 0; - node = cpuid_to_pcpu[cpu]->pc_domain; - - if (args->cpu != NULL) - error = copyout(&cpu, args->cpu, sizeof(l_int)); - if (args->node != NULL) - error = copyout(&node, args->node, sizeof(l_int)); - return (error); -} - -#if defined(__i386__) || defined(__amd64__) -int -linux_poll(struct thread *td, struct linux_poll_args *args) -{ - struct timespec ts, *tsp; - - if (args->timeout != INFTIM) { - if (args->timeout < 0) - return (EINVAL); - ts.tv_sec = args->timeout / 1000; - ts.tv_nsec = (args->timeout % 1000) * 1000000; - tsp = &ts; - } else - tsp = NULL; - - return (linux_common_ppoll(td, args->fds, args->nfds, - tsp, NULL, 0)); -} -#endif /* __i386__ || __amd64__ */ - -int -linux_seccomp(struct thread *td, struct linux_seccomp_args *args) -{ - - switch (args->op) { - case LINUX_SECCOMP_GET_ACTION_AVAIL: - return (EOPNOTSUPP); - default: - /* - * Ignore unknown operations, just like Linux kernel built - * without CONFIG_SECCOMP. - */ - return (EINVAL); - } -} - -/* - * Takes a pointer to a pointer an array of pointers in userspace, loads - * the loads the current value and updates the array pointer. - */ -static int -get_argenv_ptr(l_uintptr_t * __capability *arrayp, void * __capability *ptrp) -{ - l_uintptr_t * __capability array; -#ifdef COMPAT_LINUX32 - uint32_t ptr32; -#elif defined(COMPAT_LINUX64) - uint64_t ptr64; -#else - uintcap_t ptr; -#endif - - array = *arrayp; -#ifdef COMPAT_LINUX32 - if (fueword32(array, &ptr32) == -1) - return (EFAULT); - array += sizeof(ptr32); - *ptrp = __USER_CAP_STR((void *)(uintptr_t)ptr32); -#elif defined(COMPAT_LINUX64) - if (fueword64(array, &ptr64) == -1) - return (EFAULT); - array += sizeof(ptr64); - *ptrp = __USER_CAP_STR((void *)(uintptr_t)ptr64); -#else - if (fueptr(array, &ptr) == -1) - return (EFAULT); - array += sizeof(ptr); - *ptrp = (void * __capability)ptr; -#endif - *arrayp = array; - return (0); -} - -/* - * Custom version of exec_copyin_args(), to copy out argument and environment - * strings from the old process address space into the temporary string buffer. - * Based on freebsd32_exec_copyin_args. - */ -static int -linux_exec_copyin_args(struct image_args *args, const char * __capability fname, - enum uio_seg segflg, l_uintptr_t * __capability argv, - l_uintptr_t * __capability envv) -{ - void * __capability ptr; - int error; - - bzero(args, sizeof(*args)); - if (argv == NULL) - return (EFAULT); - - /* - * Allocate demand-paged memory for the file name, argument, and - * environment strings. - */ - error = exec_alloc_args(args); - if (error != 0) - return (error); - - /* - * Copy the file name. - */ - error = exec_args_add_fname(args, fname, segflg); - if (error != 0) - goto err_exit; - - /* - * extract arguments first - */ - for (;;) { - error = get_argenv_ptr(&argv, &ptr); - if (error != 0) - goto err_exit; - if (ptr == NULL) - break; - error = exec_args_add_arg(args, ptr, UIO_USERSPACE); - if (error != 0) - goto err_exit; - } - - /* - * This comment is from Linux do_execveat_common: - * When argv is empty, add an empty string ("") as argv[0] to - * ensure confused userspace programs that start processing - * from argv[1] won't end up walking envp. - */ - if (args->argc == 0 && - (error = exec_args_add_arg(args, "", UIO_SYSSPACE) != 0)) - goto err_exit; - - /* - * extract environment strings - */ - if (envv) { - for (;;) { - error = get_argenv_ptr(&envv, &ptr); - if (error != 0) - goto err_exit; - if (ptr == NULL) - break; - error = exec_args_add_env(args, ptr, UIO_USERSPACE); - if (error != 0) - goto err_exit; - } - } - - return (0); - -err_exit: - exec_free_args(args); - return (error); -} - -int -linux_execve(struct thread *td, struct linux_execve_args *args) -{ - struct image_args eargs; - int error; - - LINUX_CTR(execve); - - error = linux_exec_copyin_args(&eargs, __USER_CAP_PATH(args->path), - UIO_USERSPACE, __USER_CAP_UNBOUND(args->argp), - __USER_CAP_UNBOUND(args->envp)); - if (error == 0) - error = linux_common_execve(td, &eargs); - AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td); - return (error); -} - -static void -linux_up_rtprio_if(struct thread *td1, struct rtprio *rtp) -{ - struct rtprio rtp2; - - pri_to_rtp(td1, &rtp2); - if (rtp2.type < rtp->type || - (rtp2.type == rtp->type && - rtp2.prio < rtp->prio)) { - rtp->type = rtp2.type; - rtp->prio = rtp2.prio; - } -} - -#define LINUX_PRIO_DIVIDER RTP_PRIO_MAX / LINUX_IOPRIO_MAX - -static int -linux_rtprio2ioprio(struct rtprio *rtp) -{ - int ioprio, prio; - - switch (rtp->type) { - case RTP_PRIO_IDLE: - prio = RTP_PRIO_MIN; - ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_IDLE, prio); - break; - case RTP_PRIO_NORMAL: - prio = rtp->prio / LINUX_PRIO_DIVIDER; - ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_BE, prio); - break; - case RTP_PRIO_REALTIME: - prio = rtp->prio / LINUX_PRIO_DIVIDER; - ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_RT, prio); - break; - default: - prio = RTP_PRIO_MIN; - ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_NONE, prio); - break; - } - return (ioprio); -} - -static int -linux_ioprio2rtprio(int ioprio, struct rtprio *rtp) -{ - - switch (LINUX_IOPRIO_PRIO_CLASS(ioprio)) { - case LINUX_IOPRIO_CLASS_IDLE: - rtp->prio = RTP_PRIO_MIN; - rtp->type = RTP_PRIO_IDLE; - break; - case LINUX_IOPRIO_CLASS_BE: - rtp->prio = LINUX_IOPRIO_PRIO_DATA(ioprio) * LINUX_PRIO_DIVIDER; - rtp->type = RTP_PRIO_NORMAL; - break; - case LINUX_IOPRIO_CLASS_RT: - rtp->prio = LINUX_IOPRIO_PRIO_DATA(ioprio) * LINUX_PRIO_DIVIDER; - rtp->type = RTP_PRIO_REALTIME; - break; - default: - return (EINVAL); - } - return (0); -} -#undef LINUX_PRIO_DIVIDER - -int -linux_ioprio_get(struct thread *td, struct linux_ioprio_get_args *args) -{ - struct thread *td1; - struct rtprio rtp; - struct pgrp *pg; - struct proc *p; - int error, found; - - p = NULL; - td1 = NULL; - error = 0; - found = 0; - rtp.type = RTP_PRIO_IDLE; - rtp.prio = RTP_PRIO_MAX; - switch (args->which) { - case LINUX_IOPRIO_WHO_PROCESS: - if (args->who == 0) { - td1 = td; - p = td1->td_proc; - PROC_LOCK(p); - } else if (args->who > PID_MAX) { - td1 = linux_tdfind(td, args->who, -1); - if (td1 != NULL) - p = td1->td_proc; - } else - p = pfind(args->who); - if (p == NULL) - return (ESRCH); - if ((error = p_cansee(td, p))) { - PROC_UNLOCK(p); - break; - } - if (td1 != NULL) { - pri_to_rtp(td1, &rtp); - } else { - FOREACH_THREAD_IN_PROC(p, td1) { - linux_up_rtprio_if(td1, &rtp); - } - } - found++; - PROC_UNLOCK(p); - break; - case LINUX_IOPRIO_WHO_PGRP: - sx_slock(&proctree_lock); - if (args->who == 0) { - pg = td->td_proc->p_pgrp; - PGRP_LOCK(pg); - } else { - pg = pgfind(args->who); - if (pg == NULL) { - sx_sunlock(&proctree_lock); - error = ESRCH; - break; - } - } - sx_sunlock(&proctree_lock); - LIST_FOREACH(p, &pg->pg_members, p_pglist) { - PROC_LOCK(p); - if (p->p_state == PRS_NORMAL && - p_cansee(td, p) == 0) { - FOREACH_THREAD_IN_PROC(p, td1) { - linux_up_rtprio_if(td1, &rtp); - found++; - } - } - PROC_UNLOCK(p); - } - PGRP_UNLOCK(pg); - break; - case LINUX_IOPRIO_WHO_USER: - if (args->who == 0) - args->who = td->td_ucred->cr_uid; - sx_slock(&allproc_lock); - FOREACH_PROC_IN_SYSTEM(p) { - PROC_LOCK(p); - if (p->p_state == PRS_NORMAL && - p->p_ucred->cr_uid == args->who && - p_cansee(td, p) == 0) { - FOREACH_THREAD_IN_PROC(p, td1) { - linux_up_rtprio_if(td1, &rtp); - found++; - } - } - PROC_UNLOCK(p); - } - sx_sunlock(&allproc_lock); - break; - default: - error = EINVAL; - break; - } - if (error == 0) { - if (found != 0) - td->td_retval[0] = linux_rtprio2ioprio(&rtp); - else - error = ESRCH; - } - return (error); -} - -int -linux_ioprio_set(struct thread *td, struct linux_ioprio_set_args *args) -{ - struct thread *td1; - struct rtprio rtp; - struct pgrp *pg; - struct proc *p; - int error; - - if ((error = linux_ioprio2rtprio(args->ioprio, &rtp)) != 0) - return (error); - /* Attempts to set high priorities (REALTIME) require su privileges. */ - if (RTP_PRIO_BASE(rtp.type) == RTP_PRIO_REALTIME && - (error = priv_check(td, PRIV_SCHED_RTPRIO)) != 0) - return (error); - - p = NULL; - td1 = NULL; - switch (args->which) { - case LINUX_IOPRIO_WHO_PROCESS: - if (args->who == 0) { - td1 = td; - p = td1->td_proc; - PROC_LOCK(p); - } else if (args->who > PID_MAX) { - td1 = linux_tdfind(td, args->who, -1); - if (td1 != NULL) - p = td1->td_proc; - } else - p = pfind(args->who); - if (p == NULL) - return (ESRCH); - if ((error = p_cansched(td, p))) { - PROC_UNLOCK(p); - break; - } - if (td1 != NULL) { - error = rtp_to_pri(&rtp, td1); - } else { - FOREACH_THREAD_IN_PROC(p, td1) { - if ((error = rtp_to_pri(&rtp, td1)) != 0) - break; - } - } - PROC_UNLOCK(p); - break; - case LINUX_IOPRIO_WHO_PGRP: - sx_slock(&proctree_lock); - if (args->who == 0) { - pg = td->td_proc->p_pgrp; - PGRP_LOCK(pg); - } else { - pg = pgfind(args->who); - if (pg == NULL) { - sx_sunlock(&proctree_lock); - error = ESRCH; - break; - } - } - sx_sunlock(&proctree_lock); - LIST_FOREACH(p, &pg->pg_members, p_pglist) { - PROC_LOCK(p); - if (p->p_state == PRS_NORMAL && - p_cansched(td, p) == 0) { - FOREACH_THREAD_IN_PROC(p, td1) { - if ((error = rtp_to_pri(&rtp, td1)) != 0) - break; - } - } - PROC_UNLOCK(p); - if (error != 0) - break; - } - PGRP_UNLOCK(pg); - break; - case LINUX_IOPRIO_WHO_USER: - if (args->who == 0) - args->who = td->td_ucred->cr_uid; - sx_slock(&allproc_lock); - FOREACH_PROC_IN_SYSTEM(p) { - PROC_LOCK(p); - if (p->p_state == PRS_NORMAL && - p->p_ucred->cr_uid == args->who && - p_cansched(td, p) == 0) { - FOREACH_THREAD_IN_PROC(p, td1) { - if ((error = rtp_to_pri(&rtp, td1)) != 0) - break; - } - } - PROC_UNLOCK(p); - if (error != 0) - break; - } - sx_sunlock(&allproc_lock); - break; - default: - error = EINVAL; - break; - } - return (error); -} - -/* The only flag is O_NONBLOCK */ -#define B2L_MQ_FLAGS(bflags) ((bflags) != 0 ? LINUX_O_NONBLOCK : 0) -#define L2B_MQ_FLAGS(lflags) ((lflags) != 0 ? O_NONBLOCK : 0) - -int -linux_mq_open(struct thread *td, struct linux_mq_open_args *args) -{ - struct mq_attr attr; - int error, flags; - - flags = linux_common_openflags(args->oflag); - if ((flags & O_ACCMODE) == O_ACCMODE || (flags & O_EXEC) != 0) - return (EINVAL); - flags = FFLAGS(flags); - if ((flags & O_CREAT) != 0 && args->attr != NULL) { - error = copyin(args->attr, &attr, sizeof(attr)); - if (error != 0) - return (error); - attr.mq_flags = L2B_MQ_FLAGS(attr.mq_flags); - } - - return (kern_kmq_open(td, args->name, flags, args->mode, - args->attr != NULL ? &attr : NULL)); -} - -int -linux_mq_unlink(struct thread *td, struct linux_mq_unlink_args *args) -{ - struct kmq_unlink_args bsd_args = { - .path = PTRIN(args->name) - }; - - return (sys_kmq_unlink(td, &bsd_args)); -} - -int -linux_mq_timedsend(struct thread *td, struct linux_mq_timedsend_args *args) -{ - struct timespec ts, *abs_timeout; - int error; - - if (args->abs_timeout == NULL) - abs_timeout = NULL; - else { - error = linux_get_timespec(&ts, args->abs_timeout); - if (error != 0) - return (error); - abs_timeout = &ts; - } - - return (kern_kmq_timedsend(td, args->mqd, PTRIN(args->msg_ptr), - args->msg_len, args->msg_prio, abs_timeout)); -} - -int -linux_mq_timedreceive(struct thread *td, struct linux_mq_timedreceive_args *args) -{ - struct timespec ts, *abs_timeout; - int error; - - if (args->abs_timeout == NULL) - abs_timeout = NULL; - else { - error = linux_get_timespec(&ts, args->abs_timeout); - if (error != 0) - return (error); - abs_timeout = &ts; - } - - return (kern_kmq_timedreceive(td, args->mqd, PTRIN(args->msg_ptr), - args->msg_len, args->msg_prio, abs_timeout)); -} - -int -linux_mq_notify(struct thread *td, struct linux_mq_notify_args *args) -{ - struct sigevent ev, *evp; - struct l_sigevent l_ev; - int error; - - if (args->sevp == NULL) - evp = NULL; - else { - error = copyin(args->sevp, &l_ev, sizeof(l_ev)); - if (error != 0) - return (error); - error = linux_convert_l_sigevent(&l_ev, &ev); - if (error != 0) - return (error); - evp = &ev; - } - - return (kern_kmq_notify(td, args->mqd, evp)); -} - -int -linux_mq_getsetattr(struct thread *td, struct linux_mq_getsetattr_args *args) -{ - struct mq_attr attr, oattr; - int error; - - if (args->attr != NULL) { - error = copyin(args->attr, &attr, sizeof(attr)); - if (error != 0) - return (error); - attr.mq_flags = L2B_MQ_FLAGS(attr.mq_flags); - } - - error = kern_kmq_setattr(td, args->mqd, args->attr != NULL ? &attr : NULL, - &oattr); - if (error == 0 && args->oattr != NULL) { - oattr.mq_flags = B2L_MQ_FLAGS(oattr.mq_flags); - bzero(oattr.__reserved, sizeof(oattr.__reserved)); - error = copyout(&oattr, args->oattr, sizeof(oattr)); - } - - return (error); -} - -MODULE_DEPEND(linux, mqueuefs, 1, 1, 1); -// CHERI CHANGES START -// { -// "updated": 20230509, -// "target_type": "kernel", -// "changes": [ -// "iovec-macros", -// "user_capabilities" -// ] -// } -// CHERI CHANGES END +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2002 Doug Rabson + * 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 + * in this position and unchanged. + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int stclohz; /* Statistics clock frequency */ + +static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { + RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, + RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, + RLIMIT_MEMLOCK, RLIMIT_AS +}; + +struct l_sysinfo { + l_long uptime; /* Seconds since boot */ + l_ulong loads[3]; /* 1, 5, and 15 minute load averages */ +#define LINUX_SYSINFO_LOADS_SCALE 65536 + l_ulong totalram; /* Total usable main memory size */ + l_ulong freeram; /* Available memory size */ + l_ulong sharedram; /* Amount of shared memory */ + l_ulong bufferram; /* Memory used by buffers */ + l_ulong totalswap; /* Total swap space size */ + l_ulong freeswap; /* swap space still available */ + l_ushort procs; /* Number of current processes */ + l_ushort pads; + l_ulong totalhigh; + l_ulong freehigh; + l_uint mem_unit; + char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */ +}; + +struct l_pselect6arg { + l_uintptr_t ss; + l_size_t ss_len; +}; + +static int linux_utimensat_lts_to_ts(struct l_timespec *, + struct timespec *); +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +static int linux_utimensat_lts64_to_ts(struct l_timespec64 *, + struct timespec *); +#endif +static int linux_common_utimensat(struct thread *, int, + const char * __capability, struct timespec * __capability, int); +static int linux_common_pselect6(struct thread *, l_int, + l_fd_set * __capability, l_fd_set * __capability, l_fd_set * __capability, + struct timespec *, l_uintptr_t * __capability); +static int linux_common_ppoll(struct thread *, struct pollfd * __capability, + uint32_t, struct timespec *, l_sigset_t * __capability, + l_size_t); +static int linux_pollin(struct thread *, struct pollfd *, + struct pollfd * __capability, u_int); +static int linux_pollout(struct thread *, struct pollfd *, + struct pollfd * __capability, u_int); + +// Copied from vm_mmap +// Place it here temporarily +#if __has_feature(capabilities) +static int +cap_covers_pages(const void * __capability cap, size_t size) +{ + const char * __capability addr; + size_t pageoff; + + addr = cap; + pageoff = ((__cheri_addr ptraddr_t)addr & PAGE_MASK); + addr -= pageoff; + size += pageoff; + size = (vm_size_t)round_page(size); + + return (__CAP_CHECK(__DECONST_CAP(void * __capability, addr), size)); +} +#endif + +int +linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) +{ + struct l_sysinfo sysinfo; + int i, j; + struct timespec ts; + + bzero(&sysinfo, sizeof(sysinfo)); + getnanouptime(&ts); + if (ts.tv_nsec != 0) + ts.tv_sec++; + sysinfo.uptime = ts.tv_sec; + + /* Use the information from the mib to get our load averages */ + for (i = 0; i < 3; i++) + sysinfo.loads[i] = averunnable.ldavg[i] * + LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale; + + sysinfo.totalram = physmem * PAGE_SIZE; + sysinfo.freeram = (u_long)vm_free_count() * PAGE_SIZE; + + /* + * sharedram counts pages allocated to named, swap-backed objects such + * as shared memory segments and tmpfs files. There is no cheap way to + * compute this, so just leave the field unpopulated. Linux itself only + * started setting this field in the 3.x timeframe. + */ + sysinfo.sharedram = 0; + sysinfo.bufferram = 0; + + swap_pager_status(&i, &j); + sysinfo.totalswap = i * PAGE_SIZE; + sysinfo.freeswap = (i - j) * PAGE_SIZE; + + sysinfo.procs = nprocs; + + /* + * Platforms supported by the emulation layer do not have a notion of + * high memory. + */ + sysinfo.totalhigh = 0; + sysinfo.freehigh = 0; + + sysinfo.mem_unit = 1; + + return (copyout(&sysinfo, LINUX_USER_CAP_OBJ(args->info), sizeof(sysinfo))); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_alarm(struct thread *td, struct linux_alarm_args *args) +{ + struct itimerval it, old_it; + u_int secs; + int error __diagused; + + secs = args->secs; + /* + * Linux alarm() is always successful. Limit secs to INT32_MAX / 2 + * to match kern_setitimer()'s limit to avoid error from it. + * + * XXX. Linux limit secs to INT_MAX on 32 and does not limit on 64-bit + * platforms. + */ + if (secs > INT32_MAX / 2) + secs = INT32_MAX / 2; + + it.it_value.tv_sec = secs; + it.it_value.tv_usec = 0; + timevalclear(&it.it_interval); + error = kern_setitimer(td, ITIMER_REAL, &it, &old_it); + KASSERT(error == 0, ("kern_setitimer returns %d", error)); + + if ((old_it.it_value.tv_sec == 0 && old_it.it_value.tv_usec > 0) || + old_it.it_value.tv_usec >= 500000) + old_it.it_value.tv_sec++; + td->td_retval[0] = old_it.it_value.tv_sec; + return (0); +} +#endif + +int +linux_brk(struct thread *td, struct linux_brk_args *args) +{ + struct vmspace *vm = td->td_proc->p_vmspace; + uintptr_t new, old; + + old = (uintptr_t)vm->vm_daddr + ctob(vm->vm_dsize); + new = (uintptr_t)args->dsend; + if ((caddr_t)new > vm->vm_daddr && !kern_break(td, &new)) + td->td_retval[0] = (register_t)new; + else + td->td_retval[0] = (register_t)old; + + return (0); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_select(struct thread *td, struct linux_select_args *args) +{ + l_timeval ltv; + struct timeval tv0, tv1, utv, *tvp; + int error; + + /* + * Store current time for computation of the amount of + * time left. + */ + if (args->timeout) { + if ((error = copyin(LINUX_USER_CAP_OBJ(args->timeout), <v, sizeof(ltv)))) + goto select_out; + utv.tv_sec = ltv.tv_sec; + utv.tv_usec = ltv.tv_usec; + + if (itimerfix(&utv)) { + /* + * The timeval was invalid. Convert it to something + * valid that will act as it does under Linux. + */ + utv.tv_sec += utv.tv_usec / 1000000; + utv.tv_usec %= 1000000; + if (utv.tv_usec < 0) { + utv.tv_sec -= 1; + utv.tv_usec += 1000000; + } + if (utv.tv_sec < 0) + timevalclear(&utv); + } + microtime(&tv0); + tvp = &utv; + } else + tvp = NULL; + + error = kern_select(td, args->nfds, LINUX_USER_CAP_UNBOUND(args->readfds), + LINUX_USER_CAP_UNBOUND(args->writefds), + LINUX_USER_CAP_UNBOUND(args->exceptfds), tvp, LINUX_NFDBITS); + if (error) + goto select_out; + + if (args->timeout) { + if (td->td_retval[0]) { + /* + * Compute how much time was left of the timeout, + * by subtracting the current time and the time + * before we started the call, and subtracting + * that result from the user-supplied value. + */ + microtime(&tv1); + timevalsub(&tv1, &tv0); + timevalsub(&utv, &tv1); + if (utv.tv_sec < 0) + timevalclear(&utv); + } else + timevalclear(&utv); + ltv.tv_sec = utv.tv_sec; + ltv.tv_usec = utv.tv_usec; + if ((error = copyout(<v, LINUX_USER_CAP_OBJ(args->timeout), sizeof(ltv)))) + goto select_out; + } + +select_out: + return (error); +} +#endif + +int +linux_mremap(struct thread *td, struct linux_mremap_args *args) +{ + uintptr_t addr; + size_t len; + int error = 0; + +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) && !defined(COMPAT_LINUX32) + if (cap_covers_pages(args->addr, args->old_len) == 0) + return (EPROT); +#endif + + if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) { + td->td_retval[0] = 0; + return (EINVAL); + } + + /* + * Check for the page alignment. + * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK. + */ + if ((uintcap_t)args->addr & PAGE_MASK) { + td->td_retval[0] = 0; + return (EINVAL); + } + + args->new_len = round_page(args->new_len); + args->old_len = round_page(args->old_len); + + if (args->new_len > args->old_len) { + td->td_retval[0] = 0; + return (ENOMEM); + } + + if (args->new_len < args->old_len) { + addr = (uintptr_t)(uintcap_t)args->addr + args->new_len; + len = args->old_len - args->new_len; + error = kern_munmap(td, addr, len); + } + + td->td_retval[0] = error ? 0 : (uintcap_t)args->addr; + return (error); +} + +#define LINUX_MS_ASYNC 0x0001 +#define LINUX_MS_INVALIDATE 0x0002 +#define LINUX_MS_SYNC 0x0004 + +// We include the capability-specific checks by calling sys_msync +// instead of kern_msync directly when the supplied args are capabilities + +int +linux_msync(struct thread *td, struct linux_msync_args *args) +{ +#if defined(COMPAT_LINUX64) || defined(COMPAT_LINUX32) + return (kern_msync(td, args->addr, args->len, + args->fl & ~LINUX_MS_SYNC)); +#else + struct msync_args bargs = { + .addr = args->addr, + .len = args->len, + .flags = args->fl & ~LINUX_MS_SYNC + }; + + return (sys_msync(td, &bargs)); +#endif +} + +int +linux_mlock(struct thread *td, struct linux_mlock_args *uap) +{ +#if defined(COMPAT_LINUX64) || defined(COMPAT_LINUX32) + return (kern_mlock(td->td_proc, td->td_ucred, + __DECONST(uintptr_t, uap->addr), uap->len)); +#else + struct mlock_args bargs = { + .addr = uap->addr, + .len = uap->len + }; + + return (sys_mlock(td, &bargs)); +#endif +} + +int +linux_munlock(struct thread *td, struct linux_munlock_args *uap) +{ +#if defined(COMPAT_LINUX64) || defined(COMPAT_LINUX32) + return (kern_munlock(td, (uintptr_t)uap->addr, uap->len)); +#else + struct munlock_args bargs = { + .addr = uap->addr, + .len = uap->len + }; + + return (sys_munlock(td, &bargs)); +#endif +} + +// We are ignoring capability-specific checks here +// Maybe fix them in the future + +int +linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) +{ + +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) && !defined(COMPAT_LINUX32) + if (cap_covers_pages(uap->addr, uap->len) == 0) + return (EPROT); +#endif + + return (linux_mprotect_common(td, (uintptr_t)(uintcap_t)uap->addr, uap->len, + uap->prot)); +} + +int +linux_madvise(struct thread *td, struct linux_madvise_args *uap) +{ + +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) && !defined(COMPAT_LINUX32) + if (cap_covers_pages(uap->addr, uap->len) == 0) + return (EPROT); +#endif + + return (linux_madvise_common(td, (uintptr_t)(uintcap_t)uap->addr, uap->len, + uap->behav)); +} + +int +linux_mmap2(struct thread *td, struct linux_mmap2_args *uap) +{ + uint64_t actual_size = uap->pgoff; + +#if defined(LINUX_ARCHWANT_MMAP2PGOFF) + /* + * For architectures with sizeof (off_t) < sizeof (loff_t) mmap is + * implemented with mmap2 syscall and the offset is represented in + * multiples of page size. + */ + actual_size = (uint64_t)(uint32_t)uap->pgoff * PAGE_SIZE; +#endif + +#if !__has_feature(capabilities) + return (linux_mmap_common(td, PTROUT(uap->addr), uap->len, uap->prot, + uap->flags, uap->fd, actual_size)); +#elif !defined(COMPAT_LINUX64) + // Copied from sys_mmap + + int kern_flags = 0; + void * __capability source_cap; + register_t perms, reqperms; + vm_offset_t hint; + + if (uap->flags & LINUX_MAP_32BIT) { + SYSERRCAUSE("LINUX_MAP_32BIT not supported in PCuABI"); + return (EINVAL); + } + + /* + * Allow existing mapping to be replaced using the MAP_FIXED + * flag IFF the addr argument is a valid capability with the + * SW_VMEM user permission (We currently ignore SW_VMEM for + * PCuABI). In this case, the new capability is derived from + * the passed capability. In all other cases, the new capability + * is derived from the per-thread mmap capability. + */ + hint = cheri_getaddress(uap->addr); + + if (cheri_gettag(uap->addr)) { + if ((uap->flags & LINUX_MAP_FIXED) == 0) + return (EPROT); + else + source_cap = uap->addr; + } else { + if (!cheri_is_null_derived(uap->addr)) + return (EINVAL); + + /* + * When a capability is not provided, we implicitly + * request the creation of a reservation. + */ + kern_flags |= MAP_RESERVATION_CREATE; + source_cap = userspace_root_cap; + } + KASSERT(cheri_gettag(source_cap), + ("td->td_cheri_mmap_cap is untagged!")); + + /* + * If MAP_FIXED is specified, make sure that the requested + * address range fits within the source capability. + */ + if ((uap->flags & LINUX_MAP_FIXED) && + (rounddown2(hint, PAGE_SIZE) < cheri_getbase(source_cap) || + roundup2(hint + uap->len, PAGE_SIZE) > + cheri_getaddress(source_cap) + cheri_getlen(source_cap))) { + SYSERRCAUSE("MAP_FIXED and too little space in " + "capablity (0x%zx < 0x%zx)", + cheri_getlen(source_cap) - cheri_getoffset(source_cap), + roundup2(uap->len, PAGE_SIZE)); + return (EPROT); + } + + perms = cheri_getperm(source_cap); + reqperms = vm_map_prot2perms(uap->prot); +#ifdef CHERI_PERM_EXECUTIVE + if ((uap->flags & LINUX_MAP_FIXED) && (perms & CHERI_PERM_EXECUTIVE) == 0) + /* + * Don't implicity require CHERI_PERM_EXECUTIVE if it's + * not available in source capability. + */ + reqperms &= ~CHERI_PERM_EXECUTIVE; +#endif + if ((perms & reqperms) != reqperms) { + SYSERRCAUSE("capability has insufficient perms (0x%lx)" + "for request (0x%lx)", perms, reqperms); + return (EPROT); + } + + return (linux_mmap_common(td, hint, uap->len, uap->prot, + uap->flags, uap->fd, actual_size, kern_flags, source_cap)); +#elif defined(__CHERI_PURE_CAPABILITY__) + return (linux_mmap_common(td, PTROUT(uap->addr), uap->len, uap->prot, + uap->flags, uap->fd, actual_size, 0, userspace_root_cap)); +#else + return (linux_mmap_common(td, PTROUT(uap->addr), uap->len, uap->prot, + uap->flags, uap->fd, actual_size, 0, 0)); +#endif + +} + +int +linux_munmap(struct thread *td, struct linux_munmap_args *args) +{ +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) && !defined(COMPAT_LINUX32) + if (cap_covers_pages(args->addr, args->len) == 0) + return (EPROT); +#endif + return (kern_munmap(td, (uintptr_t)(uintcap_t)args->addr, args->len)); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_time(struct thread *td, struct linux_time_args *args) +{ + struct timeval tv; + l_time_t tm; + int error; + + microtime(&tv); + tm = tv.tv_sec; + if (args->tm && (error = copyout(&tm, LINUX_USER_CAP_OBJ(args->tm), sizeof(tm)))) + return (error); + td->td_retval[0] = tm; + return (0); +} +#endif + +struct l_times_argv { + l_clock_t tms_utime; + l_clock_t tms_stime; + l_clock_t tms_cutime; + l_clock_t tms_cstime; +}; + +/* + * Glibc versions prior to 2.2.1 always use hard-coded CLK_TCK value. + * Since 2.2.1 Glibc uses value exported from kernel via AT_CLKTCK + * auxiliary vector entry. + */ +#define CLK_TCK 100 + +#define CONVOTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) +#define CONVNTCK(r) (r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz)) + +#define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER(2,4,0) ? \ + CONVNTCK(r) : CONVOTCK(r)) + +int +linux_times(struct thread *td, struct linux_times_args *args) +{ + struct timeval tv, utime, stime, cutime, cstime; + struct l_times_argv tms; + struct proc *p; + int error; + + if (args->buf != NULL) { + p = td->td_proc; + PROC_LOCK(p); + PROC_STATLOCK(p); + calcru(p, &utime, &stime); + PROC_STATUNLOCK(p); + calccru(p, &cutime, &cstime); + PROC_UNLOCK(p); + + tms.tms_utime = CONVTCK(utime); + tms.tms_stime = CONVTCK(stime); + + tms.tms_cutime = CONVTCK(cutime); + tms.tms_cstime = CONVTCK(cstime); + + if ((error = copyout(&tms, LINUX_USER_CAP_OBJ(args->buf), sizeof(tms)))) + return (error); + } + + microuptime(&tv); + td->td_retval[0] = (int)CONVTCK(tv); + return (0); +} + +int +linux_newuname(struct thread *td, struct linux_newuname_args *args) +{ + struct l_new_utsname utsname; + char osname[LINUX_MAX_UTSNAME]; + char osrelease[LINUX_MAX_UTSNAME]; + char *p; + + linux_get_osname(td, osname); + linux_get_osrelease(td, osrelease); + + bzero(&utsname, sizeof(utsname)); + strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME); + getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME); + getcreddomainname(td->td_ucred, utsname.domainname, LINUX_MAX_UTSNAME); + strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME); + strlcpy(utsname.version, version, LINUX_MAX_UTSNAME); + for (p = utsname.version; *p != '\0'; ++p) + if (*p == '\n') { + *p = '\0'; + break; + } +#if defined(__amd64__) + /* + * On amd64, Linux uname(2) needs to return "x86_64" + * for both 64-bit and 32-bit applications. On 32-bit, + * the string returned by getauxval(AT_PLATFORM) needs + * to remain "i686", though. + */ +#if defined(COMPAT_LINUX32) + if (linux32_emulate_i386) + strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME); + else +#endif + strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME); +#elif defined(__aarch64__) + strlcpy(utsname.machine, "aarch64", LINUX_MAX_UTSNAME); +#elif defined(__i386__) + strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME); +#endif + + return (copyout(&utsname, LINUX_USER_CAP_OBJ(args->buf), sizeof(utsname))); +} + +struct l_utimbuf { + l_time_t l_actime; + l_time_t l_modtime; +}; + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_utime(struct thread *td, struct linux_utime_args *args) +{ + struct timeval tv[2], *tvp; + struct l_utimbuf lut; + int error; + + if (args->times) { + if ((error = copyin(LINUX_USER_CAP_OBJ(args->times), &lut, sizeof lut)) != 0) + return (error); + tv[0].tv_sec = lut.l_actime; + tv[0].tv_usec = 0; + tv[1].tv_sec = lut.l_modtime; + tv[1].tv_usec = 0; + tvp = tv; + } else + tvp = NULL; + + return (kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE, + tvp, UIO_SYSSPACE)); +} +#endif + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_utimes(struct thread *td, struct linux_utimes_args *args) +{ + l_timeval ltv[2]; + struct timeval tv[2], *tvp = NULL; + int error; + + if (args->tptr != NULL) { + if ((error = copyin(LINUX_USER_CAP_OBJ(args->tptr), ltv, sizeof ltv)) != 0) + return (error); + tv[0].tv_sec = ltv[0].tv_sec; + tv[0].tv_usec = ltv[0].tv_usec; + tv[1].tv_sec = ltv[1].tv_sec; + tv[1].tv_usec = ltv[1].tv_usec; + tvp = tv; + } + + return (kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE, + tvp, UIO_SYSSPACE)); +} +#endif + +static int +linux_utimensat_lts_to_ts(struct l_timespec *l_times, struct timespec *times) +{ + + if (l_times->tv_nsec != LINUX_UTIME_OMIT && + l_times->tv_nsec != LINUX_UTIME_NOW && + (l_times->tv_nsec < 0 || l_times->tv_nsec > 999999999)) + return (EINVAL); + + times->tv_sec = l_times->tv_sec; + switch (l_times->tv_nsec) + { + case LINUX_UTIME_OMIT: + times->tv_nsec = UTIME_OMIT; + break; + case LINUX_UTIME_NOW: + times->tv_nsec = UTIME_NOW; + break; + default: + times->tv_nsec = l_times->tv_nsec; + } + + return (0); +} + +static int +linux_common_utimensat(struct thread *td, int ldfd, const char * __capability pathname, + struct timespec * __capability timesp, int lflags) +{ + int dfd, flags = 0; + + dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd; + + if (lflags & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH)) + return (EINVAL); + + if (timesp != NULL) { + /* This breaks POSIX, but is what the Linux kernel does + * _on purpose_ (documented in the man page for utimensat(2)), + * so we must follow that behaviour. */ + if (timesp[0].tv_nsec == UTIME_OMIT && + timesp[1].tv_nsec == UTIME_OMIT) + return (0); + } + + if (lflags & LINUX_AT_SYMLINK_NOFOLLOW) + flags |= AT_SYMLINK_NOFOLLOW; + if (lflags & LINUX_AT_EMPTY_PATH) + flags |= AT_EMPTY_PATH; + + if (pathname != NULL) + return (kern_utimensat(td, dfd, pathname, + UIO_USERSPACE, timesp, UIO_SYSSPACE, flags)); + + if (lflags != 0) + return (EINVAL); + + return (kern_futimens(td, dfd, timesp, UIO_SYSSPACE)); +} + +int +linux_utimensat(struct thread *td, struct linux_utimensat_args *args) +{ + struct l_timespec l_times[2]; + struct timespec times[2], * __capability timesp; + int error; + + if (args->times != NULL) { + error = copyin(LINUX_USER_CAP(args->times, sizeof(l_times)), l_times, sizeof(l_times)); + if (error != 0) + return (error); + + error = linux_utimensat_lts_to_ts(&l_times[0], ×[0]); + if (error != 0) + return (error); + error = linux_utimensat_lts_to_ts(&l_times[1], ×[1]); + if (error != 0) + return (error); + timesp = times; + } else + timesp = NULL; + + return (linux_common_utimensat(td, args->dfd, LINUX_USER_CAP_PATH(args->pathname), + timesp, args->flags)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +static int +linux_utimensat_lts64_to_ts(struct l_timespec64 *l_times, struct timespec *times) +{ + + /* Zero out the padding in compat mode. */ + l_times->tv_nsec &= 0xFFFFFFFFUL; + + if (l_times->tv_nsec != LINUX_UTIME_OMIT && + l_times->tv_nsec != LINUX_UTIME_NOW && + (l_times->tv_nsec < 0 || l_times->tv_nsec > 999999999)) + return (EINVAL); + + times->tv_sec = l_times->tv_sec; + switch (l_times->tv_nsec) + { + case LINUX_UTIME_OMIT: + times->tv_nsec = UTIME_OMIT; + break; + case LINUX_UTIME_NOW: + times->tv_nsec = UTIME_NOW; + break; + default: + times->tv_nsec = l_times->tv_nsec; + } + + return (0); +} + +int +linux_utimensat_time64(struct thread *td, struct linux_utimensat_time64_args *args) +{ + struct l_timespec64 l_times[2]; + struct timespec times[2], * __capability timesp; + int error; + + if (args->times64 != NULL) { + error = copyin(LINUX_USER_CAP(args->times64, sizeof(l_times)), l_times, sizeof(l_times)); + if (error != 0) + return (error); + + error = linux_utimensat_lts64_to_ts(&l_times[0], ×[0]); + if (error != 0) + return (error); + error = linux_utimensat_lts64_to_ts(&l_times[1], ×[1]); + if (error != 0) + return (error); + timesp = times; + } else + timesp = NULL; + + return (linux_common_utimensat(td, args->dfd, LINUX_USER_CAP_PATH(args->pathname), + timesp, args->flags)); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_futimesat(struct thread *td, struct linux_futimesat_args *args) +{ + l_timeval ltv[2]; + struct timeval tv[2], *tvp = NULL; + int error, dfd; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + + if (args->utimes != NULL) { + if ((error = copyin(LINUX_USER_CAP(args->utimes, sizeof ltv), ltv, sizeof ltv)) != 0) + return (error); + tv[0].tv_sec = ltv[0].tv_sec; + tv[0].tv_usec = ltv[0].tv_usec; + tv[1].tv_sec = ltv[1].tv_sec; + tv[1].tv_usec = ltv[1].tv_usec; + tvp = tv; + } + + return (kern_utimesat(td, dfd, args->filename, UIO_USERSPACE, + tvp, UIO_SYSSPACE)); +} +#endif + +static int +linux_common_wait(struct thread *td, idtype_t idtype, int id, int * __capability statusp, + int options, void * __capability rup, l_siginfo_t * __capability infop) +{ + l_siginfo_t lsi; + siginfo_t siginfo; + struct __wrusage wru; + int error, status, tmpstat, sig; + + error = kern_wait6(td, idtype, id, &status, options, + rup != NULL ? &wru : NULL, &siginfo); + + if (error == 0 && statusp) { + tmpstat = status & 0xffff; + if (WIFSIGNALED(tmpstat)) { + tmpstat = (tmpstat & 0xffffff80) | + bsd_to_linux_signal(WTERMSIG(tmpstat)); + } else if (WIFSTOPPED(tmpstat)) { + tmpstat = (tmpstat & 0xffff00ff) | + (bsd_to_linux_signal(WSTOPSIG(tmpstat)) << 8); +#if defined(__aarch64__) || (defined(__amd64__) && !defined(COMPAT_LINUX32)) + if (WSTOPSIG(status) == SIGTRAP) { + tmpstat = linux_ptrace_status(td, + siginfo.si_pid, tmpstat); + } +#endif + } else if (WIFCONTINUED(tmpstat)) { + tmpstat = 0xffff; + } + error = copyout(&tmpstat, statusp, sizeof(int)); + } + if (error == 0 && rup != NULL) + error = linux_copyout_rusage(&wru.wru_self, rup); + if (error == 0 && infop != NULL && td->td_retval[0] != 0) { + sig = bsd_to_linux_signal(siginfo.si_signo); + siginfo_to_lsiginfo(&siginfo, &lsi, sig); + error = copyoutcap(&lsi, infop, sizeof(lsi)); + } + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_waitpid(struct thread *td, struct linux_waitpid_args *args) +{ + struct linux_wait4_args wait4_args = { + .pid = args->pid, + .status = args->status, + .options = args->options, + .rusage = NULL, + }; + + return (linux_wait4(td, &wait4_args)); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_wait4(struct thread *td, struct linux_wait4_args *args) +{ + struct proc *p; + int options, id, idtype; + + if (args->options & ~(LINUX_WUNTRACED | LINUX_WNOHANG | + LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL)) + return (EINVAL); + + /* -INT_MIN is not defined. */ + if (args->pid == INT_MIN) + return (ESRCH); + + options = 0; + linux_to_bsd_waitopts(args->options, &options); + + /* + * For backward compatibility we implicitly add flags WEXITED + * and WTRAPPED here. + */ + options |= WEXITED | WTRAPPED; + + if (args->pid == WAIT_ANY) { + idtype = P_ALL; + id = 0; + } else if (args->pid < 0) { + idtype = P_PGID; + id = (id_t)-args->pid; + } else if (args->pid == 0) { + idtype = P_PGID; + p = td->td_proc; + PROC_LOCK(p); + id = p->p_pgid; + PROC_UNLOCK(p); + } else { + idtype = P_PID; + id = (id_t)args->pid; + } + + return (linux_common_wait(td, idtype, id, LINUX_USER_CAP_OBJ(args->status), options, + LINUX_USER_CAP_OBJ(args->rusage), NULL)); +} + +int +linux_waitid(struct thread *td, struct linux_waitid_args *args) +{ + idtype_t idtype; + int error, options; + struct proc *p; + pid_t id; + + if (args->options & ~(LINUX_WNOHANG | LINUX_WNOWAIT | LINUX_WEXITED | + LINUX_WSTOPPED | LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL)) + return (EINVAL); + + options = 0; + linux_to_bsd_waitopts(args->options, &options); + + id = args->id; + switch (args->idtype) { + case LINUX_P_ALL: + idtype = P_ALL; + break; + case LINUX_P_PID: + if (args->id <= 0) + return (EINVAL); + idtype = P_PID; + break; + case LINUX_P_PGID: + if (linux_kernver(td) >= LINUX_KERNVER(5,4,0) && args->id == 0) { + p = td->td_proc; + PROC_LOCK(p); + id = p->p_pgid; + PROC_UNLOCK(p); + } else if (args->id <= 0) + return (EINVAL); + idtype = P_PGID; + break; + case LINUX_P_PIDFD: + LINUX_RATELIMIT_MSG("unsupported waitid P_PIDFD idtype"); + return (ENOSYS); + default: + return (EINVAL); + } + + error = linux_common_wait(td, idtype, id, NULL, options, + LINUX_USER_CAP_OBJ(args->rusage), LINUX_USER_CAP_OBJ(args->info)); + td->td_retval[0] = 0; + + return (error); +} + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_mknod(struct thread *td, struct linux_mknod_args *args) +{ + int error; + + switch (args->mode & S_IFMT) { + case S_IFIFO: + case S_IFSOCK: + error = kern_mkfifoat(td, AT_FDCWD, args->path, UIO_USERSPACE, + args->mode); + break; + + case S_IFCHR: + case S_IFBLK: + error = kern_mknodat(td, AT_FDCWD, args->path, UIO_USERSPACE, + args->mode, linux_decode_dev(args->dev)); + break; + + case S_IFDIR: + error = EPERM; + break; + + case 0: + args->mode |= S_IFREG; + /* FALLTHROUGH */ + case S_IFREG: + error = kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE, + O_WRONLY | O_CREAT | O_TRUNC, args->mode); + if (error == 0) + kern_close(td, td->td_retval[0]); + break; + + default: + error = EINVAL; + break; + } + return (error); +} +#endif + +int +linux_mknodat(struct thread *td, struct linux_mknodat_args *args) +{ + int error, dfd; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + + switch (args->mode & S_IFMT) { + case S_IFIFO: + case S_IFSOCK: + error = kern_mkfifoat(td, dfd, LINUX_USER_CAP_PATH(args->filename), UIO_USERSPACE, + args->mode); + break; + + case S_IFCHR: + case S_IFBLK: + error = kern_mknodat(td, dfd, LINUX_USER_CAP_PATH(args->filename), UIO_USERSPACE, + args->mode, linux_decode_dev(args->dev)); + break; + + case S_IFDIR: + error = EPERM; + break; + + case 0: + args->mode |= S_IFREG; + /* FALLTHROUGH */ + case S_IFREG: + error = kern_openat(td, dfd, LINUX_USER_CAP_PATH(args->filename), UIO_USERSPACE, + O_WRONLY | O_CREAT | O_TRUNC, args->mode); + if (error == 0) + kern_close(td, td->td_retval[0]); + break; + + default: + error = EINVAL; + break; + } + return (error); +} + +/* + * UGH! This is just about the dumbest idea I've ever heard!! + */ +int +linux_personality(struct thread *td, struct linux_personality_args *args) +{ + struct linux_pemuldata *pem; + struct proc *p = td->td_proc; + uint32_t old; + + PROC_LOCK(p); + pem = pem_find(p); + old = pem->persona; + if (args->per != 0xffffffff) + pem->persona = args->per; + PROC_UNLOCK(p); + + td->td_retval[0] = old; + return (0); +} + +struct l_itimerval { + l_timeval it_interval; + l_timeval it_value; +}; + +#define B2L_ITIMERVAL(bip, lip) \ + (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \ + (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \ + (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \ + (bip)->it_value.tv_usec = (lip)->it_value.tv_usec; + +int +linux_setitimer(struct thread *td, struct linux_setitimer_args *uap) +{ + int error; + struct l_itimerval ls; + struct itimerval aitv, oitv; + + if (uap->itv == NULL) { + uap->itv = uap->oitv; + return (linux_getitimer(td, (struct linux_getitimer_args *)uap)); + } + + error = copyin(LINUX_USER_CAP_OBJ(uap->itv), &ls, sizeof(ls)); + if (error != 0) + return (error); + B2L_ITIMERVAL(&aitv, &ls); + error = kern_setitimer(td, uap->which, &aitv, &oitv); + if (error != 0 || uap->oitv == NULL) + return (error); + B2L_ITIMERVAL(&ls, &oitv); + + return (copyout(&ls, LINUX_USER_CAP_OBJ(uap->oitv), sizeof(ls))); +} + +int +linux_getitimer(struct thread *td, struct linux_getitimer_args *uap) +{ + int error; + struct l_itimerval ls; + struct itimerval aitv; + + error = kern_getitimer(td, uap->which, &aitv); + if (error != 0) + return (error); + B2L_ITIMERVAL(&ls, &aitv); + return (copyout(&ls, LINUX_USER_CAP_OBJ(uap->itv), sizeof(ls))); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_nice(struct thread *td, struct linux_nice_args *args) +{ + + return (kern_setpriority(td, PRIO_PROCESS, 0, args->inc)); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_setgroups(struct thread *td, struct linux_setgroups_args *args) +{ + struct ucred *newcred, *oldcred; + l_gid_t *linux_gidset; + gid_t *bsd_gidset; + int ngrp, error; + struct proc *p; + + ngrp = args->gidsetsize; + if (ngrp < 0 || ngrp >= ngroups_max + 1) + return (EINVAL); + linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); + error = copyin(LINUX_USER_CAP_ARRAY(args->grouplist, ngrp), linux_gidset, ngrp * sizeof(l_gid_t)); + if (error) + goto out; + newcred = crget(); + crextend(newcred, ngrp + 1); + p = td->td_proc; + PROC_LOCK(p); + oldcred = p->p_ucred; + crcopy(newcred, oldcred); + + /* + * cr_groups[0] holds egid. Setting the whole set from + * the supplied set will cause egid to be changed too. + * Keep cr_groups[0] unchanged to prevent that. + */ + + if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) { + PROC_UNLOCK(p); + crfree(newcred); + goto out; + } + + if (ngrp > 0) { + newcred->cr_ngroups = ngrp + 1; + + bsd_gidset = newcred->cr_groups; + ngrp--; + while (ngrp >= 0) { + bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; + ngrp--; + } + } else + newcred->cr_ngroups = 1; + + setsugid(p); + proc_set_cred(p, newcred); + PROC_UNLOCK(p); + crfree(oldcred); + error = 0; +out: + free(linux_gidset, M_LINUX); + return (error); +} + +int +linux_getgroups(struct thread *td, struct linux_getgroups_args *args) +{ + struct ucred *cred; + l_gid_t *linux_gidset; + gid_t *bsd_gidset; + int bsd_gidsetsz, ngrp, error; + + cred = td->td_ucred; + bsd_gidset = cred->cr_groups; + bsd_gidsetsz = cred->cr_ngroups - 1; + + /* + * cr_groups[0] holds egid. Returning the whole set + * here will cause a duplicate. Exclude cr_groups[0] + * to prevent that. + */ + + if ((ngrp = args->gidsetsize) == 0) { + td->td_retval[0] = bsd_gidsetsz; + return (0); + } + + if (ngrp < bsd_gidsetsz) + return (EINVAL); + + ngrp = 0; + linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), + M_LINUX, M_WAITOK); + while (ngrp < bsd_gidsetsz) { + linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; + ngrp++; + } + + error = copyout(linux_gidset, LINUX_USER_CAP_ARRAY(args->grouplist, ngrp), ngrp * sizeof(l_gid_t)); + free(linux_gidset, M_LINUX); + if (error) + return (error); + + td->td_retval[0] = ngrp; + return (0); +} + +static bool +linux_get_dummy_limit(struct thread *td, l_uint resource, struct rlimit *rlim) +{ + ssize_t size; + int res, error; + + if (linux_dummy_rlimits == 0) + return (false); + + switch (resource) { + case LINUX_RLIMIT_LOCKS: + case LINUX_RLIMIT_RTTIME: + rlim->rlim_cur = LINUX_RLIM_INFINITY; + rlim->rlim_max = LINUX_RLIM_INFINITY; + return (true); + case LINUX_RLIMIT_NICE: + case LINUX_RLIMIT_RTPRIO: + rlim->rlim_cur = 0; + rlim->rlim_max = 0; + return (true); + case LINUX_RLIMIT_SIGPENDING: + error = kernel_sysctlbyname(td, + "kern.sigqueue.max_pending_per_proc", + &res, &size, 0, 0, 0, 0); + if (error != 0) + return (false); + rlim->rlim_cur = res; + rlim->rlim_max = res; + return (true); + case LINUX_RLIMIT_MSGQUEUE: + error = kernel_sysctlbyname(td, + "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0); + if (error != 0) + return (false); + rlim->rlim_cur = res; + rlim->rlim_max = res; + return (true); + default: + return (false); + } +} + +int +linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) +{ + struct rlimit bsd_rlim; + struct l_rlimit rlim; + u_int which; + int error; + + if (args->resource >= LINUX_RLIM_NLIMITS) + return (EINVAL); + + which = linux_to_bsd_resource[args->resource]; + if (which == -1) + return (EINVAL); + + error = copyin(LINUX_USER_CAP_OBJ(args->rlim), &rlim, sizeof(rlim)); + if (error) + return (error); + + bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur; + bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max; + return (kern_setrlimit(td, which, &bsd_rlim)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) +{ + struct l_rlimit rlim; + struct rlimit bsd_rlim; + u_int which; + + if (linux_get_dummy_limit(td, args->resource, &bsd_rlim)) { + rlim.rlim_cur = bsd_rlim.rlim_cur; + rlim.rlim_max = bsd_rlim.rlim_max; + return (copyout(&rlim, LINUX_USER_CAP_OBJ(args->rlim), sizeof(rlim))); + } + + if (args->resource >= LINUX_RLIM_NLIMITS) + return (EINVAL); + + which = linux_to_bsd_resource[args->resource]; + if (which == -1) + return (EINVAL); + + lim_rlimit(td, which, &bsd_rlim); + +#ifdef COMPAT_LINUX32 + rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur; + if (rlim.rlim_cur == UINT_MAX) + rlim.rlim_cur = INT_MAX; + rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max; + if (rlim.rlim_max == UINT_MAX) + rlim.rlim_max = INT_MAX; +#else + rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur; + if (rlim.rlim_cur == ULONG_MAX) + rlim.rlim_cur = LONG_MAX; + rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max; + if (rlim.rlim_max == ULONG_MAX) + rlim.rlim_max = LONG_MAX; +#endif + return (copyout(&rlim, LINUX_USER_CAP_OBJ(args->rlim), sizeof(rlim))); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) +{ + struct l_rlimit rlim; + struct rlimit bsd_rlim; + u_int which; + + if (linux_get_dummy_limit(td, args->resource, &bsd_rlim)) { + rlim.rlim_cur = bsd_rlim.rlim_cur; + rlim.rlim_max = bsd_rlim.rlim_max; + return (copyout(&rlim, LINUX_USER_CAP_OBJ(args->rlim), sizeof(rlim))); + } + + if (args->resource >= LINUX_RLIM_NLIMITS) + return (EINVAL); + + which = linux_to_bsd_resource[args->resource]; + if (which == -1) + return (EINVAL); + + lim_rlimit(td, which, &bsd_rlim); + + rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur; + rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max; + return (copyout(&rlim, LINUX_USER_CAP_OBJ(args->rlim), sizeof(rlim))); +} + +int +linux_getrusage(struct thread *td, struct linux_getrusage_args *args) +{ + struct rusage ru; + int error; + + error = kern_getrusage(td, args->who, &ru); + if (error == 0) + error = copyout(&ru, LINUX_USER_CAP_OBJ(args->rusage), + sizeof(struct rusage)); + return (error); +} + +int +linux_sched_setscheduler(struct thread *td, + struct linux_sched_setscheduler_args *args) +{ + struct sched_param sched_param; + struct thread *tdt; + int error, policy; + + switch (args->policy) { + case LINUX_SCHED_OTHER: + policy = SCHED_OTHER; + break; + case LINUX_SCHED_FIFO: + policy = SCHED_FIFO; + break; + case LINUX_SCHED_RR: + policy = SCHED_RR; + break; + default: + return (EINVAL); + } + + error = copyin(LINUX_USER_CAP_OBJ(args->param), &sched_param, sizeof(sched_param)); + if (error) + return (error); + + if (linux_map_sched_prio) { + switch (policy) { + case SCHED_OTHER: + if (sched_param.sched_priority != 0) + return (EINVAL); + + sched_param.sched_priority = + PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; + break; + case SCHED_FIFO: + case SCHED_RR: + if (sched_param.sched_priority < 1 || + sched_param.sched_priority >= LINUX_MAX_RT_PRIO) + return (EINVAL); + + /* + * Map [1, LINUX_MAX_RT_PRIO - 1] to + * [0, RTP_PRIO_MAX - RTP_PRIO_MIN] (rounding down). + */ + sched_param.sched_priority = + (sched_param.sched_priority - 1) * + (RTP_PRIO_MAX - RTP_PRIO_MIN + 1) / + (LINUX_MAX_RT_PRIO - 1); + break; + } + } + + tdt = linux_tdfind(td, args->pid, -1); + if (tdt == NULL) + return (ESRCH); + + error = kern_sched_setscheduler(td, tdt, policy, &sched_param); + PROC_UNLOCK(tdt->td_proc); + return (error); +} + +int +linux_sched_getscheduler(struct thread *td, + struct linux_sched_getscheduler_args *args) +{ + struct thread *tdt; + int error, policy; + + tdt = linux_tdfind(td, args->pid, -1); + if (tdt == NULL) + return (ESRCH); + + error = kern_sched_getscheduler(td, tdt, &policy); + PROC_UNLOCK(tdt->td_proc); + + switch (policy) { + case SCHED_OTHER: + td->td_retval[0] = LINUX_SCHED_OTHER; + break; + case SCHED_FIFO: + td->td_retval[0] = LINUX_SCHED_FIFO; + break; + case SCHED_RR: + td->td_retval[0] = LINUX_SCHED_RR; + break; + } + return (error); +} + +int +linux_sched_get_priority_max(struct thread *td, + struct linux_sched_get_priority_max_args *args) +{ + struct sched_get_priority_max_args bsd; + + if (linux_map_sched_prio) { + switch (args->policy) { + case LINUX_SCHED_OTHER: + td->td_retval[0] = 0; + return (0); + case LINUX_SCHED_FIFO: + case LINUX_SCHED_RR: + td->td_retval[0] = LINUX_MAX_RT_PRIO - 1; + return (0); + default: + return (EINVAL); + } + } + + switch (args->policy) { + case LINUX_SCHED_OTHER: + bsd.policy = SCHED_OTHER; + break; + case LINUX_SCHED_FIFO: + bsd.policy = SCHED_FIFO; + break; + case LINUX_SCHED_RR: + bsd.policy = SCHED_RR; + break; + default: + return (EINVAL); + } + return (sys_sched_get_priority_max(td, &bsd)); +} + +int +linux_sched_get_priority_min(struct thread *td, + struct linux_sched_get_priority_min_args *args) +{ + struct sched_get_priority_min_args bsd; + + if (linux_map_sched_prio) { + switch (args->policy) { + case LINUX_SCHED_OTHER: + td->td_retval[0] = 0; + return (0); + case LINUX_SCHED_FIFO: + case LINUX_SCHED_RR: + td->td_retval[0] = 1; + return (0); + default: + return (EINVAL); + } + } + + switch (args->policy) { + case LINUX_SCHED_OTHER: + bsd.policy = SCHED_OTHER; + break; + case LINUX_SCHED_FIFO: + bsd.policy = SCHED_FIFO; + break; + case LINUX_SCHED_RR: + bsd.policy = SCHED_RR; + break; + default: + return (EINVAL); + } + return (sys_sched_get_priority_min(td, &bsd)); +} + +#define REBOOT_CAD_ON 0x89abcdef +#define REBOOT_CAD_OFF 0 +#define REBOOT_HALT 0xcdef0123 +#define REBOOT_RESTART 0x01234567 +#define REBOOT_RESTART2 0xA1B2C3D4 +#define REBOOT_POWEROFF 0x4321FEDC +#define REBOOT_MAGIC1 0xfee1dead +#define REBOOT_MAGIC2 0x28121969 +#define REBOOT_MAGIC2A 0x05121996 +#define REBOOT_MAGIC2B 0x16041998 + +int +linux_reboot(struct thread *td, struct linux_reboot_args *args) +{ + struct reboot_args bsd_args; + + if (args->magic1 != REBOOT_MAGIC1) + return (EINVAL); + + switch (args->magic2) { + case REBOOT_MAGIC2: + case REBOOT_MAGIC2A: + case REBOOT_MAGIC2B: + break; + default: + return (EINVAL); + } + + switch (args->cmd) { + case REBOOT_CAD_ON: + case REBOOT_CAD_OFF: + return (priv_check(td, PRIV_REBOOT)); + case REBOOT_HALT: + bsd_args.opt = RB_HALT; + break; + case REBOOT_RESTART: + case REBOOT_RESTART2: + bsd_args.opt = 0; + break; + case REBOOT_POWEROFF: + bsd_args.opt = RB_POWEROFF; + break; + default: + return (EINVAL); + } + return (sys_reboot(td, &bsd_args)); +} + +int +linux_getresuid(struct thread *td, struct linux_getresuid_args *args) +{ + + return (kern_getresuid(td, LINUX_USER_CAP_OBJ(args->ruid), LINUX_USER_CAP_OBJ(args->euid), LINUX_USER_CAP_OBJ(args->suid))); +} + +int +linux_getresgid(struct thread *td, struct linux_getresgid_args *args) +{ + + return (kern_getresgid(td, LINUX_USER_CAP_OBJ(args->rgid), LINUX_USER_CAP_OBJ(args->egid), LINUX_USER_CAP_OBJ(args->sgid))); +} + +int +linux_getpid(struct thread *td, struct linux_getpid_args *args) +{ + + td->td_retval[0] = td->td_proc->p_pid; + + return (0); +} + +int +linux_gettid(struct thread *td, struct linux_gettid_args *args) +{ + struct linux_emuldata *em; + + em = em_find(td); + KASSERT(em != NULL, ("gettid: emuldata not found.\n")); + + td->td_retval[0] = em->em_tid; + + return (0); +} + +int +linux_getppid(struct thread *td, struct linux_getppid_args *args) +{ + + td->td_retval[0] = kern_getppid(td); + return (0); +} + +int +linux_getgid(struct thread *td, struct linux_getgid_args *args) +{ + + td->td_retval[0] = td->td_ucred->cr_rgid; + return (0); +} + +int +linux_getuid(struct thread *td, struct linux_getuid_args *args) +{ + + td->td_retval[0] = td->td_ucred->cr_ruid; + return (0); +} + +int +linux_getsid(struct thread *td, struct linux_getsid_args *args) +{ + + return (kern_getsid(td, args->pid)); +} + +int +linux_getpriority(struct thread *td, struct linux_getpriority_args *args) +{ + int error; + + error = kern_getpriority(td, args->which, args->who); + td->td_retval[0] = 20 - td->td_retval[0]; + return (error); +} + +int +linux_sethostname(struct thread *td, struct linux_sethostname_args *args) +{ + int name[2]; + + name[0] = CTL_KERN; + name[1] = KERN_HOSTNAME; + return (userland_sysctl(td, name, 2, 0, 0, 0, LINUX_USER_CAP(args->hostname, args->len), + args->len, 0, 0)); +} + +int +linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args) +{ + int name[2]; + + name[0] = CTL_KERN; + name[1] = KERN_NISDOMAINNAME; + return (userland_sysctl(td, name, 2, 0, 0, 0, LINUX_USER_CAP(args->name, args->len), + args->len, 0, 0)); +} + +int +linux_exit_group(struct thread *td, struct linux_exit_group_args *args) +{ + + LINUX_CTR2(exit_group, "thread(%d) (%d)", td->td_tid, + args->error_code); + + /* + * XXX: we should send a signal to the parent if + * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?) + * as it doesnt occur often. + */ + exit1(td, args->error_code, 0); + /* NOTREACHED */ +} + +int +linux_acct(struct thread *td, struct linux_acct_args *args) +{ + + return (kern_acct(td, LINUX_USER_CAP_PATH(args->path))); +} + +#define _LINUX_CAPABILITY_VERSION_1 0x19980330 +#define _LINUX_CAPABILITY_VERSION_2 0x20071026 +#define _LINUX_CAPABILITY_VERSION_3 0x20080522 + +struct l_user_cap_header { + l_int version; + l_int pid; +}; + +struct l_user_cap_data { + l_int effective; + l_int permitted; + l_int inheritable; +}; + +int +linux_capget(struct thread *td, struct linux_capget_args *uap) +{ + struct l_user_cap_header luch; + struct l_user_cap_data lucd[2]; + int error, u32s; + + if (uap->hdrp == NULL) + return (EFAULT); + + error = copyin(LINUX_USER_CAP_OBJ(uap->hdrp), &luch, sizeof(luch)); + if (error != 0) + return (error); + + switch (luch.version) { + case _LINUX_CAPABILITY_VERSION_1: + u32s = 1; + break; + case _LINUX_CAPABILITY_VERSION_2: + case _LINUX_CAPABILITY_VERSION_3: + u32s = 2; + break; + default: + luch.version = _LINUX_CAPABILITY_VERSION_1; + error = copyout(&luch, LINUX_USER_CAP_OBJ(uap->hdrp), sizeof(luch)); + if (error) + return (error); + return (EINVAL); + } + + if (luch.pid) + return (EPERM); + + if (uap->datap) { + /* + * The current implementation doesn't support setting + * a capability (it's essentially a stub) so indicate + * that no capabilities are currently set or available + * to request. + */ + memset(&lucd, 0, u32s * sizeof(lucd[0])); + error = copyout(&lucd, LINUX_USER_CAP_ARRAY(uap->datap, u32s), u32s * sizeof(lucd[0])); + } + + return (error); +} + +int +linux_capset(struct thread *td, struct linux_capset_args *uap) +{ + struct l_user_cap_header luch; + struct l_user_cap_data lucd[2]; + int error, i, u32s; + + if (uap->hdrp == NULL || uap->datap == NULL) + return (EFAULT); + + error = copyin(LINUX_USER_CAP_OBJ(uap->hdrp), &luch, sizeof(luch)); + if (error != 0) + return (error); + + switch (luch.version) { + case _LINUX_CAPABILITY_VERSION_1: + u32s = 1; + break; + case _LINUX_CAPABILITY_VERSION_2: + case _LINUX_CAPABILITY_VERSION_3: + u32s = 2; + break; + default: + luch.version = _LINUX_CAPABILITY_VERSION_1; + error = copyout(&luch, LINUX_USER_CAP_OBJ(uap->hdrp), sizeof(luch)); + if (error) + return (error); + return (EINVAL); + } + + if (luch.pid) + return (EPERM); + + error = copyin(LINUX_USER_CAP_ARRAY(uap->datap, u32s), &lucd, u32s * sizeof(lucd[0])); + if (error != 0) + return (error); + + /* We currently don't support setting any capabilities. */ + for (i = 0; i < u32s; i++) { + if (lucd[i].effective || lucd[i].permitted || + lucd[i].inheritable) { + linux_msg(td, + "capset[%d] effective=0x%x, permitted=0x%x, " + "inheritable=0x%x is not implemented", i, + (int)lucd[i].effective, (int)lucd[i].permitted, + (int)lucd[i].inheritable); + return (EPERM); + } + } + + return (0); +} + +int +linux_prctl(struct thread *td, struct linux_prctl_args *args) +{ + int error = 0, max_size, arg; + struct proc *p = td->td_proc; + char comm[LINUX_MAX_COMM_LEN]; + int pdeath_signal, trace_state; + + switch (args->option) { + case LINUX_PR_SET_PDEATHSIG: + if (!LINUX_SIG_VALID(args->arg2)) + return (EINVAL); + pdeath_signal = linux_to_bsd_signal(args->arg2); + return (kern_procctl(td, P_PID, 0, PROC_PDEATHSIG_CTL, + &pdeath_signal)); + case LINUX_PR_GET_PDEATHSIG: + error = kern_procctl(td, P_PID, 0, PROC_PDEATHSIG_STATUS, + &pdeath_signal); + if (error != 0) + return (error); + pdeath_signal = bsd_to_linux_signal(pdeath_signal); + return (copyout(&pdeath_signal, + LINUX_USER_CAP(args->arg2, sizeof(pdeath_signal)), + sizeof(pdeath_signal))); + /* + * In Linux, this flag controls if set[gu]id processes can coredump. + * There are additional semantics imposed on processes that cannot + * coredump: + * - Such processes can not be ptraced. + * - There are some semantics around ownership of process-related files + * in the /proc namespace. + * + * In FreeBSD, we can (and by default, do) disable setuid coredump + * system-wide with 'sugid_coredump.' We control tracability on a + * per-process basis with the procctl PROC_TRACE (=> P2_NOTRACE flag). + * By happy coincidence, P2_NOTRACE also prevents coredumping. So the + * procctl is roughly analogous to Linux's DUMPABLE. + * + * So, proxy these knobs to the corresponding PROC_TRACE setting. + */ + case LINUX_PR_GET_DUMPABLE: + error = kern_procctl(td, P_PID, p->p_pid, PROC_TRACE_STATUS, + &trace_state); + if (error != 0) + return (error); + td->td_retval[0] = (trace_state != -1); + return (0); + case LINUX_PR_SET_DUMPABLE: + /* + * It is only valid for userspace to set one of these two + * flags, and only one at a time. + */ + switch (args->arg2) { + case LINUX_SUID_DUMP_DISABLE: + trace_state = PROC_TRACE_CTL_DISABLE_EXEC; + break; + case LINUX_SUID_DUMP_USER: + trace_state = PROC_TRACE_CTL_ENABLE; + break; + default: + return (EINVAL); + } + return (kern_procctl(td, P_PID, p->p_pid, PROC_TRACE_CTL, + &trace_state)); + case LINUX_PR_GET_KEEPCAPS: + /* + * Indicate that we always clear the effective and + * permitted capability sets when the user id becomes + * non-zero (actually the capability sets are simply + * always zero in the current implementation). + */ + td->td_retval[0] = 0; + break; + case LINUX_PR_SET_KEEPCAPS: + /* + * Ignore requests to keep the effective and permitted + * capability sets when the user id becomes non-zero. + */ + break; + case LINUX_PR_SET_NAME: + /* + * To be on the safe side we need to make sure to not + * overflow the size a Linux program expects. We already + * do this here in the copyin, so that we don't need to + * check on copyout. + */ + max_size = MIN(sizeof(comm), sizeof(p->p_comm)); + error = copyinstr(LINUX_USER_CAP(args->arg2, max_size), comm, + max_size, NULL); + + /* Linux silently truncates the name if it is too long. */ + if (error == ENAMETOOLONG) { + /* + * XXX: copyinstr() isn't documented to populate the + * array completely, so do a copyin() to be on the + * safe side. This should be changed in case + * copyinstr() is changed to guarantee this. + */ + error = copyin(LINUX_USER_CAP(args->arg2, max_size - 1), comm, + max_size - 1); + comm[max_size - 1] = '\0'; + } + if (error) + return (error); + + PROC_LOCK(p); + strlcpy(p->p_comm, comm, sizeof(p->p_comm)); + PROC_UNLOCK(p); + break; + case LINUX_PR_GET_NAME: + PROC_LOCK(p); + strlcpy(comm, p->p_comm, sizeof(comm)); + PROC_UNLOCK(p); + error = copyout(comm, LINUX_USER_CAP(args->arg2, strlen(comm) + 1), + strlen(comm) + 1); + break; + case LINUX_PR_GET_SECCOMP: + case LINUX_PR_SET_SECCOMP: + /* + * Same as returned by Linux without CONFIG_SECCOMP enabled. + */ + error = EINVAL; + break; + case LINUX_PR_CAPBSET_READ: +#if 0 + /* + * This makes too much noise with Ubuntu Focal. + */ + linux_msg(td, "unsupported prctl PR_CAPBSET_READ %d", + (int)args->arg2); +#endif + error = EINVAL; + break; + case LINUX_PR_SET_CHILD_SUBREAPER: + if (args->arg2 == 0) { + return (kern_procctl(td, P_PID, 0, PROC_REAP_RELEASE, + NULL)); + } + + return (kern_procctl(td, P_PID, 0, PROC_REAP_ACQUIRE, + NULL)); + case LINUX_PR_SET_NO_NEW_PRIVS: + arg = args->arg2 == 1 ? + PROC_NO_NEW_PRIVS_ENABLE : PROC_NO_NEW_PRIVS_DISABLE; + error = kern_procctl(td, P_PID, p->p_pid, + PROC_NO_NEW_PRIVS_CTL, &arg); + break; + case LINUX_PR_SET_PTRACER: + linux_msg(td, "unsupported prctl PR_SET_PTRACER"); + error = EINVAL; + break; + default: + linux_msg(td, "unsupported prctl option %d", args->option); + error = EINVAL; + break; + } + + return (error); +} + +int +linux_sched_setparam(struct thread *td, + struct linux_sched_setparam_args *uap) +{ + struct sched_param sched_param; + struct thread *tdt; + int error, policy; + + error = copyin(LINUX_USER_CAP_OBJ(uap->param), &sched_param, sizeof(sched_param)); + if (error) + return (error); + + tdt = linux_tdfind(td, uap->pid, -1); + if (tdt == NULL) + return (ESRCH); + + if (linux_map_sched_prio) { + error = kern_sched_getscheduler(td, tdt, &policy); + if (error) + goto out; + + switch (policy) { + case SCHED_OTHER: + if (sched_param.sched_priority != 0) { + error = EINVAL; + goto out; + } + sched_param.sched_priority = + PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; + break; + case SCHED_FIFO: + case SCHED_RR: + if (sched_param.sched_priority < 1 || + sched_param.sched_priority >= LINUX_MAX_RT_PRIO) { + error = EINVAL; + goto out; + } + /* + * Map [1, LINUX_MAX_RT_PRIO - 1] to + * [0, RTP_PRIO_MAX - RTP_PRIO_MIN] (rounding down). + */ + sched_param.sched_priority = + (sched_param.sched_priority - 1) * + (RTP_PRIO_MAX - RTP_PRIO_MIN + 1) / + (LINUX_MAX_RT_PRIO - 1); + break; + } + } + + error = kern_sched_setparam(td, tdt, &sched_param); +out: PROC_UNLOCK(tdt->td_proc); + return (error); +} + +int +linux_sched_getparam(struct thread *td, + struct linux_sched_getparam_args *uap) +{ + struct sched_param sched_param; + struct thread *tdt; + int error, policy; + + tdt = linux_tdfind(td, uap->pid, -1); + if (tdt == NULL) + return (ESRCH); + + error = kern_sched_getparam(td, tdt, &sched_param); + if (error) { + PROC_UNLOCK(tdt->td_proc); + return (error); + } + + if (linux_map_sched_prio) { + error = kern_sched_getscheduler(td, tdt, &policy); + PROC_UNLOCK(tdt->td_proc); + if (error) + return (error); + + switch (policy) { + case SCHED_OTHER: + sched_param.sched_priority = 0; + break; + case SCHED_FIFO: + case SCHED_RR: + /* + * Map [0, RTP_PRIO_MAX - RTP_PRIO_MIN] to + * [1, LINUX_MAX_RT_PRIO - 1] (rounding up). + */ + sched_param.sched_priority = + (sched_param.sched_priority * + (LINUX_MAX_RT_PRIO - 1) + + (RTP_PRIO_MAX - RTP_PRIO_MIN - 1)) / + (RTP_PRIO_MAX - RTP_PRIO_MIN) + 1; + break; + } + } else + PROC_UNLOCK(tdt->td_proc); + + error = copyout(&sched_param, LINUX_USER_CAP_OBJ(uap->param), sizeof(sched_param)); + return (error); +} + +/* + * Get affinity of a process. + */ +int +linux_sched_getaffinity(struct thread *td, + struct linux_sched_getaffinity_args *args) +{ + struct thread *tdt; + cpuset_t *mask; + size_t size; + int error; + id_t tid; + + tdt = linux_tdfind(td, args->pid, -1); + if (tdt == NULL) + return (ESRCH); + tid = tdt->td_tid; + PROC_UNLOCK(tdt->td_proc); + + mask = malloc(sizeof(cpuset_t), M_LINUX, M_WAITOK | M_ZERO); + size = min(args->len, sizeof(cpuset_t)); + error = kern_cpuset_getaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, + tid, size, mask); + if (error == ERANGE) + error = EINVAL; + if (error == 0) + error = copyout(mask, LINUX_USER_CAP(args->user_mask_ptr, size), size); + if (error == 0) + td->td_retval[0] = size; + free(mask, M_LINUX); + return (error); +} + +/* + * Set affinity of a process. + */ +int +linux_sched_setaffinity(struct thread *td, + struct linux_sched_setaffinity_args *args) +{ + struct thread *tdt; + cpuset_t *mask; + int cpu, error; + size_t len; + id_t tid; + + tdt = linux_tdfind(td, args->pid, -1); + if (tdt == NULL) + return (ESRCH); + tid = tdt->td_tid; + PROC_UNLOCK(tdt->td_proc); + + len = min(args->len, sizeof(cpuset_t)); + mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO); + error = copyin(LINUX_USER_CAP(args->user_mask_ptr, len), mask, len); + if (error != 0) + goto out; + /* Linux ignore high bits */ + CPU_FOREACH_ISSET(cpu, mask) + if (cpu > mp_maxid) + CPU_CLR(cpu, mask); + + error = kern_cpuset_setaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, + tid, mask); + if (error == EDEADLK) + error = EINVAL; +out: + free(mask, M_TEMP); + return (error); +} + +struct linux_rlimit64 { + uint64_t rlim_cur; + uint64_t rlim_max; +}; + +int +linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) +{ + struct rlimit rlim, nrlim; + struct linux_rlimit64 lrlim; + struct proc *p; + u_int which; + int flags; + int error; + + if (args->new == NULL && args->old != NULL) { + if (linux_get_dummy_limit(td, args->resource, &rlim)) { + lrlim.rlim_cur = rlim.rlim_cur; + lrlim.rlim_max = rlim.rlim_max; + return (copyout(&lrlim, LINUX_USER_CAP(args->old, sizeof(lrlim)), sizeof(lrlim))); + } + } + + if (args->resource >= LINUX_RLIM_NLIMITS) + return (EINVAL); + + which = linux_to_bsd_resource[args->resource]; + if (which == -1) + return (EINVAL); + + if (args->new != NULL) { + /* + * Note. Unlike FreeBSD where rlim is signed 64-bit Linux + * rlim is unsigned 64-bit. FreeBSD treats negative limits + * as INFINITY so we do not need a conversion even. + */ + error = copyin(LINUX_USER_CAP_OBJ(args->new), &nrlim, sizeof(nrlim)); + if (error != 0) + return (error); + } + + flags = PGET_HOLD | PGET_NOTWEXIT; + if (args->new != NULL) + flags |= PGET_CANDEBUG; + else + flags |= PGET_CANSEE; + if (args->pid == 0) { + p = td->td_proc; + PHOLD(p); + } else { + error = pget(args->pid, flags, &p); + if (error != 0) + return (error); + } + if (args->old != NULL) { + PROC_LOCK(p); + lim_rlimit_proc(p, which, &rlim); + PROC_UNLOCK(p); + if (rlim.rlim_cur == RLIM_INFINITY) + lrlim.rlim_cur = LINUX_RLIM_INFINITY; + else + lrlim.rlim_cur = rlim.rlim_cur; + if (rlim.rlim_max == RLIM_INFINITY) + lrlim.rlim_max = LINUX_RLIM_INFINITY; + else + lrlim.rlim_max = rlim.rlim_max; + error = copyout(&lrlim, LINUX_USER_CAP(args->old, sizeof(lrlim)), sizeof(lrlim)); + if (error != 0) + goto out; + } + + if (args->new != NULL) + error = kern_proc_setrlimit(td, p, which, &nrlim); + + out: + PRELE(p); + return (error); +} + +int +linux_pselect6(struct thread *td, struct linux_pselect6_args *args) +{ + struct timespec ts, *tsp; + int error; + + if (args->tsp != NULL) { + error = linux_get_timespec(&ts, args->tsp); + if (error != 0) + return (error); + tsp = &ts; + } else + tsp = NULL; + + error = linux_common_pselect6(td, args->nfds, LINUX_USER_CAP_OBJ(args->readfds), + LINUX_USER_CAP_OBJ(args->writefds), LINUX_USER_CAP_OBJ(args->exceptfds), tsp, LINUX_USER_CAP(args->sig, sizeof(struct l_pselect6arg))); + + if (args->tsp != NULL) + linux_put_timespec(&ts, args->tsp); + return (error); +} + +static int +linux_common_pselect6(struct thread *td, l_int nfds, l_fd_set * __capability readfds, + l_fd_set * __capability writefds, l_fd_set * __capability exceptfds, struct timespec *tsp, + l_uintptr_t * __capability sig) +{ + struct timeval utv, tv0, tv1, *tvp; + struct l_pselect6arg lpse6; + sigset_t *ssp; + sigset_t ss; + int error; + + ssp = NULL; + if (sig != NULL) { + error = copyin(sig, &lpse6, sizeof(lpse6)); + if (error != 0) + return (error); + error = linux_copyin_sigset(td, LINUX_USER_CAP(lpse6.ss, lpse6.ss_len), + lpse6.ss_len, &ss, &ssp); + if (error != 0) + return (error); + } else + ssp = NULL; + + /* + * Currently glibc changes nanosecond number to microsecond. + * This mean losing precision but for now it is hardly seen. + */ + if (tsp != NULL) { + TIMESPEC_TO_TIMEVAL(&utv, tsp); + if (itimerfix(&utv)) + return (EINVAL); + + microtime(&tv0); + tvp = &utv; + } else + tvp = NULL; + + error = kern_pselect(td, nfds, readfds, + writefds, + exceptfds, tvp, ssp, LINUX_NFDBITS); + + if (tsp != NULL) { + /* + * Compute how much time was left of the timeout, + * by subtracting the current time and the time + * before we started the call, and subtracting + * that result from the user-supplied value. + */ + microtime(&tv1); + timevalsub(&tv1, &tv0); + timevalsub(&utv, &tv1); + if (utv.tv_sec < 0) + timevalclear(&utv); + TIMEVAL_TO_TIMESPEC(&utv, tsp); + } + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_pselect6_time64(struct thread *td, + struct linux_pselect6_time64_args *args) +{ + struct timespec ts, *tsp; + int error; + + if (args->tsp != NULL) { + error = linux_get_timespec64(&ts, args->tsp); + if (error != 0) + return (error); + tsp = &ts; + } else + tsp = NULL; + + error = linux_common_pselect6(td, args->nfds, args->readfds, + args->writefds, args->exceptfds, tsp, args->sig); + + if (args->tsp != NULL) + linux_put_timespec64(&ts, args->tsp); + return (error); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_ppoll(struct thread *td, struct linux_ppoll_args *args) +{ + struct timespec uts, *tsp; + int error; + + if (args->tsp != NULL) { + error = linux_get_timespec(&uts, args->tsp); + if (error != 0) + return (error); + tsp = &uts; + } else + tsp = NULL; + + error = linux_common_ppoll(td, LINUX_USER_CAP_ARRAY(args->fds, args->nfds), args->nfds, tsp, + LINUX_USER_CAP(args->sset, args->ssize), args->ssize); + if (error == 0 && args->tsp != NULL) + error = linux_put_timespec(&uts, args->tsp); + return (error); +} + +static int +linux_common_ppoll(struct thread *td, struct pollfd * __capability fds, uint32_t nfds, + struct timespec *tsp, l_sigset_t * __capability sset, l_size_t ssize) +{ + struct timespec ts0, ts1; + struct pollfd stackfds[32]; + struct pollfd *kfds; + sigset_t *ssp; + sigset_t ss; + int error; + + if (kern_poll_maxfds(nfds)) + return (EINVAL); + if (sset != NULL) { + error = linux_copyin_sigset(td, sset, ssize, &ss, &ssp); + if (error != 0) + return (error); + } else + ssp = NULL; + if (tsp != NULL) + nanotime(&ts0); + + if (nfds > nitems(stackfds)) + kfds = mallocarray(nfds, sizeof(*kfds), M_TEMP, M_WAITOK); + else + kfds = stackfds; + error = linux_pollin(td, kfds, fds, nfds); + if (error != 0) + goto out; + + error = kern_poll_kfds(td, kfds, nfds, tsp, ssp); + if (error == 0) + error = linux_pollout(td, kfds, fds, nfds); + + if (error == 0 && tsp != NULL) { + if (td->td_retval[0]) { + nanotime(&ts1); + timespecsub(&ts1, &ts0, &ts1); + timespecsub(tsp, &ts1, tsp); + if (tsp->tv_sec < 0) + timespecclear(tsp); + } else + timespecclear(tsp); + } + +out: + if (nfds > nitems(stackfds)) + free(kfds, M_TEMP); + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_ppoll_time64(struct thread *td, struct linux_ppoll_time64_args *args) +{ + struct timespec uts, *tsp; + int error; + + if (args->tsp != NULL) { + error = linux_get_timespec64(&uts, args->tsp); + if (error != 0) + return (error); + tsp = &uts; + } else + tsp = NULL; + error = linux_common_ppoll(td, args->fds, args->nfds, tsp, + args->sset, args->ssize); + if (error == 0 && args->tsp != NULL) + error = linux_put_timespec64(&uts, args->tsp); + return (error); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +static int +linux_pollin(struct thread *td, struct pollfd *fds, struct pollfd * __capability ufds, u_int nfd) +{ + int error; + u_int i; + + error = copyin(ufds, fds, nfd * sizeof(*fds)); + if (error != 0) + return (error); + + for (i = 0; i < nfd; i++) { + if (fds->events != 0) + linux_to_bsd_poll_events(td, fds->fd, + fds->events, &fds->events); + fds++; + } + return (0); +} + +static int +linux_pollout(struct thread *td, struct pollfd *fds, struct pollfd * __capability ufds, u_int nfd) +{ + int error = 0; + u_int i, n = 0; + + for (i = 0; i < nfd; i++) { + if (fds->revents != 0) { + bsd_to_linux_poll_events(fds->revents, + &fds->revents); + n++; + } + error = copyout(&fds->revents, &ufds->revents, + sizeof(ufds->revents)); + if (error) + return (error); + fds++; + ufds++; + } + td->td_retval[0] = n; + return (0); +} + +static int +linux_sched_rr_get_interval_common(struct thread *td, pid_t pid, + struct timespec *ts) +{ + struct thread *tdt; + int error; + + /* + * According to man in case the invalid pid specified + * EINVAL should be returned. + */ + if (pid < 0) + return (EINVAL); + + tdt = linux_tdfind(td, pid, -1); + if (tdt == NULL) + return (ESRCH); + + error = kern_sched_rr_get_interval_td(td, tdt, ts); + PROC_UNLOCK(tdt->td_proc); + return (error); +} + +int +linux_sched_rr_get_interval(struct thread *td, + struct linux_sched_rr_get_interval_args *uap) +{ + struct timespec ts; + int error; + + error = linux_sched_rr_get_interval_common(td, uap->pid, &ts); + if (error != 0) + return (error); + return (linux_put_timespec(&ts, uap->interval)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_sched_rr_get_interval_time64(struct thread *td, + struct linux_sched_rr_get_interval_time64_args *uap) +{ + struct timespec ts; + int error; + + error = linux_sched_rr_get_interval_common(td, uap->pid, &ts); + if (error != 0) + return (error); + return (linux_put_timespec64(&ts, uap->interval)); +} +#endif + +/* + * In case when the Linux thread is the initial thread in + * the thread group thread id is equal to the process id. + * Glibc depends on this magic (assert in pthread_getattr_np.c). + */ +struct thread * +linux_tdfind(struct thread *td, lwpid_t tid, pid_t pid) +{ + struct linux_emuldata *em; + struct thread *tdt; + struct proc *p; + + tdt = NULL; + if (tid == 0 || tid == td->td_tid) { + if (pid != -1 && td->td_proc->p_pid != pid) + return (NULL); + PROC_LOCK(td->td_proc); + return (td); + } else if (tid > PID_MAX) + return (tdfind(tid, pid)); + + /* + * Initial thread where the tid equal to the pid. + */ + p = pfind(tid); + if (p != NULL) { + if (SV_PROC_ABI(p) != SV_ABI_LINUX || + (pid != -1 && tid != pid)) { + /* + * p is not a Linuxulator process. + */ + PROC_UNLOCK(p); + return (NULL); + } + FOREACH_THREAD_IN_PROC(p, tdt) { + em = em_find(tdt); + if (tid == em->em_tid) + return (tdt); + } + PROC_UNLOCK(p); + } + return (NULL); +} + +void +linux_to_bsd_waitopts(int options, int *bsdopts) +{ + + if (options & LINUX_WNOHANG) + *bsdopts |= WNOHANG; + if (options & LINUX_WUNTRACED) + *bsdopts |= WUNTRACED; + if (options & LINUX_WEXITED) + *bsdopts |= WEXITED; + if (options & LINUX_WCONTINUED) + *bsdopts |= WCONTINUED; + if (options & LINUX_WNOWAIT) + *bsdopts |= WNOWAIT; + + if (options & __WCLONE) + *bsdopts |= WLINUXCLONE; +} + +int +linux_getrandom(struct thread *td, struct linux_getrandom_args *args) +{ + struct uio uio; + struct iovec iov; + int error; + + if (args->flags & ~(LINUX_GRND_NONBLOCK|LINUX_GRND_RANDOM)) + return (EINVAL); + if (args->count > INT_MAX) + args->count = INT_MAX; + + IOVEC_INIT_C(&iov, LINUX_USER_CAP(args->buf, args->count), args->count); + + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_resid = iov.iov_len; + uio.uio_segflg = UIO_USERSPACE; + uio.uio_rw = UIO_READ; + uio.uio_td = td; + + error = read_random_uio(&uio, args->flags & LINUX_GRND_NONBLOCK); + if (error == 0) + td->td_retval[0] = args->count - uio.uio_resid; + return (error); +} + +int +linux_mincore(struct thread *td, struct linux_mincore_args *args) +{ + + /* Needs to be page-aligned */ + if ((uintcap_t)args->start & PAGE_MASK) + return (EINVAL); + +#if defined(COMPAT_LINUX64) || defined(COMPAT_LINUX32) + return (kern_mincore(td, args->start, args->len, + LINUX_USER_CAP(args->vec, btoc(args->len)))); +#else + struct mincore_args bargs = { + .addr = args->start, + .len = args->len, + .vec = args->vec + }; + + return (sys_mincore(td, &bargs)); +#endif +} + +#define SYSLOG_TAG "<6>" + +int +linux_syslog(struct thread *td, struct linux_syslog_args *args) +{ + char buf[128], *src, * __capability dst; + u_int seq; + int buflen, error; + + if (args->type != LINUX_SYSLOG_ACTION_READ_ALL) { + linux_msg(td, "syslog unsupported type 0x%x", args->type); + return (EINVAL); + } + + if (args->len < 6) { + td->td_retval[0] = 0; + return (0); + } + + error = priv_check(td, PRIV_MSGBUF); + if (error) + return (error); + + mtx_lock(&msgbuf_lock); + msgbuf_peekbytes(msgbufp, NULL, 0, &seq); + mtx_unlock(&msgbuf_lock); + + dst = LINUX_USER_CAP(args->buf, args->len); + error = copyout(&SYSLOG_TAG, dst, sizeof(SYSLOG_TAG)); + /* The -1 is to skip the trailing '\0'. */ + dst += sizeof(SYSLOG_TAG) - 1; + + while (error == 0) { + mtx_lock(&msgbuf_lock); + buflen = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq); + mtx_unlock(&msgbuf_lock); + + if (buflen == 0) + break; + + for (src = buf; src < buf + buflen && error == 0; src++) { + if (*src == '\0') + continue; + + if ((__cheri_addr ptraddr_t)dst >= (ptraddr_t)(linuxcap_t)args->buf + args->len) + goto out; + + error = copyout(src, dst, 1); + dst++; + + if (*src == '\n' && *(src + 1) != '<' && + (__cheri_addr ptraddr_t)dst + sizeof(SYSLOG_TAG) < (ptraddr_t)(linuxcap_t)args->buf + args->len) { + error = copyout(&SYSLOG_TAG, + dst, sizeof(SYSLOG_TAG)); + dst += sizeof(SYSLOG_TAG) - 1; + } + } + } +out: + td->td_retval[0] = (__cheri_addr ptraddr_t)dst - (ptraddr_t)(linuxcap_t)args->buf; + return (error); +} + +int +linux_getcpu(struct thread *td, struct linux_getcpu_args *args) +{ + int cpu, error, node; + + cpu = td->td_oncpu; /* Make sure it doesn't change during copyout(9) */ + error = 0; + node = cpuid_to_pcpu[cpu]->pc_domain; + + if (args->cpu != NULL) + error = copyout(&cpu, LINUX_USER_CAP_OBJ(args->cpu), sizeof(l_int)); + if (args->node != NULL) + error = copyout(&node, LINUX_USER_CAP_OBJ(args->node), sizeof(l_int)); + return (error); +} + +#if defined(__i386__) || defined(__amd64__) +int +linux_poll(struct thread *td, struct linux_poll_args *args) +{ + struct timespec ts, *tsp; + + if (args->timeout != INFTIM) { + if (args->timeout < 0) + return (EINVAL); + ts.tv_sec = args->timeout / 1000; + ts.tv_nsec = (args->timeout % 1000) * 1000000; + tsp = &ts; + } else + tsp = NULL; + + return (linux_common_ppoll(td, args->fds, args->nfds, + tsp, NULL, 0)); +} +#endif /* __i386__ || __amd64__ */ + +int +linux_seccomp(struct thread *td, struct linux_seccomp_args *args) +{ + + switch (args->op) { + case LINUX_SECCOMP_GET_ACTION_AVAIL: + return (EOPNOTSUPP); + default: + /* + * Ignore unknown operations, just like Linux kernel built + * without CONFIG_SECCOMP. + */ + return (EINVAL); + } +} + +/* + * Takes a pointer to a pointer an array of pointers in userspace, loads + * the loads the current value and updates the array pointer. + */ +static int +get_argenv_ptr(l_uintptr_t * __capability *arrayp, void * __capability *ptrp) +{ + char * __capability array; +#ifdef COMPAT_LINUX32 + uint32_t ptr32; +#elif defined(COMPAT_LINUX64) + uint64_t ptr64; +#else + uintcap_t ptr; +#endif + + array = (char * __capability)*arrayp; +#ifdef COMPAT_LINUX32 + if (fueword32(array, &ptr32) == -1) + return (EFAULT); + array += sizeof(ptr32); + *ptrp = LINUX_USER_CAP_STR((void *)(uintptr_t)ptr32); +#elif defined(COMPAT_LINUX64) + if (fueword64(array, &ptr64) == -1) + return (EFAULT); + array += sizeof(ptr64); + *ptrp = LINUX_USER_CAP_STR((void *)(uintptr_t)ptr64); +#else + if (fueptr(array, &ptr) == -1) + return (EFAULT); + array += sizeof(ptr); + *ptrp = (void * __capability)ptr; +#endif + *arrayp = (l_uintptr_t * __capability)array; + return (0); +} + +/* + * Custom version of exec_copyin_args(), to copy out argument and environment + * strings from the old process address space into the temporary string buffer. + * Based on freebsd32_exec_copyin_args. + */ +static int +linux_exec_copyin_args(struct image_args *args, const char * __capability fname, + enum uio_seg segflg, l_uintptr_t * __capability argv, + l_uintptr_t * __capability envv) +{ + void * __capability ptr; + int error; + + bzero(args, sizeof(*args)); + if (argv == NULL) + return (EFAULT); + + /* + * Allocate demand-paged memory for the file name, argument, and + * environment strings. + */ + error = exec_alloc_args(args); + if (error != 0) + return (error); + + /* + * Copy the file name. + */ + error = exec_args_add_fname(args, fname, segflg); + if (error != 0) + goto err_exit; + + /* + * extract arguments first + */ + for (;;) { + error = get_argenv_ptr(&argv, &ptr); + if (error != 0) + goto err_exit; + if (ptr == NULL) + break; + error = exec_args_add_arg(args, ptr, UIO_USERSPACE); + if (error != 0) + goto err_exit; + } + + /* + * This comment is from Linux do_execveat_common: + * When argv is empty, add an empty string ("") as argv[0] to + * ensure confused userspace programs that start processing + * from argv[1] won't end up walking envp. + */ + if (args->argc == 0 && + (error = exec_args_add_arg(args, "", UIO_SYSSPACE) != 0)) + goto err_exit; + + /* + * extract environment strings + */ + if (envv) { + for (;;) { + error = get_argenv_ptr(&envv, &ptr); + if (error != 0) + goto err_exit; + if (ptr == NULL) + break; + error = exec_args_add_env(args, ptr, UIO_USERSPACE); + if (error != 0) + goto err_exit; + } + } + + return (0); + +err_exit: + exec_free_args(args); + return (error); +} + +int +linux_execve(struct thread *td, struct linux_execve_args *args) +{ + struct image_args eargs; + int error; + + LINUX_CTR(execve); + + error = linux_exec_copyin_args(&eargs, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, LINUX_USER_CAP_UNBOUND(args->argp), + LINUX_USER_CAP_UNBOUND(args->envp)); + if (error == 0) + error = linux_common_execve(td, &eargs); + AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td); + return (error); +} + +static void +linux_up_rtprio_if(struct thread *td1, struct rtprio *rtp) +{ + struct rtprio rtp2; + + pri_to_rtp(td1, &rtp2); + if (rtp2.type < rtp->type || + (rtp2.type == rtp->type && + rtp2.prio < rtp->prio)) { + rtp->type = rtp2.type; + rtp->prio = rtp2.prio; + } +} + +#define LINUX_PRIO_DIVIDER RTP_PRIO_MAX / LINUX_IOPRIO_MAX + +static int +linux_rtprio2ioprio(struct rtprio *rtp) +{ + int ioprio, prio; + + switch (rtp->type) { + case RTP_PRIO_IDLE: + prio = RTP_PRIO_MIN; + ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_IDLE, prio); + break; + case RTP_PRIO_NORMAL: + prio = rtp->prio / LINUX_PRIO_DIVIDER; + ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_BE, prio); + break; + case RTP_PRIO_REALTIME: + prio = rtp->prio / LINUX_PRIO_DIVIDER; + ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_RT, prio); + break; + default: + prio = RTP_PRIO_MIN; + ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_NONE, prio); + break; + } + return (ioprio); +} + +static int +linux_ioprio2rtprio(int ioprio, struct rtprio *rtp) +{ + + switch (LINUX_IOPRIO_PRIO_CLASS(ioprio)) { + case LINUX_IOPRIO_CLASS_IDLE: + rtp->prio = RTP_PRIO_MIN; + rtp->type = RTP_PRIO_IDLE; + break; + case LINUX_IOPRIO_CLASS_BE: + rtp->prio = LINUX_IOPRIO_PRIO_DATA(ioprio) * LINUX_PRIO_DIVIDER; + rtp->type = RTP_PRIO_NORMAL; + break; + case LINUX_IOPRIO_CLASS_RT: + rtp->prio = LINUX_IOPRIO_PRIO_DATA(ioprio) * LINUX_PRIO_DIVIDER; + rtp->type = RTP_PRIO_REALTIME; + break; + default: + return (EINVAL); + } + return (0); +} +#undef LINUX_PRIO_DIVIDER + +int +linux_ioprio_get(struct thread *td, struct linux_ioprio_get_args *args) +{ + struct thread *td1; + struct rtprio rtp; + struct pgrp *pg; + struct proc *p; + int error, found; + + p = NULL; + td1 = NULL; + error = 0; + found = 0; + rtp.type = RTP_PRIO_IDLE; + rtp.prio = RTP_PRIO_MAX; + switch (args->which) { + case LINUX_IOPRIO_WHO_PROCESS: + if (args->who == 0) { + td1 = td; + p = td1->td_proc; + PROC_LOCK(p); + } else if (args->who > PID_MAX) { + td1 = linux_tdfind(td, args->who, -1); + if (td1 != NULL) + p = td1->td_proc; + } else + p = pfind(args->who); + if (p == NULL) + return (ESRCH); + if ((error = p_cansee(td, p))) { + PROC_UNLOCK(p); + break; + } + if (td1 != NULL) { + pri_to_rtp(td1, &rtp); + } else { + FOREACH_THREAD_IN_PROC(p, td1) { + linux_up_rtprio_if(td1, &rtp); + } + } + found++; + PROC_UNLOCK(p); + break; + case LINUX_IOPRIO_WHO_PGRP: + sx_slock(&proctree_lock); + if (args->who == 0) { + pg = td->td_proc->p_pgrp; + PGRP_LOCK(pg); + } else { + pg = pgfind(args->who); + if (pg == NULL) { + sx_sunlock(&proctree_lock); + error = ESRCH; + break; + } + } + sx_sunlock(&proctree_lock); + LIST_FOREACH(p, &pg->pg_members, p_pglist) { + PROC_LOCK(p); + if (p->p_state == PRS_NORMAL && + p_cansee(td, p) == 0) { + FOREACH_THREAD_IN_PROC(p, td1) { + linux_up_rtprio_if(td1, &rtp); + found++; + } + } + PROC_UNLOCK(p); + } + PGRP_UNLOCK(pg); + break; + case LINUX_IOPRIO_WHO_USER: + if (args->who == 0) + args->who = td->td_ucred->cr_uid; + sx_slock(&allproc_lock); + FOREACH_PROC_IN_SYSTEM(p) { + PROC_LOCK(p); + if (p->p_state == PRS_NORMAL && + p->p_ucred->cr_uid == args->who && + p_cansee(td, p) == 0) { + FOREACH_THREAD_IN_PROC(p, td1) { + linux_up_rtprio_if(td1, &rtp); + found++; + } + } + PROC_UNLOCK(p); + } + sx_sunlock(&allproc_lock); + break; + default: + error = EINVAL; + break; + } + if (error == 0) { + if (found != 0) + td->td_retval[0] = linux_rtprio2ioprio(&rtp); + else + error = ESRCH; + } + return (error); +} + +int +linux_ioprio_set(struct thread *td, struct linux_ioprio_set_args *args) +{ + struct thread *td1; + struct rtprio rtp; + struct pgrp *pg; + struct proc *p; + int error; + + if ((error = linux_ioprio2rtprio(args->ioprio, &rtp)) != 0) + return (error); + /* Attempts to set high priorities (REALTIME) require su privileges. */ + if (RTP_PRIO_BASE(rtp.type) == RTP_PRIO_REALTIME && + (error = priv_check(td, PRIV_SCHED_RTPRIO)) != 0) + return (error); + + p = NULL; + td1 = NULL; + switch (args->which) { + case LINUX_IOPRIO_WHO_PROCESS: + if (args->who == 0) { + td1 = td; + p = td1->td_proc; + PROC_LOCK(p); + } else if (args->who > PID_MAX) { + td1 = linux_tdfind(td, args->who, -1); + if (td1 != NULL) + p = td1->td_proc; + } else + p = pfind(args->who); + if (p == NULL) + return (ESRCH); + if ((error = p_cansched(td, p))) { + PROC_UNLOCK(p); + break; + } + if (td1 != NULL) { + error = rtp_to_pri(&rtp, td1); + } else { + FOREACH_THREAD_IN_PROC(p, td1) { + if ((error = rtp_to_pri(&rtp, td1)) != 0) + break; + } + } + PROC_UNLOCK(p); + break; + case LINUX_IOPRIO_WHO_PGRP: + sx_slock(&proctree_lock); + if (args->who == 0) { + pg = td->td_proc->p_pgrp; + PGRP_LOCK(pg); + } else { + pg = pgfind(args->who); + if (pg == NULL) { + sx_sunlock(&proctree_lock); + error = ESRCH; + break; + } + } + sx_sunlock(&proctree_lock); + LIST_FOREACH(p, &pg->pg_members, p_pglist) { + PROC_LOCK(p); + if (p->p_state == PRS_NORMAL && + p_cansched(td, p) == 0) { + FOREACH_THREAD_IN_PROC(p, td1) { + if ((error = rtp_to_pri(&rtp, td1)) != 0) + break; + } + } + PROC_UNLOCK(p); + if (error != 0) + break; + } + PGRP_UNLOCK(pg); + break; + case LINUX_IOPRIO_WHO_USER: + if (args->who == 0) + args->who = td->td_ucred->cr_uid; + sx_slock(&allproc_lock); + FOREACH_PROC_IN_SYSTEM(p) { + PROC_LOCK(p); + if (p->p_state == PRS_NORMAL && + p->p_ucred->cr_uid == args->who && + p_cansched(td, p) == 0) { + FOREACH_THREAD_IN_PROC(p, td1) { + if ((error = rtp_to_pri(&rtp, td1)) != 0) + break; + } + } + PROC_UNLOCK(p); + if (error != 0) + break; + } + sx_sunlock(&allproc_lock); + break; + default: + error = EINVAL; + break; + } + return (error); +} + +/* The only flag is O_NONBLOCK */ +#define B2L_MQ_FLAGS(bflags) ((bflags) != 0 ? LINUX_O_NONBLOCK : 0) +#define L2B_MQ_FLAGS(lflags) ((lflags) != 0 ? O_NONBLOCK : 0) + +int +linux_mq_open(struct thread *td, struct linux_mq_open_args *args) +{ + struct mq_attr attr; + int error, flags; + + flags = linux_common_openflags(args->oflag); + if ((flags & O_ACCMODE) == O_ACCMODE || (flags & O_EXEC) != 0) + return (EINVAL); + flags = FFLAGS(flags); + if ((flags & O_CREAT) != 0 && args->attr != NULL) { + error = copyin(LINUX_USER_CAP_OBJ(args->attr), &attr, sizeof(attr)); + if (error != 0) + return (error); + attr.mq_flags = L2B_MQ_FLAGS(attr.mq_flags); + } + + return (kern_kmq_open(td, LINUX_USER_CAP_STR(args->name), flags, args->mode, + args->attr != NULL ? &attr : NULL)); +} + +int +linux_mq_unlink(struct thread *td, struct linux_mq_unlink_args *args) +{ + struct kmq_unlink_args bsd_args = { + .path = LINUX_USER_CAP_STR(args->name) + }; + + return (sys_kmq_unlink(td, &bsd_args)); +} + +int +linux_mq_timedsend(struct thread *td, struct linux_mq_timedsend_args *args) +{ + struct timespec ts, *abs_timeout; + int error; + + if (args->abs_timeout == NULL) + abs_timeout = NULL; + else { + error = linux_get_timespec(&ts, args->abs_timeout); + if (error != 0) + return (error); + abs_timeout = &ts; + } + + return (kern_kmq_timedsend(td, args->mqd, LINUX_USER_CAP(args->msg_ptr, args->msg_len), + args->msg_len, args->msg_prio, abs_timeout)); +} + +int +linux_mq_timedreceive(struct thread *td, struct linux_mq_timedreceive_args *args) +{ + struct timespec ts, *abs_timeout; + int error; + + if (args->abs_timeout == NULL) + abs_timeout = NULL; + else { + error = linux_get_timespec(&ts, args->abs_timeout); + if (error != 0) + return (error); + abs_timeout = &ts; + } + + return (kern_kmq_timedreceive(td, args->mqd, LINUX_USER_CAP(args->msg_ptr, args->msg_len), + args->msg_len, LINUX_USER_CAP_OBJ(args->msg_prio), abs_timeout)); +} + +int +linux_mq_notify(struct thread *td, struct linux_mq_notify_args *args) +{ + struct sigevent ev, *evp; + struct l_sigevent l_ev; + int error; + + if (args->sevp == NULL) + evp = NULL; + else { + error = copyincap(LINUX_USER_CAP_OBJ(args->sevp), &l_ev, sizeof(l_ev)); + if (error != 0) + return (error); + error = linux_convert_l_sigevent(&l_ev, &ev); + if (error != 0) + return (error); + evp = &ev; + } + + return (kern_kmq_notify(td, args->mqd, evp)); +} + +int +linux_mq_getsetattr(struct thread *td, struct linux_mq_getsetattr_args *args) +{ + struct mq_attr attr, oattr; + int error; + + if (args->attr != NULL) { + error = copyin(LINUX_USER_CAP_OBJ(args->attr), &attr, sizeof(attr)); + if (error != 0) + return (error); + attr.mq_flags = L2B_MQ_FLAGS(attr.mq_flags); + } + + error = kern_kmq_setattr(td, args->mqd, args->attr != NULL ? &attr : NULL, + &oattr); + if (error == 0 && args->oattr != NULL) { + oattr.mq_flags = B2L_MQ_FLAGS(oattr.mq_flags); + bzero(oattr.__reserved, sizeof(oattr.__reserved)); + error = copyout(&oattr, LINUX_USER_CAP_OBJ(args->oattr), sizeof(oattr)); + } + + return (error); +} + +int +linux_swapon(struct thread *td, struct linux_swapon_args *args) +{ + + return (kern_swapon(td, LINUX_USER_CAP_STR(args->name))); +} + +MODULE_DEPEND(linux, mqueuefs, 1, 1, 1); +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "kernel", +// "changes": [ +// "iovec-macros", +// "user_capabilities" +// ] +// } +// CHERI CHANGES END diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h index 445110c598cc..b317faafc2f8 100644 --- a/sys/compat/linux/linux_misc.h +++ b/sys/compat/linux/linux_misc.h @@ -1,217 +1,230 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2006 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. - */ - -#ifndef _LINUX_MISC_H_ -#define _LINUX_MISC_H_ - -#define LINUX_MAX_PID_NS_LEVEL 32 - - /* bits per mask */ -#define LINUX_NFDBITS sizeof(l_fd_mask) * 8 - -/* - * Miscellaneous - */ -#define LINUX_NAME_MAX 255 -#define LINUX_MAX_UTSNAME 65 - -#define LINUX_CTL_MAXNAME 10 - -/* defines for prctl */ -#define LINUX_PR_SET_PDEATHSIG 1 /* Second arg is a signal. */ -#define LINUX_PR_GET_PDEATHSIG 2 /* - * Second arg is a ptr to return the - * signal. - */ -#define LINUX_PR_GET_DUMPABLE 3 -#define LINUX_PR_SET_DUMPABLE 4 -#define LINUX_PR_GET_KEEPCAPS 7 /* Get drop capabilities on setuid */ -#define LINUX_PR_SET_KEEPCAPS 8 /* Set drop capabilities on setuid */ -#define LINUX_PR_SET_NAME 15 /* Set process name. */ -#define LINUX_PR_GET_NAME 16 /* Get process name. */ -#define LINUX_PR_GET_SECCOMP 21 -#define LINUX_PR_SET_SECCOMP 22 -#define LINUX_PR_CAPBSET_READ 23 -#define LINUX_PR_SET_CHILD_SUBREAPER 36 -#define LINUX_PR_SET_NO_NEW_PRIVS 38 -#define LINUX_PR_SET_PTRACER 1499557217 - -#define LINUX_MAX_COMM_LEN 16 /* Maximum length of the process name. */ - -/* For GET/SET DUMPABLE */ -#define LINUX_SUID_DUMP_DISABLE 0 /* Don't coredump setuid processes. */ -#define LINUX_SUID_DUMP_USER 1 /* Dump as user of process. */ -#define LINUX_SUID_DUMP_ROOT 2 /* Dump as root. */ - -#define LINUX_MREMAP_MAYMOVE 1 -#define LINUX_MREMAP_FIXED 2 - -#define LINUX_PATH_MAX 4096 - -/* - * Non-standard aux entry types used in Linux ELF binaries. - */ - -#define LINUX_AT_PLATFORM 15 /* String identifying CPU */ -#define LINUX_AT_HWCAP 16 /* CPU capabilities */ -#define LINUX_AT_CLKTCK 17 /* frequency at which times() increments */ -#define LINUX_AT_SECURE 23 /* secure mode boolean */ -#define LINUX_AT_BASE_PLATFORM 24 /* string identifying real platform, may - * differ from AT_PLATFORM. - */ -#define LINUX_AT_RANDOM 25 /* address of random bytes */ -#define LINUX_AT_HWCAP2 26 /* CPU capabilities, second part */ -#define LINUX_AT_EXECFN 31 /* filename of program */ -#define LINUX_AT_SYSINFO 32 /* vsyscall */ -#define LINUX_AT_SYSINFO_EHDR 33 /* vdso header */ - -#define LINUX_AT_RANDOM_LEN 16 /* size of random bytes */ - -#ifndef LINUX_AT_MINSIGSTKSZ -#define LINUX_AT_MINSIGSTKSZ 51 /* min stack size required by the kernel */ -#endif - -/* Linux sets the i387 to extended precision. */ -#if defined(__i386__) || defined(__amd64__) -#define __LINUX_NPXCW__ 0x37f -#endif - -/* Scheduling policies */ -#define LINUX_SCHED_OTHER 0 -#define LINUX_SCHED_FIFO 1 -#define LINUX_SCHED_RR 2 - -#define LINUX_MAX_RT_PRIO 100 - -struct l_new_utsname { - char sysname[LINUX_MAX_UTSNAME]; - char nodename[LINUX_MAX_UTSNAME]; - char release[LINUX_MAX_UTSNAME]; - char version[LINUX_MAX_UTSNAME]; - char machine[LINUX_MAX_UTSNAME]; - char domainname[LINUX_MAX_UTSNAME]; -}; - -#define LINUX_UTIME_NOW 0x3FFFFFFF -#define LINUX_UTIME_OMIT 0x3FFFFFFE - -extern int stclohz; - -#define LINUX_WNOHANG 0x00000001 -#define LINUX_WUNTRACED 0x00000002 -#define LINUX_WSTOPPED LINUX_WUNTRACED -#define LINUX_WEXITED 0x00000004 -#define LINUX_WCONTINUED 0x00000008 -#define LINUX_WNOWAIT 0x01000000 - -#define __WNOTHREAD 0x20000000 -#define __WALL 0x40000000 -#define __WCLONE 0x80000000 - -/* Linux waitid idtype */ -#define LINUX_P_ALL 0 -#define LINUX_P_PID 1 -#define LINUX_P_PGID 2 -#define LINUX_P_PIDFD 3 - -#define LINUX_RLIMIT_LOCKS 10 -#define LINUX_RLIMIT_SIGPENDING 11 -#define LINUX_RLIMIT_MSGQUEUE 12 -#define LINUX_RLIMIT_NICE 13 -#define LINUX_RLIMIT_RTPRIO 14 -#define LINUX_RLIMIT_RTTIME 15 - -#define LINUX_RLIM_INFINITY (~0UL) - -/* Linux getrandom flags */ -#define LINUX_GRND_NONBLOCK 0x0001 -#define LINUX_GRND_RANDOM 0x0002 - -/* Linux syslog flags */ -#define LINUX_SYSLOG_ACTION_READ_ALL 3 - -/* Linux seccomp flags */ -#define LINUX_SECCOMP_GET_ACTION_AVAIL 2 - -/* Linux /proc/self/oom_score_adj */ -#define LINUX_OOM_SCORE_ADJ_MIN -1000 -#define LINUX_OOM_SCORE_ADJ_MAX 1000 - -#if defined(__aarch64__) || (defined(__amd64__) && !defined(COMPAT_LINUX32)) -int linux_ptrace_status(struct thread *td, int pid, int status); -#endif -void linux_to_bsd_waitopts(int options, int *bsdopts); -struct thread *linux_tdfind(struct thread *, lwpid_t, pid_t); - -struct syscall_info { - uint8_t op; - uint32_t arch; - uint64_t instruction_pointer; - uint64_t stack_pointer; - union { - struct { - uint64_t nr; - uint64_t args[6]; - } entry; - struct { - int64_t rval; - uint8_t is_error; - } exit; - struct { - uint64_t nr; - uint64_t args[6]; - uint32_t ret_data; - } seccomp; - }; -}; - -/* Linux ioprio set/get syscalls */ -#define LINUX_IOPRIO_CLASS_SHIFT 13 -#define LINUX_IOPRIO_CLASS_MASK 0x07 -#define LINUX_IOPRIO_PRIO_MASK ((1UL << LINUX_IOPRIO_CLASS_SHIFT) - 1) - -#define LINUX_IOPRIO_PRIO_CLASS(ioprio) \ - (((ioprio) >> LINUX_IOPRIO_CLASS_SHIFT) & LINUX_IOPRIO_CLASS_MASK) -#define LINUX_IOPRIO_PRIO_DATA(ioprio) ((ioprio) & LINUX_IOPRIO_PRIO_MASK) -#define LINUX_IOPRIO_PRIO(class, data) \ - ((((class) & LINUX_IOPRIO_CLASS_MASK) << LINUX_IOPRIO_CLASS_SHIFT) | \ - ((data) & LINUX_IOPRIO_PRIO_MASK)) - -#define LINUX_IOPRIO_CLASS_NONE 0 -#define LINUX_IOPRIO_CLASS_RT 1 -#define LINUX_IOPRIO_CLASS_BE 2 -#define LINUX_IOPRIO_CLASS_IDLE 3 - -#define LINUX_IOPRIO_MIN 0 -#define LINUX_IOPRIO_MAX 7 - -#define LINUX_IOPRIO_WHO_PROCESS 1 -#define LINUX_IOPRIO_WHO_PGRP 2 -#define LINUX_IOPRIO_WHO_USER 3 - -#endif /* _LINUX_MISC_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2006 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. + */ + +#ifndef _LINUX_MISC_H_ +#define _LINUX_MISC_H_ + +#define LINUX_MAX_PID_NS_LEVEL 32 + + /* bits per mask */ +#define LINUX_NFDBITS sizeof(l_fd_mask) * 8 + +/* + * Miscellaneous + */ +#define LINUX_NAME_MAX 255 +#define LINUX_MAX_UTSNAME 65 + +#define LINUX_CTL_MAXNAME 10 + +/* defines for prctl */ +#define LINUX_PR_SET_PDEATHSIG 1 /* Second arg is a signal. */ +#define LINUX_PR_GET_PDEATHSIG 2 /* + * Second arg is a ptr to return the + * signal. + */ +#define LINUX_PR_GET_DUMPABLE 3 +#define LINUX_PR_SET_DUMPABLE 4 +#define LINUX_PR_GET_KEEPCAPS 7 /* Get drop capabilities on setuid */ +#define LINUX_PR_SET_KEEPCAPS 8 /* Set drop capabilities on setuid */ +#define LINUX_PR_SET_NAME 15 /* Set process name. */ +#define LINUX_PR_GET_NAME 16 /* Get process name. */ +#define LINUX_PR_GET_SECCOMP 21 +#define LINUX_PR_SET_SECCOMP 22 +#define LINUX_PR_CAPBSET_READ 23 +#define LINUX_PR_SET_CHILD_SUBREAPER 36 +#define LINUX_PR_SET_NO_NEW_PRIVS 38 +#define LINUX_PR_SET_PTRACER 1499557217 + +#define LINUX_MAX_COMM_LEN 16 /* Maximum length of the process name. */ + +/* For GET/SET DUMPABLE */ +#define LINUX_SUID_DUMP_DISABLE 0 /* Don't coredump setuid processes. */ +#define LINUX_SUID_DUMP_USER 1 /* Dump as user of process. */ +#define LINUX_SUID_DUMP_ROOT 2 /* Dump as root. */ + +#define LINUX_MREMAP_MAYMOVE 1 +#define LINUX_MREMAP_FIXED 2 + +#define LINUX_PATH_MAX 4096 + +/* + * Non-standard aux entry types used in Linux ELF binaries. + */ + +#define LINUX_AT_PLATFORM 15 /* String identifying CPU */ +#define LINUX_AT_HWCAP 16 /* CPU capabilities */ +#define LINUX_AT_CLKTCK 17 /* frequency at which times() increments */ +#define LINUX_AT_SECURE 23 /* secure mode boolean */ +#define LINUX_AT_BASE_PLATFORM 24 /* string identifying real platform, may + * differ from AT_PLATFORM. + */ +#define LINUX_AT_RANDOM 25 /* address of random bytes */ +#define LINUX_AT_HWCAP2 26 /* CPU capabilities, second part */ +#define LINUX_AT_EXECFN 31 /* filename of program */ +#define LINUX_AT_SYSINFO 32 /* vsyscall */ +#define LINUX_AT_SYSINFO_EHDR 33 /* vdso header */ + +#define LINUX_AT_RANDOM_LEN 16 /* size of random bytes */ + +#ifndef LINUX_AT_MINSIGSTKSZ +#define LINUX_AT_MINSIGSTKSZ 51 /* min stack size required by the kernel */ +#endif + +#define LINUX_AT_CHERI_EXEC_RW_CAP 60 +#define LINUX_AT_CHERI_EXEC_RX_CAP 61 +#define LINUX_AT_CHERI_INTERP_RW_CAP 62 +#define LINUX_AT_CHERI_INTERP_RX_CAP 63 +#define LINUX_AT_CHERI_STACK_CAP 64 +#define LINUX_AT_CHERI_SEAL_CAP 65 +#define LINUX_AT_CHERI_CID_CAP 66 + +#define LINUX_AT_ARGC 80 +#define LINUX_AT_ARGV 81 +#define LINUX_AT_ENVC 82 +#define LINUX_AT_ENVP 83 + +/* Linux sets the i387 to extended precision. */ +#if defined(__i386__) || defined(__amd64__) +#define __LINUX_NPXCW__ 0x37f +#endif + +/* Scheduling policies */ +#define LINUX_SCHED_OTHER 0 +#define LINUX_SCHED_FIFO 1 +#define LINUX_SCHED_RR 2 + +#define LINUX_MAX_RT_PRIO 100 + +struct l_new_utsname { + char sysname[LINUX_MAX_UTSNAME]; + char nodename[LINUX_MAX_UTSNAME]; + char release[LINUX_MAX_UTSNAME]; + char version[LINUX_MAX_UTSNAME]; + char machine[LINUX_MAX_UTSNAME]; + char domainname[LINUX_MAX_UTSNAME]; +}; + +#define LINUX_UTIME_NOW 0x3FFFFFFF +#define LINUX_UTIME_OMIT 0x3FFFFFFE + +extern int stclohz; + +#define LINUX_WNOHANG 0x00000001 +#define LINUX_WUNTRACED 0x00000002 +#define LINUX_WSTOPPED LINUX_WUNTRACED +#define LINUX_WEXITED 0x00000004 +#define LINUX_WCONTINUED 0x00000008 +#define LINUX_WNOWAIT 0x01000000 + +#define __WNOTHREAD 0x20000000 +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +/* Linux waitid idtype */ +#define LINUX_P_ALL 0 +#define LINUX_P_PID 1 +#define LINUX_P_PGID 2 +#define LINUX_P_PIDFD 3 + +#define LINUX_RLIMIT_LOCKS 10 +#define LINUX_RLIMIT_SIGPENDING 11 +#define LINUX_RLIMIT_MSGQUEUE 12 +#define LINUX_RLIMIT_NICE 13 +#define LINUX_RLIMIT_RTPRIO 14 +#define LINUX_RLIMIT_RTTIME 15 + +#define LINUX_RLIM_INFINITY (~0UL) + +/* Linux getrandom flags */ +#define LINUX_GRND_NONBLOCK 0x0001 +#define LINUX_GRND_RANDOM 0x0002 + +/* Linux syslog flags */ +#define LINUX_SYSLOG_ACTION_READ_ALL 3 + +/* Linux seccomp flags */ +#define LINUX_SECCOMP_GET_ACTION_AVAIL 2 + +/* Linux /proc/self/oom_score_adj */ +#define LINUX_OOM_SCORE_ADJ_MIN -1000 +#define LINUX_OOM_SCORE_ADJ_MAX 1000 + +#if defined(__aarch64__) || (defined(__amd64__) && !defined(COMPAT_LINUX32)) +int linux_ptrace_status(struct thread *td, int pid, int status); +#endif +void linux_to_bsd_waitopts(int options, int *bsdopts); +struct thread *linux_tdfind(struct thread *, lwpid_t, pid_t); + +struct syscall_info { + uint8_t op; + uint32_t arch; + uint64_t instruction_pointer; + uint64_t stack_pointer; + union { + struct { + uint64_t nr; + uint64_t args[6]; + } entry; + struct { + int64_t rval; + uint8_t is_error; + } exit; + struct { + uint64_t nr; + uint64_t args[6]; + uint32_t ret_data; + } seccomp; + }; +}; + +/* Linux ioprio set/get syscalls */ +#define LINUX_IOPRIO_CLASS_SHIFT 13 +#define LINUX_IOPRIO_CLASS_MASK 0x07 +#define LINUX_IOPRIO_PRIO_MASK ((1UL << LINUX_IOPRIO_CLASS_SHIFT) - 1) + +#define LINUX_IOPRIO_PRIO_CLASS(ioprio) \ + (((ioprio) >> LINUX_IOPRIO_CLASS_SHIFT) & LINUX_IOPRIO_CLASS_MASK) +#define LINUX_IOPRIO_PRIO_DATA(ioprio) ((ioprio) & LINUX_IOPRIO_PRIO_MASK) +#define LINUX_IOPRIO_PRIO(class, data) \ + ((((class) & LINUX_IOPRIO_CLASS_MASK) << LINUX_IOPRIO_CLASS_SHIFT) | \ + ((data) & LINUX_IOPRIO_PRIO_MASK)) + +#define LINUX_IOPRIO_CLASS_NONE 0 +#define LINUX_IOPRIO_CLASS_RT 1 +#define LINUX_IOPRIO_CLASS_BE 2 +#define LINUX_IOPRIO_CLASS_IDLE 3 + +#define LINUX_IOPRIO_MIN 0 +#define LINUX_IOPRIO_MAX 7 + +#define LINUX_IOPRIO_WHO_PROCESS 1 +#define LINUX_IOPRIO_WHO_PGRP 2 +#define LINUX_IOPRIO_WHO_USER 3 + +#endif /* _LINUX_MISC_H_ */ diff --git a/sys/compat/linux/linux_mmap.c b/sys/compat/linux/linux_mmap.c index e763a77af09f..6af21bcdb96f 100644 --- a/sys/compat/linux/linux_mmap.c +++ b/sys/compat/linux/linux_mmap.c @@ -1,438 +1,464 @@ -/*- - * Copyright (c) 2004 Tim J. Robbins - * Copyright (c) 2002 Doug Rabson - * Copyright (c) 2000 Marcel Moolenaar - * 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 - * in this position and unchanged. - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#define STACK_SIZE (2 * 1024 * 1024) -#define GUARD_SIZE (4 * PAGE_SIZE) - -#if defined(__amd64__) -static void linux_fixup_prot(struct thread *td, int *prot); -#endif - -static int -linux_mmap_check_fp(struct file *fp, int flags, int prot, int maxprot) -{ - - /* Linux mmap() just fails for O_WRONLY files */ - if ((fp->f_flag & FREAD) == 0) - return (EACCES); - - return (0); -} - -int -linux_mmap_common(struct thread *td, uintptr_t addr, size_t len, int prot, - int flags, int fd, off_t pos) -{ - struct mmap_req mr, mr_fixed; - struct proc *p = td->td_proc; - struct vmspace *vms = td->td_proc->p_vmspace; - int bsd_flags, error; - - LINUX_CTR6(mmap2, "0x%lx, %ld, %ld, 0x%08lx, %ld, 0x%lx", - addr, len, prot, flags, fd, pos); - - error = 0; - bsd_flags = 0; - - /* - * Linux mmap(2): - * You must specify exactly one of MAP_SHARED and MAP_PRIVATE - */ - if (!((flags & LINUX_MAP_SHARED) ^ (flags & LINUX_MAP_PRIVATE))) - return (EINVAL); - - if (flags & LINUX_MAP_SHARED) - bsd_flags |= MAP_SHARED; - if (flags & LINUX_MAP_PRIVATE) - bsd_flags |= MAP_PRIVATE; - if (flags & LINUX_MAP_FIXED) - bsd_flags |= MAP_FIXED; - if (flags & LINUX_MAP_ANON) { - /* Enforce pos to be on page boundary, then ignore. */ - if ((pos & PAGE_MASK) != 0) - return (EINVAL); - pos = 0; - bsd_flags |= MAP_ANON; - } else - bsd_flags |= MAP_NOSYNC; - if (flags & LINUX_MAP_GROWSDOWN) - bsd_flags |= MAP_STACK; - -#if defined(__amd64__) - /* - * According to the Linux mmap(2) man page, "MAP_32BIT flag - * is ignored when MAP_FIXED is set." - */ - if ((flags & LINUX_MAP_32BIT) && (flags & LINUX_MAP_FIXED) == 0) - bsd_flags |= MAP_32BIT; - - /* - * PROT_READ, PROT_WRITE, or PROT_EXEC implies PROT_READ and PROT_EXEC - * on Linux/i386 if the binary requires executable stack. - * We do this only for IA32 emulation as on native i386 this is does not - * make sense without PAE. - * - * XXX. Linux checks that the file system is not mounted with noexec. - */ - linux_fixup_prot(td, &prot); -#endif - - /* Linux does not check file descriptor when MAP_ANONYMOUS is set. */ - fd = (bsd_flags & MAP_ANON) ? -1 : fd; - if (flags & LINUX_MAP_GROWSDOWN) { - /* - * The Linux MAP_GROWSDOWN option does not limit auto - * growth of the region. Linux mmap with this option - * takes as addr the initial BOS, and as len, the initial - * region size. It can then grow down from addr without - * limit. However, Linux threads has an implicit internal - * limit to stack size of STACK_SIZE. Its just not - * enforced explicitly in Linux. But, here we impose - * a limit of (STACK_SIZE - GUARD_SIZE) on the stack - * region, since we can do this with our mmap. - * - * Our mmap with MAP_STACK takes addr as the maximum - * downsize limit on BOS, and as len the max size of - * the region. It then maps the top SGROWSIZ bytes, - * and auto grows the region down, up to the limit - * in addr. - * - * If we don't use the MAP_STACK option, the effect - * of this code is to allocate a stack region of a - * fixed size of (STACK_SIZE - GUARD_SIZE). - */ - - if (addr + len > vms->vm_maxsaddr) { - /* - * Some Linux apps will attempt to mmap - * thread stacks near the top of their - * address space. If their TOS is greater - * than vm_maxsaddr, vm_map_growstack() - * will confuse the thread stack with the - * process stack and deliver a SEGV if they - * attempt to grow the thread stack past their - * current stacksize rlimit. To avoid this, - * adjust vm_maxsaddr upwards to reflect - * the current stacksize rlimit rather - * than the maximum possible stacksize. - * It would be better to adjust the - * mmap'ed region, but some apps do not check - * mmap's return value. - */ - PROC_LOCK(p); - vms->vm_maxsaddr = round_page(vms->vm_stacktop) - - lim_cur_proc(p, RLIMIT_STACK); - PROC_UNLOCK(p); - } - - /* - * This gives us our maximum stack size and a new BOS. - * If we're using VM_STACK, then mmap will just map - * the top SGROWSIZ bytes, and let the stack grow down - * to the limit at BOS. If we're not using VM_STACK - * we map the full stack, since we don't have a way - * to autogrow it. - */ - if (len <= STACK_SIZE - GUARD_SIZE) { - addr = addr - (STACK_SIZE - GUARD_SIZE - len); - len = STACK_SIZE - GUARD_SIZE; - } - } - - /* - * FreeBSD is free to ignore the address hint if MAP_FIXED wasn't - * passed. However, some Linux applications, like the ART runtime, - * depend on the hint. If the MAP_FIXED wasn't passed, but the - * address is not zero, try with MAP_FIXED and MAP_EXCL first, - * and fall back to the normal behaviour if that fails. - */ - mr = (struct mmap_req) { - .mr_hint = addr, - .mr_len = len, - .mr_prot = prot, - .mr_flags = bsd_flags, - .mr_fd = fd, - .mr_pos = pos, - .mr_check_fp_fn = linux_mmap_check_fp, - }; - if (addr != 0 && (bsd_flags & MAP_FIXED) == 0 && - (bsd_flags & MAP_EXCL) == 0) { - mr_fixed = mr; - mr_fixed.mr_flags |= MAP_FIXED | MAP_EXCL; - error = kern_mmap(td, &mr_fixed); - if (error == 0) - goto out; - } - - error = kern_mmap(td, &mr); -out: - LINUX_CTR2(mmap2, "return: %d (%p)", error, td->td_retval[0]); - - return (error); -} - -int -linux_mprotect_common(struct thread *td, uintptr_t addr, size_t len, int prot) -{ - int flags = 0; - - /* XXX Ignore PROT_GROWSUP for now. */ - prot &= ~LINUX_PROT_GROWSUP; - if ((prot & ~(LINUX_PROT_GROWSDOWN | PROT_READ | PROT_WRITE | - PROT_EXEC)) != 0) - return (EINVAL); - if ((prot & LINUX_PROT_GROWSDOWN) != 0) { - prot &= ~LINUX_PROT_GROWSDOWN; - flags |= VM_MAP_PROTECT_GROWSDOWN; - } - -#if defined(__amd64__) - linux_fixup_prot(td, &prot); -#endif - return (kern_mprotect(td, addr, len, prot, flags)); -} - -/* - * Implement Linux madvise(MADV_DONTNEED), which has unusual semantics: for - * anonymous memory, pages in the range are immediately discarded. - */ -static int -linux_madvise_dontneed(struct thread *td, vm_offset_t start, vm_offset_t end) -{ - vm_map_t map; - vm_map_entry_t entry; - vm_object_t backing_object, object; - vm_offset_t estart, eend; - vm_pindex_t pstart, pend; - int error; - - map = &td->td_proc->p_vmspace->vm_map; - - if (!vm_map_range_valid(map, start, end)) - return (EINVAL); - start = trunc_page(start); - end = round_page(end); - - error = 0; - vm_map_lock_read(map); - if (!vm_map_lookup_entry(map, start, &entry)) - entry = vm_map_entry_succ(entry); - for (; entry->start < end; entry = vm_map_entry_succ(entry)) { - if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) - continue; - - if (entry->wired_count != 0) { - error = EINVAL; - break; - } - - object = entry->object.vm_object; - if (object == NULL) - continue; - if ((object->flags & (OBJ_UNMANAGED | OBJ_FICTITIOUS)) != 0) - continue; - - pstart = OFF_TO_IDX(entry->offset); - if (start > entry->start) { - pstart += atop(start - entry->start); - estart = start; - } else { - estart = entry->start; - } - pend = OFF_TO_IDX(entry->offset) + - atop(entry->end - entry->start); - if (entry->end > end) { - pend -= atop(entry->end - end); - eend = end; - } else { - eend = entry->end; - } - - if ((object->flags & (OBJ_ANON | OBJ_ONEMAPPING)) == - (OBJ_ANON | OBJ_ONEMAPPING)) { - /* - * Singly-mapped anonymous memory is discarded. This - * does not match Linux's semantics when the object - * belongs to a shadow chain of length > 1, since - * subsequent faults may retrieve pages from an - * intermediate anonymous object. However, handling - * this case correctly introduces a fair bit of - * complexity. - */ - VM_OBJECT_WLOCK(object); - if ((object->flags & OBJ_ONEMAPPING) != 0) { - vm_object_collapse(object); - vm_object_page_remove(object, pstart, pend, 0); - backing_object = object->backing_object; - if (backing_object != NULL && - (backing_object->flags & OBJ_ANON) != 0) - linux_msg(td, - "possibly incorrect MADV_DONTNEED"); - VM_OBJECT_WUNLOCK(object); - continue; - } - VM_OBJECT_WUNLOCK(object); - } - - /* - * Handle shared mappings. Remove them outright instead of - * calling pmap_advise(), for consistency with Linux. - */ - pmap_remove(map->pmap, estart, eend); - vm_object_madvise(object, pstart, pend, MADV_DONTNEED); - } - vm_map_unlock_read(map); - - return (error); -} - -int -linux_madvise_common(struct thread *td, uintptr_t addr, size_t len, int behav) -{ - - switch (behav) { - case LINUX_MADV_NORMAL: - return (kern_madvise(td, addr, len, MADV_NORMAL)); - case LINUX_MADV_RANDOM: - return (kern_madvise(td, addr, len, MADV_RANDOM)); - case LINUX_MADV_SEQUENTIAL: - return (kern_madvise(td, addr, len, MADV_SEQUENTIAL)); - case LINUX_MADV_WILLNEED: - return (kern_madvise(td, addr, len, MADV_WILLNEED)); - case LINUX_MADV_DONTNEED: - return (linux_madvise_dontneed(td, addr, addr + len)); - case LINUX_MADV_FREE: - return (kern_madvise(td, addr, len, MADV_FREE)); - case LINUX_MADV_REMOVE: - linux_msg(curthread, "unsupported madvise MADV_REMOVE"); - return (EINVAL); - case LINUX_MADV_DONTFORK: - return (kern_minherit(td, addr, len, INHERIT_NONE)); - case LINUX_MADV_DOFORK: - return (kern_minherit(td, addr, len, INHERIT_COPY)); - case LINUX_MADV_MERGEABLE: - linux_msg(curthread, "unsupported madvise MADV_MERGEABLE"); - return (EINVAL); - case LINUX_MADV_UNMERGEABLE: - /* We don't merge anyway. */ - return (0); - case LINUX_MADV_HUGEPAGE: - /* Ignored; on FreeBSD huge pages are always on. */ - return (0); - case LINUX_MADV_NOHUGEPAGE: -#if 0 - /* - * Don't warn - Firefox uses it a lot, and in real Linux it's - * an optional feature. - */ - linux_msg(curthread, "unsupported madvise MADV_NOHUGEPAGE"); -#endif - return (EINVAL); - case LINUX_MADV_DONTDUMP: - return (kern_madvise(td, addr, len, MADV_NOCORE)); - case LINUX_MADV_DODUMP: - return (kern_madvise(td, addr, len, MADV_CORE)); - case LINUX_MADV_WIPEONFORK: - return (kern_minherit(td, addr, len, INHERIT_ZERO)); - case LINUX_MADV_KEEPONFORK: - return (kern_minherit(td, addr, len, INHERIT_COPY)); - case LINUX_MADV_HWPOISON: - linux_msg(curthread, "unsupported madvise MADV_HWPOISON"); - return (EINVAL); - case LINUX_MADV_SOFT_OFFLINE: - linux_msg(curthread, "unsupported madvise MADV_SOFT_OFFLINE"); - return (EINVAL); - case -1: - /* - * -1 is sometimes used as a dummy value to detect simplistic - * madvise(2) stub implementations. This safeguard is used by - * BoringSSL, for example, before assuming MADV_WIPEONFORK is - * safe to use. Don't produce an "unsupported" error message - * for this special dummy value, which is unlikely to be used - * by any new advisory behavior feature. - */ - return (EINVAL); - default: - linux_msg(curthread, "unsupported madvise behav %d", behav); - return (EINVAL); - } -} - -#if defined(__amd64__) -static void -linux_fixup_prot(struct thread *td, int *prot) -{ - struct linux_pemuldata *pem; - - if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && *prot & PROT_READ) { - pem = pem_find(td->td_proc); - if (pem->persona & LINUX_READ_IMPLIES_EXEC) - *prot |= PROT_EXEC; - } - -} -#endif -// CHERI CHANGES START -// { -// "updated": 20230509, -// "target_type": "kernel", -// "changes": [ -// "support" -// ], -// "changes_purecap": [ -// "pointer_as_integer" -// ], -// "change_comment": "PROT_MAX" -// } -// CHERI CHANGES END +/*- + * Copyright (c) 2004 Tim J. Robbins + * Copyright (c) 2002 Doug Rabson + * Copyright (c) 2000 Marcel Moolenaar + * 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 + * in this position and unchanged. + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#define STACK_SIZE (2 * 1024 * 1024) +#define GUARD_SIZE (4 * PAGE_SIZE) + +#if defined(__amd64__) +static void linux_fixup_prot(struct thread *td, int *prot); +#endif + +static int +linux_mmap_check_fp(struct file *fp, int flags, int prot, int maxprot) +{ + + /* Linux mmap() just fails for O_WRONLY files */ + if ((fp->f_flag & FREAD) == 0) + return (EACCES); + + return (0); +} + +#if __has_feature(capabilities) +int +linux_mmap_common(struct thread *td, uintptr_t addr, size_t len, int prot, + int flags, int fd, off_t pos, int kern_flags, void * __capability source_cap) +#else +int +linux_mmap_common(struct thread *td, uintptr_t addr, size_t len, int prot, + int flags, int fd, off_t pos) +#endif +{ + struct mmap_req mr, mr_fixed; + struct proc *p = td->td_proc; + struct vmspace *vms = td->td_proc->p_vmspace; + int bsd_flags, error; + + LINUX_CTR6(mmap2, "0x%lx, %ld, %ld, 0x%08lx, %ld, 0x%lx", + addr, len, prot, flags, fd, pos); + + error = 0; + bsd_flags = 0; + + /* + * Linux mmap(2): + * You must specify exactly one of MAP_SHARED and MAP_PRIVATE + */ + if (!((flags & LINUX_MAP_SHARED) ^ (flags & LINUX_MAP_PRIVATE))) + return (EINVAL); + + if (flags & LINUX_MAP_SHARED) + bsd_flags |= MAP_SHARED; + if (flags & LINUX_MAP_PRIVATE) + bsd_flags |= MAP_PRIVATE; + if (flags & LINUX_MAP_FIXED) + bsd_flags |= MAP_FIXED; + if (flags & LINUX_MAP_ANON) { + /* Enforce pos to be on page boundary, then ignore. */ + if ((pos & PAGE_MASK) != 0) + return (EINVAL); + pos = 0; + bsd_flags |= MAP_ANON; + } else + bsd_flags |= MAP_NOSYNC; + if (flags & LINUX_MAP_GROWSDOWN) +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) && !defined(COMPAT_LINUX32) + return (EOPNOTSUPP); +#else + bsd_flags |= MAP_STACK; +#endif + +#if defined(__amd64__) + /* + * According to the Linux mmap(2) man page, "MAP_32BIT flag + * is ignored when MAP_FIXED is set." + */ + if ((flags & LINUX_MAP_32BIT) && (flags & LINUX_MAP_FIXED) == 0) + bsd_flags |= MAP_32BIT; + + /* + * PROT_READ, PROT_WRITE, or PROT_EXEC implies PROT_READ and PROT_EXEC + * on Linux/i386 if the binary requires executable stack. + * We do this only for IA32 emulation as on native i386 this is does not + * make sense without PAE. + * + * XXX. Linux checks that the file system is not mounted with noexec. + */ + linux_fixup_prot(td, &prot); +#endif + + /* Linux does not check file descriptor when MAP_ANONYMOUS is set. */ + fd = (bsd_flags & MAP_ANON) ? -1 : fd; + if (flags & LINUX_MAP_GROWSDOWN) { + /* + * The Linux MAP_GROWSDOWN option does not limit auto + * growth of the region. Linux mmap with this option + * takes as addr the initial BOS, and as len, the initial + * region size. It can then grow down from addr without + * limit. However, Linux threads has an implicit internal + * limit to stack size of STACK_SIZE. Its just not + * enforced explicitly in Linux. But, here we impose + * a limit of (STACK_SIZE - GUARD_SIZE) on the stack + * region, since we can do this with our mmap. + * + * Our mmap with MAP_STACK takes addr as the maximum + * downsize limit on BOS, and as len the max size of + * the region. It then maps the top SGROWSIZ bytes, + * and auto grows the region down, up to the limit + * in addr. + * + * If we don't use the MAP_STACK option, the effect + * of this code is to allocate a stack region of a + * fixed size of (STACK_SIZE - GUARD_SIZE). + */ + + if (addr + len > vms->vm_maxsaddr) { + /* + * Some Linux apps will attempt to mmap + * thread stacks near the top of their + * address space. If their TOS is greater + * than vm_maxsaddr, vm_map_growstack() + * will confuse the thread stack with the + * process stack and deliver a SEGV if they + * attempt to grow the thread stack past their + * current stacksize rlimit. To avoid this, + * adjust vm_maxsaddr upwards to reflect + * the current stacksize rlimit rather + * than the maximum possible stacksize. + * It would be better to adjust the + * mmap'ed region, but some apps do not check + * mmap's return value. + */ + PROC_LOCK(p); + vms->vm_maxsaddr = round_page(vms->vm_stacktop) - + lim_cur_proc(p, RLIMIT_STACK); + PROC_UNLOCK(p); + } + + /* + * This gives us our maximum stack size and a new BOS. + * If we're using VM_STACK, then mmap will just map + * the top SGROWSIZ bytes, and let the stack grow down + * to the limit at BOS. If we're not using VM_STACK + * we map the full stack, since we don't have a way + * to autogrow it. + */ + if (len <= STACK_SIZE - GUARD_SIZE) { + addr = addr - (STACK_SIZE - GUARD_SIZE - len); + len = STACK_SIZE - GUARD_SIZE; + } + } + + // If MAP_FIXED specified and we are creating new reservation + // requirements, then MAP_EXCL is implied to prevent changing + // page contents without permission. +#if __has_feature(capabilities) + if (kern_flags & MAP_RESERVATION_CREATE) + if (bsd_flags & MAP_FIXED) + bsd_flags |= MAP_EXCL; +#endif + + /* + * FreeBSD is free to ignore the address hint if MAP_FIXED wasn't + * passed. However, some Linux applications, like the ART runtime, + * depend on the hint. If the MAP_FIXED wasn't passed, but the + * address is not zero, try with MAP_FIXED and MAP_EXCL first, + * and fall back to the normal behaviour if that fails. + */ + mr = (struct mmap_req) { + .mr_hint = addr, + .mr_len = len, + .mr_prot = prot, + .mr_flags = bsd_flags, + .mr_fd = fd, + .mr_pos = pos, + .mr_check_fp_fn = linux_mmap_check_fp, +#if __has_feature(capabilities) + .mr_kern_flags = kern_flags, + .mr_source_cap = source_cap, + .mr_max_addr = cheri_gettop(source_cap), +#endif + }; + if (addr != 0 && (bsd_flags & MAP_FIXED) == 0 && + (bsd_flags & MAP_EXCL) == 0) { + mr_fixed = mr; + mr_fixed.mr_flags |= MAP_FIXED | MAP_EXCL; + error = kern_mmap(td, &mr_fixed); + if (error == 0) + goto out; + } + + error = kern_mmap(td, &mr); +out: + LINUX_CTR2(mmap2, "return: %d (%p)", error, td->td_retval[0]); + + return (error); +} + +int +linux_mprotect_common(struct thread *td, uintptr_t addr, size_t len, int prot) +{ + int flags = 0; + + /* XXX Ignore PROT_GROWSUP for now. */ + prot &= ~LINUX_PROT_GROWSUP; + if ((prot & ~(LINUX_PROT_GROWSDOWN | PROT_READ | PROT_WRITE | + PROT_EXEC)) != 0) + return (EINVAL); + if ((prot & LINUX_PROT_GROWSDOWN) != 0) { + prot &= ~LINUX_PROT_GROWSDOWN; + flags |= VM_MAP_PROTECT_GROWSDOWN; + } + +#if defined(__amd64__) + linux_fixup_prot(td, &prot); +#endif + return (kern_mprotect(td, addr, len, prot, flags)); +} + +/* + * Implement Linux madvise(MADV_DONTNEED), which has unusual semantics: for + * anonymous memory, pages in the range are immediately discarded. + */ +static int +linux_madvise_dontneed(struct thread *td, vm_offset_t start, vm_offset_t end) +{ + vm_map_t map; + vm_map_entry_t entry; + vm_object_t backing_object, object; + vm_offset_t estart, eend; + vm_pindex_t pstart, pend; + int error; + + map = &td->td_proc->p_vmspace->vm_map; + + if (!vm_map_range_valid(map, start, end)) + return (EINVAL); + start = trunc_page(start); + end = round_page(end); + + error = 0; + vm_map_lock_read(map); + if (!vm_map_lookup_entry(map, start, &entry)) + entry = vm_map_entry_succ(entry); + for (; entry->start < end; entry = vm_map_entry_succ(entry)) { + if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) + continue; + + if (entry->wired_count != 0) { + error = EINVAL; + break; + } + + object = entry->object.vm_object; + if (object == NULL) + continue; + if ((object->flags & (OBJ_UNMANAGED | OBJ_FICTITIOUS)) != 0) + continue; + + pstart = OFF_TO_IDX(entry->offset); + if (start > entry->start) { + pstart += atop(start - entry->start); + estart = start; + } else { + estart = entry->start; + } + pend = OFF_TO_IDX(entry->offset) + + atop(entry->end - entry->start); + if (entry->end > end) { + pend -= atop(entry->end - end); + eend = end; + } else { + eend = entry->end; + } + + if ((object->flags & (OBJ_ANON | OBJ_ONEMAPPING)) == + (OBJ_ANON | OBJ_ONEMAPPING)) { + /* + * Singly-mapped anonymous memory is discarded. This + * does not match Linux's semantics when the object + * belongs to a shadow chain of length > 1, since + * subsequent faults may retrieve pages from an + * intermediate anonymous object. However, handling + * this case correctly introduces a fair bit of + * complexity. + */ + VM_OBJECT_WLOCK(object); + if ((object->flags & OBJ_ONEMAPPING) != 0) { + vm_object_collapse(object); + vm_object_page_remove(object, pstart, pend, 0); + backing_object = object->backing_object; + if (backing_object != NULL && + (backing_object->flags & OBJ_ANON) != 0) + linux_msg(td, + "possibly incorrect MADV_DONTNEED"); + VM_OBJECT_WUNLOCK(object); + continue; + } + VM_OBJECT_WUNLOCK(object); + } + + /* + * Handle shared mappings. Remove them outright instead of + * calling pmap_advise(), for consistency with Linux. + */ + pmap_remove(map->pmap, estart, eend); + vm_object_madvise(object, pstart, pend, MADV_DONTNEED); + } + vm_map_unlock_read(map); + + return (error); +} + +int +linux_madvise_common(struct thread *td, uintptr_t addr, size_t len, int behav) +{ + + switch (behav) { + case LINUX_MADV_NORMAL: + return (kern_madvise(td, addr, len, MADV_NORMAL)); + case LINUX_MADV_RANDOM: + return (kern_madvise(td, addr, len, MADV_RANDOM)); + case LINUX_MADV_SEQUENTIAL: + return (kern_madvise(td, addr, len, MADV_SEQUENTIAL)); + case LINUX_MADV_WILLNEED: + return (kern_madvise(td, addr, len, MADV_WILLNEED)); + case LINUX_MADV_DONTNEED: + return (linux_madvise_dontneed(td, addr, addr + len)); + case LINUX_MADV_FREE: + return (kern_madvise(td, addr, len, MADV_FREE)); + case LINUX_MADV_REMOVE: + linux_msg(curthread, "unsupported madvise MADV_REMOVE"); + return (EINVAL); + case LINUX_MADV_DONTFORK: + return (kern_minherit(td, addr, len, INHERIT_NONE)); + case LINUX_MADV_DOFORK: + return (kern_minherit(td, addr, len, INHERIT_COPY)); + case LINUX_MADV_MERGEABLE: + linux_msg(curthread, "unsupported madvise MADV_MERGEABLE"); + return (EINVAL); + case LINUX_MADV_UNMERGEABLE: + /* We don't merge anyway. */ + return (0); + case LINUX_MADV_HUGEPAGE: + /* Ignored; on FreeBSD huge pages are always on. */ + return (0); + case LINUX_MADV_NOHUGEPAGE: +#if 0 + /* + * Don't warn - Firefox uses it a lot, and in real Linux it's + * an optional feature. + */ + linux_msg(curthread, "unsupported madvise MADV_NOHUGEPAGE"); +#endif + return (EINVAL); + case LINUX_MADV_DONTDUMP: + return (kern_madvise(td, addr, len, MADV_NOCORE)); + case LINUX_MADV_DODUMP: + return (kern_madvise(td, addr, len, MADV_CORE)); + case LINUX_MADV_WIPEONFORK: + return (kern_minherit(td, addr, len, INHERIT_ZERO)); + case LINUX_MADV_KEEPONFORK: + return (kern_minherit(td, addr, len, INHERIT_COPY)); + case LINUX_MADV_HWPOISON: + linux_msg(curthread, "unsupported madvise MADV_HWPOISON"); + return (EINVAL); + case LINUX_MADV_SOFT_OFFLINE: + linux_msg(curthread, "unsupported madvise MADV_SOFT_OFFLINE"); + return (EINVAL); + case -1: + /* + * -1 is sometimes used as a dummy value to detect simplistic + * madvise(2) stub implementations. This safeguard is used by + * BoringSSL, for example, before assuming MADV_WIPEONFORK is + * safe to use. Don't produce an "unsupported" error message + * for this special dummy value, which is unlikely to be used + * by any new advisory behavior feature. + */ + return (EINVAL); + default: + linux_msg(curthread, "unsupported madvise behav %d", behav); + return (EINVAL); + } +} + +#if defined(__amd64__) +static void +linux_fixup_prot(struct thread *td, int *prot) +{ + struct linux_pemuldata *pem; + + if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && *prot & PROT_READ) { + pem = pem_find(td->td_proc); + if (pem->persona & LINUX_READ_IMPLIES_EXEC) + *prot |= PROT_EXEC; + } + +} +#endif +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "kernel", +// "changes": [ +// "support" +// ], +// "changes_purecap": [ +// "pointer_as_integer" +// ], +// "change_comment": "PROT_MAX" +// } +// CHERI CHANGES END diff --git a/sys/compat/linux/linux_mmap.h b/sys/compat/linux/linux_mmap.h index 043dec9d40b7..91486f038470 100644 --- a/sys/compat/linux/linux_mmap.h +++ b/sys/compat/linux/linux_mmap.h @@ -1,71 +1,76 @@ -/*- - * Copyright (c) 2004 Tim J. Robbins - * Copyright (c) 2002 Doug Rabson - * Copyright (c) 2000 Marcel Moolenaar - * 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 - * in this position and unchanged. - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - */ - -#ifndef _LINUX_MMAP_H_ -#define _LINUX_MMAP_H_ - -/* mmap options */ -#define LINUX_MAP_SHARED 0x0001 -#define LINUX_MAP_PRIVATE 0x0002 -#define LINUX_MAP_FIXED 0x0010 -#define LINUX_MAP_ANON 0x0020 -#define LINUX_MAP_32BIT 0x0040 -#define LINUX_MAP_GROWSDOWN 0x0100 - -#define LINUX_PROT_GROWSDOWN 0x01000000 -#define LINUX_PROT_GROWSUP 0x02000000 - -#define LINUX_MADV_NORMAL 0 -#define LINUX_MADV_RANDOM 1 -#define LINUX_MADV_SEQUENTIAL 2 -#define LINUX_MADV_WILLNEED 3 -#define LINUX_MADV_DONTNEED 4 -#define LINUX_MADV_FREE 8 -#define LINUX_MADV_REMOVE 9 -#define LINUX_MADV_DONTFORK 10 -#define LINUX_MADV_DOFORK 11 -#define LINUX_MADV_MERGEABLE 12 -#define LINUX_MADV_UNMERGEABLE 13 -#define LINUX_MADV_HUGEPAGE 14 -#define LINUX_MADV_NOHUGEPAGE 15 -#define LINUX_MADV_DONTDUMP 16 -#define LINUX_MADV_DODUMP 17 -#define LINUX_MADV_WIPEONFORK 18 -#define LINUX_MADV_KEEPONFORK 19 -#define LINUX_MADV_HWPOISON 100 -#define LINUX_MADV_SOFT_OFFLINE 101 - -int linux_mmap_common(struct thread *, uintptr_t, size_t, int, int, - int, off_t); -int linux_mprotect_common(struct thread *, uintptr_t, size_t, int); -int linux_madvise_common(struct thread *, uintptr_t, size_t, int); - -#endif /* _LINUX_MMAP_H_ */ +/*- + * Copyright (c) 2004 Tim J. Robbins + * Copyright (c) 2002 Doug Rabson + * Copyright (c) 2000 Marcel Moolenaar + * 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 + * in this position and unchanged. + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#ifndef _LINUX_MMAP_H_ +#define _LINUX_MMAP_H_ + +/* mmap options */ +#define LINUX_MAP_SHARED 0x0001 +#define LINUX_MAP_PRIVATE 0x0002 +#define LINUX_MAP_FIXED 0x0010 +#define LINUX_MAP_ANON 0x0020 +#define LINUX_MAP_32BIT 0x0040 +#define LINUX_MAP_GROWSDOWN 0x0100 + +#define LINUX_PROT_GROWSDOWN 0x01000000 +#define LINUX_PROT_GROWSUP 0x02000000 + +#define LINUX_MADV_NORMAL 0 +#define LINUX_MADV_RANDOM 1 +#define LINUX_MADV_SEQUENTIAL 2 +#define LINUX_MADV_WILLNEED 3 +#define LINUX_MADV_DONTNEED 4 +#define LINUX_MADV_FREE 8 +#define LINUX_MADV_REMOVE 9 +#define LINUX_MADV_DONTFORK 10 +#define LINUX_MADV_DOFORK 11 +#define LINUX_MADV_MERGEABLE 12 +#define LINUX_MADV_UNMERGEABLE 13 +#define LINUX_MADV_HUGEPAGE 14 +#define LINUX_MADV_NOHUGEPAGE 15 +#define LINUX_MADV_DONTDUMP 16 +#define LINUX_MADV_DODUMP 17 +#define LINUX_MADV_WIPEONFORK 18 +#define LINUX_MADV_KEEPONFORK 19 +#define LINUX_MADV_HWPOISON 100 +#define LINUX_MADV_SOFT_OFFLINE 101 + +#if __has_feature(capabilities) +int linux_mmap_common(struct thread *, uintptr_t, size_t, int, int, + int, off_t, int, void * __capability); +#else +int linux_mmap_common(struct thread *, uintptr_t, size_t, int, int, + int, off_t); +#endif +int linux_mprotect_common(struct thread *, uintptr_t, size_t, int); +int linux_madvise_common(struct thread *, uintptr_t, size_t, int); + +#endif /* _LINUX_MMAP_H_ */ diff --git a/sys/compat/linux/linux_netlink.c b/sys/compat/linux/linux_netlink.c index f51838ee00d7..6c1c1decd45b 100644 --- a/sys/compat/linux/linux_netlink.c +++ b/sys/compat/linux/linux_netlink.c @@ -1,623 +1,623 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2022 Alexander V. Chernikov - * - * 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 "opt_inet.h" -#include "opt_inet6.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define DEBUG_MOD_NAME nl_linux -#define DEBUG_MAX_LEVEL LOG_DEBUG3 -#include -_DECLARE_DEBUG(LOG_INFO); - -static bool -valid_rta_size(const struct rtattr *rta, int sz) -{ - return (NL_RTA_DATA_LEN(rta) == sz); -} - -static bool -valid_rta_u32(const struct rtattr *rta) -{ - return (valid_rta_size(rta, sizeof(uint32_t))); -} - -static uint32_t -_rta_get_uint32(const struct rtattr *rta) -{ - return (*((const uint32_t *)NL_RTA_DATA_CONST(rta))); -} - -static int -rtnl_neigh_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) -{ - struct ndmsg *ndm = (struct ndmsg *)(hdr + 1); - sa_family_t f; - - if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct ndmsg)) - return (EBADMSG); - if ((f = linux_to_bsd_domain(ndm->ndm_family)) == AF_UNKNOWN) - return (EPFNOSUPPORT); - - ndm->ndm_family = f; - - return (0); -} - -static int -rtnl_ifaddr_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) -{ - struct ifaddrmsg *ifam = (struct ifaddrmsg *)(hdr + 1); - sa_family_t f; - - if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + - offsetof(struct ifaddrmsg, ifa_family) + sizeof(ifam->ifa_family)) - return (EBADMSG); - if ((f = linux_to_bsd_domain(ifam->ifa_family)) == AF_UNKNOWN) - return (EPFNOSUPPORT); - - ifam->ifa_family = f; - - return (0); -} - -/* - * XXX: in case of error state of hdr is inconsistent. - */ -static int -rtnl_route_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) -{ - /* Tweak address families and default fib only */ - struct rtmsg *rtm = (struct rtmsg *)(hdr + 1); - struct nlattr *nla, *nla_head; - int attrs_len; - sa_family_t f; - - if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct rtmsg)) - return (EBADMSG); - if ((f = linux_to_bsd_domain(rtm->rtm_family)) == AF_UNKNOWN) - return (EPFNOSUPPORT); - rtm->rtm_family = f; - - if (rtm->rtm_table == 254) - rtm->rtm_table = 0; - - attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr); - attrs_len -= NETLINK_ALIGN(sizeof(struct rtmsg)); - nla_head = (struct nlattr *)((char *)rtm + NETLINK_ALIGN(sizeof(struct rtmsg))); - - NLA_FOREACH(nla, nla_head, attrs_len) { - RT_LOG(LOG_DEBUG3, "GOT type %d len %d total %d", - nla->nla_type, nla->nla_len, attrs_len); - struct rtattr *rta = (struct rtattr *)nla; - if (rta->rta_len < sizeof(struct rtattr)) { - break; - } - switch (rta->rta_type) { - case NL_RTA_TABLE: - if (!valid_rta_u32(rta)) - return (EBADMSG); - rtm->rtm_table = 0; - uint32_t fibnum = _rta_get_uint32(rta); - RT_LOG(LOG_DEBUG3, "GET RTABLE: %u", fibnum); - if (fibnum == 254) { - *((uint32_t *)NL_RTA_DATA(rta)) = 0; - } - break; - } - } - - return (0); -} - -static int -rtnl_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) -{ - - switch (hdr->nlmsg_type) { - case NL_RTM_GETROUTE: - case NL_RTM_NEWROUTE: - case NL_RTM_DELROUTE: - return (rtnl_route_from_linux(hdr, npt)); - case NL_RTM_GETNEIGH: - return (rtnl_neigh_from_linux(hdr, npt)); - case NL_RTM_GETADDR: - return (rtnl_ifaddr_from_linux(hdr, npt)); - /* Silence warning for the messages where no translation is required */ - case NL_RTM_NEWLINK: - case NL_RTM_DELLINK: - case NL_RTM_GETLINK: - break; - default: - RT_LOG(LOG_DEBUG, "Passing message type %d untranslated", - hdr->nlmsg_type); - /* XXXGL: maybe return error? */ - } - - return (0); -} - -static int -nlmsg_from_linux(int netlink_family, struct nlmsghdr **hdr, - struct nl_pstate *npt) -{ - switch (netlink_family) { - case NETLINK_ROUTE: - return (rtnl_from_linux(*hdr, npt)); - } - - return (0); -} - - -/************************************************************ - * Kernel -> Linux - ************************************************************/ - -static bool -handle_default_out(struct nlmsghdr *hdr, struct nl_writer *nw) -{ - char *out_hdr; - out_hdr = nlmsg_reserve_data(nw, NLMSG_ALIGN(hdr->nlmsg_len), char); - - if (out_hdr != NULL) { - memcpy(out_hdr, hdr, hdr->nlmsg_len); - nw->num_messages++; - return (true); - } - return (false); -} - -static bool -nlmsg_copy_header(struct nlmsghdr *hdr, struct nl_writer *nw) -{ - return (nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, hdr->nlmsg_type, - hdr->nlmsg_flags, 0)); -} - -static void * -_nlmsg_copy_next_header(struct nlmsghdr *hdr, struct nl_writer *nw, int sz) -{ - void *next_hdr = nlmsg_reserve_data(nw, sz, void); - memcpy(next_hdr, hdr + 1, NLMSG_ALIGN(sz)); - - return (next_hdr); -} -#define nlmsg_copy_next_header(_hdr, _ns, _t) \ - ((_t *)(_nlmsg_copy_next_header(_hdr, _ns, sizeof(_t)))) - -static bool -nlmsg_copy_nla(const struct nlattr *nla_orig, struct nl_writer *nw) -{ - struct nlattr *nla = nlmsg_reserve_data(nw, nla_orig->nla_len, struct nlattr); - if (nla != NULL) { - memcpy(nla, nla_orig, nla_orig->nla_len); - return (true); - } - return (false); -} - -/* - * Translate a FreeBSD interface name to a Linux interface name. - */ -static bool -nlmsg_translate_ifname_nla(struct nlattr *nla, struct nl_writer *nw) -{ - char ifname[LINUX_IFNAMSIZ]; - - if (ifname_bsd_to_linux_name((char *)(nla + 1), ifname, - sizeof(ifname)) <= 0) - return (false); - return (nlattr_add_string(nw, IFLA_IFNAME, ifname)); -} - -#define LINUX_NLA_UNHANDLED -1 -/* - * Translate a FreeBSD attribute to a Linux attribute. - * Returns LINUX_NLA_UNHANDLED when the attribute is not processed - * and the caller must take care of it, otherwise the result is returned. - */ -static int -nlmsg_translate_all_nla(struct nlmsghdr *hdr, struct nlattr *nla, - struct nl_writer *nw) -{ - - switch (hdr->nlmsg_type) { - case NL_RTM_NEWLINK: - case NL_RTM_DELLINK: - case NL_RTM_GETLINK: - switch (nla->nla_type) { - case IFLA_IFNAME: - return (nlmsg_translate_ifname_nla(nla, nw)); - default: - break; - } - default: - break; - } - return (LINUX_NLA_UNHANDLED); -} - -static bool -nlmsg_copy_all_nla(struct nlmsghdr *hdr, int raw_hdrlen, struct nl_writer *nw) -{ - struct nlattr *nla; - int ret; - - int hdrlen = NETLINK_ALIGN(raw_hdrlen); - int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; - struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen); - - NLA_FOREACH(nla, nla_head, attrs_len) { - RT_LOG(LOG_DEBUG3, "reading attr %d len %d", nla->nla_type, nla->nla_len); - if (nla->nla_len < sizeof(struct nlattr)) { - return (false); - } - ret = nlmsg_translate_all_nla(hdr, nla, nw); - if (ret == LINUX_NLA_UNHANDLED) - ret = nlmsg_copy_nla(nla, nw); - if (!ret) - return (false); - } - return (true); -} -#undef LINUX_NLA_UNHANDLED - -static unsigned int -rtnl_if_flags_to_linux(unsigned int if_flags) -{ - unsigned int result = 0; - - for (int i = 0; i < 31; i++) { - unsigned int flag = 1 << i; - if (!(flag & if_flags)) - continue; - switch (flag) { - case IFF_UP: - case IFF_BROADCAST: - case IFF_DEBUG: - case IFF_LOOPBACK: - case IFF_POINTOPOINT: - case IFF_DRV_RUNNING: - case IFF_NOARP: - case IFF_PROMISC: - case IFF_ALLMULTI: - result |= flag; - break; - case IFF_NEEDSEPOCH: - case IFF_DRV_OACTIVE: - case IFF_SIMPLEX: - case IFF_LINK0: - case IFF_LINK1: - case IFF_LINK2: - case IFF_CANTCONFIG: - case IFF_PPROMISC: - case IFF_MONITOR: - case IFF_STATICARP: - case IFF_STICKYARP: - case IFF_DYING: - case IFF_RENAMING: - /* No Linux analogue */ - break; - case IFF_MULTICAST: - result |= 1 << 12; - } - } - return (result); -} - -static bool -rtnl_newlink_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, - struct nl_writer *nw) -{ - if (!nlmsg_copy_header(hdr, nw)) - return (false); - - struct ifinfomsg *ifinfo; - ifinfo = nlmsg_copy_next_header(hdr, nw, struct ifinfomsg); - - ifinfo->ifi_family = bsd_to_linux_domain(ifinfo->ifi_family); - /* Convert interface type */ - switch (ifinfo->ifi_type) { - case IFT_ETHER: - ifinfo->ifi_type = LINUX_ARPHRD_ETHER; - break; - } - ifinfo->ifi_flags = rtnl_if_flags_to_linux(ifinfo->ifi_flags); - - /* Copy attributes unchanged */ - if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifinfomsg), nw)) - return (false); - - /* make ip(8) happy */ - if (!nlattr_add_string(nw, IFLA_QDISC, "noqueue")) - return (false); - - if (!nlattr_add_u32(nw, IFLA_TXQLEN, 1000)) - return (false); - - nlmsg_end(nw); - RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); - return (true); -} - -static bool -rtnl_newaddr_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, - struct nl_writer *nw) -{ - if (!nlmsg_copy_header(hdr, nw)) - return (false); - - struct ifaddrmsg *ifamsg; - ifamsg = nlmsg_copy_next_header(hdr, nw, struct ifaddrmsg); - - ifamsg->ifa_family = bsd_to_linux_domain(ifamsg->ifa_family); - /* XXX: fake ifa_flags? */ - - /* Copy attributes unchanged */ - if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifaddrmsg), nw)) - return (false); - - nlmsg_end(nw); - RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); - return (true); -} - -static bool -rtnl_newneigh_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, - struct nl_writer *nw) -{ - if (!nlmsg_copy_header(hdr, nw)) - return (false); - - struct ndmsg *ndm; - ndm = nlmsg_copy_next_header(hdr, nw, struct ndmsg); - - ndm->ndm_family = bsd_to_linux_domain(ndm->ndm_family); - - /* Copy attributes unchanged */ - if (!nlmsg_copy_all_nla(hdr, sizeof(struct ndmsg), nw)) - return (false); - - nlmsg_end(nw); - RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); - return (true); -} - -static bool -rtnl_newroute_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, - struct nl_writer *nw) -{ - if (!nlmsg_copy_header(hdr, nw)) - return (false); - - struct rtmsg *rtm; - rtm = nlmsg_copy_next_header(hdr, nw, struct rtmsg); - rtm->rtm_family = bsd_to_linux_domain(rtm->rtm_family); - - struct nlattr *nla; - - int hdrlen = NETLINK_ALIGN(sizeof(struct rtmsg)); - int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; - struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen); - - NLA_FOREACH(nla, nla_head, attrs_len) { - struct rtattr *rta = (struct rtattr *)nla; - //RT_LOG(LOG_DEBUG, "READING attr %d len %d", nla->nla_type, nla->nla_len); - if (rta->rta_len < sizeof(struct rtattr)) { - break; - } - - switch (rta->rta_type) { - case NL_RTA_TABLE: - { - uint32_t fibnum; - fibnum = _rta_get_uint32(rta); - if (fibnum == 0) - fibnum = 254; - RT_LOG(LOG_DEBUG3, "XFIBNUM %u", fibnum); - if (!nlattr_add_u32(nw, NL_RTA_TABLE, fibnum)) - return (false); - } - break; - default: - if (!nlmsg_copy_nla(nla, nw)) - return (false); - break; - } - } - - nlmsg_end(nw); - RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); - return (true); -} - -static bool -rtnl_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) -{ - RT_LOG(LOG_DEBUG2, "Got message type %d", hdr->nlmsg_type); - - switch (hdr->nlmsg_type) { - case NL_RTM_NEWLINK: - case NL_RTM_DELLINK: - case NL_RTM_GETLINK: - return (rtnl_newlink_to_linux(hdr, nlp, nw)); - case NL_RTM_NEWADDR: - case NL_RTM_DELADDR: - return (rtnl_newaddr_to_linux(hdr, nlp, nw)); - case NL_RTM_NEWROUTE: - case NL_RTM_DELROUTE: - return (rtnl_newroute_to_linux(hdr, nlp, nw)); - case NL_RTM_NEWNEIGH: - case NL_RTM_DELNEIGH: - case NL_RTM_GETNEIGH: - return (rtnl_newneigh_to_linux(hdr, nlp, nw)); - default: - RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated", - hdr->nlmsg_type); - return (handle_default_out(hdr, nw)); - } -} - -static bool -nlmsg_error_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) -{ - if (!nlmsg_copy_header(hdr, nw)) - return (false); - - struct nlmsgerr *nlerr; - nlerr = nlmsg_copy_next_header(hdr, nw, struct nlmsgerr); - nlerr->error = bsd_to_linux_errno(nlerr->error); - - int copied_len = sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr); - if (hdr->nlmsg_len == copied_len) { - nlmsg_end(nw); - return (true); - } - - /* - * CAP_ACK was not set. Original request needs to be translated. - * XXX: implement translation of the original message - */ - RT_LOG(LOG_DEBUG, "[WARN] Passing ack message type %d untranslated", - nlerr->msg.nlmsg_type); - char *dst_payload, *src_payload; - int copy_len = hdr->nlmsg_len - copied_len; - dst_payload = nlmsg_reserve_data(nw, NLMSG_ALIGN(copy_len), char); - - src_payload = (char *)hdr + copied_len; - - memcpy(dst_payload, src_payload, copy_len); - nlmsg_end(nw); - - return (true); -} - -static bool -nlmsg_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) -{ - if (hdr->nlmsg_type < NLMSG_MIN_TYPE) { - switch (hdr->nlmsg_type) { - case NLMSG_ERROR: - return (nlmsg_error_to_linux(hdr, nlp, nw)); - case NLMSG_NOOP: - case NLMSG_DONE: - case NLMSG_OVERRUN: - return (handle_default_out(hdr, nw)); - default: - RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated", - hdr->nlmsg_type); - return (handle_default_out(hdr, nw)); - } - } - - switch (nlp->nl_proto) { - case NETLINK_ROUTE: - return (rtnl_to_linux(hdr, nlp, nw)); - default: - return (handle_default_out(hdr, nw)); - } -} - -static bool -nlmsgs_to_linux(struct nl_writer *nw, struct nlpcb *nlp) -{ - struct nl_buf *nb, *orig; - u_int offset, msglen, orig_messages; - - RT_LOG(LOG_DEBUG3, "%p: in %u bytes %u messages", __func__, - nw->buf->datalen, nw->num_messages); - - orig = nw->buf; - nb = nl_buf_alloc(orig->datalen + SCRATCH_BUFFER_SIZE, M_NOWAIT); - if (__predict_false(nb == NULL)) - return (false); - nw->buf = nb; - orig_messages = nw->num_messages; - nw->num_messages = 0; - - /* Assume correct headers. Buffer IS mutable */ - for (offset = 0; - offset + sizeof(struct nlmsghdr) <= orig->datalen; - offset += msglen) { - struct nlmsghdr *hdr = (struct nlmsghdr *)&orig->data[offset]; - - msglen = NLMSG_ALIGN(hdr->nlmsg_len); - if (!nlmsg_to_linux(hdr, nlp, nw)) { - RT_LOG(LOG_DEBUG, "failed to process msg type %d", - hdr->nlmsg_type); - nl_buf_free(nb); - nw->buf = orig; - nw->num_messages = orig_messages; - return (false); - } - } - - MPASS(nw->num_messages == orig_messages); - MPASS(nw->buf == nb); - nl_buf_free(orig); - RT_LOG(LOG_DEBUG3, "%p: out %u bytes", __func__, offset); - - return (true); -} - -static struct linux_netlink_provider linux_netlink_v1 = { - .msgs_to_linux = nlmsgs_to_linux, - .msg_from_linux = nlmsg_from_linux, -}; - -void -linux_netlink_register(void) -{ - linux_netlink_p = &linux_netlink_v1; -} - -void -linux_netlink_deregister(void) -{ - linux_netlink_p = NULL; -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Alexander V. Chernikov + * + * 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 "opt_inet.h" +#include "opt_inet6.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DEBUG_MOD_NAME nl_linux +#define DEBUG_MAX_LEVEL LOG_DEBUG3 +#include +_DECLARE_DEBUG(LOG_INFO); + +static bool +valid_rta_size(const struct rtattr *rta, int sz) +{ + return (NL_RTA_DATA_LEN(rta) == sz); +} + +static bool +valid_rta_u32(const struct rtattr *rta) +{ + return (valid_rta_size(rta, sizeof(uint32_t))); +} + +static uint32_t +_rta_get_uint32(const struct rtattr *rta) +{ + return (*((const uint32_t *)NL_RTA_DATA_CONST(rta))); +} + +static int +rtnl_neigh_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct ndmsg *ndm = (struct ndmsg *)(hdr + 1); + sa_family_t f; + + if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct ndmsg)) + return (EBADMSG); + if ((f = linux_to_bsd_domain(ndm->ndm_family)) == AF_UNKNOWN) + return (EPFNOSUPPORT); + + ndm->ndm_family = f; + + return (0); +} + +static int +rtnl_ifaddr_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct ifaddrmsg *ifam = (struct ifaddrmsg *)(hdr + 1); + sa_family_t f; + + if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + + offsetof(struct ifaddrmsg, ifa_family) + sizeof(ifam->ifa_family)) + return (EBADMSG); + if ((f = linux_to_bsd_domain(ifam->ifa_family)) == AF_UNKNOWN) + return (EPFNOSUPPORT); + + ifam->ifa_family = f; + + return (0); +} + +/* + * XXX: in case of error state of hdr is inconsistent. + */ +static int +rtnl_route_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + /* Tweak address families and default fib only */ + struct rtmsg *rtm = (struct rtmsg *)(hdr + 1); + struct nlattr *nla, *nla_head; + int attrs_len; + sa_family_t f; + + if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct rtmsg)) + return (EBADMSG); + if ((f = linux_to_bsd_domain(rtm->rtm_family)) == AF_UNKNOWN) + return (EPFNOSUPPORT); + rtm->rtm_family = f; + + if (rtm->rtm_table == 254) + rtm->rtm_table = 0; + + attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr); + attrs_len -= NETLINK_ALIGN(sizeof(struct rtmsg)); + nla_head = (struct nlattr *)((char *)rtm + NETLINK_ALIGN(sizeof(struct rtmsg))); + + NLA_FOREACH(nla, nla_head, attrs_len) { + RT_LOG(LOG_DEBUG3, "GOT type %d len %d total %d", + nla->nla_type, nla->nla_len, attrs_len); + struct rtattr *rta = (struct rtattr *)nla; + if (rta->rta_len < sizeof(struct rtattr)) { + break; + } + switch (rta->rta_type) { + case NL_RTA_TABLE: + if (!valid_rta_u32(rta)) + return (EBADMSG); + rtm->rtm_table = 0; + uint32_t fibnum = _rta_get_uint32(rta); + RT_LOG(LOG_DEBUG3, "GET RTABLE: %u", fibnum); + if (fibnum == 254) { + *((uint32_t *)NL_RTA_DATA(rta)) = 0; + } + break; + } + } + + return (0); +} + +static int +rtnl_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + + switch (hdr->nlmsg_type) { + case NL_RTM_GETROUTE: + case NL_RTM_NEWROUTE: + case NL_RTM_DELROUTE: + return (rtnl_route_from_linux(hdr, npt)); + case NL_RTM_GETNEIGH: + return (rtnl_neigh_from_linux(hdr, npt)); + case NL_RTM_GETADDR: + return (rtnl_ifaddr_from_linux(hdr, npt)); + /* Silence warning for the messages where no translation is required */ + case NL_RTM_NEWLINK: + case NL_RTM_DELLINK: + case NL_RTM_GETLINK: + break; + default: + RT_LOG(LOG_DEBUG, "Passing message type %d untranslated", + hdr->nlmsg_type); + /* XXXGL: maybe return error? */ + } + + return (0); +} + +static int +nlmsg_from_linux(int netlink_family, struct nlmsghdr **hdr, + struct nl_pstate *npt) +{ + switch (netlink_family) { + case NETLINK_ROUTE: + return (rtnl_from_linux(*hdr, npt)); + } + + return (0); +} + + +/************************************************************ + * Kernel -> Linux + ************************************************************/ + +static bool +handle_default_out(struct nlmsghdr *hdr, struct nl_writer *nw) +{ + char *out_hdr; + out_hdr = nlmsg_reserve_data(nw, NLMSG_ALIGN(hdr->nlmsg_len), char); + + if (out_hdr != NULL) { + memcpy(out_hdr, hdr, hdr->nlmsg_len); + nw->num_messages++; + return (true); + } + return (false); +} + +static bool +nlmsg_copy_header(struct nlmsghdr *hdr, struct nl_writer *nw) +{ + return (nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, hdr->nlmsg_type, + hdr->nlmsg_flags, 0)); +} + +static void * +_nlmsg_copy_next_header(struct nlmsghdr *hdr, struct nl_writer *nw, int sz) +{ + void *next_hdr = nlmsg_reserve_data(nw, sz, void); + memcpy(next_hdr, hdr + 1, NLMSG_ALIGN(sz)); + + return (next_hdr); +} +#define nlmsg_copy_next_header(_hdr, _ns, _t) \ + ((_t *)(_nlmsg_copy_next_header(_hdr, _ns, sizeof(_t)))) + +static bool +nlmsg_copy_nla(const struct nlattr *nla_orig, struct nl_writer *nw) +{ + struct nlattr *nla = nlmsg_reserve_data(nw, nla_orig->nla_len, struct nlattr); + if (nla != NULL) { + memcpy(nla, nla_orig, nla_orig->nla_len); + return (true); + } + return (false); +} + +/* + * Translate a FreeBSD interface name to a Linux interface name. + */ +static bool +nlmsg_translate_ifname_nla(struct nlattr *nla, struct nl_writer *nw) +{ + char ifname[LINUX_IFNAMSIZ]; + + if (ifname_bsd_to_linux_name((char *)(nla + 1), ifname, + sizeof(ifname)) <= 0) + return (false); + return (nlattr_add_string(nw, IFLA_IFNAME, ifname)); +} + +#define LINUX_NLA_UNHANDLED -1 +/* + * Translate a FreeBSD attribute to a Linux attribute. + * Returns LINUX_NLA_UNHANDLED when the attribute is not processed + * and the caller must take care of it, otherwise the result is returned. + */ +static int +nlmsg_translate_all_nla(struct nlmsghdr *hdr, struct nlattr *nla, + struct nl_writer *nw) +{ + + switch (hdr->nlmsg_type) { + case NL_RTM_NEWLINK: + case NL_RTM_DELLINK: + case NL_RTM_GETLINK: + switch (nla->nla_type) { + case IFLA_IFNAME: + return (nlmsg_translate_ifname_nla(nla, nw)); + default: + break; + } + default: + break; + } + return (LINUX_NLA_UNHANDLED); +} + +static bool +nlmsg_copy_all_nla(struct nlmsghdr *hdr, int raw_hdrlen, struct nl_writer *nw) +{ + struct nlattr *nla; + int ret; + + int hdrlen = NETLINK_ALIGN(raw_hdrlen); + int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; + struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen); + + NLA_FOREACH(nla, nla_head, attrs_len) { + RT_LOG(LOG_DEBUG3, "reading attr %d len %d", nla->nla_type, nla->nla_len); + if (nla->nla_len < sizeof(struct nlattr)) { + return (false); + } + ret = nlmsg_translate_all_nla(hdr, nla, nw); + if (ret == LINUX_NLA_UNHANDLED) + ret = nlmsg_copy_nla(nla, nw); + if (!ret) + return (false); + } + return (true); +} +#undef LINUX_NLA_UNHANDLED + +static unsigned int +rtnl_if_flags_to_linux(unsigned int if_flags) +{ + unsigned int result = 0; + + for (int i = 0; i < 31; i++) { + unsigned int flag = 1 << i; + if (!(flag & if_flags)) + continue; + switch (flag) { + case IFF_UP: + case IFF_BROADCAST: + case IFF_DEBUG: + case IFF_LOOPBACK: + case IFF_POINTOPOINT: + case IFF_DRV_RUNNING: + case IFF_NOARP: + case IFF_PROMISC: + case IFF_ALLMULTI: + result |= flag; + break; + case IFF_NEEDSEPOCH: + case IFF_DRV_OACTIVE: + case IFF_SIMPLEX: + case IFF_LINK0: + case IFF_LINK1: + case IFF_LINK2: + case IFF_CANTCONFIG: + case IFF_PPROMISC: + case IFF_MONITOR: + case IFF_STATICARP: + case IFF_STICKYARP: + case IFF_DYING: + case IFF_RENAMING: + /* No Linux analogue */ + break; + case IFF_MULTICAST: + result |= 1 << 12; + } + } + return (result); +} + +static bool +rtnl_newlink_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, + struct nl_writer *nw) +{ + if (!nlmsg_copy_header(hdr, nw)) + return (false); + + struct ifinfomsg *ifinfo; + ifinfo = nlmsg_copy_next_header(hdr, nw, struct ifinfomsg); + + ifinfo->ifi_family = bsd_to_linux_domain(ifinfo->ifi_family); + /* Convert interface type */ + switch (ifinfo->ifi_type) { + case IFT_ETHER: + ifinfo->ifi_type = LINUX_ARPHRD_ETHER; + break; + } + ifinfo->ifi_flags = rtnl_if_flags_to_linux(ifinfo->ifi_flags); + + /* Copy attributes unchanged */ + if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifinfomsg), nw)) + return (false); + + /* make ip(8) happy */ + if (!nlattr_add_string(nw, IFLA_QDISC, "noqueue")) + return (false); + + if (!nlattr_add_u32(nw, IFLA_TXQLEN, 1000)) + return (false); + + nlmsg_end(nw); + RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); + return (true); +} + +static bool +rtnl_newaddr_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, + struct nl_writer *nw) +{ + if (!nlmsg_copy_header(hdr, nw)) + return (false); + + struct ifaddrmsg *ifamsg; + ifamsg = nlmsg_copy_next_header(hdr, nw, struct ifaddrmsg); + + ifamsg->ifa_family = bsd_to_linux_domain(ifamsg->ifa_family); + /* XXX: fake ifa_flags? */ + + /* Copy attributes unchanged */ + if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifaddrmsg), nw)) + return (false); + + nlmsg_end(nw); + RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); + return (true); +} + +static bool +rtnl_newneigh_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, + struct nl_writer *nw) +{ + if (!nlmsg_copy_header(hdr, nw)) + return (false); + + struct ndmsg *ndm; + ndm = nlmsg_copy_next_header(hdr, nw, struct ndmsg); + + ndm->ndm_family = bsd_to_linux_domain(ndm->ndm_family); + + /* Copy attributes unchanged */ + if (!nlmsg_copy_all_nla(hdr, sizeof(struct ndmsg), nw)) + return (false); + + nlmsg_end(nw); + RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); + return (true); +} + +static bool +rtnl_newroute_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, + struct nl_writer *nw) +{ + if (!nlmsg_copy_header(hdr, nw)) + return (false); + + struct rtmsg *rtm; + rtm = nlmsg_copy_next_header(hdr, nw, struct rtmsg); + rtm->rtm_family = bsd_to_linux_domain(rtm->rtm_family); + + struct nlattr *nla; + + int hdrlen = NETLINK_ALIGN(sizeof(struct rtmsg)); + int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; + struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen); + + NLA_FOREACH(nla, nla_head, attrs_len) { + struct rtattr *rta = (struct rtattr *)nla; + //RT_LOG(LOG_DEBUG, "READING attr %d len %d", nla->nla_type, nla->nla_len); + if (rta->rta_len < sizeof(struct rtattr)) { + break; + } + + switch (rta->rta_type) { + case NL_RTA_TABLE: + { + uint32_t fibnum; + fibnum = _rta_get_uint32(rta); + if (fibnum == 0) + fibnum = 254; + RT_LOG(LOG_DEBUG3, "XFIBNUM %u", fibnum); + if (!nlattr_add_u32(nw, NL_RTA_TABLE, fibnum)) + return (false); + } + break; + default: + if (!nlmsg_copy_nla(nla, nw)) + return (false); + break; + } + } + + nlmsg_end(nw); + RT_LOG(LOG_DEBUG2, "done processing nw %p", nw); + return (true); +} + +static bool +rtnl_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) +{ + RT_LOG(LOG_DEBUG2, "Got message type %d", hdr->nlmsg_type); + + switch (hdr->nlmsg_type) { + case NL_RTM_NEWLINK: + case NL_RTM_DELLINK: + case NL_RTM_GETLINK: + return (rtnl_newlink_to_linux(hdr, nlp, nw)); + case NL_RTM_NEWADDR: + case NL_RTM_DELADDR: + return (rtnl_newaddr_to_linux(hdr, nlp, nw)); + case NL_RTM_NEWROUTE: + case NL_RTM_DELROUTE: + return (rtnl_newroute_to_linux(hdr, nlp, nw)); + case NL_RTM_NEWNEIGH: + case NL_RTM_DELNEIGH: + case NL_RTM_GETNEIGH: + return (rtnl_newneigh_to_linux(hdr, nlp, nw)); + default: + RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated", + hdr->nlmsg_type); + return (handle_default_out(hdr, nw)); + } +} + +static bool +nlmsg_error_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) +{ + if (!nlmsg_copy_header(hdr, nw)) + return (false); + + struct nlmsgerr *nlerr; + nlerr = nlmsg_copy_next_header(hdr, nw, struct nlmsgerr); + nlerr->error = bsd_to_linux_errno(nlerr->error); + + int copied_len = sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr); + if (hdr->nlmsg_len == copied_len) { + nlmsg_end(nw); + return (true); + } + + /* + * CAP_ACK was not set. Original request needs to be translated. + * XXX: implement translation of the original message + */ + RT_LOG(LOG_DEBUG, "[WARN] Passing ack message type %d untranslated", + nlerr->msg.nlmsg_type); + char *dst_payload, *src_payload; + int copy_len = hdr->nlmsg_len - copied_len; + dst_payload = nlmsg_reserve_data(nw, NLMSG_ALIGN(copy_len), char); + + src_payload = (char *)hdr + copied_len; + + memcpy(dst_payload, src_payload, copy_len); + nlmsg_end(nw); + + return (true); +} + +static bool +nlmsg_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw) +{ + if (hdr->nlmsg_type < NLMSG_MIN_TYPE) { + switch (hdr->nlmsg_type) { + case NLMSG_ERROR: + return (nlmsg_error_to_linux(hdr, nlp, nw)); + case NLMSG_NOOP: + case NLMSG_DONE: + case NLMSG_OVERRUN: + return (handle_default_out(hdr, nw)); + default: + RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated", + hdr->nlmsg_type); + return (handle_default_out(hdr, nw)); + } + } + + switch (nlp->nl_proto) { + case NETLINK_ROUTE: + return (rtnl_to_linux(hdr, nlp, nw)); + default: + return (handle_default_out(hdr, nw)); + } +} + +static bool +nlmsgs_to_linux(struct nl_writer *nw, struct nlpcb *nlp) +{ + struct nl_buf *nb, *orig; + u_int offset, msglen, orig_messages; + + RT_LOG(LOG_DEBUG3, "%p: in %u bytes %u messages", __func__, + nw->buf->datalen, nw->num_messages); + + orig = nw->buf; + nb = nl_buf_alloc(orig->datalen + SCRATCH_BUFFER_SIZE, M_NOWAIT); + if (__predict_false(nb == NULL)) + return (false); + nw->buf = nb; + orig_messages = nw->num_messages; + nw->num_messages = 0; + + /* Assume correct headers. Buffer IS mutable */ + for (offset = 0; + offset + sizeof(struct nlmsghdr) <= orig->datalen; + offset += msglen) { + struct nlmsghdr *hdr = (struct nlmsghdr *)&orig->data[offset]; + + msglen = NLMSG_ALIGN(hdr->nlmsg_len); + if (!nlmsg_to_linux(hdr, nlp, nw)) { + RT_LOG(LOG_DEBUG, "failed to process msg type %d", + hdr->nlmsg_type); + nl_buf_free(nb); + nw->buf = orig; + nw->num_messages = orig_messages; + return (false); + } + } + + MPASS(nw->num_messages == orig_messages); + MPASS(nw->buf == nb); + nl_buf_free(orig); + RT_LOG(LOG_DEBUG3, "%p: out %u bytes", __func__, offset); + + return (true); +} + +static struct linux_netlink_provider linux_netlink_v1 = { + .msgs_to_linux = nlmsgs_to_linux, + .msg_from_linux = nlmsg_from_linux, +}; + +void +linux_netlink_register(void) +{ + linux_netlink_p = &linux_netlink_v1; +} + +void +linux_netlink_deregister(void) +{ + linux_netlink_p = NULL; +} diff --git a/sys/compat/linux/linux_persona.h b/sys/compat/linux/linux_persona.h index 18aef6f02d76..a799c77005b9 100644 --- a/sys/compat/linux/linux_persona.h +++ b/sys/compat/linux/linux_persona.h @@ -1,53 +1,53 @@ - -#ifndef LINUX_PERSONALITY_H -#define LINUX_PERSONALITY_H - -/* - * Flags for bug emulation. - * - * These occupy the top three bytes. - */ -enum { - LINUX_UNAME26 = 0x0020000, - LINUX_ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization - * of VA space - */ - LINUX_FDPIC_FUNCPTRS = 0x0080000, /* userspace function - * ptrs point to descriptors - * (signal handling) - */ - LINUX_MMAP_PAGE_ZERO = 0x0100000, - LINUX_ADDR_COMPAT_LAYOUT = 0x0200000, - LINUX_READ_IMPLIES_EXEC = 0x0400000, - LINUX_ADDR_LIMIT_32BIT = 0x0800000, - LINUX_SHORT_INODE = 0x1000000, - LINUX_WHOLE_SECONDS = 0x2000000, - LINUX_STICKY_TIMEOUTS = 0x4000000, - LINUX_ADDR_LIMIT_3GB = 0x8000000, -}; - -/* - * Security-relevant compatibility flags that must be - * cleared upon setuid or setgid exec: - */ -#define LINUX_PER_CLEAR_ON_SETID (LINUX_READ_IMPLIES_EXEC | \ - LINUX_ADDR_NO_RANDOMIZE | \ - LINUX_ADDR_COMPAT_LAYOUT | \ - LINUX_MMAP_PAGE_ZERO) - -/* - * Personality types. - * - * These go in the low byte. Avoid using the top bit, it will - * conflict with error returns. - */ -enum { - LINUX_PER_LINUX = 0x0000, - LINUX_PER_LINUX_32BIT = 0x0000 | LINUX_ADDR_LIMIT_32BIT, - LINUX_PER_LINUX_FDPIC = 0x0000 | LINUX_FDPIC_FUNCPTRS, - LINUX_PER_LINUX32 = 0x0008, - LINUX_PER_LINUX32_3GB = 0x0008 | LINUX_ADDR_LIMIT_3GB, - LINUX_PER_MASK = 0x00ff, -}; - -#endif /* LINUX_PERSONALITY_H */ + +#ifndef LINUX_PERSONALITY_H +#define LINUX_PERSONALITY_H + +/* + * Flags for bug emulation. + * + * These occupy the top three bytes. + */ +enum { + LINUX_UNAME26 = 0x0020000, + LINUX_ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization + * of VA space + */ + LINUX_FDPIC_FUNCPTRS = 0x0080000, /* userspace function + * ptrs point to descriptors + * (signal handling) + */ + LINUX_MMAP_PAGE_ZERO = 0x0100000, + LINUX_ADDR_COMPAT_LAYOUT = 0x0200000, + LINUX_READ_IMPLIES_EXEC = 0x0400000, + LINUX_ADDR_LIMIT_32BIT = 0x0800000, + LINUX_SHORT_INODE = 0x1000000, + LINUX_WHOLE_SECONDS = 0x2000000, + LINUX_STICKY_TIMEOUTS = 0x4000000, + LINUX_ADDR_LIMIT_3GB = 0x8000000, +}; + +/* + * Security-relevant compatibility flags that must be + * cleared upon setuid or setgid exec: + */ +#define LINUX_PER_CLEAR_ON_SETID (LINUX_READ_IMPLIES_EXEC | \ + LINUX_ADDR_NO_RANDOMIZE | \ + LINUX_ADDR_COMPAT_LAYOUT | \ + LINUX_MMAP_PAGE_ZERO) + +/* + * Personality types. + * + * These go in the low byte. Avoid using the top bit, it will + * conflict with error returns. + */ +enum { + LINUX_PER_LINUX = 0x0000, + LINUX_PER_LINUX_32BIT = 0x0000 | LINUX_ADDR_LIMIT_32BIT, + LINUX_PER_LINUX_FDPIC = 0x0000 | LINUX_FDPIC_FUNCPTRS, + LINUX_PER_LINUX32 = 0x0008, + LINUX_PER_LINUX32_3GB = 0x0008 | LINUX_ADDR_LIMIT_3GB, + LINUX_PER_MASK = 0x00ff, +}; + +#endif /* LINUX_PERSONALITY_H */ diff --git a/sys/compat/linux/linux_ptrace.c b/sys/compat/linux/linux_ptrace.c index 421760eab2a9..73ef8eb3e074 100644 --- a/sys/compat/linux/linux_ptrace.c +++ b/sys/compat/linux/linux_ptrace.c @@ -1,564 +1,577 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2017 Edward Tomasz Napierala - * - * This software was developed by SRI International and the University of - * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) - * ("CTSRD"), as part of the DARPA CRASH research programme. - * - * 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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define LINUX_PTRACE_TRACEME 0 -#define LINUX_PTRACE_PEEKTEXT 1 -#define LINUX_PTRACE_PEEKDATA 2 -#define LINUX_PTRACE_PEEKUSER 3 -#define LINUX_PTRACE_POKETEXT 4 -#define LINUX_PTRACE_POKEDATA 5 -#define LINUX_PTRACE_POKEUSER 6 -#define LINUX_PTRACE_CONT 7 -#define LINUX_PTRACE_KILL 8 -#define LINUX_PTRACE_SINGLESTEP 9 -#define LINUX_PTRACE_GETREGS 12 -#define LINUX_PTRACE_SETREGS 13 -#define LINUX_PTRACE_GETFPREGS 14 -#define LINUX_PTRACE_SETFPREGS 15 -#define LINUX_PTRACE_ATTACH 16 -#define LINUX_PTRACE_DETACH 17 -#define LINUX_PTRACE_SYSCALL 24 -#define LINUX_PTRACE_SETOPTIONS 0x4200 -#define LINUX_PTRACE_GETEVENTMSG 0x4201 -#define LINUX_PTRACE_GETSIGINFO 0x4202 -#define LINUX_PTRACE_GETREGSET 0x4204 -#define LINUX_PTRACE_SEIZE 0x4206 -#define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e - -#define LINUX_PTRACE_EVENT_EXEC 4 -#define LINUX_PTRACE_EVENT_EXIT 6 - -#define LINUX_PTRACE_O_TRACESYSGOOD 1 -#define LINUX_PTRACE_O_TRACEFORK 2 -#define LINUX_PTRACE_O_TRACEVFORK 4 -#define LINUX_PTRACE_O_TRACECLONE 8 -#define LINUX_PTRACE_O_TRACEEXEC 16 -#define LINUX_PTRACE_O_TRACEVFORKDONE 32 -#define LINUX_PTRACE_O_TRACEEXIT 64 -#define LINUX_PTRACE_O_TRACESECCOMP 128 -#define LINUX_PTRACE_O_EXITKILL 1048576 -#define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152 - -#define LINUX_NT_PRSTATUS 0x1 -#define LINUX_NT_PRFPREG 0x2 -#define LINUX_NT_X86_XSTATE 0x202 - -#define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \ - LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \ - LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \ - LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \ - LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \ - LINUX_PTRACE_O_SUSPEND_SECCOMP) - -#define LINUX_PTRACE_SYSCALL_INFO_NONE 0 -#define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1 -#define LINUX_PTRACE_SYSCALL_INFO_EXIT 2 - -static int -map_signum(int lsig, int *bsigp) -{ - int bsig; - - if (lsig == 0) { - *bsigp = 0; - return (0); - } - - if (lsig < 0 || lsig > LINUX_SIGRTMAX) - return (EINVAL); - - bsig = linux_to_bsd_signal(lsig); - if (bsig == SIGSTOP) - bsig = 0; - - *bsigp = bsig; - return (0); -} - -int -linux_ptrace_status(struct thread *td, pid_t pid, int status) -{ - struct ptrace_lwpinfo lwpinfo; - struct linux_pemuldata *pem; - register_t saved_retval; - int error; - - saved_retval = td->td_retval[0]; - error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); - td->td_retval[0] = saved_retval; - if (error != 0) { - linux_msg(td, "PT_LWPINFO failed with error %d", error); - return (status); - } - - pem = pem_find(td->td_proc); - KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); - - LINUX_PEM_SLOCK(pem); - if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && - lwpinfo.pl_flags & PL_FLAG_SCE) - status |= (LINUX_SIGTRAP | 0x80) << 8; - if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && - lwpinfo.pl_flags & PL_FLAG_SCX) { - if (lwpinfo.pl_flags & PL_FLAG_EXEC) - status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8; - else - status |= (LINUX_SIGTRAP | 0x80) << 8; - } - if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) && - lwpinfo.pl_flags & PL_FLAG_EXITED) - status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8; - LINUX_PEM_SUNLOCK(pem); - - return (status); -} - -static int -linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data) -{ - int error; - - error = kern_ptrace(td, PT_READ_I, pid, addr, 0); - if (error == 0) - error = copyout(td->td_retval, data, sizeof(l_int)); - else if (error == ENOMEM) - error = EIO; - td->td_retval[0] = error; - - return (error); -} - -static int -linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data) -{ - struct linux_pemuldata *pem; - int mask; - - mask = 0; - - if (data & ~LINUX_PTRACE_O_MASK) { - linux_msg(td, "unknown ptrace option %lx set; " - "returning EINVAL", - data & ~LINUX_PTRACE_O_MASK); - return (EINVAL); - } - - pem = pem_find(td->td_proc); - KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); - - /* - * PTRACE_O_EXITKILL is ignored, we do that by default. - */ - - LINUX_PEM_XLOCK(pem); - if (data & LINUX_PTRACE_O_TRACESYSGOOD) { - pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD; - } else { - pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD; - } - LINUX_PEM_XUNLOCK(pem); - - if (data & LINUX_PTRACE_O_TRACEFORK) - mask |= PTRACE_FORK; - - if (data & LINUX_PTRACE_O_TRACEVFORK) - mask |= PTRACE_VFORK; - - if (data & LINUX_PTRACE_O_TRACECLONE) - mask |= PTRACE_VFORK; - - if (data & LINUX_PTRACE_O_TRACEEXEC) - mask |= PTRACE_EXEC; - - if (data & LINUX_PTRACE_O_TRACEVFORKDONE) - mask |= PTRACE_VFORK; /* XXX: Close enough? */ - - if (data & LINUX_PTRACE_O_TRACEEXIT) { - pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT; - } else { - pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT; - } - - return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask))); -} - -static int -linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data) -{ - - linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL"); - return (EINVAL); -} - -static int -linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data) -{ - struct ptrace_lwpinfo lwpinfo; - l_siginfo_t l_siginfo; - int error, sig; - - error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); - if (error != 0) { - linux_msg(td, "PT_LWPINFO failed with error %d", error); - return (error); - } - - if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) { - error = EINVAL; - linux_msg(td, "no PL_FLAG_SI, returning %d", error); - return (error); - } - - sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo); - memset(&l_siginfo, 0, sizeof(l_siginfo)); - siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig); - error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo)); - return (error); -} - -static int -linux_ptrace_getregs(struct thread *td, pid_t pid, void *data) -{ - struct reg b_reg; - struct linux_pt_regset l_regset; - int error; - - error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); - if (error != 0) - return (error); - - bsd_to_linux_regset(&b_reg, &l_regset); - error = linux_ptrace_getregs_machdep(td, pid, &l_regset); - if (error != 0) - return (error); - - error = copyout(&l_regset, (void *)data, sizeof(l_regset)); - return (error); -} - -static int -linux_ptrace_setregs(struct thread *td, pid_t pid, void *data) -{ - struct reg b_reg; - struct linux_pt_regset l_regset; - int error; - - error = copyin(data, &l_regset, sizeof(l_regset)); - if (error != 0) - return (error); - linux_to_bsd_regset(&b_reg, &l_regset); - error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0); - return (error); -} - -static int -linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data) -{ - struct reg b_reg; - struct linux_pt_regset l_regset; - struct iovec iov; - size_t len; - int error; - - error = copyin((const void *)data, &iov, sizeof(iov)); - if (error != 0) { - linux_msg(td, "copyin error %d", error); - return (error); - } - - error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); - if (error != 0) - return (error); - - bsd_to_linux_regset(&b_reg, &l_regset); - error = linux_ptrace_getregs_machdep(td, pid, &l_regset); - if (error != 0) - return (error); - - len = MIN(iov.iov_len, sizeof(l_regset)); - error = copyout(&l_regset, (void *)iov.iov_base, len); - if (error != 0) { - linux_msg(td, "copyout error %d", error); - return (error); - } - - iov.iov_len = len; - error = copyout(&iov, (void *)data, sizeof(iov)); - if (error != 0) { - linux_msg(td, "iov copyout error %d", error); - return (error); - } - - return (error); -} - -static int -linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) -{ - - switch (addr) { - case LINUX_NT_PRSTATUS: - return (linux_ptrace_getregset_prstatus(td, pid, data)); - case LINUX_NT_PRFPREG: - linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; " - "returning EINVAL"); - return (EINVAL); - case LINUX_NT_X86_XSTATE: - linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; " - "returning EINVAL"); - return (EINVAL); - default: - linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; " - "returning EINVAL", addr); - return (EINVAL); - } -} - -static int -linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) -{ - - linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL"); - return (EINVAL); -} - -static int -linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, - l_ulong len, l_ulong data) -{ - struct ptrace_lwpinfo lwpinfo; - struct ptrace_sc_ret sr; - struct reg b_reg; - struct syscall_info si; - int error; - - error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); - if (error != 0) { - linux_msg(td, "PT_LWPINFO failed with error %d", error); - return (error); - } - - memset(&si, 0, sizeof(si)); - - if (lwpinfo.pl_flags & PL_FLAG_SCE) { - si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY; - si.entry.nr = lwpinfo.pl_syscall_code; - /* - * The use of PT_GET_SC_ARGS there is special, - * implementation of PT_GET_SC_ARGS for Linux-ABI - * callers emulates Linux bug which strace(1) depends - * on: at initialization it tests whether ptrace works - * by calling close(2), or some other single-argument - * syscall, _with six arguments_, and then verifies - * whether it can fetch them all using this API; - * otherwise it bails out. - */ - error = kern_ptrace(td, PT_GET_SC_ARGS, pid, - &si.entry.args, sizeof(si.entry.args)); - if (error != 0) { - linux_msg(td, "PT_GET_SC_ARGS failed with error %d", - error); - return (error); - } - } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { - si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT; - error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr)); - - if (error != 0) { - linux_msg(td, "PT_GET_SC_RET failed with error %d", - error); - return (error); - } - - if (sr.sr_error == 0) { - si.exit.rval = sr.sr_retval[0]; - si.exit.is_error = 0; - } else if (sr.sr_error == EJUSTRETURN) { - /* - * EJUSTRETURN means the actual value to return - * has already been put into td_frame; instead - * of extracting it and trying to determine whether - * it's an error or not just bail out and let - * the ptracing process fall back to another method. - */ - si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; - } else if (sr.sr_error == ERESTART) { - si.exit.rval = -LINUX_ERESTARTSYS; - si.exit.is_error = 1; - } else { - si.exit.rval = bsd_to_linux_errno(sr.sr_error); - si.exit.is_error = 1; - } - } else { - si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; - } - - error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); - if (error != 0) - return (error); - - linux_ptrace_get_syscall_info_machdep(&b_reg, &si); - - len = MIN(len, sizeof(si)); - error = copyout(&si, (void *)data, len); - if (error == 0) - td->td_retval[0] = sizeof(si); - - return (error); -} - -int -linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) -{ - void *addr; - pid_t pid; - int error, sig; - - if (!allow_ptrace) - return (ENOSYS); - - pid = (pid_t)uap->pid; - addr = (void *)uap->addr; - - switch (uap->req) { - case LINUX_PTRACE_TRACEME: - error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0); - break; - case LINUX_PTRACE_PEEKTEXT: - case LINUX_PTRACE_PEEKDATA: - error = linux_ptrace_peek(td, pid, addr, (void *)uap->data); - if (error != 0) - goto out; - /* - * Linux expects this syscall to read 64 bits, not 32. - */ - error = linux_ptrace_peek(td, pid, - (void *)(uap->addr + 4), (void *)(uap->data + 4)); - break; - case LINUX_PTRACE_PEEKUSER: - error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data); - break; - case LINUX_PTRACE_POKETEXT: - case LINUX_PTRACE_POKEDATA: - error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data); - if (error != 0) - goto out; - /* - * Linux expects this syscall to write 64 bits, not 32. - */ - error = kern_ptrace(td, PT_WRITE_D, pid, - (void *)(uap->addr + 4), uap->data >> 32); - break; - case LINUX_PTRACE_POKEUSER: - error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data); - break; - case LINUX_PTRACE_CONT: - error = map_signum(uap->data, &sig); - if (error != 0) - break; - error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig); - break; - case LINUX_PTRACE_KILL: - error = kern_ptrace(td, PT_KILL, pid, addr, uap->data); - break; - case LINUX_PTRACE_SINGLESTEP: - error = map_signum(uap->data, &sig); - if (error != 0) - break; - error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig); - break; - case LINUX_PTRACE_GETREGS: - error = linux_ptrace_getregs(td, pid, (void *)uap->data); - break; - case LINUX_PTRACE_SETREGS: - error = linux_ptrace_setregs(td, pid, (void *)uap->data); - break; - case LINUX_PTRACE_ATTACH: - error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); - break; - case LINUX_PTRACE_DETACH: - error = map_signum(uap->data, &sig); - if (error != 0) - break; - error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig); - break; - case LINUX_PTRACE_SYSCALL: - error = map_signum(uap->data, &sig); - if (error != 0) - break; - error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig); - break; - case LINUX_PTRACE_SETOPTIONS: - error = linux_ptrace_setoptions(td, pid, uap->data); - break; - case LINUX_PTRACE_GETEVENTMSG: - error = linux_ptrace_geteventmsg(td, pid, uap->data); - break; - case LINUX_PTRACE_GETSIGINFO: - error = linux_ptrace_getsiginfo(td, pid, uap->data); - break; - case LINUX_PTRACE_GETREGSET: - error = linux_ptrace_getregset(td, pid, uap->addr, uap->data); - break; - case LINUX_PTRACE_SEIZE: - error = linux_ptrace_seize(td, pid, uap->addr, uap->data); - break; - case LINUX_PTRACE_GET_SYSCALL_INFO: - error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data); - break; - default: - linux_msg(td, "ptrace(%ld, ...) not implemented; " - "returning EINVAL", uap->req); - error = EINVAL; - break; - } - -out: - if (error == EBUSY) - error = ESRCH; - - return (error); -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2017 Edward Tomasz Napierala + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * 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 +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +#define LINUX_PTRACE_TRACEME 0 +#define LINUX_PTRACE_PEEKTEXT 1 +#define LINUX_PTRACE_PEEKDATA 2 +#define LINUX_PTRACE_PEEKUSER 3 +#define LINUX_PTRACE_POKETEXT 4 +#define LINUX_PTRACE_POKEDATA 5 +#define LINUX_PTRACE_POKEUSER 6 +#define LINUX_PTRACE_CONT 7 +#define LINUX_PTRACE_KILL 8 +#define LINUX_PTRACE_SINGLESTEP 9 +#define LINUX_PTRACE_GETREGS 12 +#define LINUX_PTRACE_SETREGS 13 +#define LINUX_PTRACE_GETFPREGS 14 +#define LINUX_PTRACE_SETFPREGS 15 +#define LINUX_PTRACE_ATTACH 16 +#define LINUX_PTRACE_DETACH 17 +#define LINUX_PTRACE_SYSCALL 24 +#define LINUX_PTRACE_SETOPTIONS 0x4200 +#define LINUX_PTRACE_GETEVENTMSG 0x4201 +#define LINUX_PTRACE_GETSIGINFO 0x4202 +#define LINUX_PTRACE_GETREGSET 0x4204 +#define LINUX_PTRACE_SEIZE 0x4206 +#define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e + +#define LINUX_PTRACE_EVENT_EXEC 4 +#define LINUX_PTRACE_EVENT_EXIT 6 + +#define LINUX_PTRACE_O_TRACESYSGOOD 1 +#define LINUX_PTRACE_O_TRACEFORK 2 +#define LINUX_PTRACE_O_TRACEVFORK 4 +#define LINUX_PTRACE_O_TRACECLONE 8 +#define LINUX_PTRACE_O_TRACEEXEC 16 +#define LINUX_PTRACE_O_TRACEVFORKDONE 32 +#define LINUX_PTRACE_O_TRACEEXIT 64 +#define LINUX_PTRACE_O_TRACESECCOMP 128 +#define LINUX_PTRACE_O_EXITKILL 1048576 +#define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152 + +#define LINUX_NT_PRSTATUS 0x1 +#define LINUX_NT_PRFPREG 0x2 +#define LINUX_NT_X86_XSTATE 0x202 + +#define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \ + LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \ + LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \ + LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \ + LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \ + LINUX_PTRACE_O_SUSPEND_SECCOMP) + +#define LINUX_PTRACE_SYSCALL_INFO_NONE 0 +#define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1 +#define LINUX_PTRACE_SYSCALL_INFO_EXIT 2 + +static int +map_signum(int lsig, int *bsigp) +{ + int bsig; + + if (lsig == 0) { + *bsigp = 0; + return (0); + } + + if (lsig < 0 || lsig > LINUX_SIGRTMAX) + return (EINVAL); + + bsig = linux_to_bsd_signal(lsig); + if (bsig == SIGSTOP) + bsig = 0; + + *bsigp = bsig; + return (0); +} + +int +linux_ptrace_status(struct thread *td, pid_t pid, int status) +{ + struct ptrace_lwpinfo lwpinfo; + struct linux_pemuldata *pem; + register_t saved_retval; + int error; + + saved_retval = td->td_retval[0]; + error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); + td->td_retval[0] = saved_retval; + if (error != 0) { + linux_msg(td, "PT_LWPINFO failed with error %d", error); + return (status); + } + + pem = pem_find(td->td_proc); + KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); + + LINUX_PEM_SLOCK(pem); + if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && + lwpinfo.pl_flags & PL_FLAG_SCE) + status |= (LINUX_SIGTRAP | 0x80) << 8; + if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && + lwpinfo.pl_flags & PL_FLAG_SCX) { + if (lwpinfo.pl_flags & PL_FLAG_EXEC) + status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8; + else + status |= (LINUX_SIGTRAP | 0x80) << 8; + } + if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) && + lwpinfo.pl_flags & PL_FLAG_EXITED) + status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8; + LINUX_PEM_SUNLOCK(pem); + + return (status); +} + +static int +linux_ptrace_peek(struct thread *td, pid_t pid, void * __capability addr, void * __capability data) +{ + int error; + + error = kern_ptrace(td, PT_READ_I, pid, addr, 0); + if (error == 0) + error = copyout(td->td_retval, data, sizeof(l_int)); + else if (error == ENOMEM) + error = EIO; + td->td_retval[0] = error; + + return (error); +} + +static int +linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data) +{ + struct linux_pemuldata *pem; + int mask; + + mask = 0; + + if (data & ~LINUX_PTRACE_O_MASK) { + linux_msg(td, "unknown ptrace option %lx set; " + "returning EINVAL", + data & ~LINUX_PTRACE_O_MASK); + return (EINVAL); + } + + pem = pem_find(td->td_proc); + KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); + + /* + * PTRACE_O_EXITKILL is ignored, we do that by default. + */ + + LINUX_PEM_XLOCK(pem); + if (data & LINUX_PTRACE_O_TRACESYSGOOD) { + pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD; + } else { + pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD; + } + LINUX_PEM_XUNLOCK(pem); + + if (data & LINUX_PTRACE_O_TRACEFORK) + mask |= PTRACE_FORK; + + if (data & LINUX_PTRACE_O_TRACEVFORK) + mask |= PTRACE_VFORK; + + if (data & LINUX_PTRACE_O_TRACECLONE) + mask |= PTRACE_VFORK; + + if (data & LINUX_PTRACE_O_TRACEEXEC) + mask |= PTRACE_EXEC; + + if (data & LINUX_PTRACE_O_TRACEVFORKDONE) + mask |= PTRACE_VFORK; /* XXX: Close enough? */ + + if (data & LINUX_PTRACE_O_TRACEEXIT) { + pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT; + } else { + pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT; + } + + return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask))); +} + +static int +linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data) +{ + + linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL"); + return (EINVAL); +} + +static int +linux_ptrace_getsiginfo(struct thread *td, pid_t pid, void * __capability data) +{ + struct ptrace_lwpinfo lwpinfo; + l_siginfo_t l_siginfo; + int error, sig; + + error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); + if (error != 0) { + linux_msg(td, "PT_LWPINFO failed with error %d", error); + return (error); + } + + if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) { + error = EINVAL; + linux_msg(td, "no PL_FLAG_SI, returning %d", error); + return (error); + } + + sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo); + memset(&l_siginfo, 0, sizeof(l_siginfo)); + siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig); + error = copyoutcap(&l_siginfo, data, sizeof(l_siginfo)); + return (error); +} + +static int +linux_ptrace_getregs(struct thread *td, pid_t pid, void * __capability data) +{ + struct reg b_reg; + struct linux_pt_regset l_regset; + int error; + + error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); + if (error != 0) + return (error); + + bsd_to_linux_regset(&b_reg, &l_regset); + error = linux_ptrace_getregs_machdep(td, pid, &l_regset); + if (error != 0) + return (error); + + error = copyout(&l_regset, data, sizeof(l_regset)); + return (error); +} + +static int +linux_ptrace_setregs(struct thread *td, pid_t pid, void * __capability data) +{ + struct reg b_reg; + struct linux_pt_regset l_regset; + int error; + + error = copyin(data, &l_regset, sizeof(l_regset)); + if (error != 0) + return (error); + linux_to_bsd_regset(&b_reg, &l_regset); + error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0); + return (error); +} + +static int +linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, void * __capability data) +{ + struct reg b_reg; + struct linux_pt_regset l_regset; +#ifdef COMPAT_LINUX64 + struct l_iovec64 iov; +#else + struct iovec iov; +#endif + size_t len; + int error; + + error = copyin(data, &iov, sizeof(iov)); + if (error != 0) { + linux_msg(td, "copyin error %d", error); + return (error); + } + + error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); + if (error != 0) + return (error); + + bsd_to_linux_regset(&b_reg, &l_regset); + error = linux_ptrace_getregs_machdep(td, pid, &l_regset); + if (error != 0) + return (error); + + len = MIN(iov.iov_len, sizeof(l_regset)); + error = copyout(&l_regset, LINUX_USER_CAP(iov.iov_base, len), len); + if (error != 0) { + linux_msg(td, "copyout error %d", error); + return (error); + } + + iov.iov_len = len; + error = copyout(&iov, data, sizeof(iov)); + if (error != 0) { + linux_msg(td, "iov copyout error %d", error); + return (error); + } + + return (error); +} + +static int +linux_ptrace_getregset(struct thread *td, pid_t pid, l_uintptr_t addr, void * __capability data) +{ + + switch (addr) { + case LINUX_NT_PRSTATUS: + return (linux_ptrace_getregset_prstatus(td, pid, data)); + case LINUX_NT_PRFPREG: + linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; " + "returning EINVAL"); + return (EINVAL); + case LINUX_NT_X86_XSTATE: + linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; " + "returning EINVAL"); + return (EINVAL); + default: + linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; " + "returning EINVAL", (unsigned long)addr); + return (EINVAL); + } +} + +static int +linux_ptrace_seize(struct thread *td, pid_t pid, l_uintptr_t addr, l_uintptr_t data) +{ + + linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL"); + return (EINVAL); +} + +static int +linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, + l_ulong len, void* __capability data) +{ + struct ptrace_lwpinfo lwpinfo; + struct ptrace_sc_ret sr; + struct reg b_reg; + struct syscall_info si; + int error; + + error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); + if (error != 0) { + linux_msg(td, "PT_LWPINFO failed with error %d", error); + return (error); + } + + memset(&si, 0, sizeof(si)); + + if (lwpinfo.pl_flags & PL_FLAG_SCE) { + si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY; + si.entry.nr = lwpinfo.pl_syscall_code; + /* + * The use of PT_GET_SC_ARGS there is special, + * implementation of PT_GET_SC_ARGS for Linux-ABI + * callers emulates Linux bug which strace(1) depends + * on: at initialization it tests whether ptrace works + * by calling close(2), or some other single-argument + * syscall, _with six arguments_, and then verifies + * whether it can fetch them all using this API; + * otherwise it bails out. + */ + error = kern_ptrace(td, PT_GET_SC_ARGS, pid, + &si.entry.args, sizeof(si.entry.args)); + if (error != 0) { + linux_msg(td, "PT_GET_SC_ARGS failed with error %d", + error); + return (error); + } + } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { + si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT; + error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr)); + + if (error != 0) { + linux_msg(td, "PT_GET_SC_RET failed with error %d", + error); + return (error); + } + + if (sr.sr_error == 0) { + si.exit.rval = sr.sr_retval[0]; + si.exit.is_error = 0; + } else if (sr.sr_error == EJUSTRETURN) { + /* + * EJUSTRETURN means the actual value to return + * has already been put into td_frame; instead + * of extracting it and trying to determine whether + * it's an error or not just bail out and let + * the ptracing process fall back to another method. + */ + si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; + } else if (sr.sr_error == ERESTART) { + si.exit.rval = -LINUX_ERESTARTSYS; + si.exit.is_error = 1; + } else { + si.exit.rval = bsd_to_linux_errno(sr.sr_error); + si.exit.is_error = 1; + } + } else { + si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; + } + + error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); + if (error != 0) + return (error); + + linux_ptrace_get_syscall_info_machdep(&b_reg, &si); + + len = MIN(len, sizeof(si)); + error = copyout(&si, data, len); + if (error == 0) + td->td_retval[0] = sizeof(si); + + return (error); +} + +int +linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) +{ + void * __capability addr; + pid_t pid; + int error, sig; + + if (!allow_ptrace) + return (ENOSYS); + + pid = (pid_t)uap->pid; + addr = LINUX_USER_CAP_UNBOUND(uap->addr); + + switch (uap->req) { + case LINUX_PTRACE_TRACEME: + error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0); + break; + case LINUX_PTRACE_PEEKTEXT: + case LINUX_PTRACE_PEEKDATA: + error = linux_ptrace_peek(td, pid, addr, LINUX_USER_CAP(uap->data, sizeof(l_int))); + if (error != 0) + goto out; + /* + * Linux expects this syscall to read 64 bits, not 32. + */ + error = linux_ptrace_peek(td, pid, + LINUX_USER_CAP_UNBOUND(uap->addr + 4), LINUX_USER_CAP(uap->data + 4, sizeof(l_int))); + break; + case LINUX_PTRACE_PEEKUSER: + error = linux_ptrace_peekuser(td, pid, addr, LINUX_USER_CAP(uap->data, sizeof(l_int))); + break; + case LINUX_PTRACE_POKETEXT: + case LINUX_PTRACE_POKEDATA: + error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data); + if (error != 0) + goto out; + /* + * Linux expects this syscall to write 64 bits, not 32. + */ + error = kern_ptrace(td, PT_WRITE_D, pid, + LINUX_USER_CAP_UNBOUND(uap->addr + 4), uap->data >> 32); + break; + case LINUX_PTRACE_POKEUSER: + error = linux_ptrace_pokeuser(td, pid, addr, LINUX_USER_CAP(uap->data, sizeof(l_int))); + break; + case LINUX_PTRACE_CONT: + error = map_signum(uap->data, &sig); + if (error != 0) + break; + error = kern_ptrace(td, PT_CONTINUE, pid, LINUX_USER_CAP_UNBOUND(1), sig); + break; + case LINUX_PTRACE_KILL: + error = kern_ptrace(td, PT_KILL, pid, addr, uap->data); + break; + case LINUX_PTRACE_SINGLESTEP: + error = map_signum(uap->data, &sig); + if (error != 0) + break; + error = kern_ptrace(td, PT_STEP, pid, LINUX_USER_CAP_UNBOUND(1), sig); + break; + case LINUX_PTRACE_GETREGS: + error = linux_ptrace_getregs(td, pid, LINUX_USER_CAP(uap->data, sizeof(struct linux_pt_regset))); + break; + case LINUX_PTRACE_SETREGS: + error = linux_ptrace_setregs(td, pid, LINUX_USER_CAP(uap->data, sizeof(struct linux_pt_regset))); + break; + case LINUX_PTRACE_ATTACH: + error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); + break; + case LINUX_PTRACE_DETACH: + error = map_signum(uap->data, &sig); + if (error != 0) + break; + error = kern_ptrace(td, PT_DETACH, pid, LINUX_USER_CAP_UNBOUND(1), sig); + break; + case LINUX_PTRACE_SYSCALL: + error = map_signum(uap->data, &sig); + if (error != 0) + break; + error = kern_ptrace(td, PT_SYSCALL, pid, LINUX_USER_CAP_UNBOUND(1), sig); + break; + case LINUX_PTRACE_SETOPTIONS: + error = linux_ptrace_setoptions(td, pid, uap->data); + break; + case LINUX_PTRACE_GETEVENTMSG: + error = linux_ptrace_geteventmsg(td, pid, uap->data); + break; + case LINUX_PTRACE_GETSIGINFO: + error = linux_ptrace_getsiginfo(td, pid, LINUX_USER_CAP(uap->data, sizeof(l_siginfo_t))); + break; + case LINUX_PTRACE_GETREGSET: + error = linux_ptrace_getregset(td, pid, uap->addr, LINUX_USER_CAP(uap->data, sizeof(struct l_iovec64))); + break; + case LINUX_PTRACE_SEIZE: + error = linux_ptrace_seize(td, pid, uap->addr, uap->data); + break; + case LINUX_PTRACE_GET_SYSCALL_INFO: + error = linux_ptrace_get_syscall_info(td, pid, uap->addr, LINUX_USER_CAP(uap->data, uap->addr)); + break; + default: + linux_msg(td, "ptrace(%ld, ...) not implemented; " + "returning EINVAL", uap->req); + error = EINVAL; + break; + } + +out: + if (error == EBUSY) + error = ESRCH; + + return (error); +} diff --git a/sys/compat/linux/linux_rseq.c b/sys/compat/linux/linux_rseq.c index e8de17318d60..9aa1113fdf7f 100644 --- a/sys/compat/linux/linux_rseq.c +++ b/sys/compat/linux/linux_rseq.c @@ -1,84 +1,86 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2022 Dmitry Chagin - * - * 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 -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif - - -enum linux_rseq_cpu_id_state { - LINUX_RSEQ_CPU_ID_UNINITIALIZED = -1, - LINUX_RSEQ_CPU_ID_REGISTRATION_FAILED = -2, -}; - -enum linux_rseq_flags { - LINUX_RSEQ_FLAG_UNREGISTER = (1 << 0), -}; - -enum linux_rseq_cs_flags_bit { - LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0, - LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1, - LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2, -}; - -enum linux_rseq_cs_flags { - LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT = - (1U << LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT), - LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL = - (1U << LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT), - LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE = - (1U << LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT), -}; - -struct linux_rseq_cs { - uint32_t version; - uint32_t flags; - uint64_t start_ip; - uint64_t post_commit_offset; - uint64_t abort_ip; -} __attribute__((aligned(4 * sizeof(uint64_t)))); - -struct linux_rseq { - uint32_t cpu_id_start; - uint32_t cpu_id; - uint64_t rseq_cs; - uint32_t flags; -} __attribute__((aligned(4 * sizeof(uint64_t)))); - -int -linux_rseq(struct thread *td, struct linux_rseq_args *args) -{ - - return (ENOSYS); -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Dmitry Chagin + * + * 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 +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +enum linux_rseq_cpu_id_state { + LINUX_RSEQ_CPU_ID_UNINITIALIZED = -1, + LINUX_RSEQ_CPU_ID_REGISTRATION_FAILED = -2, +}; + +enum linux_rseq_flags { + LINUX_RSEQ_FLAG_UNREGISTER = (1 << 0), +}; + +enum linux_rseq_cs_flags_bit { + LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0, + LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1, + LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2, +}; + +enum linux_rseq_cs_flags { + LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT = + (1U << LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT), + LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL = + (1U << LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT), + LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE = + (1U << LINUX_RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT), +}; + +struct linux_rseq_cs { + uint32_t version; + uint32_t flags; + uint64_t start_ip; + uint64_t post_commit_offset; + uint64_t abort_ip; +} __attribute__((aligned(4 * sizeof(uint64_t)))); + +struct linux_rseq { + uint32_t cpu_id_start; + uint32_t cpu_id; + uint64_t rseq_cs; + uint32_t flags; +} __attribute__((aligned(4 * sizeof(uint64_t)))); + +int +linux_rseq(struct thread *td, struct linux_rseq_args *args) +{ + + return (ENOSYS); +} diff --git a/sys/compat/linux/linux_siginfo.h b/sys/compat/linux/linux_siginfo.h index f254b6a22bbd..1fac41026bd9 100644 --- a/sys/compat/linux/linux_siginfo.h +++ b/sys/compat/linux/linux_siginfo.h @@ -1,234 +1,275 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2004 Tim J. Robbins - * Copyright (c) 2001 Doug Rabson - * Copyright (c) 1994-1996 Søren Schmidt - * All rights reserved. - * Copyright (c) 2022 Dmitry Chagin - * - * 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 - * in this position and unchanged. - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - */ - -#ifndef _LINUX_SIGINFO_H_ -#define _LINUX_SIGINFO_H_ - -/* - * si_code values - */ -#define LINUX_SI_USER 0 /* sent by kill, sigsend, raise */ -#define LINUX_SI_KERNEL 0x80 /* sent by the kernel from somewhere */ -#define LINUX_SI_QUEUE -1 /* sent by sigqueue */ -#define LINUX_SI_TIMER -2 /* sent by timer expiration */ -#define LINUX_SI_MESGQ -3 /* sent by real time mesq state change */ -#define LINUX_SI_ASYNCIO -4 /* sent by AIO completion */ -#define LINUX_SI_SIGIO -5 /* sent by queued SIGIO */ -#define LINUX_SI_TKILL -6 /* sent by tkill system call */ - -/* - * SIGILL si_codes - */ -#define LINUX_ILL_ILLOPC 1 /* illegal opcode */ -#define LINUX_ILL_ILLOPN 2 /* illegal operand */ -#define LINUX_ILL_ILLADR 3 /* illegal addressing mode */ -#define LINUX_ILL_ILLTRP 4 /* illegal trap */ -#define LINUX_ILL_PRVOPC 5 /* privileged opcode */ -#define LINUX_ILL_PRVREG 6 /* privileged register */ -#define LINUX_ILL_COPROC 7 /* coprocessor error */ -#define LINUX_ILL_BADSTK 8 /* internal stack error */ -#define LINUX_ILL_BADIADDR 9 /* unimplemented instruction address */ -#define LINUX___ILL_BREAK 10 /* (ia64) illegal break */ -#define LINUX___ILL_BNDMOD 11 /* (ia64) bundle-update (modification) - * in progress - */ - -/* - * SIGFPE si_codes - */ -#define LINUX_FPE_INTDIV 1 /* integer divide by zero */ -#define LINUX_FPE_INTOVF 2 /* integer overflow */ -#define LINUX_FPE_FLTDIV 3 /* floating point divide by zero */ -#define LINUX_FPE_FLTOVF 4 /* floating point overflow */ -#define LINUX_FPE_FLTUND 5 /* floating point underflow */ -#define LINUX_FPE_FLTRES 6 /* floating point inexact result */ -#define LINUX_FPE_FLTINV 7 /* floating point invalid operation */ -#define LINUX_FPE_FLTSUB 8 /* (ia64) subscript out of range */ -#define LINUX___FPE_DECOVF 9 /* (ia64) decimal overflow */ -#define LINUX___FPE_DECDIV 10 /* (ia64) decimal division by zero */ -#define LINUX___FPE_DECERR 11 /* (ia64) packed decimal error */ -#define LINUX___FPE_INVASC 12 /* (ia64) invalid ASCII digit */ -#define LINUX___FPE_INVDEC 13 /* (ia64) invalid decimal digit */ -#define LINUX_FPE_FLTUNK 14 /* undiagnosed floating-point exception */ -#define LINUX_FPE_CONDTRAP 15 /* trap on condition */ - -/* - * SIGSEGV si_codes - */ -#define LINUX_SEGV_MAPERR 1 /* address not mapped to object */ -#define LINUX_SEGV_ACCERR 2 /* invalid permissions for mapped object */ -#define LINUX_SEGV_BNDERR 3 /* failed address bound checks */ -#ifdef __ia64__ -#define LINUX___SEGV_PSTKOVF 4 /* paragraph stack overflow */ -#else -#define LINUX_SEGV_PKUERR 4 /* failed protection key checks */ -#endif -#define LINUX_SEGV_ACCADI 5 /* ADI not enabled for mapped object */ -#define LINUX_SEGV_ADIDERR 6 /* Disrupting MCD error */ -#define LINUX_SEGV_ADIPERR 7 /* Precise MCD exception */ -#define LINUX_SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */ -#define LINUX_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */ - -/* - * SIGBUS si_codes - */ -#define LINUX_BUS_ADRALN 1 /* invalid address alignment */ -#define LINUX_BUS_ADRERR 2 /* non-existent physical address */ -#define LINUX_BUS_OBJERR 3 /* object specific hardware error */ - -#define LINUX_BUS_MCEERR_AR 4 /* hardware memory error consumed - * on a machine check: - * action required - */ -#define LINUX_BUS_MCEERR_AO 5 /* hardware memory error detected - * in process but not consumed: - * action optional - */ - -/* - * SIGTRAP si_codes - */ -#define LINUX_TRAP_BRKPT 1 /* process breakpoint */ -#define LINUX_TRAP_TRACE 2 /* process trace trap */ -#define LINUX_TRAP_BRANCH 3 /* process taken branch trap */ -#define LINUX_TRAP_HWBKPT 4 /* hardware breakpoint/watchpoint */ -#define LINUX_TRAP_UNK 5 /* undiagnosed trap */ -#define LINUX_TRAP_PERF 6 /* perf event with sigtrap=1 */ - -/* - * SIGCHLD si_codes - */ -#define LINUX_CLD_EXITED 1 /* child has exited */ -#define LINUX_CLD_KILLED 2 /* child was killed */ -#define LINUX_CLD_DUMPED 3 /* child terminated abnormally */ -#define LINUX_CLD_TRAPPED 4 /* traced child has trapped */ -#define LINUX_CLD_STOPPED 5 /* child has stopped */ -#define LINUX_CLD_CONTINUED 6 /* stopped child has continued */ - -/* - * SIGPOLL (or any other signal without signal specific si_codes) si_codes - */ -#define LINUX_POLL_IN 1 /* data input available */ -#define LINUX_POLL_OUT 2 /* output buffers available */ -#define LINUX_POLL_MSG 3 /* input message available */ -#define LINUX_POLL_ERR 4 /* i/o error */ -#define LINUX_POLL_PRI 5 /* high priority input available */ -#define LINUX_POLL_HUP 6 /* device disconnected */ - -/* - * SIGSYS si_codes - */ -#define LINUX_SYS_SECCOMP 1 /* seccomp triggered */ -#define LINUX_SYS_USER_DISPATCH 2 /* syscall user dispatch triggered */ - -/* - * SIGEMT si_codes - */ -#define LINUX_EMT_TAGOVF 1 /* tag overflow */ - -typedef union l_sigval { - l_int sival_int; - l_uintptr_t sival_ptr; -} l_sigval_t; - -#define LINUX_SI_MAX_SIZE 128 - -union __sifields { - struct { - l_pid_t _pid; - l_uid_t _uid; - } _kill; - - struct { - l_timer_t _tid; - l_int _overrun; - char _pad[sizeof(l_uid_t) - sizeof(int)]; - union l_sigval _sigval; - l_uint _sys_private; - } _timer; - - struct { - l_pid_t _pid; /* sender's pid */ - l_uid_t _uid; /* sender's uid */ - union l_sigval _sigval; - } _rt; - - struct { - l_pid_t _pid; /* which child */ - l_uid_t _uid; /* sender's uid */ - l_int _status; /* exit code */ - l_clock_t _utime; - l_clock_t _stime; - } _sigchld; - - struct { - l_uintptr_t _addr; /* Faulting insn/memory ref. */ - } _sigfault; - - struct { - l_long _band; /* POLL_IN,POLL_OUT,POLL_MSG */ - l_int _fd; - } _sigpoll; -}; - -typedef struct l_siginfo { - union { - struct { - l_int lsi_signo; - l_int lsi_errno; - l_int lsi_code; - union __sifields _sifields; - }; - l_int _pad[LINUX_SI_MAX_SIZE/sizeof(l_int)]; - }; -} l_siginfo_t; - -_Static_assert(sizeof(l_siginfo_t) == LINUX_SI_MAX_SIZE, "l_siginfo_t size"); - -#define lsi_pid _sifields._kill._pid -#define lsi_uid _sifields._kill._uid -#define lsi_tid _sifields._timer._tid -#define lsi_overrun _sifields._timer._overrun -#define lsi_sys_private _sifields._timer._sys_private -#define lsi_status _sifields._sigchld._status -#define lsi_utime _sifields._sigchld._utime -#define lsi_stime _sifields._sigchld._stime -#define lsi_value _sifields._rt._sigval -#define lsi_int _sifields._rt._sigval.sival_int -#define lsi_ptr _sifields._rt._sigval.sival_ptr -#define lsi_addr _sifields._sigfault._addr -#define lsi_band _sifields._sigpoll._band -#define lsi_fd _sifields._sigpoll._fd - -#endif /* _LINUX_SIGINFO_H_ */ - +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2004 Tim J. Robbins + * Copyright (c) 2001 Doug Rabson + * Copyright (c) 1994-1996 Søren Schmidt + * All rights reserved. + * Copyright (c) 2022 Dmitry Chagin + * + * 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 + * in this position and unchanged. + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#ifndef _LINUX_SIGINFO_H_ +#define _LINUX_SIGINFO_H_ + +#include + +/* + * si_code values + */ +#define LINUX_SI_USER 0 /* sent by kill, sigsend, raise */ +#define LINUX_SI_KERNEL 0x80 /* sent by the kernel from somewhere */ +#define LINUX_SI_QUEUE -1 /* sent by sigqueue */ +#define LINUX_SI_TIMER -2 /* sent by timer expiration */ +#define LINUX_SI_MESGQ -3 /* sent by real time mesq state change */ +#define LINUX_SI_ASYNCIO -4 /* sent by AIO completion */ +#define LINUX_SI_SIGIO -5 /* sent by queued SIGIO */ +#define LINUX_SI_TKILL -6 /* sent by tkill system call */ + +/* + * SIGILL si_codes + */ +#define LINUX_ILL_ILLOPC 1 /* illegal opcode */ +#define LINUX_ILL_ILLOPN 2 /* illegal operand */ +#define LINUX_ILL_ILLADR 3 /* illegal addressing mode */ +#define LINUX_ILL_ILLTRP 4 /* illegal trap */ +#define LINUX_ILL_PRVOPC 5 /* privileged opcode */ +#define LINUX_ILL_PRVREG 6 /* privileged register */ +#define LINUX_ILL_COPROC 7 /* coprocessor error */ +#define LINUX_ILL_BADSTK 8 /* internal stack error */ +#define LINUX_ILL_BADIADDR 9 /* unimplemented instruction address */ +#define LINUX___ILL_BREAK 10 /* (ia64) illegal break */ +#define LINUX___ILL_BNDMOD 11 /* (ia64) bundle-update (modification) + * in progress + */ + +/* + * SIGFPE si_codes + */ +#define LINUX_FPE_INTDIV 1 /* integer divide by zero */ +#define LINUX_FPE_INTOVF 2 /* integer overflow */ +#define LINUX_FPE_FLTDIV 3 /* floating point divide by zero */ +#define LINUX_FPE_FLTOVF 4 /* floating point overflow */ +#define LINUX_FPE_FLTUND 5 /* floating point underflow */ +#define LINUX_FPE_FLTRES 6 /* floating point inexact result */ +#define LINUX_FPE_FLTINV 7 /* floating point invalid operation */ +#define LINUX_FPE_FLTSUB 8 /* (ia64) subscript out of range */ +#define LINUX___FPE_DECOVF 9 /* (ia64) decimal overflow */ +#define LINUX___FPE_DECDIV 10 /* (ia64) decimal division by zero */ +#define LINUX___FPE_DECERR 11 /* (ia64) packed decimal error */ +#define LINUX___FPE_INVASC 12 /* (ia64) invalid ASCII digit */ +#define LINUX___FPE_INVDEC 13 /* (ia64) invalid decimal digit */ +#define LINUX_FPE_FLTUNK 14 /* undiagnosed floating-point exception */ +#define LINUX_FPE_CONDTRAP 15 /* trap on condition */ + +/* + * SIGSEGV si_codes + */ +#define LINUX_SEGV_MAPERR 1 /* address not mapped to object */ +#define LINUX_SEGV_ACCERR 2 /* invalid permissions for mapped object */ +#define LINUX_SEGV_BNDERR 3 /* failed address bound checks */ +#ifdef __ia64__ +#define LINUX___SEGV_PSTKOVF 4 /* paragraph stack overflow */ +#else +#define LINUX_SEGV_PKUERR 4 /* failed protection key checks */ +#endif +#define LINUX_SEGV_ACCADI 5 /* ADI not enabled for mapped object */ +#define LINUX_SEGV_ADIDERR 6 /* Disrupting MCD error */ +#define LINUX_SEGV_ADIPERR 7 /* Precise MCD exception */ +#define LINUX_SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */ +#define LINUX_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */ + +/* + * SIGBUS si_codes + */ +#define LINUX_BUS_ADRALN 1 /* invalid address alignment */ +#define LINUX_BUS_ADRERR 2 /* non-existent physical address */ +#define LINUX_BUS_OBJERR 3 /* object specific hardware error */ + +#define LINUX_BUS_MCEERR_AR 4 /* hardware memory error consumed + * on a machine check: + * action required + */ +#define LINUX_BUS_MCEERR_AO 5 /* hardware memory error detected + * in process but not consumed: + * action optional + */ + +/* + * SIGTRAP si_codes + */ +#define LINUX_TRAP_BRKPT 1 /* process breakpoint */ +#define LINUX_TRAP_TRACE 2 /* process trace trap */ +#define LINUX_TRAP_BRANCH 3 /* process taken branch trap */ +#define LINUX_TRAP_HWBKPT 4 /* hardware breakpoint/watchpoint */ +#define LINUX_TRAP_UNK 5 /* undiagnosed trap */ +#define LINUX_TRAP_PERF 6 /* perf event with sigtrap=1 */ + +/* + * SIGCHLD si_codes + */ +#define LINUX_CLD_EXITED 1 /* child has exited */ +#define LINUX_CLD_KILLED 2 /* child was killed */ +#define LINUX_CLD_DUMPED 3 /* child terminated abnormally */ +#define LINUX_CLD_TRAPPED 4 /* traced child has trapped */ +#define LINUX_CLD_STOPPED 5 /* child has stopped */ +#define LINUX_CLD_CONTINUED 6 /* stopped child has continued */ + +/* + * SIGPOLL (or any other signal without signal specific si_codes) si_codes + */ +#define LINUX_POLL_IN 1 /* data input available */ +#define LINUX_POLL_OUT 2 /* output buffers available */ +#define LINUX_POLL_MSG 3 /* input message available */ +#define LINUX_POLL_ERR 4 /* i/o error */ +#define LINUX_POLL_PRI 5 /* high priority input available */ +#define LINUX_POLL_HUP 6 /* device disconnected */ + +/* + * SIGSYS si_codes + */ +#define LINUX_SYS_SECCOMP 1 /* seccomp triggered */ +#define LINUX_SYS_USER_DISPATCH 2 /* syscall user dispatch triggered */ + +/* + * SIGEMT si_codes + */ +#define LINUX_EMT_TAGOVF 1 /* tag overflow */ + +typedef union l_sigval { + l_int sival_int; + l_uintptr_t sival_ptr; +} l_sigval_t; + +#define LINUX_SI_MAX_SIZE 128 + +union __sifields { + struct { + l_pid_t _pid; + l_uid_t _uid; + } _kill; + + struct { + l_timer_t _tid; + l_int _overrun; + char _pad[sizeof(l_uid_t) - sizeof(int)]; + union l_sigval _sigval; + l_uint _sys_private; + } _timer; + + struct { + l_pid_t _pid; /* sender's pid */ + l_uid_t _uid; /* sender's uid */ + union l_sigval _sigval; + } _rt; + + struct { + l_pid_t _pid; /* which child */ + l_uid_t _uid; /* sender's uid */ + l_int _status; /* exit code */ + l_clock_t _utime; + l_clock_t _stime; + } _sigchld; + + struct { + l_uintptr_t _addr; /* Faulting insn/memory ref. */ + } _sigfault; + + struct { + l_long _band; /* POLL_IN,POLL_OUT,POLL_MSG */ + l_int _fd; + } _sigpoll; +}; + +typedef struct l_siginfo { + union { + struct { + l_int lsi_signo; + l_int lsi_errno; + l_int lsi_code; + union __sifields _sifields; + }; + l_int _pad[LINUX_SI_MAX_SIZE/sizeof(l_int)]; + }; +} l_siginfo_t; + +_Static_assert(sizeof(l_siginfo_t) == LINUX_SI_MAX_SIZE, "l_siginfo_t size"); + +#define lsi_pid _sifields._kill._pid +#define lsi_uid _sifields._kill._uid +#define lsi_tid _sifields._timer._tid +#define lsi_overrun _sifields._timer._overrun +#define lsi_sys_private _sifields._timer._sys_private +#define lsi_status _sifields._sigchld._status +#define lsi_utime _sifields._sigchld._utime +#define lsi_stime _sifields._sigchld._stime +#define lsi_value _sifields._rt._sigval +#define lsi_int _sifields._rt._sigval.sival_int +#define lsi_ptr _sifields._rt._sigval.sival_ptr +#define lsi_addr _sifields._sigfault._addr +#define lsi_band _sifields._sigpoll._band +#define lsi_fd _sifields._sigpoll._fd + +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) +_Static_assert(__alignof__(l_siginfo_t) == 16, "l_siginfo_t alignment"); +_Static_assert(offsetof(l_siginfo_t, lsi_signo) == 0x00, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_errno) == 0x04, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_code) == 0x08, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_pid) == 0x10, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_uid) == 0x14, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_tid) == 0x10, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_overrun) == 0x14, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_status) == 0x18, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_utime) == 0x20, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_stime) == 0x28, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_value) == 0x20, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_int) == 0x20, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_ptr) == 0x20, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_addr) == 0x10, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_band) == 0x10, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_fd) == 0x18, "l_siginfo_t layout"); +#else +_Static_assert(__alignof__(l_siginfo_t) == 8, "l_siginfo_t alignment"); +_Static_assert(offsetof(l_siginfo_t, lsi_signo) == 0x00, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_errno) == 0x04, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_code) == 0x08, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_pid) == 0x10, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_uid) == 0x14, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_tid) == 0x10, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_overrun) == 0x14, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_status) == 0x18, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_utime) == 0x20, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_stime) == 0x28, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_value) == 0x18, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_int) == 0x18, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_ptr) == 0x18, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_addr) == 0x10, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_band) == 0x10, "l_siginfo_t layout"); +_Static_assert(offsetof(l_siginfo_t, lsi_fd) == 0x18, "l_siginfo_t layout"); +#endif + + +#endif /* _LINUX_SIGINFO_H_ */ + diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c index 9a84700b3949..fb3e7cec9027 100644 --- a/sys/compat/linux/linux_signal.c +++ b/sys/compat/linux/linux_signal.c @@ -1,981 +1,985 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * 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 "opt_ktrace.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef KTRACE -#include -#endif - -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif -#include -#include -#include -#include -#include -#include - -static int linux_pksignal(struct thread *td, int pid, int sig, - ksiginfo_t *ksi); -static int linux_psignal(struct thread *td, int pid, int sig); -static int linux_tdksignal(struct thread *td, lwpid_t tid, - int tgid, int sig, ksiginfo_t *ksi); -static int linux_tdsignal(struct thread *td, lwpid_t tid, - int tgid, int sig); -static void sicode_to_lsicode(int sig, int si_code, int *lsi_code); -static int linux_common_rt_sigtimedwait(struct thread *, - l_sigset_t *, struct timespec *, l_siginfo_t *, - l_size_t); - -static void -linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa) -{ - unsigned long flags; - - linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask); - bsa->sa_handler = PTRIN(lsa->lsa_handler); - bsa->sa_flags = 0; - - flags = lsa->lsa_flags; - if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) { - flags &= ~LINUX_SA_NOCLDSTOP; - bsa->sa_flags |= SA_NOCLDSTOP; - } - if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) { - flags &= ~LINUX_SA_NOCLDWAIT; - bsa->sa_flags |= SA_NOCLDWAIT; - } - if (lsa->lsa_flags & LINUX_SA_SIGINFO) { - flags &= ~LINUX_SA_SIGINFO; - bsa->sa_flags |= SA_SIGINFO; -#ifdef notyet - /* - * XXX: We seem to be missing code to convert - * some of the fields in ucontext_t. - */ - linux_msg(curthread, - "partially unsupported sigaction flag SA_SIGINFO"); -#endif - } - if (lsa->lsa_flags & LINUX_SA_RESTORER) { - flags &= ~LINUX_SA_RESTORER; - /* - * We ignore the lsa_restorer and always use our own signal - * trampoline instead. It looks like SA_RESTORER is obsolete - * in Linux too - it doesn't seem to be used at all on arm64. - * In any case: see Linux sigreturn(2). - */ - } - if (lsa->lsa_flags & LINUX_SA_ONSTACK) { - flags &= ~LINUX_SA_ONSTACK; - bsa->sa_flags |= SA_ONSTACK; - } - if (lsa->lsa_flags & LINUX_SA_RESTART) { - flags &= ~LINUX_SA_RESTART; - bsa->sa_flags |= SA_RESTART; - } - if (lsa->lsa_flags & LINUX_SA_INTERRUPT) { - flags &= ~LINUX_SA_INTERRUPT; - /* Documented to be a "historical no-op". */ - } - if (lsa->lsa_flags & LINUX_SA_ONESHOT) { - flags &= ~LINUX_SA_ONESHOT; - bsa->sa_flags |= SA_RESETHAND; - } - if (lsa->lsa_flags & LINUX_SA_NOMASK) { - flags &= ~LINUX_SA_NOMASK; - bsa->sa_flags |= SA_NODEFER; - } - - if (flags != 0) - linux_msg(curthread, "unsupported sigaction flag %#lx", flags); -} - -static void -bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa) -{ - - bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask); -#ifdef COMPAT_LINUX32 - lsa->lsa_handler = (uintptr_t)bsa->sa_handler; -#else - lsa->lsa_handler = bsa->sa_handler; -#endif - lsa->lsa_restorer = 0; /* unsupported */ - lsa->lsa_flags = 0; - if (bsa->sa_flags & SA_NOCLDSTOP) - lsa->lsa_flags |= LINUX_SA_NOCLDSTOP; - if (bsa->sa_flags & SA_NOCLDWAIT) - lsa->lsa_flags |= LINUX_SA_NOCLDWAIT; - if (bsa->sa_flags & SA_SIGINFO) - lsa->lsa_flags |= LINUX_SA_SIGINFO; - if (bsa->sa_flags & SA_ONSTACK) - lsa->lsa_flags |= LINUX_SA_ONSTACK; - if (bsa->sa_flags & SA_RESTART) - lsa->lsa_flags |= LINUX_SA_RESTART; - if (bsa->sa_flags & SA_RESETHAND) - lsa->lsa_flags |= LINUX_SA_ONESHOT; - if (bsa->sa_flags & SA_NODEFER) - lsa->lsa_flags |= LINUX_SA_NOMASK; -} - -int -linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa, - l_sigaction_t *linux_osa) -{ - struct sigaction act, oact, *nsa, *osa; - int error, sig; - - if (!LINUX_SIG_VALID(linux_sig)) - return (EINVAL); - sig = linux_to_bsd_signal(linux_sig); - - osa = (linux_osa != NULL) ? &oact : NULL; - if (linux_nsa != NULL) { - nsa = &act; - linux_to_bsd_sigaction(linux_nsa, nsa); -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&linux_nsa->lsa_mask, - sizeof(linux_nsa->lsa_mask)); -#endif - if ((sig == SIGKILL || sig == SIGSTOP) && - nsa->sa_handler == SIG_DFL) - return (EINVAL); - } else - nsa = NULL; - - error = kern_sigaction(td, sig, nsa, osa, 0); - if (error != 0) - return (error); - - if (linux_osa != NULL) { - bsd_to_linux_sigaction(osa, linux_osa); -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&linux_osa->lsa_mask, - sizeof(linux_osa->lsa_mask)); -#endif - } - return (0); -} - -int -linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) -{ - stack_t ss, oss; - l_stack_t lss; - int error; - - memset(&lss, 0, sizeof(lss)); - LINUX_CTR2(sigaltstack, "%p, %p", uap->uss, uap->uoss); - - if (uap->uss != NULL) { - error = copyin(uap->uss, &lss, sizeof(lss)); - if (error != 0) - return (error); - - ss.ss_sp = PTRIN(lss.ss_sp); - ss.ss_size = lss.ss_size; - ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags); - } - error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL, - (uap->uoss != NULL) ? &oss : NULL); - if (error == 0 && uap->uoss != NULL) { - lss.ss_sp = PTROUT(oss.ss_sp); - lss.ss_size = oss.ss_size; - lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags); - error = copyout(&lss, uap->uoss, sizeof(lss)); - } - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_signal(struct thread *td, struct linux_signal_args *args) -{ - l_sigaction_t nsa, osa; - int error; - - nsa.lsa_handler = args->handler; - nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK; - LINUX_SIGEMPTYSET(nsa.lsa_mask); - - error = linux_do_sigaction(td, args->sig, &nsa, &osa); - td->td_retval[0] = (int)(intptr_t)osa.lsa_handler; - - return (error); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args) -{ - l_sigaction_t nsa, osa; - int error; - - if (args->sigsetsize != sizeof(l_sigset_t)) - return (EINVAL); - - if (args->act != NULL) { - error = copyin(args->act, &nsa, sizeof(nsa)); - if (error != 0) - return (error); - } - - error = linux_do_sigaction(td, args->sig, - args->act ? &nsa : NULL, - args->oact ? &osa : NULL); - - if (args->oact != NULL && error == 0) - error = copyout(&osa, args->oact, sizeof(osa)); - - return (error); -} - -static int -linux_do_sigprocmask(struct thread *td, int how, sigset_t *new, - l_sigset_t *old) -{ - sigset_t omask; - int error; - - td->td_retval[0] = 0; - - switch (how) { - case LINUX_SIG_BLOCK: - how = SIG_BLOCK; - break; - case LINUX_SIG_UNBLOCK: - how = SIG_UNBLOCK; - break; - case LINUX_SIG_SETMASK: - how = SIG_SETMASK; - break; - default: - return (EINVAL); - } - error = kern_sigprocmask(td, how, new, &omask, 0); - if (error == 0 && old != NULL) - bsd_to_linux_sigset(&omask, old); - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args) -{ - l_osigset_t mask; - l_sigset_t lset, oset; - sigset_t set; - int error; - - if (args->mask != NULL) { - error = copyin(args->mask, &mask, sizeof(mask)); - if (error != 0) - return (error); - LINUX_SIGEMPTYSET(lset); - lset.__mask = mask; -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&lset, sizeof(lset)); -#endif - linux_to_bsd_sigset(&lset, &set); - } - - error = linux_do_sigprocmask(td, args->how, - args->mask ? &set : NULL, - args->omask ? &oset : NULL); - - if (args->omask != NULL && error == 0) { -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&oset, sizeof(oset)); -#endif - mask = oset.__mask; - error = copyout(&mask, args->omask, sizeof(mask)); - } - - return (error); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args) -{ - l_sigset_t oset; - sigset_t set, *pset; - int error; - - error = linux_copyin_sigset(td, args->mask, args->sigsetsize, - &set, &pset); - if (error != 0) - return (EINVAL); - - error = linux_do_sigprocmask(td, args->how, pset, - args->omask ? &oset : NULL); - - if (args->omask != NULL && error == 0) { -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&oset, sizeof(oset)); -#endif - error = copyout(&oset, args->omask, sizeof(oset)); - } - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args) -{ - struct proc *p = td->td_proc; - l_sigset_t mask; - - PROC_LOCK(p); - bsd_to_linux_sigset(&td->td_sigmask, &mask); - PROC_UNLOCK(p); - td->td_retval[0] = mask.__mask; -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&mask, sizeof(mask)); -#endif - return (0); -} - -int -linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args) -{ - struct proc *p = td->td_proc; - l_sigset_t lset; - sigset_t bset; - - PROC_LOCK(p); - bsd_to_linux_sigset(&td->td_sigmask, &lset); - td->td_retval[0] = lset.__mask; - LINUX_SIGEMPTYSET(lset); - lset.__mask = args->mask; - linux_to_bsd_sigset(&lset, &bset); -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&lset, sizeof(lset)); -#endif - td->td_sigmask = bset; - SIG_CANTMASK(td->td_sigmask); - signotify(td); - PROC_UNLOCK(p); - return (0); -} - -int -linux_sigpending(struct thread *td, struct linux_sigpending_args *args) -{ - struct proc *p = td->td_proc; - sigset_t bset; - l_sigset_t lset; - l_osigset_t mask; - - PROC_LOCK(p); - bset = p->p_siglist; - SIGSETOR(bset, td->td_siglist); - SIGSETAND(bset, td->td_sigmask); - PROC_UNLOCK(p); - bsd_to_linux_sigset(&bset, &lset); -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&lset, sizeof(lset)); -#endif - mask = lset.__mask; - return (copyout(&mask, args->mask, sizeof(mask))); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -/* - * MPSAFE - */ -int -linux_rt_sigpending(struct thread *td, struct linux_rt_sigpending_args *args) -{ - struct proc *p = td->td_proc; - sigset_t bset; - l_sigset_t lset; - - if (args->sigsetsize > sizeof(lset)) - return (EINVAL); - /* NOT REACHED */ - - PROC_LOCK(p); - bset = p->p_siglist; - SIGSETOR(bset, td->td_siglist); - SIGSETAND(bset, td->td_sigmask); - PROC_UNLOCK(p); - bsd_to_linux_sigset(&bset, &lset); -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&lset, sizeof(lset)); -#endif - return (copyout(&lset, args->set, args->sigsetsize)); -} - -int -linux_rt_sigtimedwait(struct thread *td, - struct linux_rt_sigtimedwait_args *args) -{ - struct timespec ts, *tsa; - int error; - - if (args->timeout) { - error = linux_get_timespec(&ts, args->timeout); - if (error != 0) - return (error); - tsa = &ts; - } else - tsa = NULL; - - return (linux_common_rt_sigtimedwait(td, args->mask, tsa, - args->ptr, args->sigsetsize)); -} - -static int -linux_common_rt_sigtimedwait(struct thread *td, l_sigset_t *mask, - struct timespec *tsa, l_siginfo_t *ptr, l_size_t sigsetsize) -{ - int error, sig; - sigset_t bset; - l_siginfo_t lsi; - ksiginfo_t ksi; - - error = linux_copyin_sigset(td, mask, sigsetsize, &bset, NULL); - if (error != 0) - return (error); - - ksiginfo_init(&ksi); - error = kern_sigtimedwait(td, bset, &ksi, tsa); - if (error != 0) - return (error); - - sig = bsd_to_linux_signal(ksi.ksi_signo); - - if (ptr) { - memset(&lsi, 0, sizeof(lsi)); - siginfo_to_lsiginfo(&ksi.ksi_info, &lsi, sig); - error = copyout(&lsi, ptr, sizeof(lsi)); - } - if (error == 0) - td->td_retval[0] = sig; - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_rt_sigtimedwait_time64(struct thread *td, - struct linux_rt_sigtimedwait_time64_args *args) -{ - struct timespec ts, *tsa; - int error; - - if (args->timeout) { - error = linux_get_timespec64(&ts, args->timeout); - if (error != 0) - return (error); - tsa = &ts; - } else - tsa = NULL; - - return (linux_common_rt_sigtimedwait(td, args->mask, tsa, - args->ptr, args->sigsetsize)); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_kill(struct thread *td, struct linux_kill_args *args) -{ - int sig; - - /* - * Allow signal 0 as a means to check for privileges - */ - if (!LINUX_SIG_VALID(args->signum) && args->signum != 0) - return (EINVAL); - - if (args->signum > 0) - sig = linux_to_bsd_signal(args->signum); - else - sig = 0; - - if (args->pid > PID_MAX) - return (linux_psignal(td, args->pid, sig)); - else - return (kern_kill(td, args->pid, sig)); -} - -int -linux_tgkill(struct thread *td, struct linux_tgkill_args *args) -{ - int sig; - - if (args->pid <= 0 || args->tgid <=0) - return (EINVAL); - - /* - * Allow signal 0 as a means to check for privileges - */ - if (!LINUX_SIG_VALID(args->sig) && args->sig != 0) - return (EINVAL); - - if (args->sig > 0) - sig = linux_to_bsd_signal(args->sig); - else - sig = 0; - - return (linux_tdsignal(td, args->pid, args->tgid, sig)); -} - -/* - * Deprecated since 2.5.75. Replaced by tgkill(). - */ -int -linux_tkill(struct thread *td, struct linux_tkill_args *args) -{ - int sig; - - if (args->tid <= 0) - return (EINVAL); - - if (!LINUX_SIG_VALID(args->sig)) - return (EINVAL); - - sig = linux_to_bsd_signal(args->sig); - - return (linux_tdsignal(td, args->tid, -1, sig)); -} - -static int -sigfpe_sicode2lsicode(int si_code) -{ - - switch (si_code) { - case FPE_INTOVF: - return (LINUX_FPE_INTOVF); - case FPE_INTDIV: - return (LINUX_FPE_INTDIV); - case FPE_FLTIDO: - return (LINUX_FPE_FLTUNK); - default: - return (si_code); - } -} - -static int -sigbus_sicode2lsicode(int si_code) -{ - - switch (si_code) { - case BUS_OOMERR: - return (LINUX_BUS_MCEERR_AR); - default: - return (si_code); - } -} - -static int -sigsegv_sicode2lsicode(int si_code) -{ - - switch (si_code) { - case SEGV_PKUERR: - return (LINUX_SEGV_PKUERR); - default: - return (si_code); - } -} - -static int -sigtrap_sicode2lsicode(int si_code) -{ - - switch (si_code) { - case TRAP_DTRACE: - return (LINUX_TRAP_TRACE); - case TRAP_CAP: - return (LINUX_TRAP_UNK); - default: - return (si_code); - } -} - -static void -sicode_to_lsicode(int sig, int si_code, int *lsi_code) -{ - - switch (si_code) { - case SI_USER: - *lsi_code = LINUX_SI_USER; - break; - case SI_KERNEL: - *lsi_code = LINUX_SI_KERNEL; - break; - case SI_QUEUE: - *lsi_code = LINUX_SI_QUEUE; - break; - case SI_TIMER: - *lsi_code = LINUX_SI_TIMER; - break; - case SI_MESGQ: - *lsi_code = LINUX_SI_MESGQ; - break; - case SI_ASYNCIO: - *lsi_code = LINUX_SI_ASYNCIO; - break; - case SI_LWP: - *lsi_code = LINUX_SI_TKILL; - break; - default: - switch (sig) { - case LINUX_SIGFPE: - *lsi_code = sigfpe_sicode2lsicode(si_code); - break; - case LINUX_SIGBUS: - *lsi_code = sigbus_sicode2lsicode(si_code); - break; - case LINUX_SIGSEGV: - *lsi_code = sigsegv_sicode2lsicode(si_code); - break; - case LINUX_SIGTRAP: - *lsi_code = sigtrap_sicode2lsicode(si_code); - break; - default: - *lsi_code = si_code; - break; - } - break; - } -} - -void -siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig) -{ - - /* sig already converted */ - lsi->lsi_signo = sig; - sicode_to_lsicode(sig, si->si_code, &lsi->lsi_code); - - switch (si->si_code) { - case SI_LWP: - lsi->lsi_pid = si->si_pid; - lsi->lsi_uid = si->si_uid; - break; - - case SI_TIMER: - lsi->lsi_int = si->si_value.sival_int; - lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr); - lsi->lsi_tid = si->si_timerid; - break; - - case SI_QUEUE: - lsi->lsi_pid = si->si_pid; - lsi->lsi_uid = si->si_uid; - lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr); - break; - - case SI_ASYNCIO: - lsi->lsi_int = si->si_value.sival_int; - lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr); - break; - - default: - switch (sig) { - case LINUX_SIGPOLL: - /* XXX si_fd? */ - lsi->lsi_band = si->si_band; - break; - - case LINUX_SIGCHLD: - lsi->lsi_errno = 0; - lsi->lsi_pid = si->si_pid; - lsi->lsi_uid = si->si_uid; - - if (si->si_code == CLD_STOPPED || si->si_code == CLD_KILLED) - lsi->lsi_status = bsd_to_linux_signal(si->si_status); - else if (si->si_code == CLD_CONTINUED) - lsi->lsi_status = bsd_to_linux_signal(SIGCONT); - else - lsi->lsi_status = si->si_status; - break; - - case LINUX_SIGBUS: - case LINUX_SIGILL: - case LINUX_SIGFPE: - case LINUX_SIGSEGV: - lsi->lsi_addr = PTROUT(si->si_addr); - break; - - default: - lsi->lsi_pid = si->si_pid; - lsi->lsi_uid = si->si_uid; - if (sig >= LINUX_SIGRTMIN) { - lsi->lsi_int = si->si_value.sival_int; - lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr); - } - break; - } - break; - } -} - -static int -lsiginfo_to_siginfo(struct thread *td, const l_siginfo_t *lsi, - siginfo_t *si, int sig) -{ - - switch (lsi->lsi_code) { - case LINUX_SI_TKILL: - if (linux_kernver(td) >= LINUX_KERNVER(2,6,39)) { - linux_msg(td, "SI_TKILL forbidden since 2.6.39"); - return (EPERM); - } - si->si_code = SI_LWP; - case LINUX_SI_QUEUE: - si->si_code = SI_QUEUE; - break; - case LINUX_SI_TIMER: - si->si_code = SI_TIMER; - break; - case LINUX_SI_MESGQ: - si->si_code = SI_MESGQ; - break; - case LINUX_SI_ASYNCIO: - si->si_code = SI_ASYNCIO; - break; - default: - si->si_code = lsi->lsi_code; - break; - } - - si->si_signo = sig; - si->si_pid = td->td_proc->p_pid; - si->si_uid = td->td_ucred->cr_ruid; - si->si_value.sival_ptr = PTRIN(lsi->lsi_value.sival_ptr); - return (0); -} - -int -linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args) -{ - l_siginfo_t linfo; - ksiginfo_t ksi; - int error; - int sig; - - if (!LINUX_SIG_VALID(args->sig)) - return (EINVAL); - - error = copyin(args->info, &linfo, sizeof(linfo)); - if (error != 0) - return (error); - - if (linfo.lsi_code >= 0) - /* SI_USER, SI_KERNEL */ - return (EPERM); - - sig = linux_to_bsd_signal(args->sig); - ksiginfo_init(&ksi); - error = lsiginfo_to_siginfo(td, &linfo, &ksi.ksi_info, sig); - if (error != 0) - return (error); - - return (linux_pksignal(td, args->pid, sig, &ksi)); -} - -int -linux_rt_tgsigqueueinfo(struct thread *td, struct linux_rt_tgsigqueueinfo_args *args) -{ - l_siginfo_t linfo; - ksiginfo_t ksi; - int error; - int sig; - - if (!LINUX_SIG_VALID(args->sig)) - return (EINVAL); - - error = copyin(args->uinfo, &linfo, sizeof(linfo)); - if (error != 0) - return (error); - - if (linfo.lsi_code >= 0) - return (EPERM); - - sig = linux_to_bsd_signal(args->sig); - ksiginfo_init(&ksi); - error = lsiginfo_to_siginfo(td, &linfo, &ksi.ksi_info, sig); - if (error != 0) - return (error); - - return (linux_tdksignal(td, args->tid, args->tgid, sig, &ksi)); -} - -int -linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap) -{ - sigset_t sigmask; - int error; - - error = linux_copyin_sigset(td, uap->newset, uap->sigsetsize, - &sigmask, NULL); - if (error != 0) - return (error); - - return (kern_sigsuspend(td, sigmask)); -} - -static int -linux_tdksignal(struct thread *td, lwpid_t tid, int tgid, int sig, - ksiginfo_t *ksi) -{ - struct thread *tdt; - struct proc *p; - int error; - - tdt = linux_tdfind(td, tid, tgid); - if (tdt == NULL) - return (ESRCH); - - p = tdt->td_proc; - AUDIT_ARG_SIGNUM(sig); - AUDIT_ARG_PID(p->p_pid); - AUDIT_ARG_PROCESS(p); - - error = p_cansignal(td, p, sig); - if (error != 0 || sig == 0) - goto out; - - tdksignal(tdt, sig, ksi); - -out: - PROC_UNLOCK(p); - return (error); -} - -static int -linux_tdsignal(struct thread *td, lwpid_t tid, int tgid, int sig) -{ - ksiginfo_t ksi; - - ksiginfo_init(&ksi); - ksi.ksi_signo = sig; - ksi.ksi_code = SI_LWP; - ksi.ksi_pid = td->td_proc->p_pid; - ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid; - return (linux_tdksignal(td, tid, tgid, sig, &ksi)); -} - -static int -linux_pksignal(struct thread *td, int pid, int sig, ksiginfo_t *ksi) -{ - struct thread *tdt; - struct proc *p; - int error; - - tdt = linux_tdfind(td, pid, -1); - if (tdt == NULL) - return (ESRCH); - - p = tdt->td_proc; - AUDIT_ARG_SIGNUM(sig); - AUDIT_ARG_PID(p->p_pid); - AUDIT_ARG_PROCESS(p); - - error = p_cansignal(td, p, sig); - if (error != 0 || sig == 0) - goto out; - - pksignal(p, sig, ksi); - -out: - PROC_UNLOCK(p); - return (error); -} - -static int -linux_psignal(struct thread *td, int pid, int sig) -{ - ksiginfo_t ksi; - - ksiginfo_init(&ksi); - ksi.ksi_signo = sig; - ksi.ksi_code = SI_LWP; - ksi.ksi_pid = td->td_proc->p_pid; - ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid; - return (linux_pksignal(td, pid, sig, &ksi)); -} - -int -linux_copyin_sigset(struct thread *td, l_sigset_t *lset, - l_size_t sigsetsize, sigset_t *set, sigset_t **pset) -{ - l_sigset_t lmask; - int error; - - if (sigsetsize != sizeof(l_sigset_t)) - return (EINVAL); - if (lset != NULL) { - error = copyin(lset, &lmask, sizeof(lmask)); - if (error != 0) - return (error); - linux_to_bsd_sigset(&lmask, set); - if (pset != NULL) - *pset = set; -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - linux_ktrsigset(&lmask, sizeof(lmask)); -#endif - } else if (pset != NULL) - *pset = NULL; - return (0); -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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 "opt_ktrace.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef KTRACE +#include +#endif + +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +static int linux_pksignal(struct thread *td, int pid, int sig, + ksiginfo_t *ksi); +static int linux_psignal(struct thread *td, int pid, int sig); +static int linux_tdksignal(struct thread *td, lwpid_t tid, + int tgid, int sig, ksiginfo_t *ksi); +static int linux_tdsignal(struct thread *td, lwpid_t tid, + int tgid, int sig); +static void sicode_to_lsicode(int sig, int si_code, int *lsi_code); +static int linux_common_rt_sigtimedwait(struct thread *, + l_sigset_t * __capability, struct timespec *, l_siginfo_t * __capability, + l_size_t); + +static void +linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa) +{ + unsigned long flags; + + linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask); + bsa->sa_handler = LINUX_USER_CODE_CAP(lsa->lsa_handler); + bsa->sa_flags = 0; + + flags = lsa->lsa_flags; + if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) { + flags &= ~LINUX_SA_NOCLDSTOP; + bsa->sa_flags |= SA_NOCLDSTOP; + } + if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) { + flags &= ~LINUX_SA_NOCLDWAIT; + bsa->sa_flags |= SA_NOCLDWAIT; + } + if (lsa->lsa_flags & LINUX_SA_SIGINFO) { + flags &= ~LINUX_SA_SIGINFO; + bsa->sa_flags |= SA_SIGINFO; +#ifdef notyet + /* + * XXX: We seem to be missing code to convert + * some of the fields in ucontext_t. + */ + linux_msg(curthread, + "partially unsupported sigaction flag SA_SIGINFO"); +#endif + } + if (lsa->lsa_flags & LINUX_SA_RESTORER) { + flags &= ~LINUX_SA_RESTORER; + /* + * We ignore the lsa_restorer and always use our own signal + * trampoline instead. It looks like SA_RESTORER is obsolete + * in Linux too - it doesn't seem to be used at all on arm64. + * In any case: see Linux sigreturn(2). + */ + } + if (lsa->lsa_flags & LINUX_SA_ONSTACK) { + flags &= ~LINUX_SA_ONSTACK; + bsa->sa_flags |= SA_ONSTACK; + } + if (lsa->lsa_flags & LINUX_SA_RESTART) { + flags &= ~LINUX_SA_RESTART; + bsa->sa_flags |= SA_RESTART; + } + if (lsa->lsa_flags & LINUX_SA_INTERRUPT) { + flags &= ~LINUX_SA_INTERRUPT; + /* Documented to be a "historical no-op". */ + } + if (lsa->lsa_flags & LINUX_SA_ONESHOT) { + flags &= ~LINUX_SA_ONESHOT; + bsa->sa_flags |= SA_RESETHAND; + } + if (lsa->lsa_flags & LINUX_SA_NOMASK) { + flags &= ~LINUX_SA_NOMASK; + bsa->sa_flags |= SA_NODEFER; + } + + if (flags != 0) + linux_msg(curthread, "unsupported sigaction flag %#lx", flags); +} + +static void +bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa) +{ + + bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask); +#ifdef COMPAT_LINUX32 + lsa->lsa_handler = (uintptr_t)bsa->sa_handler; +#else + lsa->lsa_handler = (l_uintptr_t)(uintcap_t)bsa->sa_handler; +#endif + lsa->lsa_restorer = 0; /* unsupported */ + lsa->lsa_flags = 0; + if (bsa->sa_flags & SA_NOCLDSTOP) + lsa->lsa_flags |= LINUX_SA_NOCLDSTOP; + if (bsa->sa_flags & SA_NOCLDWAIT) + lsa->lsa_flags |= LINUX_SA_NOCLDWAIT; + if (bsa->sa_flags & SA_SIGINFO) + lsa->lsa_flags |= LINUX_SA_SIGINFO; + if (bsa->sa_flags & SA_ONSTACK) + lsa->lsa_flags |= LINUX_SA_ONSTACK; + if (bsa->sa_flags & SA_RESTART) + lsa->lsa_flags |= LINUX_SA_RESTART; + if (bsa->sa_flags & SA_RESETHAND) + lsa->lsa_flags |= LINUX_SA_ONESHOT; + if (bsa->sa_flags & SA_NODEFER) + lsa->lsa_flags |= LINUX_SA_NOMASK; +} + +int +linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa, + l_sigaction_t *linux_osa) +{ + struct sigaction act, oact, *nsa, *osa; + int error, sig; + + if (!LINUX_SIG_VALID(linux_sig)) + return (EINVAL); + sig = linux_to_bsd_signal(linux_sig); + + osa = (linux_osa != NULL) ? &oact : NULL; + if (linux_nsa != NULL) { + nsa = &act; + linux_to_bsd_sigaction(linux_nsa, nsa); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&linux_nsa->lsa_mask, + sizeof(linux_nsa->lsa_mask)); +#endif + if ((sig == SIGKILL || sig == SIGSTOP) && + nsa->sa_handler == SIG_DFL) + return (EINVAL); + } else + nsa = NULL; + + error = kern_sigaction(td, sig, nsa, osa, 0); + if (error != 0) + return (error); + + if (linux_osa != NULL) { + bsd_to_linux_sigaction(osa, linux_osa); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&linux_osa->lsa_mask, + sizeof(linux_osa->lsa_mask)); +#endif + } + return (0); +} + +int +linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) +{ + stack_t ss, oss; + l_stack_t lss; + int error; + + memset(&lss, 0, sizeof(lss)); + LINUX_CTR2(sigaltstack, "%p, %p", uap->uss, uap->uoss); + + if (uap->uss != NULL) { + error = copyincap(LINUX_USER_CAP_OBJ(uap->uss), &lss, sizeof(lss)); + if (error != 0) + return (error); + + ss.ss_sp = LINUX_USER_CAP_UNBOUND(lss.ss_sp); + ss.ss_size = lss.ss_size; + ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags); + } + error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL, + (uap->uoss != NULL) ? &oss : NULL); + if (error == 0 && uap->uoss != NULL) { + lss.ss_sp = (uintcap_t)oss.ss_sp; + lss.ss_size = oss.ss_size; + lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags); + error = copyout(&lss, LINUX_USER_CAP_OBJ(uap->uoss), sizeof(lss)); + } + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_signal(struct thread *td, struct linux_signal_args *args) +{ + l_sigaction_t nsa, osa; + int error; + + nsa.lsa_handler = args->handler; + nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK; + LINUX_SIGEMPTYSET(nsa.lsa_mask); + + error = linux_do_sigaction(td, args->sig, &nsa, &osa); + td->td_retval[0] = (int)(intptr_t)osa.lsa_handler; + + return (error); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args) +{ + l_sigaction_t nsa, osa; + int error; + + if (args->sigsetsize != sizeof(l_sigset_t)) + return (EINVAL); + + if (args->act != NULL) { + error = copyincap(LINUX_USER_CAP_OBJ(args->act), &nsa, sizeof(nsa)); + if (error != 0) + return (error); + } + + error = linux_do_sigaction(td, args->sig, + args->act ? &nsa : NULL, + args->oact ? &osa : NULL); + + if (args->oact != NULL && error == 0) + error = copyout(&osa, LINUX_USER_CAP_OBJ(args->oact), sizeof(osa)); + + return (error); +} + +static int +linux_do_sigprocmask(struct thread *td, int how, sigset_t *new, + l_sigset_t *old) +{ + sigset_t omask; + int error; + + td->td_retval[0] = 0; + + switch (how) { + case LINUX_SIG_BLOCK: + how = SIG_BLOCK; + break; + case LINUX_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + case LINUX_SIG_SETMASK: + how = SIG_SETMASK; + break; + default: + return (EINVAL); + } + error = kern_sigprocmask(td, how, new, &omask, 0); + if (error == 0 && old != NULL) + bsd_to_linux_sigset(&omask, old); + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args) +{ + l_osigset_t mask; + l_sigset_t lset, oset; + sigset_t set; + int error; + + if (args->mask != NULL) { + error = copyin(args->mask, &mask, sizeof(mask)); + if (error != 0) + return (error); + LINUX_SIGEMPTYSET(lset); + lset.__mask = mask; +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&lset, sizeof(lset)); +#endif + linux_to_bsd_sigset(&lset, &set); + } + + error = linux_do_sigprocmask(td, args->how, + args->mask ? &set : NULL, + args->omask ? &oset : NULL); + + if (args->omask != NULL && error == 0) { +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&oset, sizeof(oset)); +#endif + mask = oset.__mask; + error = copyout(&mask, args->omask, sizeof(mask)); + } + + return (error); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args) +{ + l_sigset_t oset; + sigset_t set, *pset; + int error; + + error = linux_copyin_sigset(td, LINUX_USER_CAP(args->mask, args->sigsetsize), args->sigsetsize, + &set, &pset); + if (error != 0) + return (EINVAL); + + error = linux_do_sigprocmask(td, args->how, pset, + args->omask ? &oset : NULL); + + if (args->omask != NULL && error == 0) { +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&oset, sizeof(oset)); +#endif + error = copyout(&oset, LINUX_USER_CAP_OBJ(args->omask), sizeof(oset)); + } + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args) +{ + struct proc *p = td->td_proc; + l_sigset_t mask; + + PROC_LOCK(p); + bsd_to_linux_sigset(&td->td_sigmask, &mask); + PROC_UNLOCK(p); + td->td_retval[0] = mask.__mask; +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&mask, sizeof(mask)); +#endif + return (0); +} + +int +linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args) +{ + struct proc *p = td->td_proc; + l_sigset_t lset; + sigset_t bset; + + PROC_LOCK(p); + bsd_to_linux_sigset(&td->td_sigmask, &lset); + td->td_retval[0] = lset.__mask; + LINUX_SIGEMPTYSET(lset); + lset.__mask = args->mask; + linux_to_bsd_sigset(&lset, &bset); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&lset, sizeof(lset)); +#endif + td->td_sigmask = bset; + SIG_CANTMASK(td->td_sigmask); + signotify(td); + PROC_UNLOCK(p); + return (0); +} + +int +linux_sigpending(struct thread *td, struct linux_sigpending_args *args) +{ + struct proc *p = td->td_proc; + sigset_t bset; + l_sigset_t lset; + l_osigset_t mask; + + PROC_LOCK(p); + bset = p->p_siglist; + SIGSETOR(bset, td->td_siglist); + SIGSETAND(bset, td->td_sigmask); + PROC_UNLOCK(p); + bsd_to_linux_sigset(&bset, &lset); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&lset, sizeof(lset)); +#endif + mask = lset.__mask; + return (copyout(&mask, args->mask, sizeof(mask))); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +/* + * MPSAFE + */ +int +linux_rt_sigpending(struct thread *td, struct linux_rt_sigpending_args *args) +{ + struct proc *p = td->td_proc; + sigset_t bset; + l_sigset_t lset; + + if (args->sigsetsize > sizeof(lset)) + return (EINVAL); + /* NOT REACHED */ + + PROC_LOCK(p); + bset = p->p_siglist; + SIGSETOR(bset, td->td_siglist); + SIGSETAND(bset, td->td_sigmask); + PROC_UNLOCK(p); + bsd_to_linux_sigset(&bset, &lset); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&lset, sizeof(lset)); +#endif + return (copyout(&lset, LINUX_USER_CAP(args->set, args->sigsetsize), args->sigsetsize)); +} + +int +linux_rt_sigtimedwait(struct thread *td, + struct linux_rt_sigtimedwait_args *args) +{ + struct timespec ts, *tsa; + int error; + + if (args->timeout) { + error = linux_get_timespec(&ts, args->timeout); + if (error != 0) + return (error); + tsa = &ts; + } else + tsa = NULL; + + return (linux_common_rt_sigtimedwait(td, LINUX_USER_CAP_OBJ(args->mask), tsa, + LINUX_USER_CAP_OBJ(args->ptr), args->sigsetsize)); +} + +static int +linux_common_rt_sigtimedwait(struct thread *td, l_sigset_t * __capability mask, + struct timespec *tsa, l_siginfo_t * __capability ptr, l_size_t sigsetsize) +{ + int error, sig; + sigset_t bset; + l_siginfo_t lsi; + ksiginfo_t ksi; + + error = linux_copyin_sigset(td, mask, sigsetsize, &bset, NULL); + if (error != 0) + return (error); + + ksiginfo_init(&ksi); + error = kern_sigtimedwait(td, bset, &ksi, tsa); + if (error != 0) + return (error); + + sig = bsd_to_linux_signal(ksi.ksi_signo); + + if (ptr) { + memset(&lsi, 0, sizeof(lsi)); + siginfo_to_lsiginfo(&ksi.ksi_info, &lsi, sig); + error = copyoutcap(&lsi, ptr, sizeof(lsi)); + } + if (error == 0) + td->td_retval[0] = sig; + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_rt_sigtimedwait_time64(struct thread *td, + struct linux_rt_sigtimedwait_time64_args *args) +{ + struct timespec ts, *tsa; + int error; + + if (args->timeout) { + error = linux_get_timespec64(&ts, args->timeout); + if (error != 0) + return (error); + tsa = &ts; + } else + tsa = NULL; + + return (linux_common_rt_sigtimedwait(td, args->mask, tsa, + args->ptr, args->sigsetsize)); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_kill(struct thread *td, struct linux_kill_args *args) +{ + int sig; + + /* + * Allow signal 0 as a means to check for privileges + */ + if (!LINUX_SIG_VALID(args->signum) && args->signum != 0) + return (EINVAL); + + if (args->signum > 0) + sig = linux_to_bsd_signal(args->signum); + else + sig = 0; + + if (args->pid > PID_MAX) + return (linux_psignal(td, args->pid, sig)); + else + return (kern_kill(td, args->pid, sig)); +} + +int +linux_tgkill(struct thread *td, struct linux_tgkill_args *args) +{ + int sig; + + if (args->pid <= 0 || args->tgid <=0) + return (EINVAL); + + /* + * Allow signal 0 as a means to check for privileges + */ + if (!LINUX_SIG_VALID(args->sig) && args->sig != 0) + return (EINVAL); + + if (args->sig > 0) + sig = linux_to_bsd_signal(args->sig); + else + sig = 0; + + return (linux_tdsignal(td, args->pid, args->tgid, sig)); +} + +/* + * Deprecated since 2.5.75. Replaced by tgkill(). + */ +int +linux_tkill(struct thread *td, struct linux_tkill_args *args) +{ + int sig; + + if (args->tid <= 0) + return (EINVAL); + + if (!LINUX_SIG_VALID(args->sig)) + return (EINVAL); + + sig = linux_to_bsd_signal(args->sig); + + return (linux_tdsignal(td, args->tid, -1, sig)); +} + +static int +sigfpe_sicode2lsicode(int si_code) +{ + + switch (si_code) { + case FPE_INTOVF: + return (LINUX_FPE_INTOVF); + case FPE_INTDIV: + return (LINUX_FPE_INTDIV); + case FPE_FLTIDO: + return (LINUX_FPE_FLTUNK); + default: + return (si_code); + } +} + +static int +sigbus_sicode2lsicode(int si_code) +{ + + switch (si_code) { + case BUS_OOMERR: + return (LINUX_BUS_MCEERR_AR); + default: + return (si_code); + } +} + +static int +sigsegv_sicode2lsicode(int si_code) +{ + + switch (si_code) { + case SEGV_PKUERR: + return (LINUX_SEGV_PKUERR); + default: + return (si_code); + } +} + +static int +sigtrap_sicode2lsicode(int si_code) +{ + + switch (si_code) { + case TRAP_DTRACE: + return (LINUX_TRAP_TRACE); + case TRAP_CAP: + return (LINUX_TRAP_UNK); + default: + return (si_code); + } +} + +static void +sicode_to_lsicode(int sig, int si_code, int *lsi_code) +{ + + switch (si_code) { + case SI_USER: + *lsi_code = LINUX_SI_USER; + break; + case SI_KERNEL: + *lsi_code = LINUX_SI_KERNEL; + break; + case SI_QUEUE: + *lsi_code = LINUX_SI_QUEUE; + break; + case SI_TIMER: + *lsi_code = LINUX_SI_TIMER; + break; + case SI_MESGQ: + *lsi_code = LINUX_SI_MESGQ; + break; + case SI_ASYNCIO: + *lsi_code = LINUX_SI_ASYNCIO; + break; + case SI_LWP: + *lsi_code = LINUX_SI_TKILL; + break; + default: + switch (sig) { + case LINUX_SIGFPE: + *lsi_code = sigfpe_sicode2lsicode(si_code); + break; + case LINUX_SIGBUS: + *lsi_code = sigbus_sicode2lsicode(si_code); + break; + case LINUX_SIGSEGV: + *lsi_code = sigsegv_sicode2lsicode(si_code); + break; + case LINUX_SIGTRAP: + *lsi_code = sigtrap_sicode2lsicode(si_code); + break; + default: + *lsi_code = si_code; + break; + } + break; + } +} + +void +siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig) +{ + + /* sig already converted */ + lsi->lsi_signo = sig; + sicode_to_lsicode(sig, si->si_code, &lsi->lsi_code); + + switch (si->si_code) { + case SI_LWP: + lsi->lsi_pid = si->si_pid; + lsi->lsi_uid = si->si_uid; + break; + + case SI_TIMER: + lsi->lsi_int = si->si_value.sival_int; + lsi->lsi_ptr = (uintcap_t)(si->si_value.sival_ptr); + lsi->lsi_tid = si->si_timerid; + break; + + case SI_QUEUE: + lsi->lsi_pid = si->si_pid; + lsi->lsi_uid = si->si_uid; + lsi->lsi_ptr = (uintcap_t)(si->si_value.sival_ptr); + break; + + case SI_ASYNCIO: + lsi->lsi_int = si->si_value.sival_int; + lsi->lsi_ptr = (uintcap_t)(si->si_value.sival_ptr); + break; + + default: + switch (sig) { + case LINUX_SIGPOLL: + /* XXX si_fd? */ + lsi->lsi_band = si->si_band; + break; + + case LINUX_SIGCHLD: + lsi->lsi_errno = 0; + lsi->lsi_pid = si->si_pid; + lsi->lsi_uid = si->si_uid; + + if (si->si_code == CLD_STOPPED || si->si_code == CLD_KILLED) + lsi->lsi_status = bsd_to_linux_signal(si->si_status); + else if (si->si_code == CLD_CONTINUED) + lsi->lsi_status = bsd_to_linux_signal(SIGCONT); + else + lsi->lsi_status = si->si_status; + break; + + case LINUX_SIGBUS: + case LINUX_SIGILL: + case LINUX_SIGFPE: + case LINUX_SIGSEGV: + lsi->lsi_addr = (uintcap_t)(si->si_addr); + break; + + default: + lsi->lsi_pid = si->si_pid; + lsi->lsi_uid = si->si_uid; + // Pass these info for SIGUSR1 and SIGUSR2 as well to improve compatibility + if (sig >= LINUX_SIGRTMIN || sig == LINUX_SIGUSR1 || sig == LINUX_SIGUSR2) { + lsi->lsi_int = si->si_value.sival_int; + lsi->lsi_ptr = (uintcap_t)(si->si_value.sival_ptr); + } + break; + } + break; + } +} + +static int +lsiginfo_to_siginfo(struct thread *td, const l_siginfo_t *lsi, + siginfo_t *si, int sig) +{ + + switch (lsi->lsi_code) { + case LINUX_SI_TKILL: + if (linux_kernver(td) >= LINUX_KERNVER(2,6,39)) { + linux_msg(td, "SI_TKILL forbidden since 2.6.39"); + return (EPERM); + } + si->si_code = SI_LWP; + case LINUX_SI_QUEUE: + si->si_code = SI_QUEUE; + break; + case LINUX_SI_TIMER: + si->si_code = SI_TIMER; + break; + case LINUX_SI_MESGQ: + si->si_code = SI_MESGQ; + break; + case LINUX_SI_ASYNCIO: + si->si_code = SI_ASYNCIO; + break; + default: + si->si_code = lsi->lsi_code; + break; + } + + si->si_signo = sig; + si->si_pid = td->td_proc->p_pid; + si->si_uid = td->td_ucred->cr_ruid; + si->si_value.sival_ptr = LINUX_USER_CODE_CAP(lsi->lsi_value.sival_ptr); + return (0); +} + +int +linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args) +{ + l_siginfo_t linfo; + ksiginfo_t ksi; + int error; + int sig; + + if (!LINUX_SIG_VALID(args->sig)) + return (EINVAL); + + error = copyincap(LINUX_USER_CAP_OBJ(args->info), &linfo, sizeof(linfo)); + if (error != 0) + return (error); + + if (linfo.lsi_code >= 0) + /* SI_USER, SI_KERNEL */ + return (EPERM); + + sig = linux_to_bsd_signal(args->sig); + ksiginfo_init(&ksi); + error = lsiginfo_to_siginfo(td, &linfo, &ksi.ksi_info, sig); + if (error != 0) + return (error); + + return (linux_pksignal(td, args->pid, sig, &ksi)); +} + +int +linux_rt_tgsigqueueinfo(struct thread *td, struct linux_rt_tgsigqueueinfo_args *args) +{ + l_siginfo_t linfo; + ksiginfo_t ksi; + int error; + int sig; + + if (!LINUX_SIG_VALID(args->sig)) + return (EINVAL); + + error = copyincap(LINUX_USER_CAP_OBJ(args->uinfo), &linfo, sizeof(linfo)); + if (error != 0) + return (error); + + if (linfo.lsi_code >= 0) + return (EPERM); + + sig = linux_to_bsd_signal(args->sig); + ksiginfo_init(&ksi); + error = lsiginfo_to_siginfo(td, &linfo, &ksi.ksi_info, sig); + if (error != 0) + return (error); + + return (linux_tdksignal(td, args->tid, args->tgid, sig, &ksi)); +} + +int +linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap) +{ + sigset_t sigmask; + int error; + + error = linux_copyin_sigset(td, LINUX_USER_CAP(uap->newset, uap->sigsetsize), uap->sigsetsize, + &sigmask, NULL); + if (error != 0) + return (error); + + return (kern_sigsuspend(td, sigmask)); +} + +static int +linux_tdksignal(struct thread *td, lwpid_t tid, int tgid, int sig, + ksiginfo_t *ksi) +{ + struct thread *tdt; + struct proc *p; + int error; + + tdt = linux_tdfind(td, tid, tgid); + if (tdt == NULL) + return (ESRCH); + + p = tdt->td_proc; + AUDIT_ARG_SIGNUM(sig); + AUDIT_ARG_PID(p->p_pid); + AUDIT_ARG_PROCESS(p); + + error = p_cansignal(td, p, sig); + if (error != 0 || sig == 0) + goto out; + + tdksignal(tdt, sig, ksi); + +out: + PROC_UNLOCK(p); + return (error); +} + +static int +linux_tdsignal(struct thread *td, lwpid_t tid, int tgid, int sig) +{ + ksiginfo_t ksi; + + ksiginfo_init(&ksi); + ksi.ksi_signo = sig; + ksi.ksi_code = SI_LWP; + ksi.ksi_pid = td->td_proc->p_pid; + ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid; + return (linux_tdksignal(td, tid, tgid, sig, &ksi)); +} + +static int +linux_pksignal(struct thread *td, int pid, int sig, ksiginfo_t *ksi) +{ + struct thread *tdt; + struct proc *p; + int error; + + tdt = linux_tdfind(td, pid, -1); + if (tdt == NULL) + return (ESRCH); + + p = tdt->td_proc; + AUDIT_ARG_SIGNUM(sig); + AUDIT_ARG_PID(p->p_pid); + AUDIT_ARG_PROCESS(p); + + error = p_cansignal(td, p, sig); + if (error != 0 || sig == 0) + goto out; + + pksignal(p, sig, ksi); + +out: + PROC_UNLOCK(p); + return (error); +} + +static int +linux_psignal(struct thread *td, int pid, int sig) +{ + ksiginfo_t ksi; + + ksiginfo_init(&ksi); + ksi.ksi_signo = sig; + ksi.ksi_code = SI_LWP; + ksi.ksi_pid = td->td_proc->p_pid; + ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid; + return (linux_pksignal(td, pid, sig, &ksi)); +} + +int +linux_copyin_sigset(struct thread *td, l_sigset_t * __capability lset, + l_size_t sigsetsize, sigset_t *set, sigset_t **pset) +{ + l_sigset_t lmask; + int error; + + if (sigsetsize != sizeof(l_sigset_t)) + return (EINVAL); + if (lset != NULL) { + error = copyin(lset, &lmask, sizeof(lmask)); + if (error != 0) + return (error); + linux_to_bsd_sigset(&lmask, set); + if (pset != NULL) + *pset = set; +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + linux_ktrsigset(&lmask, sizeof(lmask)); +#endif + } else if (pset != NULL) + *pset = NULL; + return (0); +} diff --git a/sys/compat/linux/linux_signal.h b/sys/compat/linux/linux_signal.h index 3f3599f4027e..c7601e3dc9c1 100644 --- a/sys/compat/linux/linux_signal.h +++ b/sys/compat/linux/linux_signal.h @@ -1,37 +1,37 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2000 Marcel Moolenaar - * 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. - */ - -#ifndef _LINUX_SIGNAL_H_ -#define _LINUX_SIGNAL_H_ - -int linux_do_sigaction(struct thread *, int, l_sigaction_t *, l_sigaction_t *); -void siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig); -int linux_copyin_sigset(struct thread *td, l_sigset_t *, l_size_t, sigset_t *, - sigset_t **); - -#endif /* _LINUX_SIGNAL_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2000 Marcel Moolenaar + * 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. + */ + +#ifndef _LINUX_SIGNAL_H_ +#define _LINUX_SIGNAL_H_ + +int linux_do_sigaction(struct thread *, int, l_sigaction_t *, l_sigaction_t *); +void siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig); +int linux_copyin_sigset(struct thread *td, l_sigset_t * __capability, l_size_t, sigset_t *, + sigset_t **); + +#endif /* _LINUX_SIGNAL_H_ */ diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index 46ea9f83b92f..6cf5eb90bbb4 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -1,2761 +1,2771 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 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 "opt_inet6.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#ifdef INET6 -#include -#include -#endif - -#ifdef COMPAT_LINUX32 -#include -#include -#include -#else -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -_Static_assert(offsetof(struct l_ifreq, ifr_ifru) == - offsetof(struct ifreq, ifr_ifru), - "Linux ifreq members names should be equal to FreeeBSD"); -_Static_assert(offsetof(struct l_ifreq, ifr_index) == - offsetof(struct ifreq, ifr_index), - "Linux ifreq members names should be equal to FreeeBSD"); -_Static_assert(offsetof(struct l_ifreq, ifr_name) == - offsetof(struct ifreq, ifr_name), - "Linux ifreq members names should be equal to FreeeBSD"); - -#define SECURITY_CONTEXT_STRING "unconfined" - -static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *, - l_uint); -static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *, - l_uint, struct msghdr *); -static int linux_set_socket_flags(int, int *); - -#define SOL_NETLINK 270 - -static int -linux_to_bsd_sockopt_level(int level) -{ - - if (level == LINUX_SOL_SOCKET) - return (SOL_SOCKET); - /* Remaining values are RFC-defined protocol numbers. */ - return (level); -} - -static int -bsd_to_linux_sockopt_level(int level) -{ - - if (level == SOL_SOCKET) - return (LINUX_SOL_SOCKET); - return (level); -} - -static int -linux_to_bsd_ip_sockopt(int opt) -{ - - switch (opt) { - /* known and translated sockopts */ - case LINUX_IP_TOS: - return (IP_TOS); - case LINUX_IP_TTL: - return (IP_TTL); - case LINUX_IP_HDRINCL: - return (IP_HDRINCL); - case LINUX_IP_OPTIONS: - return (IP_OPTIONS); - case LINUX_IP_RECVOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVOPTS"); - return (IP_RECVOPTS); - case LINUX_IP_RETOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_REETOPTS"); - return (IP_RETOPTS); - case LINUX_IP_RECVTTL: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVTTL"); - return (IP_RECVTTL); - case LINUX_IP_RECVTOS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVTOS"); - return (IP_RECVTOS); - case LINUX_IP_FREEBIND: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_FREEBIND"); - return (IP_BINDANY); - case LINUX_IP_IPSEC_POLICY: - /* we have this option, but not documented in ip(4) manpage */ - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_IPSEC_POLICY"); - return (IP_IPSEC_POLICY); - case LINUX_IP_MINTTL: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MINTTL"); - return (IP_MINTTL); - case LINUX_IP_MULTICAST_IF: - return (IP_MULTICAST_IF); - case LINUX_IP_MULTICAST_TTL: - return (IP_MULTICAST_TTL); - case LINUX_IP_MULTICAST_LOOP: - return (IP_MULTICAST_LOOP); - case LINUX_IP_ADD_MEMBERSHIP: - return (IP_ADD_MEMBERSHIP); - case LINUX_IP_DROP_MEMBERSHIP: - return (IP_DROP_MEMBERSHIP); - case LINUX_IP_UNBLOCK_SOURCE: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_UNBLOCK_SOURCE"); - return (IP_UNBLOCK_SOURCE); - case LINUX_IP_BLOCK_SOURCE: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_BLOCK_SOURCE"); - return (IP_BLOCK_SOURCE); - case LINUX_IP_ADD_SOURCE_MEMBERSHIP: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_ADD_SOURCE_MEMBERSHIP"); - return (IP_ADD_SOURCE_MEMBERSHIP); - case LINUX_IP_DROP_SOURCE_MEMBERSHIP: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_DROP_SOURCE_MEMBERSHIP"); - return (IP_DROP_SOURCE_MEMBERSHIP); - case LINUX_MCAST_JOIN_GROUP: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_JOIN_GROUP"); - return (MCAST_JOIN_GROUP); - case LINUX_MCAST_LEAVE_GROUP: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_LEAVE_GROUP"); - return (MCAST_LEAVE_GROUP); - case LINUX_MCAST_JOIN_SOURCE_GROUP: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_JOIN_SOURCE_GROUP"); - return (MCAST_JOIN_SOURCE_GROUP); - case LINUX_MCAST_LEAVE_SOURCE_GROUP: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_LEAVE_SOURCE_GROUP"); - return (MCAST_LEAVE_SOURCE_GROUP); - case LINUX_IP_RECVORIGDSTADDR: - return (IP_RECVORIGDSTADDR); - - /* known but not implemented sockopts */ - case LINUX_IP_ROUTER_ALERT: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_ROUTER_ALERT (%d), you can not do user-space routing from linux programs", - opt); - return (-2); - case LINUX_IP_PKTINFO: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_PKTINFO (%d), you can not get extended packet info for datagram sockets in linux programs", - opt); - return (-2); - case LINUX_IP_PKTOPTIONS: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_PKTOPTIONS (%d)", - opt); - return (-2); - case LINUX_IP_MTU_DISCOVER: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_MTU_DISCOVER (%d), your linux program can not control path-MTU discovery", - opt); - return (-2); - case LINUX_IP_RECVERR: - /* needed by steam */ - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_RECVERR (%d), you can not get extended reliability info in linux programs", - opt); - return (-2); - case LINUX_IP_MTU: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_MTU (%d), your linux program can not control the MTU on this socket", - opt); - return (-2); - case LINUX_IP_XFRM_POLICY: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_XFRM_POLICY (%d)", - opt); - return (-2); - case LINUX_IP_PASSSEC: - /* needed by steam */ - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_PASSSEC (%d), you can not get IPSEC related credential information associated with this socket in linux programs -- if you do not use IPSEC, you can ignore this", - opt); - return (-2); - case LINUX_IP_TRANSPARENT: - /* IP_BINDANY or more? */ - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_TRANSPARENT (%d), you can not enable transparent proxying in linux programs -- note, IP_FREEBIND is supported, no idea if the FreeBSD IP_BINDANY is equivalent to the Linux IP_TRANSPARENT or not, any info is welcome", - opt); - return (-2); - case LINUX_IP_NODEFRAG: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_NODEFRAG (%d)", - opt); - return (-2); - case LINUX_IP_CHECKSUM: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_CHECKSUM (%d)", - opt); - return (-2); - case LINUX_IP_BIND_ADDRESS_NO_PORT: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_BIND_ADDRESS_NO_PORT (%d)", - opt); - return (-2); - case LINUX_IP_RECVFRAGSIZE: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_RECVFRAGSIZE (%d)", - opt); - return (-2); - case LINUX_MCAST_MSFILTER: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_MCAST_MSFILTER (%d)", - opt); - return (-2); - case LINUX_IP_MULTICAST_ALL: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_MULTICAST_ALL (%d), your linux program will not see all multicast groups joined by the entire system, only those the program joined itself on this socket", - opt); - return (-2); - case LINUX_IP_UNICAST_IF: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv4 socket option IP_UNICAST_IF (%d)", - opt); - return (-2); - - /* unknown sockopts */ - default: - return (-1); - } -} - -static int -linux_to_bsd_ip6_sockopt(int opt) -{ - - switch (opt) { - /* known and translated sockopts */ - case LINUX_IPV6_2292PKTINFO: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292PKTINFO"); - return (IPV6_2292PKTINFO); - case LINUX_IPV6_2292HOPOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292HOPOPTS"); - return (IPV6_2292HOPOPTS); - case LINUX_IPV6_2292DSTOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292DSTOPTS"); - return (IPV6_2292DSTOPTS); - case LINUX_IPV6_2292RTHDR: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292RTHDR"); - return (IPV6_2292RTHDR); - case LINUX_IPV6_2292PKTOPTIONS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292PKTOPTIONS"); - return (IPV6_2292PKTOPTIONS); - case LINUX_IPV6_CHECKSUM: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_CHECKSUM"); - return (IPV6_CHECKSUM); - case LINUX_IPV6_2292HOPLIMIT: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292HOPLIMIT"); - return (IPV6_2292HOPLIMIT); - case LINUX_IPV6_NEXTHOP: - return (IPV6_NEXTHOP); - case LINUX_IPV6_UNICAST_HOPS: - return (IPV6_UNICAST_HOPS); - case LINUX_IPV6_MULTICAST_IF: - return (IPV6_MULTICAST_IF); - case LINUX_IPV6_MULTICAST_HOPS: - return (IPV6_MULTICAST_HOPS); - case LINUX_IPV6_MULTICAST_LOOP: - return (IPV6_MULTICAST_LOOP); - case LINUX_IPV6_ADD_MEMBERSHIP: - return (IPV6_JOIN_GROUP); - case LINUX_IPV6_DROP_MEMBERSHIP: - return (IPV6_LEAVE_GROUP); - case LINUX_IPV6_V6ONLY: - return (IPV6_V6ONLY); - case LINUX_IPV6_IPSEC_POLICY: - /* we have this option, but not documented in ip6(4) manpage */ - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_IPSEC_POLICY"); - return (IPV6_IPSEC_POLICY); - case LINUX_MCAST_JOIN_GROUP: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_JOIN_GROUP"); - return (IPV6_JOIN_GROUP); - case LINUX_MCAST_LEAVE_GROUP: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_LEAVE_GROUP"); - return (IPV6_LEAVE_GROUP); - case LINUX_IPV6_RECVPKTINFO: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVPKTINFO"); - return (IPV6_RECVPKTINFO); - case LINUX_IPV6_PKTINFO: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_PKTINFO"); - return (IPV6_PKTINFO); - case LINUX_IPV6_RECVHOPLIMIT: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVHOPLIMIT"); - return (IPV6_RECVHOPLIMIT); - case LINUX_IPV6_HOPLIMIT: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_HOPLIMIT"); - return (IPV6_HOPLIMIT); - case LINUX_IPV6_RECVHOPOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVHOPOPTS"); - return (IPV6_RECVHOPOPTS); - case LINUX_IPV6_HOPOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_HOPOPTS"); - return (IPV6_HOPOPTS); - case LINUX_IPV6_RTHDRDSTOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RTHDRDSTOPTS"); - return (IPV6_RTHDRDSTOPTS); - case LINUX_IPV6_RECVRTHDR: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVRTHDR"); - return (IPV6_RECVRTHDR); - case LINUX_IPV6_RTHDR: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RTHDR"); - return (IPV6_RTHDR); - case LINUX_IPV6_RECVDSTOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVDSTOPTS"); - return (IPV6_RECVDSTOPTS); - case LINUX_IPV6_DSTOPTS: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_DSTOPTS"); - return (IPV6_DSTOPTS); - case LINUX_IPV6_RECVPATHMTU: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVPATHMTU"); - return (IPV6_RECVPATHMTU); - case LINUX_IPV6_PATHMTU: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_PATHMTU"); - return (IPV6_PATHMTU); - case LINUX_IPV6_DONTFRAG: - return (IPV6_DONTFRAG); - case LINUX_IPV6_AUTOFLOWLABEL: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_AUTOFLOWLABEL"); - return (IPV6_AUTOFLOWLABEL); - case LINUX_IPV6_ORIGDSTADDR: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_ORIGDSTADDR"); - return (IPV6_ORIGDSTADDR); - case LINUX_IPV6_FREEBIND: - LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_FREEBIND"); - return (IPV6_BINDANY); - - /* known but not implemented sockopts */ - case LINUX_IPV6_ADDRFORM: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_ADDRFORM (%d), you linux program can not convert the socket to IPv4", - opt); - return (-2); - case LINUX_IPV6_AUTHHDR: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_AUTHHDR (%d), your linux program can not get the authentication header info of IPv6 packets", - opt); - return (-2); - case LINUX_IPV6_FLOWINFO: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_FLOWINFO (%d), your linux program can not get the flowid of IPv6 packets", - opt); - return (-2); - case LINUX_IPV6_ROUTER_ALERT: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_ROUTER_ALERT (%d), you can not do user-space routing from linux programs", - opt); - return (-2); - case LINUX_IPV6_MTU_DISCOVER: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_MTU_DISCOVER (%d), your linux program can not control path-MTU discovery", - opt); - return (-2); - case LINUX_IPV6_MTU: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_MTU (%d), your linux program can not control the MTU on this socket", - opt); - return (-2); - case LINUX_IPV6_JOIN_ANYCAST: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_JOIN_ANYCAST (%d)", - opt); - return (-2); - case LINUX_IPV6_LEAVE_ANYCAST: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_LEAVE_ANYCAST (%d)", - opt); - return (-2); - case LINUX_IPV6_MULTICAST_ALL: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_MULTICAST_ALL (%d)", - opt); - return (-2); - case LINUX_IPV6_ROUTER_ALERT_ISOLATE: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_ROUTER_ALERT_ISOLATE (%d)", - opt); - return (-2); - case LINUX_IPV6_FLOWLABEL_MGR: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_FLOWLABEL_MGR (%d)", - opt); - return (-2); - case LINUX_IPV6_FLOWINFO_SEND: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_FLOWINFO_SEND (%d)", - opt); - return (-2); - case LINUX_IPV6_XFRM_POLICY: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_XFRM_POLICY (%d)", - opt); - return (-2); - case LINUX_IPV6_HDRINCL: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_HDRINCL (%d)", - opt); - return (-2); - case LINUX_MCAST_BLOCK_SOURCE: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option MCAST_BLOCK_SOURCE (%d), your linux program may see more multicast stuff than it wants", - opt); - return (-2); - case LINUX_MCAST_UNBLOCK_SOURCE: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option MCAST_UNBLOCK_SOURCE (%d), your linux program may not see all the multicast stuff it wants", - opt); - return (-2); - case LINUX_MCAST_JOIN_SOURCE_GROUP: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option MCAST_JOIN_SOURCE_GROUP (%d), your linux program is not able to join a multicast source group", - opt); - return (-2); - case LINUX_MCAST_LEAVE_SOURCE_GROUP: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option MCAST_LEAVE_SOURCE_GROUP (%d), your linux program is not able to leave a multicast source group -- but it was also not able to join one, so no issue", - opt); - return (-2); - case LINUX_MCAST_MSFILTER: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option MCAST_MSFILTER (%d), your linux program can not manipulate the multicast filter, it may see more multicast data than it wants to see", - opt); - return (-2); - case LINUX_IPV6_ADDR_PREFERENCES: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_ADDR_PREFERENCES (%d)", - opt); - return (-2); - case LINUX_IPV6_MINHOPCOUNT: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_MINHOPCOUNT (%d)", - opt); - return (-2); - case LINUX_IPV6_TRANSPARENT: - /* IP_BINDANY or more? */ - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_TRANSPARENT (%d), you can not enable transparent proxying in linux programs -- note, IP_FREEBIND is supported, no idea if the FreeBSD IP_BINDANY is equivalent to the Linux IP_TRANSPARENT or not, any info is welcome", - opt); - return (-2); - case LINUX_IPV6_UNICAST_IF: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_UNICAST_IF (%d)", - opt); - return (-2); - case LINUX_IPV6_RECVFRAGSIZE: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_RECVFRAGSIZE (%d)", - opt); - return (-2); - case LINUX_IPV6_RECVERR: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported IPv6 socket option IPV6_RECVERR (%d), you can not get extended reliability info in linux programs", - opt); - return (-2); - - /* unknown sockopts */ - default: - return (-1); - } -} - -static int -linux_to_bsd_so_sockopt(int opt) -{ - - switch (opt) { - case LINUX_SO_DEBUG: - return (SO_DEBUG); - case LINUX_SO_REUSEADDR: - return (SO_REUSEADDR); - case LINUX_SO_TYPE: - return (SO_TYPE); - case LINUX_SO_ERROR: - return (SO_ERROR); - case LINUX_SO_DONTROUTE: - return (SO_DONTROUTE); - case LINUX_SO_BROADCAST: - return (SO_BROADCAST); - case LINUX_SO_SNDBUF: - case LINUX_SO_SNDBUFFORCE: - return (SO_SNDBUF); - case LINUX_SO_RCVBUF: - case LINUX_SO_RCVBUFFORCE: - return (SO_RCVBUF); - case LINUX_SO_KEEPALIVE: - return (SO_KEEPALIVE); - case LINUX_SO_OOBINLINE: - return (SO_OOBINLINE); - case LINUX_SO_LINGER: - return (SO_LINGER); - case LINUX_SO_REUSEPORT: - return (SO_REUSEPORT_LB); - case LINUX_SO_PASSCRED: - return (LOCAL_CREDS_PERSISTENT); - case LINUX_SO_PEERCRED: - return (LOCAL_PEERCRED); - case LINUX_SO_RCVLOWAT: - return (SO_RCVLOWAT); - case LINUX_SO_SNDLOWAT: - return (SO_SNDLOWAT); - case LINUX_SO_RCVTIMEO: - return (SO_RCVTIMEO); - case LINUX_SO_SNDTIMEO: - return (SO_SNDTIMEO); - case LINUX_SO_TIMESTAMPO: - case LINUX_SO_TIMESTAMPN: - return (SO_TIMESTAMP); - case LINUX_SO_TIMESTAMPNSO: - case LINUX_SO_TIMESTAMPNSN: - return (SO_BINTIME); - case LINUX_SO_ACCEPTCONN: - return (SO_ACCEPTCONN); - case LINUX_SO_PROTOCOL: - return (SO_PROTOCOL); - case LINUX_SO_DOMAIN: - return (SO_DOMAIN); - } - return (-1); -} - -static int -linux_to_bsd_tcp_sockopt(int opt) -{ - - switch (opt) { - case LINUX_TCP_NODELAY: - return (TCP_NODELAY); - case LINUX_TCP_MAXSEG: - return (TCP_MAXSEG); - case LINUX_TCP_CORK: - return (TCP_NOPUSH); - case LINUX_TCP_KEEPIDLE: - return (TCP_KEEPIDLE); - case LINUX_TCP_KEEPINTVL: - return (TCP_KEEPINTVL); - case LINUX_TCP_KEEPCNT: - return (TCP_KEEPCNT); - case LINUX_TCP_INFO: - LINUX_RATELIMIT_MSG_OPT1( - "unsupported TCP socket option TCP_INFO (%d)", opt); - return (-2); - case LINUX_TCP_MD5SIG: - return (TCP_MD5SIG); - } - return (-1); -} - -static int -linux_to_bsd_msg_flags(int flags) -{ - int ret_flags = 0; - - if (flags & LINUX_MSG_OOB) - ret_flags |= MSG_OOB; - if (flags & LINUX_MSG_PEEK) - ret_flags |= MSG_PEEK; - if (flags & LINUX_MSG_DONTROUTE) - ret_flags |= MSG_DONTROUTE; - if (flags & LINUX_MSG_CTRUNC) - ret_flags |= MSG_CTRUNC; - if (flags & LINUX_MSG_TRUNC) - ret_flags |= MSG_TRUNC; - if (flags & LINUX_MSG_DONTWAIT) - ret_flags |= MSG_DONTWAIT; - if (flags & LINUX_MSG_EOR) - ret_flags |= MSG_EOR; - if (flags & LINUX_MSG_WAITALL) - ret_flags |= MSG_WAITALL; - if (flags & LINUX_MSG_NOSIGNAL) - ret_flags |= MSG_NOSIGNAL; - if (flags & LINUX_MSG_PROXY) - LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_PROXY (%d) not handled", - LINUX_MSG_PROXY); - if (flags & LINUX_MSG_FIN) - LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_FIN (%d) not handled", - LINUX_MSG_FIN); - if (flags & LINUX_MSG_SYN) - LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_SYN (%d) not handled", - LINUX_MSG_SYN); - if (flags & LINUX_MSG_CONFIRM) - LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_CONFIRM (%d) not handled", - LINUX_MSG_CONFIRM); - if (flags & LINUX_MSG_RST) - LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_RST (%d) not handled", - LINUX_MSG_RST); - if (flags & LINUX_MSG_ERRQUEUE) - LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_ERRQUEUE (%d) not handled", - LINUX_MSG_ERRQUEUE); - return (ret_flags); -} - -static int -linux_to_bsd_cmsg_type(int cmsg_type) -{ - - switch (cmsg_type) { - case LINUX_SCM_RIGHTS: - return (SCM_RIGHTS); - case LINUX_SCM_CREDENTIALS: - return (SCM_CREDS); - } - return (-1); -} - -static int -bsd_to_linux_ip_cmsg_type(int cmsg_type) -{ - - switch (cmsg_type) { - case IP_RECVORIGDSTADDR: - return (LINUX_IP_RECVORIGDSTADDR); - } - return (-1); -} - -static int -bsd_to_linux_cmsg_type(struct proc *p, int cmsg_type, int cmsg_level) -{ - struct linux_pemuldata *pem; - - if (cmsg_level == IPPROTO_IP) - return (bsd_to_linux_ip_cmsg_type(cmsg_type)); - if (cmsg_level != SOL_SOCKET) - return (-1); - - pem = pem_find(p); - - switch (cmsg_type) { - case SCM_RIGHTS: - return (LINUX_SCM_RIGHTS); - case SCM_CREDS: - return (LINUX_SCM_CREDENTIALS); - case SCM_CREDS2: - return (LINUX_SCM_CREDENTIALS); - case SCM_TIMESTAMP: - return (pem->so_timestamp); - case SCM_BINTIME: - return (pem->so_timestampns); - } - return (-1); -} - -static int -linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) -{ - if (lhdr->msg_controllen > INT_MAX) - return (ENOBUFS); - - bhdr->msg_name = PTRIN(lhdr->msg_name); - bhdr->msg_namelen = lhdr->msg_namelen; - bhdr->msg_iov = PTRIN(lhdr->msg_iov); - bhdr->msg_iovlen = lhdr->msg_iovlen; - bhdr->msg_control = PTRIN(lhdr->msg_control); - - /* - * msg_controllen is skipped since BSD and LINUX control messages - * are potentially different sizes (e.g. the cred structure used - * by SCM_CREDS is different between the two operating system). - * - * The caller can set it (if necessary) after converting all the - * control messages. - */ - - bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); - return (0); -} - -static int -bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) -{ - lhdr->msg_name = PTROUT(bhdr->msg_name); - lhdr->msg_namelen = bhdr->msg_namelen; - lhdr->msg_iov = PTROUT(bhdr->msg_iov); - lhdr->msg_iovlen = bhdr->msg_iovlen; - lhdr->msg_control = PTROUT(bhdr->msg_control); - - /* - * msg_controllen is skipped since BSD and LINUX control messages - * are potentially different sizes (e.g. the cred structure used - * by SCM_CREDS is different between the two operating system). - * - * The caller can set it (if necessary) after converting all the - * control messages. - */ - - /* msg_flags skipped */ - return (0); -} - -static int -linux_set_socket_flags(int lflags, int *flags) -{ - - if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) - return (EINVAL); - if (lflags & LINUX_SOCK_NONBLOCK) - *flags |= SOCK_NONBLOCK; - if (lflags & LINUX_SOCK_CLOEXEC) - *flags |= SOCK_CLOEXEC; - return (0); -} - -static int -linux_copyout_sockaddr(const struct sockaddr *sa, void *uaddr, size_t len) -{ - struct l_sockaddr *lsa; - int error; - - error = bsd_to_linux_sockaddr(sa, &lsa, len); - if (error != 0) - return (error); - - error = copyout(lsa, uaddr, len); - free(lsa, M_LINUX); - - return (error); -} - -static int -linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, - struct mbuf *control, enum uio_seg segflg) -{ - struct sockaddr *to; - int error, len; - - if (mp->msg_name != NULL) { - len = mp->msg_namelen; - error = linux_to_bsd_sockaddr(mp->msg_name, &to, &len); - if (error != 0) - return (error); - mp->msg_name = to; - } else - to = NULL; - - error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, - segflg); - - if (to) - free(to, M_SONAME); - return (error); -} - -/* Return 0 if IP_HDRINCL is set for the given socket. */ -static int -linux_check_hdrincl(struct thread *td, int s) -{ - int error, optval; - socklen_t size_val; - - size_val = sizeof(optval); - error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, - &optval, UIO_SYSSPACE, &size_val); - if (error != 0) - return (error); - - return (optval == 0); -} - -/* - * Updated sendto() when IP_HDRINCL is set: - * tweak endian-dependent fields in the IP packet. - */ -static int -linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) -{ -/* - * linux_ip_copysize defines how many bytes we should copy - * from the beginning of the IP packet before we customize it for BSD. - * It should include all the fields we modify (ip_len and ip_off). - */ -#define linux_ip_copysize 8 - - struct ip *packet; - struct msghdr msg; - struct iovec aiov[1]; - int error; - - /* Check that the packet isn't too big or too small. */ - if (linux_args->len < linux_ip_copysize || - linux_args->len > IP_MAXPACKET) - return (EINVAL); - - packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK); - - /* Make kernel copy of the packet to be sent */ - if ((error = copyin(PTRIN(linux_args->msg), packet, - linux_args->len))) - goto goout; - - /* Convert fields from Linux to BSD raw IP socket format */ - packet->ip_len = linux_args->len; - packet->ip_off = ntohs(packet->ip_off); - - /* Prepare the msghdr and iovec structures describing the new packet */ - msg.msg_name = PTRIN(linux_args->to); - msg.msg_namelen = linux_args->tolen; - msg.msg_iov = aiov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_flags = 0; - IOVEC_INIT(&aiov[0], packet, linux_args->len); - error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, - NULL, UIO_SYSSPACE); -goout: - free(packet, M_LINUX); - return (error); -} - -static const char *linux_netlink_names[] = { - [LINUX_NETLINK_ROUTE] = "ROUTE", - [LINUX_NETLINK_SOCK_DIAG] = "SOCK_DIAG", - [LINUX_NETLINK_NFLOG] = "NFLOG", - [LINUX_NETLINK_SELINUX] = "SELINUX", - [LINUX_NETLINK_AUDIT] = "AUDIT", - [LINUX_NETLINK_FIB_LOOKUP] = "FIB_LOOKUP", - [LINUX_NETLINK_NETFILTER] = "NETFILTER", - [LINUX_NETLINK_KOBJECT_UEVENT] = "KOBJECT_UEVENT", -}; - -int -linux_socket(struct thread *td, struct linux_socket_args *args) -{ - int retval_socket, type; - sa_family_t domain; - - type = args->type & LINUX_SOCK_TYPE_MASK; - if (type < 0 || type > LINUX_SOCK_MAX) - return (EINVAL); - retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, - &type); - if (retval_socket != 0) - return (retval_socket); - domain = linux_to_bsd_domain(args->domain); - if (domain == AF_UNKNOWN) { - /* Mask off SOCK_NONBLOCK / CLOEXEC for error messages. */ - type = args->type & LINUX_SOCK_TYPE_MASK; - if (args->domain == LINUX_AF_NETLINK && - args->protocol == LINUX_NETLINK_AUDIT) { - ; /* Do nothing, quietly. */ - } else if (args->domain == LINUX_AF_NETLINK) { - const char *nl_name; - - if (args->protocol >= 0 && - args->protocol < nitems(linux_netlink_names)) - nl_name = linux_netlink_names[args->protocol]; - else - nl_name = NULL; - if (nl_name != NULL) - linux_msg(curthread, - "unsupported socket(AF_NETLINK, %d, " - "NETLINK_%s)", type, nl_name); - else - linux_msg(curthread, - "unsupported socket(AF_NETLINK, %d, %d)", - type, args->protocol); - } else { - linux_msg(curthread, "unsupported socket domain %d, " - "type %d, protocol %d", args->domain, type, - args->protocol); - } - return (EAFNOSUPPORT); - } - - retval_socket = kern_socket(td, domain, type, args->protocol); - if (retval_socket) - return (retval_socket); - - if (type == SOCK_RAW - && (args->protocol == IPPROTO_RAW || args->protocol == 0) - && domain == PF_INET) { - /* It's a raw IP socket: set the IP_HDRINCL option. */ - int hdrincl; - - hdrincl = 1; - /* We ignore any error returned by kern_setsockopt() */ - kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, - &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); - } -#ifdef INET6 - /* - * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default - * and some apps depend on this. So, set V6ONLY to 0 for Linux apps. - * For simplicity we do this unconditionally of the net.inet6.ip6.v6only - * sysctl value. - */ - if (domain == PF_INET6) { - int v6only; - - v6only = 0; - /* We ignore any error returned by setsockopt() */ - kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, - &v6only, UIO_SYSSPACE, sizeof(v6only)); - } -#endif - - return (retval_socket); -} - -int -linux_bind(struct thread *td, struct linux_bind_args *args) -{ - struct sockaddr *sa; - int error; - - error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa, - &args->namelen); - if (error != 0) - return (error); - - error = kern_bindat(td, AT_FDCWD, args->s, sa); - free(sa, M_SONAME); - - /* XXX */ - if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) - return (EINVAL); - return (error); -} - -int -linux_connect(struct thread *td, struct linux_connect_args *args) -{ - struct socket *so; - struct sockaddr *sa; - struct file *fp; - int error; - - error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa, - &args->namelen); - if (error != 0) - return (error); - - error = kern_connectat(td, AT_FDCWD, args->s, sa); - free(sa, M_SONAME); - if (error != EISCONN) - return (error); - - /* - * Linux doesn't return EISCONN the first time it occurs, - * when on a non-blocking socket. Instead it returns the - * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. - */ - error = getsock(td, args->s, &cap_connect_rights, &fp); - if (error != 0) - return (error); - - error = EISCONN; - so = fp->f_data; - if (atomic_load_int(&fp->f_flag) & FNONBLOCK) { - SOCK_LOCK(so); - if (so->so_emuldata == 0) - error = so->so_error; - so->so_emuldata = (void *)1; - SOCK_UNLOCK(so); - } - fdrop(fp, td); - - return (error); -} - -int -linux_listen(struct thread *td, struct linux_listen_args *args) -{ - - return (kern_listen(td, args->s, args->backlog)); -} - -static int -linux_accept_common(struct thread *td, int s, l_uintptr_t addr, - l_uintptr_t namelen, int flags) -{ - struct sockaddr_storage ss = { .ss_len = sizeof(ss) }; - struct file *fp, *fp1; - struct socket *so; - socklen_t len; - int bflags, error, error1; - - bflags = 0; - fp = NULL; - - error = linux_set_socket_flags(flags, &bflags); - if (error != 0) - return (error); - - if (PTRIN(addr) != NULL) { - error = copyin(PTRIN(namelen), &len, sizeof(len)); - if (error != 0) - return (error); - if (len < 0) - return (EINVAL); - } else - len = 0; - - error = kern_accept4(td, s, (struct sockaddr *)&ss, bflags, &fp); - - /* - * Translate errno values into ones used by Linux. - */ - if (error != 0) { - /* - * XXX. This is wrong, different sockaddr structures - * have different sizes. - */ - switch (error) { - case EFAULT: - if (namelen != sizeof(struct sockaddr_in)) - error = EINVAL; - break; - case EINVAL: - error1 = getsock(td, s, &cap_accept_rights, &fp1); - if (error1 != 0) { - error = error1; - break; - } - so = fp1->f_data; - if (so->so_type == SOCK_DGRAM) - error = EOPNOTSUPP; - fdrop(fp1, td); - break; - } - return (error); - } - - if (PTRIN(addr) != NULL) { - len = min(ss.ss_len, len); - error = linux_copyout_sockaddr((struct sockaddr *)&ss, - PTRIN(addr), len); - if (error == 0) { - len = ss.ss_len; - error = copyout(&len, PTRIN(namelen), sizeof(len)); - } - if (error != 0) { - fdclose(td, fp, td->td_retval[0]); - td->td_retval[0] = 0; - } - } - if (fp != NULL) - fdrop(fp, td); - return (error); -} - -int -linux_accept(struct thread *td, struct linux_accept_args *args) -{ - - return (linux_accept_common(td, args->s, args->addr, - args->namelen, 0)); -} - -int -linux_accept4(struct thread *td, struct linux_accept4_args *args) -{ - - return (linux_accept_common(td, args->s, args->addr, - args->namelen, args->flags)); -} - -int -linux_getsockname(struct thread *td, struct linux_getsockname_args *args) -{ - struct sockaddr_storage ss = { .ss_len = sizeof(ss) }; - socklen_t len; - int error; - - error = copyin(PTRIN(args->namelen), &len, sizeof(len)); - if (error != 0) - return (error); - - error = kern_getsockname(td, args->s, (struct sockaddr *)&ss); - if (error != 0) - return (error); - - len = min(ss.ss_len, len); - error = linux_copyout_sockaddr((struct sockaddr *)&ss, - PTRIN(args->addr), len); - if (error == 0) { - len = ss.ss_len; - error = copyout(&len, PTRIN(args->namelen), sizeof(len)); - } - return (error); -} - -int -linux_getpeername(struct thread *td, struct linux_getpeername_args *args) -{ - struct sockaddr_storage ss = { .ss_len = sizeof(ss) }; - socklen_t len; - int error; - - error = copyin(PTRIN(args->namelen), &len, sizeof(len)); - if (error != 0) - return (error); - - error = kern_getpeername(td, args->s, (struct sockaddr *)&ss); - if (error != 0) - return (error); - - len = min(ss.ss_len, len); - error = linux_copyout_sockaddr((struct sockaddr *)&ss, - PTRIN(args->addr), len); - if (error == 0) { - len = ss.ss_len; - error = copyout(&len, PTRIN(args->namelen), sizeof(len)); - } - return (error); -} - -int -linux_socketpair(struct thread *td, struct linux_socketpair_args *args) -{ - int domain, error, sv[2], type; - - domain = linux_to_bsd_domain(args->domain); - if (domain != PF_LOCAL) - return (EAFNOSUPPORT); - type = args->type & LINUX_SOCK_TYPE_MASK; - if (type < 0 || type > LINUX_SOCK_MAX) - return (EINVAL); - error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, - &type); - if (error != 0) - return (error); - if (args->protocol != 0 && args->protocol != PF_UNIX) { - /* - * Use of PF_UNIX as protocol argument is not right, - * but Linux does it. - * Do not map PF_UNIX as its Linux value is identical - * to FreeBSD one. - */ - return (EPROTONOSUPPORT); - } - error = kern_socketpair(td, domain, type, 0, sv); - if (error != 0) - return (error); - error = copyout(sv, PTRIN(args->rsv), 2 * sizeof(int)); - if (error != 0) { - (void)kern_close(td, sv[0]); - (void)kern_close(td, sv[1]); - } - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -struct linux_send_args { - register_t s; - register_t msg; - register_t len; - register_t flags; -}; - -static int -linux_send(struct thread *td, struct linux_send_args *args) -{ - struct sendto_args /* { - int s; - caddr_t buf; - int len; - int flags; - caddr_t to; - int tolen; - } */ bsd_args; - struct file *fp; - int error; - - bsd_args.s = args->s; - bsd_args.buf = (caddr_t)PTRIN(args->msg); - bsd_args.len = args->len; - bsd_args.flags = linux_to_bsd_msg_flags(args->flags); - bsd_args.to = NULL; - bsd_args.tolen = 0; - error = sys_sendto(td, &bsd_args); - if (error == ENOTCONN) { - /* - * Linux doesn't return ENOTCONN for non-blocking sockets. - * Instead it returns the EAGAIN. - */ - error = getsock(td, args->s, &cap_send_rights, &fp); - if (error == 0) { - if (atomic_load_int(&fp->f_flag) & FNONBLOCK) - error = EAGAIN; - fdrop(fp, td); - } - } - return (error); -} - -struct linux_recv_args { - register_t s; - register_t msg; - register_t len; - register_t flags; -}; - -static int -linux_recv(struct thread *td, struct linux_recv_args *args) -{ - struct recvfrom_args /* { - int s; - caddr_t buf; - int len; - int flags; - struct sockaddr *from; - socklen_t fromlenaddr; - } */ bsd_args; - - bsd_args.s = args->s; - bsd_args.buf = (caddr_t)PTRIN(args->msg); - bsd_args.len = args->len; - bsd_args.flags = linux_to_bsd_msg_flags(args->flags); - bsd_args.from = NULL; - bsd_args.fromlenaddr = 0; - return (sys_recvfrom(td, &bsd_args)); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_sendto(struct thread *td, struct linux_sendto_args *args) -{ - struct msghdr msg; - struct iovec aiov; - struct socket *so; - struct file *fp; - int error; - - if (linux_check_hdrincl(td, args->s) == 0) - /* IP_HDRINCL set, tweak the packet before sending */ - return (linux_sendto_hdrincl(td, args)); - - bzero(&msg, sizeof(msg)); - error = getsock(td, args->s, &cap_send_connect_rights, &fp); - if (error != 0) - return (error); - so = fp->f_data; - if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0) { - msg.msg_name = __USER_CAP(PTRIN(args->to), args->tolen); - msg.msg_namelen = args->tolen; - } - msg.msg_iov = &aiov; - msg.msg_iovlen = 1; - IOVEC_INIT(&aiov, PTRIN(args->msg), args->len); - fdrop(fp, td); - return (linux_sendit(td, args->s, &msg, args->flags, NULL, - UIO_USERSPACE)); -} - -int -linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) -{ - struct sockaddr *sa; - struct msghdr msg; - struct iovec aiov; - int error, fromlen; - - if (PTRIN(args->fromlen) != NULL) { - error = copyin(PTRIN(args->fromlen), &fromlen, - sizeof(fromlen)); - if (error != 0) - return (error); - if (fromlen < 0) - return (EINVAL); - fromlen = min(fromlen, SOCK_MAXADDRLEN); - sa = malloc(fromlen, M_SONAME, M_WAITOK); - } else { - fromlen = 0; - sa = NULL; - } - - msg.msg_name = sa; - msg.msg_namelen = fromlen; - msg.msg_iov = &aiov; - msg.msg_iovlen = 1; - IOVEC_INIT(&aiov, PTRIN(args->buf), args->len); - msg.msg_control = 0; - msg.msg_flags = linux_to_bsd_msg_flags(args->flags); - - error = kern_recvit(td, args->s, &msg, UIO_SYSSPACE, NULL); - if (error != 0) - goto out; - - /* - * XXX. Seems that FreeBSD is different from Linux here. Linux - * fill source address if underlying protocol provides it, while - * FreeBSD fill it if underlying protocol is not connection-oriented. - * So, kern_recvit() set msg.msg_namelen to 0 if protocol pr_flags - * does not contains PR_ADDR flag. - */ - if (PTRIN(args->from) != NULL && msg.msg_namelen != 0) - error = linux_copyout_sockaddr(sa, PTRIN(args->from), - msg.msg_namelen); - - if (error == 0 && PTRIN(args->fromlen) != NULL) - error = copyout(&msg.msg_namelen, PTRIN(args->fromlen), - sizeof(msg.msg_namelen)); -out: - free(sa, M_SONAME); - return (error); -} - -static int -linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, - l_uint flags) -{ - struct sockaddr_storage ss = { .ss_len = sizeof(ss) }; - struct cmsghdr *cmsg; - struct mbuf *control; - struct msghdr msg; - struct l_cmsghdr linux_cmsg; - struct l_cmsghdr *ptr_cmsg; - struct l_msghdr linux_msghdr; - struct iovec *iov; - socklen_t datalen; - struct socket *so; - sa_family_t sa_family; - struct file *fp; - void *data; - l_size_t len; - l_size_t clen; - int error; - - error = copyin(msghdr, &linux_msghdr, sizeof(linux_msghdr)); - if (error != 0) - return (error); - - /* - * Some Linux applications (ping) define a non-NULL control data - * pointer, but a msg_controllen of 0, which is not allowed in the - * FreeBSD system call interface. NULL the msg_control pointer in - * order to handle this case. This should be checked, but allows the - * Linux ping to work. - */ - if (PTRIN(linux_msghdr.msg_control) != NULL && - linux_msghdr.msg_controllen == 0) - linux_msghdr.msg_control = PTROUT(NULL); - - error = linux_to_bsd_msghdr(&msg, &linux_msghdr); - if (error != 0) - return (error); - -#ifdef COMPAT_LINUX32 - error = freebsd32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, - &iov, EMSGSIZE); -#else - error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); -#endif - if (error != 0) - return (error); - - control = NULL; - - error = kern_getsockname(td, s, (struct sockaddr *)&ss); - if (error != 0) - goto bad; - sa_family = ss.ss_family; - - if (flags & LINUX_MSG_OOB) { - error = EOPNOTSUPP; - if (sa_family == AF_UNIX) - goto bad; - - error = getsock(td, s, &cap_send_rights, &fp); - if (error != 0) - goto bad; - so = fp->f_data; - if (so->so_type != SOCK_STREAM) - error = EOPNOTSUPP; - fdrop(fp, td); - if (error != 0) - goto bad; - } - - if (linux_msghdr.msg_controllen >= sizeof(struct l_cmsghdr)) { - error = ENOBUFS; - control = m_get(M_WAITOK, MT_CONTROL); - MCLGET(control, M_WAITOK); - data = mtod(control, void *); - datalen = 0; - - ptr_cmsg = PTRIN(linux_msghdr.msg_control); - clen = linux_msghdr.msg_controllen; - do { - error = copyin(ptr_cmsg, &linux_cmsg, - sizeof(struct l_cmsghdr)); - if (error != 0) - goto bad; - - error = EINVAL; - if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || - linux_cmsg.cmsg_len > clen) - goto bad; - - if (datalen + CMSG_HDRSZ > MCLBYTES) - goto bad; - - /* - * Now we support only SCM_RIGHTS and SCM_CRED, - * so return EINVAL in any other cmsg_type - */ - cmsg = data; - cmsg->cmsg_type = - linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); - cmsg->cmsg_level = - linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); - if (cmsg->cmsg_type == -1 - || cmsg->cmsg_level != SOL_SOCKET) { - linux_msg(curthread, - "unsupported sendmsg cmsg level %d type %d", - linux_cmsg.cmsg_level, linux_cmsg.cmsg_type); - goto bad; - } - - /* - * Some applications (e.g. pulseaudio) attempt to - * send ancillary data even if the underlying protocol - * doesn't support it which is not allowed in the - * FreeBSD system call interface. - */ - if (sa_family != AF_UNIX) - goto next; - - if (cmsg->cmsg_type == SCM_CREDS) { - len = sizeof(struct cmsgcred); - if (datalen + CMSG_SPACE(len) > MCLBYTES) - goto bad; - - /* - * The lower levels will fill in the structure - */ - memset(CMSG_DATA(data), 0, len); - } else { - len = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; - if (datalen + CMSG_SPACE(len) < datalen || - datalen + CMSG_SPACE(len) > MCLBYTES) - goto bad; - - error = copyin(LINUX_CMSG_DATA(ptr_cmsg), - CMSG_DATA(data), len); - if (error != 0) - goto bad; - } - - cmsg->cmsg_len = CMSG_LEN(len); - data = (char *)data + CMSG_SPACE(len); - datalen += CMSG_SPACE(len); - -next: - if (clen <= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)) - break; - - clen -= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len); - ptr_cmsg = (struct l_cmsghdr *)((char *)ptr_cmsg + - LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)); - } while(clen >= sizeof(struct l_cmsghdr)); - - control->m_len = datalen; - if (datalen == 0) { - m_freem(control); - control = NULL; - } - } - - msg.msg_iov = iov; - msg.msg_flags = 0; - error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE); - control = NULL; - -bad: - m_freem(control); - free(iov, M_IOV); - return (error); -} - -int -linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) -{ - - return (linux_sendmsg_common(td, args->s, PTRIN(args->msg), - args->flags)); -} - -int -linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args) -{ - struct l_mmsghdr *msg; - l_uint retval; - int error, datagrams; - - if (args->vlen > UIO_MAXIOV) - args->vlen = UIO_MAXIOV; - - msg = PTRIN(args->msg); - datagrams = 0; - while (datagrams < args->vlen) { - error = linux_sendmsg_common(td, args->s, &msg->msg_hdr, - args->flags); - if (error != 0) - break; - - retval = td->td_retval[0]; - error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); - if (error != 0) - break; - ++msg; - ++datagrams; - } - if (error == 0) - td->td_retval[0] = datagrams; - return (error); -} - -static int -recvmsg_scm_rights(struct thread *td, l_uint flags, socklen_t *datalen, - void **data, void **udata) -{ - int i, fd, fds, *fdp; - - if (flags & LINUX_MSG_CMSG_CLOEXEC) { - fds = *datalen / sizeof(int); - fdp = *data; - for (i = 0; i < fds; i++) { - fd = *fdp++; - (void)kern_fcntl(td, fd, F_SETFD, FD_CLOEXEC); - } - } - return (0); -} - - -static int -recvmsg_scm_creds(socklen_t *datalen, void **data, void **udata) -{ - struct cmsgcred *cmcred; - struct l_ucred lu; - - cmcred = *data; - lu.pid = cmcred->cmcred_pid; - lu.uid = cmcred->cmcred_uid; - lu.gid = cmcred->cmcred_gid; - memmove(*data, &lu, sizeof(lu)); - *datalen = sizeof(lu); - return (0); -} -_Static_assert(sizeof(struct cmsgcred) >= sizeof(struct l_ucred), - "scm_creds sizeof l_ucred"); - -static int -recvmsg_scm_creds2(socklen_t *datalen, void **data, void **udata) -{ - struct sockcred2 *scred; - struct l_ucred lu; - - scred = *data; - lu.pid = scred->sc_pid; - lu.uid = scred->sc_uid; - lu.gid = scred->sc_gid; - memmove(*data, &lu, sizeof(lu)); - *datalen = sizeof(lu); - return (0); -} -_Static_assert(sizeof(struct sockcred2) >= sizeof(struct l_ucred), - "scm_creds2 sizeof l_ucred"); - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -static int -recvmsg_scm_timestamp(l_int msg_type, socklen_t *datalen, void **data, - void **udata) -{ - l_sock_timeval ltv64; - l_timeval ltv; - struct timeval *tv; - socklen_t len; - void *buf; - - if (*datalen != sizeof(struct timeval)) - return (EMSGSIZE); - - tv = *data; -#if defined(COMPAT_LINUX32) - if (msg_type == LINUX_SCM_TIMESTAMPO && - (tv->tv_sec > INT_MAX || tv->tv_sec < INT_MIN)) - return (EOVERFLOW); -#endif - if (msg_type == LINUX_SCM_TIMESTAMPN) - len = sizeof(ltv64); - else - len = sizeof(ltv); - - buf = malloc(len, M_LINUX, M_WAITOK); - if (msg_type == LINUX_SCM_TIMESTAMPN) { - ltv64.tv_sec = tv->tv_sec; - ltv64.tv_usec = tv->tv_usec; - memmove(buf, <v64, len); - } else { - ltv.tv_sec = tv->tv_sec; - ltv.tv_usec = tv->tv_usec; - memmove(buf, <v, len); - } - *data = *udata = buf; - *datalen = len; - return (0); -} -#else -_Static_assert(sizeof(struct timeval) == sizeof(l_timeval), - "scm_timestamp sizeof l_timeval"); -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -static int -recvmsg_scm_timestampns(l_int msg_type, socklen_t *datalen, void **data, - void **udata) -{ - struct l_timespec64 ts64; - struct l_timespec ts32; - struct timespec ts; - socklen_t len; - void *buf; - - if (msg_type == LINUX_SCM_TIMESTAMPNSO) - len = sizeof(ts32); - else - len = sizeof(ts64); - - buf = malloc(len, M_LINUX, M_WAITOK); - bintime2timespec(*data, &ts); - if (msg_type == LINUX_SCM_TIMESTAMPNSO) { - ts32.tv_sec = ts.tv_sec; - ts32.tv_nsec = ts.tv_nsec; - memmove(buf, &ts32, len); - } else { - ts64.tv_sec = ts.tv_sec; - ts64.tv_nsec = ts.tv_nsec; - memmove(buf, &ts64, len); - } - *data = *udata = buf; - *datalen = len; - return (0); -} -#else -static int -recvmsg_scm_timestampns(l_int msg_type, socklen_t *datalen, void **data, - void **udata) -{ - struct timespec ts; - - bintime2timespec(*data, &ts); - memmove(*data, &ts, sizeof(struct timespec)); - *datalen = sizeof(struct timespec); - return (0); -} -_Static_assert(sizeof(struct bintime) >= sizeof(struct timespec), - "scm_timestampns sizeof timespec"); -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -static int -recvmsg_scm_sol_socket(struct thread *td, l_int msg_type, l_int lmsg_type, - l_uint flags, socklen_t *datalen, void **data, void **udata) -{ - int error; - - error = 0; - switch (msg_type) { - case SCM_RIGHTS: - error = recvmsg_scm_rights(td, flags, datalen, - data, udata); - break; - case SCM_CREDS: - error = recvmsg_scm_creds(datalen, data, udata); - break; - case SCM_CREDS2: - error = recvmsg_scm_creds2(datalen, data, udata); - break; - case SCM_TIMESTAMP: -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) - error = recvmsg_scm_timestamp(lmsg_type, datalen, - data, udata); -#endif - break; - case SCM_BINTIME: - error = recvmsg_scm_timestampns(lmsg_type, datalen, - data, udata); - break; - } - - return (error); -} - -static int -recvmsg_scm_ip_origdstaddr(socklen_t *datalen, void **data, void **udata) -{ - struct l_sockaddr *lsa; - int error; - - error = bsd_to_linux_sockaddr(*data, &lsa, *datalen); - if (error == 0) { - *data = *udata = lsa; - *datalen = sizeof(*lsa); - } - return (error); -} - -static int -recvmsg_scm_ipproto_ip(l_int msg_type, l_int lmsg_type, socklen_t *datalen, - void **data, void **udata) -{ - int error; - - error = 0; - switch (msg_type) { - case IP_ORIGDSTADDR: - error = recvmsg_scm_ip_origdstaddr(datalen, data, - udata); - break; - } - - return (error); -} - -static int -linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, - l_uint flags, struct msghdr *msg) -{ - struct proc *p = td->td_proc; - struct cmsghdr *cm; - struct l_cmsghdr *lcm = NULL; - socklen_t datalen, maxlen, outlen; - struct l_msghdr l_msghdr; - struct iovec *iov, *uiov; - struct mbuf *m, *control = NULL; - struct mbuf **controlp; - struct sockaddr *sa; - caddr_t outbuf; - void *data, *udata; - int error, skiped; - - error = copyin(msghdr, &l_msghdr, sizeof(l_msghdr)); - if (error != 0) - return (error); - - /* - * Pass user-supplied recvmsg() flags in msg_flags field, - * following sys_recvmsg() convention. - */ - l_msghdr.msg_flags = flags; - - error = linux_to_bsd_msghdr(msg, &l_msghdr); - if (error != 0) - return (error); - -#ifdef COMPAT_LINUX32 - error = freebsd32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen, - &iov, EMSGSIZE); -#else - error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE); -#endif - if (error != 0) - return (error); - - if (msg->msg_name != NULL && msg->msg_namelen > 0) { - msg->msg_namelen = min(msg->msg_namelen, SOCK_MAXADDRLEN); - sa = malloc(msg->msg_namelen, M_SONAME, M_WAITOK); - msg->msg_name = sa; - } else { - sa = NULL; - msg->msg_name = NULL; - } - - uiov = msg->msg_iov; - msg->msg_iov = iov; - controlp = (msg->msg_control != NULL) ? &control : NULL; - error = kern_recvit(td, s, msg, UIO_SYSSPACE, controlp); - msg->msg_iov = uiov; - if (error != 0) - goto bad; - - /* - * Note that kern_recvit() updates msg->msg_namelen. - */ - if (msg->msg_name != NULL && msg->msg_namelen > 0) { - msg->msg_name = PTRIN(l_msghdr.msg_name); - error = linux_copyout_sockaddr(sa, msg->msg_name, - msg->msg_namelen); - if (error != 0) - goto bad; - } - - error = bsd_to_linux_msghdr(msg, &l_msghdr); - if (error != 0) - goto bad; - - skiped = outlen = 0; - maxlen = l_msghdr.msg_controllen; - if (control == NULL) - goto out; - - lcm = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO); - msg->msg_control = mtod(control, struct cmsghdr *); - msg->msg_controllen = control->m_len; - outbuf = PTRIN(l_msghdr.msg_control); - for (m = control; m != NULL; m = m->m_next) { - cm = mtod(m, struct cmsghdr *); - lcm->cmsg_type = bsd_to_linux_cmsg_type(p, cm->cmsg_type, - cm->cmsg_level); - lcm->cmsg_level = bsd_to_linux_sockopt_level(cm->cmsg_level); - - if (lcm->cmsg_type == -1 || - cm->cmsg_level == -1) { - LINUX_RATELIMIT_MSG_OPT2( - "unsupported recvmsg cmsg level %d type %d", - cm->cmsg_level, cm->cmsg_type); - /* Skip unsupported messages */ - skiped++; - continue; - } - data = CMSG_DATA(cm); - datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; - udata = NULL; - error = 0; - - switch (cm->cmsg_level) { - case IPPROTO_IP: - error = recvmsg_scm_ipproto_ip(cm->cmsg_type, - lcm->cmsg_type, &datalen, &data, &udata); - break; - case SOL_SOCKET: - error = recvmsg_scm_sol_socket(td, cm->cmsg_type, - lcm->cmsg_type, flags, &datalen, &data, &udata); - break; - } - - /* The recvmsg_scm_ is responsible to free udata on error. */ - if (error != 0) - goto bad; - - if (outlen + LINUX_CMSG_LEN(datalen) > maxlen) { - if (outlen == 0) { - error = EMSGSIZE; - goto err; - } else { - l_msghdr.msg_flags |= LINUX_MSG_CTRUNC; - m_dispose_extcontrolm(control); - free(udata, M_LINUX); - goto out; - } - } - - lcm->cmsg_len = LINUX_CMSG_LEN(datalen); - error = copyout(lcm, outbuf, L_CMSG_HDRSZ); - if (error == 0) { - error = copyout(data, LINUX_CMSG_DATA(outbuf), datalen); - if (error == 0) { - outbuf += LINUX_CMSG_SPACE(datalen); - outlen += LINUX_CMSG_SPACE(datalen); - } - } -err: - free(udata, M_LINUX); - if (error != 0) - goto bad; - } - if (outlen == 0 && skiped > 0) { - error = EINVAL; - goto bad; - } - -out: - l_msghdr.msg_controllen = outlen; - error = copyout(&l_msghdr, msghdr, sizeof(l_msghdr)); - -bad: - if (control != NULL) { - if (error != 0) - m_dispose_extcontrolm(control); - m_freem(control); - } - free(iov, M_IOV); - free(lcm, M_LINUX); - free(sa, M_SONAME); - - return (error); -} - -int -linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) -{ - struct msghdr bsd_msg; - struct file *fp; - int error; - - error = getsock(td, args->s, &cap_recv_rights, &fp); - if (error != 0) - return (error); - fdrop(fp, td); - return (linux_recvmsg_common(td, args->s, PTRIN(args->msg), - args->flags, &bsd_msg)); -} - -static int -linux_recvmmsg_common(struct thread *td, l_int s, struct l_mmsghdr *msg, - l_uint vlen, l_uint flags, struct timespec *tts) -{ - struct msghdr bsd_msg; - struct timespec ts; - struct file *fp; - l_uint retval; - int error, datagrams; - - error = getsock(td, s, &cap_recv_rights, &fp); - if (error != 0) - return (error); - datagrams = 0; - while (datagrams < vlen) { - error = linux_recvmsg_common(td, s, &msg->msg_hdr, - flags & ~LINUX_MSG_WAITFORONE, &bsd_msg); - if (error != 0) - break; - - retval = td->td_retval[0]; - error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); - if (error != 0) - break; - ++msg; - ++datagrams; - - /* - * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet. - */ - if (flags & LINUX_MSG_WAITFORONE) - flags |= LINUX_MSG_DONTWAIT; - - /* - * See BUGS section of recvmmsg(2). - */ - if (tts) { - getnanotime(&ts); - timespecsub(&ts, tts, &ts); - if (!timespecisset(&ts) || ts.tv_sec > 0) - break; - } - /* Out of band data, return right away. */ - if (bsd_msg.msg_flags & MSG_OOB) - break; - } - if (error == 0) - td->td_retval[0] = datagrams; - fdrop(fp, td); - return (error); -} - -int -linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args) -{ - struct timespec ts, tts, *ptts; - int error; - - if (args->timeout) { - error = linux_get_timespec(&ts, args->timeout); - if (error != 0) - return (error); - getnanotime(&tts); - timespecadd(&tts, &ts, &tts); - ptts = &tts; - } - else ptts = NULL; - - return (linux_recvmmsg_common(td, args->s, PTRIN(args->msg), - args->vlen, args->flags, ptts)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_recvmmsg_time64(struct thread *td, struct linux_recvmmsg_time64_args *args) -{ - struct timespec ts, tts, *ptts; - int error; - - if (args->timeout) { - error = linux_get_timespec64(&ts, args->timeout); - if (error != 0) - return (error); - getnanotime(&tts); - timespecadd(&tts, &ts, &tts); - ptts = &tts; - } - else ptts = NULL; - - return (linux_recvmmsg_common(td, args->s, PTRIN(args->msg), - args->vlen, args->flags, ptts)); -} -#endif - -int -linux_shutdown(struct thread *td, struct linux_shutdown_args *args) -{ - - return (kern_shutdown(td, args->s, args->how)); -} - -int -linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) -{ - struct proc *p = td->td_proc; - struct linux_pemuldata *pem; - l_timeval linux_tv; - struct sockaddr *sa; - struct timeval tv; - socklen_t len; - int error, level, name, val; - - level = linux_to_bsd_sockopt_level(args->level); - switch (level) { - case SOL_SOCKET: - name = linux_to_bsd_so_sockopt(args->optname); - switch (name) { - case LOCAL_CREDS_PERSISTENT: - level = SOL_LOCAL; - break; - case SO_RCVTIMEO: - /* FALLTHROUGH */ - case SO_SNDTIMEO: - error = copyin(PTRIN(args->optval), &linux_tv, - sizeof(linux_tv)); - if (error != 0) - return (error); - tv.tv_sec = linux_tv.tv_sec; - tv.tv_usec = linux_tv.tv_usec; - return (kern_setsockopt(td, args->s, level, - name, &tv, UIO_SYSSPACE, sizeof(tv))); - /* NOTREACHED */ - case SO_TIMESTAMP: - /* overwrite SO_BINTIME */ - val = 0; - error = kern_setsockopt(td, args->s, level, - SO_BINTIME, &val, UIO_SYSSPACE, sizeof(val)); - if (error != 0) - return (error); - pem = pem_find(p); - pem->so_timestamp = args->optname; - break; - case SO_BINTIME: - /* overwrite SO_TIMESTAMP */ - val = 0; - error = kern_setsockopt(td, args->s, level, - SO_TIMESTAMP, &val, UIO_SYSSPACE, sizeof(val)); - if (error != 0) - return (error); - pem = pem_find(p); - pem->so_timestampns = args->optname; - break; - default: - break; - } - break; - case IPPROTO_IP: - if (args->optname == LINUX_IP_RECVERR && - linux_ignore_ip_recverr) { - /* - * XXX: This is a hack to unbreak DNS resolution - * with glibc 2.30 and above. - */ - return (0); - } - name = linux_to_bsd_ip_sockopt(args->optname); - break; - case IPPROTO_IPV6: - if (args->optname == LINUX_IPV6_RECVERR && - linux_ignore_ip_recverr) { - /* - * XXX: This is a hack to unbreak DNS resolution - * with glibc 2.30 and above. - */ - return (0); - } - name = linux_to_bsd_ip6_sockopt(args->optname); - break; - case IPPROTO_TCP: - name = linux_to_bsd_tcp_sockopt(args->optname); - break; - case SOL_NETLINK: - name = args->optname; - break; - default: - name = -1; - break; - } - if (name < 0) { - if (name == -1) - linux_msg(curthread, - "unsupported setsockopt level %d optname %d", - args->level, args->optname); - return (ENOPROTOOPT); - } - - if (name == IPV6_NEXTHOP) { - len = args->optlen; - error = linux_to_bsd_sockaddr(PTRIN(args->optval), &sa, &len); - if (error != 0) - return (error); - - error = kern_setsockopt(td, args->s, level, - name, sa, UIO_SYSSPACE, len); - free(sa, M_SONAME); - } else { - error = kern_setsockopt(td, args->s, level, - name, PTRIN(args->optval), UIO_USERSPACE, args->optlen); - } - - return (error); -} - -static int -linux_sockopt_copyout(struct thread *td, void *val, socklen_t len, - struct linux_getsockopt_args *args) -{ - int error; - - error = copyout(val, PTRIN(args->optval), len); - if (error == 0) - error = copyout(&len, PTRIN(args->optlen), sizeof(len)); - return (error); -} - -static int -linux_getsockopt_so_peergroups(struct thread *td, - struct linux_getsockopt_args *args) -{ - struct xucred xu; - socklen_t xulen, len; - int error, i; - - xulen = sizeof(xu); - error = kern_getsockopt(td, args->s, 0, - LOCAL_PEERCRED, &xu, UIO_SYSSPACE, &xulen); - if (error != 0) - return (error); - - len = xu.cr_ngroups * sizeof(l_gid_t); - if (args->optlen < len) { - error = copyout(&len, PTRIN(args->optlen), sizeof(len)); - if (error == 0) - error = ERANGE; - return (error); - } - - /* - * "- 1" to skip the primary group. - */ - for (i = 0; i < xu.cr_ngroups - 1; i++) { - error = copyout(xu.cr_groups + i + 1, - (void *)(args->optval + i * sizeof(l_gid_t)), - sizeof(l_gid_t)); - if (error != 0) - return (error); - } - - error = copyout(&len, PTRIN(args->optlen), sizeof(len)); - return (error); -} - -static int -linux_getsockopt_so_peersec(struct thread *td, - struct linux_getsockopt_args *args) -{ - socklen_t len; - int error; - - len = sizeof(SECURITY_CONTEXT_STRING); - if (args->optlen < len) { - error = copyout(&len, PTRIN(args->optlen), sizeof(len)); - if (error == 0) - error = ERANGE; - return (error); - } - - return (linux_sockopt_copyout(td, SECURITY_CONTEXT_STRING, - len, args)); -} - -static int -linux_getsockopt_so_linger(struct thread *td, - struct linux_getsockopt_args *args) -{ - struct linger ling; - socklen_t len; - int error; - - len = sizeof(ling); - error = kern_getsockopt(td, args->s, SOL_SOCKET, - SO_LINGER, &ling, UIO_SYSSPACE, &len); - if (error != 0) - return (error); - ling.l_onoff = ((ling.l_onoff & SO_LINGER) != 0); - return (linux_sockopt_copyout(td, &ling, len, args)); -} - -int -linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) -{ - l_timeval linux_tv; - struct timeval tv; - socklen_t tv_len, xulen, len; - struct sockaddr *sa; - struct xucred xu; - struct l_ucred lxu; - int error, level, name, newval; - - level = linux_to_bsd_sockopt_level(args->level); - switch (level) { - case SOL_SOCKET: - switch (args->optname) { - case LINUX_SO_PEERGROUPS: - return (linux_getsockopt_so_peergroups(td, args)); - case LINUX_SO_PEERSEC: - return (linux_getsockopt_so_peersec(td, args)); - default: - break; - } - - name = linux_to_bsd_so_sockopt(args->optname); - switch (name) { - case LOCAL_CREDS_PERSISTENT: - level = SOL_LOCAL; - break; - case SO_RCVTIMEO: - /* FALLTHROUGH */ - case SO_SNDTIMEO: - tv_len = sizeof(tv); - error = kern_getsockopt(td, args->s, level, - name, &tv, UIO_SYSSPACE, &tv_len); - if (error != 0) - return (error); - linux_tv.tv_sec = tv.tv_sec; - linux_tv.tv_usec = tv.tv_usec; - return (linux_sockopt_copyout(td, &linux_tv, - sizeof(linux_tv), args)); - /* NOTREACHED */ - case LOCAL_PEERCRED: - if (args->optlen < sizeof(lxu)) - return (EINVAL); - /* - * LOCAL_PEERCRED is not served at the SOL_SOCKET level, - * but by the Unix socket's level 0. - */ - level = 0; - xulen = sizeof(xu); - error = kern_getsockopt(td, args->s, level, - name, &xu, UIO_SYSSPACE, &xulen); - if (error != 0) - return (error); - lxu.pid = xu.cr_pid; - lxu.uid = xu.cr_uid; - lxu.gid = xu.cr_gid; - return (linux_sockopt_copyout(td, &lxu, - sizeof(lxu), args)); - /* NOTREACHED */ - case SO_ERROR: - len = sizeof(newval); - error = kern_getsockopt(td, args->s, level, - name, &newval, UIO_SYSSPACE, &len); - if (error != 0) - return (error); - newval = -bsd_to_linux_errno(newval); - return (linux_sockopt_copyout(td, &newval, - len, args)); - /* NOTREACHED */ - case SO_DOMAIN: - len = sizeof(newval); - error = kern_getsockopt(td, args->s, level, - name, &newval, UIO_SYSSPACE, &len); - if (error != 0) - return (error); - newval = bsd_to_linux_domain((sa_family_t)newval); - if (newval == AF_UNKNOWN) - return (ENOPROTOOPT); - return (linux_sockopt_copyout(td, &newval, - len, args)); - /* NOTREACHED */ - case SO_LINGER: - return (linux_getsockopt_so_linger(td, args)); - /* NOTREACHED */ - default: - break; - } - break; - case IPPROTO_IP: - name = linux_to_bsd_ip_sockopt(args->optname); - break; - case IPPROTO_IPV6: - name = linux_to_bsd_ip6_sockopt(args->optname); - break; - case IPPROTO_TCP: - name = linux_to_bsd_tcp_sockopt(args->optname); - break; - default: - name = -1; - break; - } - if (name < 0) { - if (name == -1) - linux_msg(curthread, - "unsupported getsockopt level %d optname %d", - args->level, args->optname); - return (EINVAL); - } - - if (name == IPV6_NEXTHOP) { - error = copyin(PTRIN(args->optlen), &len, sizeof(len)); - if (error != 0) - return (error); - sa = malloc(len, M_SONAME, M_WAITOK); - - error = kern_getsockopt(td, args->s, level, - name, sa, UIO_SYSSPACE, &len); - if (error != 0) - goto out; - - error = linux_copyout_sockaddr(sa, PTRIN(args->optval), len); - if (error == 0) - error = copyout(&len, PTRIN(args->optlen), - sizeof(len)); -out: - free(sa, M_SONAME); - } else { - if (args->optval) { - error = copyin(PTRIN(args->optlen), &len, sizeof(len)); - if (error != 0) - return (error); - } - error = kern_getsockopt(td, args->s, level, - name, PTRIN(args->optval), UIO_USERSPACE, &len); - if (error == 0) - error = copyout(&len, PTRIN(args->optlen), - sizeof(len)); - } - - return (error); -} - -/* - * Based on sendfile_getsock from kern_sendfile.c - * Determines whether an fd is a stream socket that can be used - * with FreeBSD sendfile. - */ -static bool -is_sendfile(struct file *fp, struct file *ofp) -{ - struct socket *so; - - /* - * FreeBSD sendfile() system call sends a regular file or - * shared memory object out a stream socket. - */ - if ((fp->f_type != DTYPE_SHM && fp->f_type != DTYPE_VNODE) || - (fp->f_type == DTYPE_VNODE && - (fp->f_vnode == NULL || fp->f_vnode->v_type != VREG))) - return (false); - /* - * The socket must be a stream socket and connected. - */ - if (ofp->f_type != DTYPE_SOCKET) - return (false); - so = ofp->f_data; - if (so->so_type != SOCK_STREAM) - return (false); - /* - * SCTP one-to-one style sockets currently don't work with - * sendfile(). - */ - if (so->so_proto->pr_protocol == IPPROTO_SCTP) - return (false); - return (!SOLISTENING(so)); -} - -static bool -is_regular_file(struct file *fp) -{ - - return (fp->f_type == DTYPE_VNODE && fp->f_vnode != NULL && - fp->f_vnode->v_type == VREG); -} - -static int -sendfile_fallback(struct thread *td, struct file *fp, l_int out, - off_t *offset, l_size_t count, off_t *sbytes) -{ - off_t current_offset, out_offset, to_send; - l_size_t bytes_sent, n_read; - struct file *ofp; - struct iovec aiov; - struct uio auio; - bool seekable; - size_t bufsz; - void *buf; - int flags, error; - - if (offset == NULL) { - if ((error = fo_seek(fp, 0, SEEK_CUR, td)) != 0) - return (error); - current_offset = td->td_uretoff.tdu_off; - } else { - if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) - return (ESPIPE); - current_offset = *offset; - } - error = fget_write(td, out, &cap_pwrite_rights, &ofp); - if (error != 0) - return (error); - seekable = (ofp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0; - if (seekable) { - if ((error = fo_seek(ofp, 0, SEEK_CUR, td)) != 0) - goto drop; - out_offset = td->td_uretoff.tdu_off; - } else - out_offset = 0; - - flags = FOF_OFFSET | FOF_NOUPDATE; - bufsz = min(count, maxphys); - buf = malloc(bufsz, M_LINUX, M_WAITOK); - bytes_sent = 0; - while (bytes_sent < count) { - to_send = min(count - bytes_sent, bufsz); - aiov.iov_base = buf; - aiov.iov_len = bufsz; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_td = td; - auio.uio_rw = UIO_READ; - auio.uio_offset = current_offset; - auio.uio_resid = to_send; - error = fo_read(fp, &auio, fp->f_cred, flags, td); - if (error != 0) - break; - n_read = to_send - auio.uio_resid; - if (n_read == 0) - break; - aiov.iov_base = buf; - aiov.iov_len = bufsz; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_td = td; - auio.uio_rw = UIO_WRITE; - auio.uio_offset = (seekable) ? out_offset : 0; - auio.uio_resid = n_read; - error = fo_write(ofp, &auio, ofp->f_cred, flags, td); - if (error != 0) - break; - bytes_sent += n_read; - current_offset += n_read; - out_offset += n_read; - } - free(buf, M_LINUX); - - if (error == 0) { - *sbytes = bytes_sent; - if (offset != NULL) - *offset = current_offset; - else - error = fo_seek(fp, current_offset, SEEK_SET, td); - } - if (error == 0 && seekable) - error = fo_seek(ofp, out_offset, SEEK_SET, td); - -drop: - fdrop(ofp, td); - return (error); -} - -static int -sendfile_sendfile(struct thread *td, struct file *fp, l_int out, - off_t *offset, l_size_t count, off_t *sbytes) -{ - off_t current_offset; - int error; - - if (offset == NULL) { - if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) - return (ESPIPE); - if ((error = fo_seek(fp, 0, SEEK_CUR, td)) != 0) - return (error); - current_offset = td->td_uretoff.tdu_off; - } else - current_offset = *offset; - error = fo_sendfile(fp, out, NULL, NULL, current_offset, count, - sbytes, 0, td); - if (error == 0) { - current_offset += *sbytes; - if (offset != NULL) - *offset = current_offset; - else - error = fo_seek(fp, current_offset, SEEK_SET, td); - } - return (error); -} - -static int -linux_sendfile_common(struct thread *td, l_int out, l_int in, - off_t *offset, l_size_t count) -{ - struct file *fp, *ofp; - off_t sbytes; - int error; - - /* Linux cannot have 0 count. */ - if (count <= 0 || (offset != NULL && *offset < 0)) - return (EINVAL); - - AUDIT_ARG_FD(in); - error = fget_read(td, in, &cap_pread_rights, &fp); - if (error != 0) - return (error); - if ((fp->f_type != DTYPE_SHM && fp->f_type != DTYPE_VNODE) || - (fp->f_type == DTYPE_VNODE && - (fp->f_vnode == NULL || fp->f_vnode->v_type != VREG))) { - error = EINVAL; - goto drop; - } - error = fget_unlocked(td, out, &cap_no_rights, &ofp); - if (error != 0) - goto drop; - - if (is_regular_file(fp) && is_regular_file(ofp)) { - error = kern_copy_file_range(td, in, offset, out, NULL, count, - 0); - } else { - sbytes = 0; - if (is_sendfile(fp, ofp)) - error = sendfile_sendfile(td, fp, out, offset, count, - &sbytes); - else - error = sendfile_fallback(td, fp, out, offset, count, - &sbytes); - if (error == ENOBUFS && (ofp->f_flag & FNONBLOCK) != 0) - error = EAGAIN; - if (error == 0) - td->td_retval[0] = sbytes; - } - fdrop(ofp, td); - -drop: - fdrop(fp, td); - return (error); -} - -int -linux_sendfile(struct thread *td, struct linux_sendfile_args *arg) -{ - /* - * Differences between FreeBSD and Linux sendfile: - * - Linux doesn't send anything when count is 0 (FreeBSD uses 0 to - * mean send the whole file). - * - Linux can send to any fd whereas FreeBSD only supports sockets. - * We therefore use FreeBSD sendfile where possible for performance, - * but fall back on a manual copy (sendfile_fallback). - * - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr. - * - Linux takes an offset pointer and updates it to the read location. - * FreeBSD takes in an offset and a 'bytes read' parameter which is - * only filled if it isn't NULL. We use this parameter to update the - * offset pointer if it exists. - * - Linux sendfile returns bytes read on success while FreeBSD - * returns 0. We use the 'bytes read' parameter to get this value. - */ - - off_t offset64; - l_off_t offset; - int error; - - if (arg->offset != NULL) { - error = copyin(arg->offset, &offset, sizeof(offset)); - if (error != 0) - return (error); - offset64 = offset; - } - - error = linux_sendfile_common(td, arg->out, arg->in, - arg->offset != NULL ? &offset64 : NULL, arg->count); - - if (error == 0 && arg->offset != NULL) { -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) - if (offset64 > INT32_MAX) - return (EOVERFLOW); -#endif - offset = (l_off_t)offset64; - error = copyout(&offset, arg->offset, sizeof(offset)); - } - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_sendfile64(struct thread *td, struct linux_sendfile64_args *arg) -{ - off_t offset; - int error; - - if (arg->offset != NULL) { - error = copyin(arg->offset, &offset, sizeof(offset)); - if (error != 0) - return (error); - } - - error = linux_sendfile_common(td, arg->out, arg->in, - arg->offset != NULL ? &offset : NULL, arg->count); - - if (error == 0 && arg->offset != NULL) - error = copyout(&offset, arg->offset, sizeof(offset)); - - return (error); -} - -/* Argument list sizes for linux_socketcall */ -static const unsigned char lxs_args_cnt[] = { - 0 /* unused*/, 3 /* socket */, - 3 /* bind */, 3 /* connect */, - 2 /* listen */, 3 /* accept */, - 3 /* getsockname */, 3 /* getpeername */, - 4 /* socketpair */, 4 /* send */, - 4 /* recv */, 6 /* sendto */, - 6 /* recvfrom */, 2 /* shutdown */, - 5 /* setsockopt */, 5 /* getsockopt */, - 3 /* sendmsg */, 3 /* recvmsg */, - 4 /* accept4 */, 5 /* recvmmsg */, - 4 /* sendmmsg */, 4 /* sendfile */ -}; -#define LINUX_ARGS_CNT (nitems(lxs_args_cnt) - 1) -#define LINUX_ARG_SIZE(x) (lxs_args_cnt[x] * sizeof(l_ulong)) - -int -linux_socketcall(struct thread *td, struct linux_socketcall_args *args) -{ - l_ulong a[6]; -#if defined(__amd64__) && defined(COMPAT_LINUX32) - register_t l_args[6]; -#endif - void *arg; - int error; - - if (args->what < LINUX_SOCKET || args->what > LINUX_ARGS_CNT) - return (EINVAL); - error = copyin(PTRIN(args->args), a, LINUX_ARG_SIZE(args->what)); - if (error != 0) - return (error); - -#if defined(__amd64__) && defined(COMPAT_LINUX32) - for (int i = 0; i < lxs_args_cnt[args->what]; ++i) - l_args[i] = a[i]; - arg = l_args; -#else - arg = a; -#endif - switch (args->what) { - case LINUX_SOCKET: - return (linux_socket(td, arg)); - case LINUX_BIND: - return (linux_bind(td, arg)); - case LINUX_CONNECT: - return (linux_connect(td, arg)); - case LINUX_LISTEN: - return (linux_listen(td, arg)); - case LINUX_ACCEPT: - return (linux_accept(td, arg)); - case LINUX_GETSOCKNAME: - return (linux_getsockname(td, arg)); - case LINUX_GETPEERNAME: - return (linux_getpeername(td, arg)); - case LINUX_SOCKETPAIR: - return (linux_socketpair(td, arg)); - case LINUX_SEND: - return (linux_send(td, arg)); - case LINUX_RECV: - return (linux_recv(td, arg)); - case LINUX_SENDTO: - return (linux_sendto(td, arg)); - case LINUX_RECVFROM: - return (linux_recvfrom(td, arg)); - case LINUX_SHUTDOWN: - return (linux_shutdown(td, arg)); - case LINUX_SETSOCKOPT: - return (linux_setsockopt(td, arg)); - case LINUX_GETSOCKOPT: - return (linux_getsockopt(td, arg)); - case LINUX_SENDMSG: - return (linux_sendmsg(td, arg)); - case LINUX_RECVMSG: - return (linux_recvmsg(td, arg)); - case LINUX_ACCEPT4: - return (linux_accept4(td, arg)); - case LINUX_RECVMMSG: - return (linux_recvmmsg(td, arg)); - case LINUX_SENDMMSG: - return (linux_sendmmsg(td, arg)); - case LINUX_SENDFILE: - return (linux_sendfile(td, arg)); - } - - linux_msg(td, "socket type %d not implemented", args->what); - return (ENOSYS); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ -// CHERI CHANGES START -// { -// "updated": 20230509, -// "target_type": "kernel", -// "changes": [ -// "iovec-macros" -// ] -// } -// CHERI CHANGES END +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 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 "opt_inet6.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#ifdef INET6 +#include +#include +#endif + +#if defined(COMPAT_LINUX32) +#include +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +_Static_assert(offsetof(struct l_ifreq, ifr_ifru) == + offsetof(struct ifreq, ifr_ifru), + "Linux ifreq members names should be equal to FreeeBSD"); +_Static_assert(offsetof(struct l_ifreq, ifr_index) == + offsetof(struct ifreq, ifr_index), + "Linux ifreq members names should be equal to FreeeBSD"); +_Static_assert(offsetof(struct l_ifreq, ifr_name) == + offsetof(struct ifreq, ifr_name), + "Linux ifreq members names should be equal to FreeeBSD"); + +#define SECURITY_CONTEXT_STRING "unconfined" + +static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr * __capability, + l_uint); +static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr * __capability, + l_uint, struct msghdr *); +static int linux_set_socket_flags(int, int *); + +#define SOL_NETLINK 270 + +static int +linux_to_bsd_sockopt_level(int level) +{ + + if (level == LINUX_SOL_SOCKET) + return (SOL_SOCKET); + /* Remaining values are RFC-defined protocol numbers. */ + return (level); +} + +static int +bsd_to_linux_sockopt_level(int level) +{ + + if (level == SOL_SOCKET) + return (LINUX_SOL_SOCKET); + return (level); +} + +static int +linux_to_bsd_ip_sockopt(int opt) +{ + + switch (opt) { + /* known and translated sockopts */ + case LINUX_IP_TOS: + return (IP_TOS); + case LINUX_IP_TTL: + return (IP_TTL); + case LINUX_IP_HDRINCL: + return (IP_HDRINCL); + case LINUX_IP_OPTIONS: + return (IP_OPTIONS); + case LINUX_IP_RECVOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVOPTS"); + return (IP_RECVOPTS); + case LINUX_IP_RETOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_REETOPTS"); + return (IP_RETOPTS); + case LINUX_IP_RECVTTL: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVTTL"); + return (IP_RECVTTL); + case LINUX_IP_RECVTOS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_RECVTOS"); + return (IP_RECVTOS); + case LINUX_IP_FREEBIND: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_FREEBIND"); + return (IP_BINDANY); + case LINUX_IP_IPSEC_POLICY: + /* we have this option, but not documented in ip(4) manpage */ + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_IPSEC_POLICY"); + return (IP_IPSEC_POLICY); + case LINUX_IP_MINTTL: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MINTTL"); + return (IP_MINTTL); + case LINUX_IP_MULTICAST_IF: + return (IP_MULTICAST_IF); + case LINUX_IP_MULTICAST_TTL: + return (IP_MULTICAST_TTL); + case LINUX_IP_MULTICAST_LOOP: + return (IP_MULTICAST_LOOP); + case LINUX_IP_ADD_MEMBERSHIP: + return (IP_ADD_MEMBERSHIP); + case LINUX_IP_DROP_MEMBERSHIP: + return (IP_DROP_MEMBERSHIP); + case LINUX_IP_UNBLOCK_SOURCE: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_UNBLOCK_SOURCE"); + return (IP_UNBLOCK_SOURCE); + case LINUX_IP_BLOCK_SOURCE: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_BLOCK_SOURCE"); + return (IP_BLOCK_SOURCE); + case LINUX_IP_ADD_SOURCE_MEMBERSHIP: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_ADD_SOURCE_MEMBERSHIP"); + return (IP_ADD_SOURCE_MEMBERSHIP); + case LINUX_IP_DROP_SOURCE_MEMBERSHIP: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_DROP_SOURCE_MEMBERSHIP"); + return (IP_DROP_SOURCE_MEMBERSHIP); + case LINUX_MCAST_JOIN_GROUP: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_JOIN_GROUP"); + return (MCAST_JOIN_GROUP); + case LINUX_MCAST_LEAVE_GROUP: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_LEAVE_GROUP"); + return (MCAST_LEAVE_GROUP); + case LINUX_MCAST_JOIN_SOURCE_GROUP: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_JOIN_SOURCE_GROUP"); + return (MCAST_JOIN_SOURCE_GROUP); + case LINUX_MCAST_LEAVE_SOURCE_GROUP: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv4 socket option IP_MCAST_LEAVE_SOURCE_GROUP"); + return (MCAST_LEAVE_SOURCE_GROUP); + case LINUX_IP_RECVORIGDSTADDR: + return (IP_RECVORIGDSTADDR); + + /* known but not implemented sockopts */ + case LINUX_IP_ROUTER_ALERT: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_ROUTER_ALERT (%d), you can not do user-space routing from linux programs", + opt); + return (-2); + case LINUX_IP_PKTINFO: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_PKTINFO (%d), you can not get extended packet info for datagram sockets in linux programs", + opt); + return (-2); + case LINUX_IP_PKTOPTIONS: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_PKTOPTIONS (%d)", + opt); + return (-2); + case LINUX_IP_MTU_DISCOVER: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_MTU_DISCOVER (%d), your linux program can not control path-MTU discovery", + opt); + return (-2); + case LINUX_IP_RECVERR: + /* needed by steam */ + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_RECVERR (%d), you can not get extended reliability info in linux programs", + opt); + return (-2); + case LINUX_IP_MTU: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_MTU (%d), your linux program can not control the MTU on this socket", + opt); + return (-2); + case LINUX_IP_XFRM_POLICY: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_XFRM_POLICY (%d)", + opt); + return (-2); + case LINUX_IP_PASSSEC: + /* needed by steam */ + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_PASSSEC (%d), you can not get IPSEC related credential information associated with this socket in linux programs -- if you do not use IPSEC, you can ignore this", + opt); + return (-2); + case LINUX_IP_TRANSPARENT: + /* IP_BINDANY or more? */ + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_TRANSPARENT (%d), you can not enable transparent proxying in linux programs -- note, IP_FREEBIND is supported, no idea if the FreeBSD IP_BINDANY is equivalent to the Linux IP_TRANSPARENT or not, any info is welcome", + opt); + return (-2); + case LINUX_IP_NODEFRAG: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_NODEFRAG (%d)", + opt); + return (-2); + case LINUX_IP_CHECKSUM: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_CHECKSUM (%d)", + opt); + return (-2); + case LINUX_IP_BIND_ADDRESS_NO_PORT: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_BIND_ADDRESS_NO_PORT (%d)", + opt); + return (-2); + case LINUX_IP_RECVFRAGSIZE: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_RECVFRAGSIZE (%d)", + opt); + return (-2); + case LINUX_MCAST_MSFILTER: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_MCAST_MSFILTER (%d)", + opt); + return (-2); + case LINUX_IP_MULTICAST_ALL: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_MULTICAST_ALL (%d), your linux program will not see all multicast groups joined by the entire system, only those the program joined itself on this socket", + opt); + return (-2); + case LINUX_IP_UNICAST_IF: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv4 socket option IP_UNICAST_IF (%d)", + opt); + return (-2); + + /* unknown sockopts */ + default: + return (-1); + } +} + +static int +linux_to_bsd_ip6_sockopt(int opt) +{ + + switch (opt) { + /* known and translated sockopts */ + case LINUX_IPV6_2292PKTINFO: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292PKTINFO"); + return (IPV6_2292PKTINFO); + case LINUX_IPV6_2292HOPOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292HOPOPTS"); + return (IPV6_2292HOPOPTS); + case LINUX_IPV6_2292DSTOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292DSTOPTS"); + return (IPV6_2292DSTOPTS); + case LINUX_IPV6_2292RTHDR: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292RTHDR"); + return (IPV6_2292RTHDR); + case LINUX_IPV6_2292PKTOPTIONS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292PKTOPTIONS"); + return (IPV6_2292PKTOPTIONS); + case LINUX_IPV6_CHECKSUM: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_CHECKSUM"); + return (IPV6_CHECKSUM); + case LINUX_IPV6_2292HOPLIMIT: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_2292HOPLIMIT"); + return (IPV6_2292HOPLIMIT); + case LINUX_IPV6_NEXTHOP: + return (IPV6_NEXTHOP); + case LINUX_IPV6_UNICAST_HOPS: + return (IPV6_UNICAST_HOPS); + case LINUX_IPV6_MULTICAST_IF: + return (IPV6_MULTICAST_IF); + case LINUX_IPV6_MULTICAST_HOPS: + return (IPV6_MULTICAST_HOPS); + case LINUX_IPV6_MULTICAST_LOOP: + return (IPV6_MULTICAST_LOOP); + case LINUX_IPV6_ADD_MEMBERSHIP: + return (IPV6_JOIN_GROUP); + case LINUX_IPV6_DROP_MEMBERSHIP: + return (IPV6_LEAVE_GROUP); + case LINUX_IPV6_V6ONLY: + return (IPV6_V6ONLY); + case LINUX_IPV6_IPSEC_POLICY: + /* we have this option, but not documented in ip6(4) manpage */ + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_IPSEC_POLICY"); + return (IPV6_IPSEC_POLICY); + case LINUX_MCAST_JOIN_GROUP: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_JOIN_GROUP"); + return (IPV6_JOIN_GROUP); + case LINUX_MCAST_LEAVE_GROUP: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_LEAVE_GROUP"); + return (IPV6_LEAVE_GROUP); + case LINUX_IPV6_RECVPKTINFO: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVPKTINFO"); + return (IPV6_RECVPKTINFO); + case LINUX_IPV6_PKTINFO: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_PKTINFO"); + return (IPV6_PKTINFO); + case LINUX_IPV6_RECVHOPLIMIT: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVHOPLIMIT"); + return (IPV6_RECVHOPLIMIT); + case LINUX_IPV6_HOPLIMIT: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_HOPLIMIT"); + return (IPV6_HOPLIMIT); + case LINUX_IPV6_RECVHOPOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVHOPOPTS"); + return (IPV6_RECVHOPOPTS); + case LINUX_IPV6_HOPOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_HOPOPTS"); + return (IPV6_HOPOPTS); + case LINUX_IPV6_RTHDRDSTOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RTHDRDSTOPTS"); + return (IPV6_RTHDRDSTOPTS); + case LINUX_IPV6_RECVRTHDR: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVRTHDR"); + return (IPV6_RECVRTHDR); + case LINUX_IPV6_RTHDR: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RTHDR"); + return (IPV6_RTHDR); + case LINUX_IPV6_RECVDSTOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVDSTOPTS"); + return (IPV6_RECVDSTOPTS); + case LINUX_IPV6_DSTOPTS: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_DSTOPTS"); + return (IPV6_DSTOPTS); + case LINUX_IPV6_RECVPATHMTU: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_RECVPATHMTU"); + return (IPV6_RECVPATHMTU); + case LINUX_IPV6_PATHMTU: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_PATHMTU"); + return (IPV6_PATHMTU); + case LINUX_IPV6_DONTFRAG: + return (IPV6_DONTFRAG); + case LINUX_IPV6_AUTOFLOWLABEL: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_AUTOFLOWLABEL"); + return (IPV6_AUTOFLOWLABEL); + case LINUX_IPV6_ORIGDSTADDR: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_ORIGDSTADDR"); + return (IPV6_ORIGDSTADDR); + case LINUX_IPV6_FREEBIND: + LINUX_RATELIMIT_MSG_NOTTESTED("IPv6 socket option IPV6_FREEBIND"); + return (IPV6_BINDANY); + + /* known but not implemented sockopts */ + case LINUX_IPV6_ADDRFORM: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_ADDRFORM (%d), you linux program can not convert the socket to IPv4", + opt); + return (-2); + case LINUX_IPV6_AUTHHDR: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_AUTHHDR (%d), your linux program can not get the authentication header info of IPv6 packets", + opt); + return (-2); + case LINUX_IPV6_FLOWINFO: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_FLOWINFO (%d), your linux program can not get the flowid of IPv6 packets", + opt); + return (-2); + case LINUX_IPV6_ROUTER_ALERT: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_ROUTER_ALERT (%d), you can not do user-space routing from linux programs", + opt); + return (-2); + case LINUX_IPV6_MTU_DISCOVER: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_MTU_DISCOVER (%d), your linux program can not control path-MTU discovery", + opt); + return (-2); + case LINUX_IPV6_MTU: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_MTU (%d), your linux program can not control the MTU on this socket", + opt); + return (-2); + case LINUX_IPV6_JOIN_ANYCAST: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_JOIN_ANYCAST (%d)", + opt); + return (-2); + case LINUX_IPV6_LEAVE_ANYCAST: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_LEAVE_ANYCAST (%d)", + opt); + return (-2); + case LINUX_IPV6_MULTICAST_ALL: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_MULTICAST_ALL (%d)", + opt); + return (-2); + case LINUX_IPV6_ROUTER_ALERT_ISOLATE: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_ROUTER_ALERT_ISOLATE (%d)", + opt); + return (-2); + case LINUX_IPV6_FLOWLABEL_MGR: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_FLOWLABEL_MGR (%d)", + opt); + return (-2); + case LINUX_IPV6_FLOWINFO_SEND: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_FLOWINFO_SEND (%d)", + opt); + return (-2); + case LINUX_IPV6_XFRM_POLICY: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_XFRM_POLICY (%d)", + opt); + return (-2); + case LINUX_IPV6_HDRINCL: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_HDRINCL (%d)", + opt); + return (-2); + case LINUX_MCAST_BLOCK_SOURCE: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option MCAST_BLOCK_SOURCE (%d), your linux program may see more multicast stuff than it wants", + opt); + return (-2); + case LINUX_MCAST_UNBLOCK_SOURCE: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option MCAST_UNBLOCK_SOURCE (%d), your linux program may not see all the multicast stuff it wants", + opt); + return (-2); + case LINUX_MCAST_JOIN_SOURCE_GROUP: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option MCAST_JOIN_SOURCE_GROUP (%d), your linux program is not able to join a multicast source group", + opt); + return (-2); + case LINUX_MCAST_LEAVE_SOURCE_GROUP: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option MCAST_LEAVE_SOURCE_GROUP (%d), your linux program is not able to leave a multicast source group -- but it was also not able to join one, so no issue", + opt); + return (-2); + case LINUX_MCAST_MSFILTER: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option MCAST_MSFILTER (%d), your linux program can not manipulate the multicast filter, it may see more multicast data than it wants to see", + opt); + return (-2); + case LINUX_IPV6_ADDR_PREFERENCES: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_ADDR_PREFERENCES (%d)", + opt); + return (-2); + case LINUX_IPV6_MINHOPCOUNT: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_MINHOPCOUNT (%d)", + opt); + return (-2); + case LINUX_IPV6_TRANSPARENT: + /* IP_BINDANY or more? */ + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_TRANSPARENT (%d), you can not enable transparent proxying in linux programs -- note, IP_FREEBIND is supported, no idea if the FreeBSD IP_BINDANY is equivalent to the Linux IP_TRANSPARENT or not, any info is welcome", + opt); + return (-2); + case LINUX_IPV6_UNICAST_IF: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_UNICAST_IF (%d)", + opt); + return (-2); + case LINUX_IPV6_RECVFRAGSIZE: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_RECVFRAGSIZE (%d)", + opt); + return (-2); + case LINUX_IPV6_RECVERR: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported IPv6 socket option IPV6_RECVERR (%d), you can not get extended reliability info in linux programs", + opt); + return (-2); + + /* unknown sockopts */ + default: + return (-1); + } +} + +static int +linux_to_bsd_so_sockopt(int opt) +{ + + switch (opt) { + case LINUX_SO_DEBUG: + return (SO_DEBUG); + case LINUX_SO_REUSEADDR: + return (SO_REUSEADDR); + case LINUX_SO_TYPE: + return (SO_TYPE); + case LINUX_SO_ERROR: + return (SO_ERROR); + case LINUX_SO_DONTROUTE: + return (SO_DONTROUTE); + case LINUX_SO_BROADCAST: + return (SO_BROADCAST); + case LINUX_SO_SNDBUF: + case LINUX_SO_SNDBUFFORCE: + return (SO_SNDBUF); + case LINUX_SO_RCVBUF: + case LINUX_SO_RCVBUFFORCE: + return (SO_RCVBUF); + case LINUX_SO_KEEPALIVE: + return (SO_KEEPALIVE); + case LINUX_SO_OOBINLINE: + return (SO_OOBINLINE); + case LINUX_SO_LINGER: + return (SO_LINGER); + case LINUX_SO_REUSEPORT: + return (SO_REUSEPORT_LB); + case LINUX_SO_PASSCRED: + return (LOCAL_CREDS_PERSISTENT); + case LINUX_SO_PEERCRED: + return (LOCAL_PEERCRED); + case LINUX_SO_RCVLOWAT: + return (SO_RCVLOWAT); + case LINUX_SO_SNDLOWAT: + return (SO_SNDLOWAT); + case LINUX_SO_RCVTIMEO: + return (SO_RCVTIMEO); + case LINUX_SO_SNDTIMEO: + return (SO_SNDTIMEO); + case LINUX_SO_TIMESTAMPO: + case LINUX_SO_TIMESTAMPN: + return (SO_TIMESTAMP); + case LINUX_SO_TIMESTAMPNSO: + case LINUX_SO_TIMESTAMPNSN: + return (SO_BINTIME); + case LINUX_SO_ACCEPTCONN: + return (SO_ACCEPTCONN); + case LINUX_SO_PROTOCOL: + return (SO_PROTOCOL); + case LINUX_SO_DOMAIN: + return (SO_DOMAIN); + } + return (-1); +} + +static int +linux_to_bsd_tcp_sockopt(int opt) +{ + + switch (opt) { + case LINUX_TCP_NODELAY: + return (TCP_NODELAY); + case LINUX_TCP_MAXSEG: + return (TCP_MAXSEG); + case LINUX_TCP_CORK: + return (TCP_NOPUSH); + case LINUX_TCP_KEEPIDLE: + return (TCP_KEEPIDLE); + case LINUX_TCP_KEEPINTVL: + return (TCP_KEEPINTVL); + case LINUX_TCP_KEEPCNT: + return (TCP_KEEPCNT); + case LINUX_TCP_INFO: + LINUX_RATELIMIT_MSG_OPT1( + "unsupported TCP socket option TCP_INFO (%d)", opt); + return (-2); + case LINUX_TCP_MD5SIG: + return (TCP_MD5SIG); + } + return (-1); +} + +static int +linux_to_bsd_msg_flags(int flags) +{ + int ret_flags = 0; + + if (flags & LINUX_MSG_OOB) + ret_flags |= MSG_OOB; + if (flags & LINUX_MSG_PEEK) + ret_flags |= MSG_PEEK; + if (flags & LINUX_MSG_DONTROUTE) + ret_flags |= MSG_DONTROUTE; + if (flags & LINUX_MSG_CTRUNC) + ret_flags |= MSG_CTRUNC; + if (flags & LINUX_MSG_TRUNC) + ret_flags |= MSG_TRUNC; + if (flags & LINUX_MSG_DONTWAIT) + ret_flags |= MSG_DONTWAIT; + if (flags & LINUX_MSG_EOR) + ret_flags |= MSG_EOR; + if (flags & LINUX_MSG_WAITALL) + ret_flags |= MSG_WAITALL; + if (flags & LINUX_MSG_NOSIGNAL) + ret_flags |= MSG_NOSIGNAL; + if (flags & LINUX_MSG_PROXY) + LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_PROXY (%d) not handled", + LINUX_MSG_PROXY); + if (flags & LINUX_MSG_FIN) + LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_FIN (%d) not handled", + LINUX_MSG_FIN); + if (flags & LINUX_MSG_SYN) + LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_SYN (%d) not handled", + LINUX_MSG_SYN); + if (flags & LINUX_MSG_CONFIRM) + LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_CONFIRM (%d) not handled", + LINUX_MSG_CONFIRM); + if (flags & LINUX_MSG_RST) + LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_RST (%d) not handled", + LINUX_MSG_RST); + if (flags & LINUX_MSG_ERRQUEUE) + LINUX_RATELIMIT_MSG_OPT1("socket message flag MSG_ERRQUEUE (%d) not handled", + LINUX_MSG_ERRQUEUE); + return (ret_flags); +} + +static int +linux_to_bsd_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case LINUX_SCM_RIGHTS: + return (SCM_RIGHTS); + case LINUX_SCM_CREDENTIALS: + return (SCM_CREDS); + } + return (-1); +} + +static int +bsd_to_linux_ip_cmsg_type(int cmsg_type) +{ + + switch (cmsg_type) { + case IP_RECVORIGDSTADDR: + return (LINUX_IP_RECVORIGDSTADDR); + } + return (-1); +} + +static int +bsd_to_linux_cmsg_type(struct proc *p, int cmsg_type, int cmsg_level) +{ + struct linux_pemuldata *pem; + + if (cmsg_level == IPPROTO_IP) + return (bsd_to_linux_ip_cmsg_type(cmsg_type)); + if (cmsg_level != SOL_SOCKET) + return (-1); + + pem = pem_find(p); + + switch (cmsg_type) { + case SCM_RIGHTS: + return (LINUX_SCM_RIGHTS); + case SCM_CREDS: + return (LINUX_SCM_CREDENTIALS); + case SCM_CREDS2: + return (LINUX_SCM_CREDENTIALS); + case SCM_TIMESTAMP: + return (pem->so_timestamp); + case SCM_BINTIME: + return (pem->so_timestampns); + } + return (-1); +} + +static int +linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) +{ + if (lhdr->msg_controllen > INT_MAX) + return (ENOBUFS); + + bhdr->msg_name = LINUX_USER_CAP(lhdr->msg_name, lhdr->msg_namelen); + bhdr->msg_namelen = lhdr->msg_namelen; + bhdr->msg_iov = LINUX_USER_CAP(lhdr->msg_iov, lhdr->msg_iovlen * sizeof(struct l_iovec64)); + bhdr->msg_iovlen = lhdr->msg_iovlen; + // TODO: Check + bhdr->msg_control = LINUX_USER_CAP_UNBOUND(lhdr->msg_control); + + /* + * msg_controllen is skipped since BSD and LINUX control messages + * are potentially different sizes (e.g. the cred structure used + * by SCM_CREDS is different between the two operating system). + * + * The caller can set it (if necessary) after converting all the + * control messages. + */ + + bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); + return (0); +} + +static int +bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) +{ + lhdr->msg_name = (uintcap_t)(bhdr->msg_name); + lhdr->msg_namelen = bhdr->msg_namelen; + lhdr->msg_iov = (uintcap_t)(bhdr->msg_iov); + lhdr->msg_iovlen = bhdr->msg_iovlen; + lhdr->msg_control = (uintcap_t)(bhdr->msg_control); + + /* + * msg_controllen is skipped since BSD and LINUX control messages + * are potentially different sizes (e.g. the cred structure used + * by SCM_CREDS is different between the two operating system). + * + * The caller can set it (if necessary) after converting all the + * control messages. + */ + + /* msg_flags skipped */ + return (0); +} + +static int +linux_set_socket_flags(int lflags, int *flags) +{ + + if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) + return (EINVAL); + if (lflags & LINUX_SOCK_NONBLOCK) + *flags |= SOCK_NONBLOCK; + if (lflags & LINUX_SOCK_CLOEXEC) + *flags |= SOCK_CLOEXEC; + return (0); +} + +static int +linux_copyout_sockaddr(const struct sockaddr *sa, void *uaddr, size_t len) +{ + struct l_sockaddr *lsa; + int error; + + error = bsd_to_linux_sockaddr(sa, &lsa, len); + if (error != 0) + return (error); + + error = copyout(lsa, LINUX_USER_CAP(uaddr, len), len); + free(lsa, M_LINUX); + + return (error); +} + +static int +linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, + struct mbuf *control, enum uio_seg segflg) +{ + struct sockaddr *to; + int error, len; + + if (mp->msg_name != NULL) { + len = mp->msg_namelen; + error = linux_to_bsd_sockaddr(mp->msg_name, &to, &len); + if (error != 0) + return (error); + mp->msg_name = PTR2CAP(to); + } else + to = NULL; + + error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, + segflg); + + if (to) + free(to, M_SONAME); + return (error); +} + +/* Return 0 if IP_HDRINCL is set for the given socket. */ +static int +linux_check_hdrincl(struct thread *td, int s) +{ + int error, optval; + socklen_t size_val; + + size_val = sizeof(optval); + error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, + &optval, UIO_SYSSPACE, &size_val); + if (error != 0) + return (error); + + return (optval == 0); +} + +/* + * Updated sendto() when IP_HDRINCL is set: + * tweak endian-dependent fields in the IP packet. + */ +static int +linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) +{ +/* + * linux_ip_copysize defines how many bytes we should copy + * from the beginning of the IP packet before we customize it for BSD. + * It should include all the fields we modify (ip_len and ip_off). + */ +#define linux_ip_copysize 8 + + struct ip *packet; + struct msghdr msg; + struct iovec aiov[1]; + int error; + + /* Check that the packet isn't too big or too small. */ + if (linux_args->len < linux_ip_copysize || + linux_args->len > IP_MAXPACKET) + return (EINVAL); + + packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK); + + /* Make kernel copy of the packet to be sent */ + if ((error = copyin(LINUX_USER_CAP(linux_args->msg, linux_args->len), packet, + linux_args->len))) + goto goout; + + /* Convert fields from Linux to BSD raw IP socket format */ + packet->ip_len = linux_args->len; + packet->ip_off = ntohs(packet->ip_off); + + /* Prepare the msghdr and iovec structures describing the new packet */ + msg.msg_name = LINUX_USER_CAP(linux_args->to, linux_args->tolen); + msg.msg_namelen = linux_args->tolen; + msg.msg_iov = aiov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_flags = 0; + IOVEC_INIT(&aiov[0], packet, linux_args->len); + error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, + NULL, UIO_SYSSPACE); +goout: + free(packet, M_LINUX); + return (error); +} + +static const char *linux_netlink_names[] = { + [LINUX_NETLINK_ROUTE] = "ROUTE", + [LINUX_NETLINK_SOCK_DIAG] = "SOCK_DIAG", + [LINUX_NETLINK_NFLOG] = "NFLOG", + [LINUX_NETLINK_SELINUX] = "SELINUX", + [LINUX_NETLINK_AUDIT] = "AUDIT", + [LINUX_NETLINK_FIB_LOOKUP] = "FIB_LOOKUP", + [LINUX_NETLINK_NETFILTER] = "NETFILTER", + [LINUX_NETLINK_KOBJECT_UEVENT] = "KOBJECT_UEVENT", +}; + +int +linux_socket(struct thread *td, struct linux_socket_args *args) +{ + int retval_socket, type; + sa_family_t domain; + + type = args->type & LINUX_SOCK_TYPE_MASK; + if (type < 0 || type > LINUX_SOCK_MAX) + return (EINVAL); + retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, + &type); + if (retval_socket != 0) + return (retval_socket); + domain = linux_to_bsd_domain(args->domain); + if (domain == AF_UNKNOWN) { + /* Mask off SOCK_NONBLOCK / CLOEXEC for error messages. */ + type = args->type & LINUX_SOCK_TYPE_MASK; + if (args->domain == LINUX_AF_NETLINK && + args->protocol == LINUX_NETLINK_AUDIT) { + ; /* Do nothing, quietly. */ + } else if (args->domain == LINUX_AF_NETLINK) { + const char *nl_name; + + if (args->protocol >= 0 && + args->protocol < nitems(linux_netlink_names)) + nl_name = linux_netlink_names[args->protocol]; + else + nl_name = NULL; + if (nl_name != NULL) + linux_msg(curthread, + "unsupported socket(AF_NETLINK, %d, " + "NETLINK_%s)", type, nl_name); + else + linux_msg(curthread, + "unsupported socket(AF_NETLINK, %d, %d)", + type, args->protocol); + } else { + linux_msg(curthread, "unsupported socket domain %d, " + "type %d, protocol %d", args->domain, type, + args->protocol); + } + return (EAFNOSUPPORT); + } + + retval_socket = kern_socket(td, domain, type, args->protocol); + if (retval_socket) + return (retval_socket); + + if (type == SOCK_RAW + && (args->protocol == IPPROTO_RAW || args->protocol == 0) + && domain == PF_INET) { + /* It's a raw IP socket: set the IP_HDRINCL option. */ + int hdrincl; + + hdrincl = 1; + /* We ignore any error returned by kern_setsockopt() */ + kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, + &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); + } +#ifdef INET6 + /* + * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default + * and some apps depend on this. So, set V6ONLY to 0 for Linux apps. + * For simplicity we do this unconditionally of the net.inet6.ip6.v6only + * sysctl value. + */ + if (domain == PF_INET6) { + int v6only; + + v6only = 0; + /* We ignore any error returned by setsockopt() */ + kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, + &v6only, UIO_SYSSPACE, sizeof(v6only)); + } +#endif + + return (retval_socket); +} + +int +linux_bind(struct thread *td, struct linux_bind_args *args) +{ + struct sockaddr *sa; + int error; + + error = linux_to_bsd_sockaddr(LINUX_USER_CAP(args->name, args->namelen), &sa, + &args->namelen); + if (error != 0) + return (error); + + error = kern_bindat(td, AT_FDCWD, args->s, sa); + free(sa, M_SONAME); + + /* XXX */ + if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) + return (EINVAL); + return (error); +} + +int +linux_connect(struct thread *td, struct linux_connect_args *args) +{ + struct socket *so; + struct sockaddr *sa; + struct file *fp; + int error; + + error = linux_to_bsd_sockaddr(LINUX_USER_CAP(args->name, args->namelen), &sa, + &args->namelen); + if (error != 0) + return (error); + + error = kern_connectat(td, AT_FDCWD, args->s, sa); + free(sa, M_SONAME); + if (error != EISCONN) + return (error); + + /* + * Linux doesn't return EISCONN the first time it occurs, + * when on a non-blocking socket. Instead it returns the + * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. + */ + error = getsock(td, args->s, &cap_connect_rights, &fp); + if (error != 0) + return (error); + + error = EISCONN; + so = fp->f_data; + if (atomic_load_int(&fp->f_flag) & FNONBLOCK) { + SOCK_LOCK(so); + if (so->so_emuldata == 0) + error = so->so_error; + so->so_emuldata = (void *)1; + SOCK_UNLOCK(so); + } + fdrop(fp, td); + + return (error); +} + +int +linux_listen(struct thread *td, struct linux_listen_args *args) +{ + + return (kern_listen(td, args->s, args->backlog)); +} + +static int +linux_accept_common(struct thread *td, int s, l_uintptr_t addr, + l_uintptr_t namelen, int flags) +{ + struct sockaddr_storage ss = { .ss_len = sizeof(ss) }; + struct file *fp, *fp1; + struct socket *so; + socklen_t len; + int bflags, error, error1; + + bflags = 0; + fp = NULL; + + error = linux_set_socket_flags(flags, &bflags); + if (error != 0) + return (error); + + if (PTRIN(addr) != NULL) { + error = copyin(LINUX_USER_CAP(namelen, sizeof(len)), &len, sizeof(len)); + if (error != 0) + return (error); + if (len < 0) + return (EINVAL); + } else + len = 0; + + error = kern_accept4(td, s, (struct sockaddr *)&ss, bflags, &fp); + + /* + * Translate errno values into ones used by Linux. + */ + if (error != 0) { + /* + * XXX. This is wrong, different sockaddr structures + * have different sizes. + */ + switch (error) { + case EFAULT: + if (namelen != sizeof(struct sockaddr_in)) + error = EINVAL; + break; + case EINVAL: + error1 = getsock(td, s, &cap_accept_rights, &fp1); + if (error1 != 0) { + error = error1; + break; + } + so = fp1->f_data; + if (so->so_type == SOCK_DGRAM) + error = EOPNOTSUPP; + fdrop(fp1, td); + break; + } + return (error); + } + + if (PTRIN(addr) != NULL) { + len = min(ss.ss_len, len); + error = linux_copyout_sockaddr((struct sockaddr *)&ss, + PTRIN(addr), len); + if (error == 0) { + len = ss.ss_len; + error = copyout(&len, LINUX_USER_CAP(namelen, sizeof(len)), sizeof(len)); + } + if (error != 0) { + fdclose(td, fp, td->td_retval[0]); + td->td_retval[0] = 0; + } + } + if (fp != NULL) + fdrop(fp, td); + return (error); +} + +int +linux_accept(struct thread *td, struct linux_accept_args *args) +{ + + return (linux_accept_common(td, args->s, args->addr, + args->namelen, 0)); +} + +int +linux_accept4(struct thread *td, struct linux_accept4_args *args) +{ + + return (linux_accept_common(td, args->s, args->addr, + args->namelen, args->flags)); +} + +int +linux_getsockname(struct thread *td, struct linux_getsockname_args *args) +{ + struct sockaddr_storage ss = { .ss_len = sizeof(ss) }; + socklen_t len; + int error; + + error = copyin(LINUX_USER_CAP(args->namelen, sizeof(len)), &len, sizeof(len)); + if (error != 0) + return (error); + + error = kern_getsockname(td, args->s, (struct sockaddr *)&ss); + if (error != 0) + return (error); + + len = min(ss.ss_len, len); + error = linux_copyout_sockaddr((struct sockaddr *)&ss, + PTRIN(args->addr), len); + if (error == 0) { + len = ss.ss_len; + error = copyout(&len, LINUX_USER_CAP(args->namelen, sizeof(len)), sizeof(len)); + } + return (error); +} + +int +linux_getpeername(struct thread *td, struct linux_getpeername_args *args) +{ + struct sockaddr_storage ss = { .ss_len = sizeof(ss) }; + socklen_t len; + int error; + + error = copyin(LINUX_USER_CAP(args->namelen, sizeof(len)), &len, sizeof(len)); + if (error != 0) + return (error); + + error = kern_getpeername(td, args->s, (struct sockaddr *)&ss); + if (error != 0) + return (error); + + len = min(ss.ss_len, len); + error = linux_copyout_sockaddr((struct sockaddr *)&ss, + PTRIN(args->addr), len); + if (error == 0) { + len = ss.ss_len; + error = copyout(&len, LINUX_USER_CAP(args->namelen, sizeof(len)), sizeof(len)); + } + return (error); +} + +int +linux_socketpair(struct thread *td, struct linux_socketpair_args *args) +{ + int domain, error, sv[2], type; + + domain = linux_to_bsd_domain(args->domain); + if (domain != PF_LOCAL) + return (EAFNOSUPPORT); + type = args->type & LINUX_SOCK_TYPE_MASK; + if (type < 0 || type > LINUX_SOCK_MAX) + return (EINVAL); + error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, + &type); + if (error != 0) + return (error); + if (args->protocol != 0 && args->protocol != PF_UNIX) { + /* + * Use of PF_UNIX as protocol argument is not right, + * but Linux does it. + * Do not map PF_UNIX as its Linux value is identical + * to FreeBSD one. + */ + return (EPROTONOSUPPORT); + } + error = kern_socketpair(td, domain, type, 0, sv); + if (error != 0) + return (error); + error = copyout(sv, LINUX_USER_CAP(args->rsv, 2 * sizeof(int)), 2 * sizeof(int)); + if (error != 0) { + (void)kern_close(td, sv[0]); + (void)kern_close(td, sv[1]); + } + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +struct linux_send_args { + register_t s; + register_t msg; + register_t len; + register_t flags; +}; + +static int +linux_send(struct thread *td, struct linux_send_args *args) +{ + struct sendto_args /* { + int s; + caddr_t buf; + int len; + int flags; + caddr_t to; + int tolen; + } */ bsd_args; + struct file *fp; + int error; + + bsd_args.s = args->s; + bsd_args.buf = (caddr_t)PTRIN(args->msg); + bsd_args.len = args->len; + bsd_args.flags = linux_to_bsd_msg_flags(args->flags); + bsd_args.to = NULL; + bsd_args.tolen = 0; + error = sys_sendto(td, &bsd_args); + if (error == ENOTCONN) { + /* + * Linux doesn't return ENOTCONN for non-blocking sockets. + * Instead it returns the EAGAIN. + */ + error = getsock(td, args->s, &cap_send_rights, &fp); + if (error == 0) { + if (atomic_load_int(&fp->f_flag) & FNONBLOCK) + error = EAGAIN; + fdrop(fp, td); + } + } + return (error); +} + +struct linux_recv_args { + register_t s; + register_t msg; + register_t len; + register_t flags; +}; + +static int +linux_recv(struct thread *td, struct linux_recv_args *args) +{ + struct recvfrom_args /* { + int s; + caddr_t buf; + int len; + int flags; + struct sockaddr *from; + socklen_t fromlenaddr; + } */ bsd_args; + + bsd_args.s = args->s; + bsd_args.buf = (caddr_t)PTRIN(args->msg); + bsd_args.len = args->len; + bsd_args.flags = linux_to_bsd_msg_flags(args->flags); + bsd_args.from = NULL; + bsd_args.fromlenaddr = 0; + return (sys_recvfrom(td, &bsd_args)); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_sendto(struct thread *td, struct linux_sendto_args *args) +{ + struct msghdr msg; + struct iovec aiov; + struct socket *so; + struct file *fp; + int error; + + if (linux_check_hdrincl(td, args->s) == 0) + /* IP_HDRINCL set, tweak the packet before sending */ + return (linux_sendto_hdrincl(td, args)); + + bzero(&msg, sizeof(msg)); + error = getsock(td, args->s, &cap_send_connect_rights, &fp); + if (error != 0) + return (error); + so = fp->f_data; + if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0) { + msg.msg_name = LINUX_USER_CAP(args->to, args->tolen); + msg.msg_namelen = args->tolen; + } + msg.msg_iov = &aiov; + msg.msg_iovlen = 1; + IOVEC_INIT_C(&aiov, LINUX_USER_CAP(args->msg, args->len), args->len); + fdrop(fp, td); + return (linux_sendit(td, args->s, &msg, args->flags, NULL, + UIO_USERSPACE)); +} + +int +linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) +{ + struct sockaddr * __capability sa; + struct msghdr msg; + struct iovec aiov; + int error, fromlen; + + if (PTRIN(args->fromlen) != NULL) { + error = copyin(LINUX_USER_CAP(args->fromlen, sizeof(fromlen)), &fromlen, + sizeof(fromlen)); + if (error != 0) + return (error); + if (fromlen < 0) + return (EINVAL); + fromlen = min(fromlen, SOCK_MAXADDRLEN); + sa = malloc_c(fromlen, M_SONAME, M_WAITOK); + } else { + fromlen = 0; + sa = NULL; + } + + msg.msg_name = sa; + msg.msg_namelen = fromlen; + msg.msg_iov = &aiov; + msg.msg_iovlen = 1; + IOVEC_INIT_C(&aiov, LINUX_USER_CAP(args->buf, args->len), args->len); + msg.msg_control = 0; + msg.msg_flags = linux_to_bsd_msg_flags(args->flags); + + error = kern_recvit(td, args->s, &msg, UIO_SYSSPACE, NULL); + if (error != 0) + goto out; + + /* + * XXX. Seems that FreeBSD is different from Linux here. Linux + * fill source address if underlying protocol provides it, while + * FreeBSD fill it if underlying protocol is not connection-oriented. + * So, kern_recvit() set msg.msg_namelen to 0 if protocol pr_flags + * does not contains PR_ADDR flag. + */ + if (PTRIN(args->from) != NULL && msg.msg_namelen != 0) + error = linux_copyout_sockaddr((__cheri_fromcap const struct sockaddr *)sa, PTRIN(args->from), + msg.msg_namelen); + + if (error == 0 && PTRIN(args->fromlen) != NULL) + error = copyout(&msg.msg_namelen, LINUX_USER_CAP(args->fromlen, sizeof(msg.msg_namelen)), + sizeof(msg.msg_namelen)); +out: + free_c(sa, M_SONAME); + return (error); +} + +static int +linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr * __capability msghdr, + l_uint flags) +{ + struct sockaddr_storage ss = { .ss_len = sizeof(ss) }; + struct cmsghdr *cmsg; + struct mbuf *control; + struct msghdr msg; + struct l_cmsghdr linux_cmsg; + struct l_cmsghdr * __capability ptr_cmsg; + struct l_msghdr linux_msghdr; + struct iovec *iov; + socklen_t datalen; + struct socket *so; + sa_family_t sa_family; + struct file *fp; + void *data; + l_size_t len; + l_size_t clen; + int error; + + error = copyin(msghdr, &linux_msghdr, sizeof(linux_msghdr)); + if (error != 0) + return (error); + + /* + * Some Linux applications (ping) define a non-NULL control data + * pointer, but a msg_controllen of 0, which is not allowed in the + * FreeBSD system call interface. NULL the msg_control pointer in + * order to handle this case. This should be checked, but allows the + * Linux ping to work. + */ + if (PTRIN(linux_msghdr.msg_control) != NULL && + linux_msghdr.msg_controllen == 0) + linux_msghdr.msg_control = PTROUT(NULL); + + error = linux_to_bsd_msghdr(&msg, &linux_msghdr); + if (error != 0) + return (error); + +#if defined(COMPAT_LINUX32) + error = freebsd32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, + &iov, EMSGSIZE); +#elif defined(COMPAT_LINUX64) + error = linux64_copyiniov((void * __capability)msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); +#else + error = copyiniov((void * __capability)msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); +#endif + if (error != 0) + return (error); + + control = NULL; + + error = kern_getsockname(td, s, (struct sockaddr *)&ss); + if (error != 0) + goto bad; + sa_family = ss.ss_family; + + if (flags & LINUX_MSG_OOB) { + error = EOPNOTSUPP; + if (sa_family == AF_UNIX) + goto bad; + + error = getsock(td, s, &cap_send_rights, &fp); + if (error != 0) + goto bad; + so = fp->f_data; + if (so->so_type != SOCK_STREAM) + error = EOPNOTSUPP; + fdrop(fp, td); + if (error != 0) + goto bad; + } + + if (linux_msghdr.msg_controllen >= sizeof(struct l_cmsghdr)) { + error = ENOBUFS; + control = m_get(M_WAITOK, MT_CONTROL); + MCLGET(control, M_WAITOK); + data = mtod(control, void *); + datalen = 0; + + ptr_cmsg = LINUX_USER_CAP(linux_msghdr.msg_control, linux_msghdr.msg_controllen); + clen = linux_msghdr.msg_controllen; + do { + error = copyin(ptr_cmsg, &linux_cmsg, + sizeof(struct l_cmsghdr)); + if (error != 0) + goto bad; + + error = EINVAL; + if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || + linux_cmsg.cmsg_len > clen) + goto bad; + + if (datalen + CMSG_HDRSZ > MCLBYTES) + goto bad; + + /* + * Now we support only SCM_RIGHTS and SCM_CRED, + * so return EINVAL in any other cmsg_type + */ + cmsg = data; + cmsg->cmsg_type = + linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); + cmsg->cmsg_level = + linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); + if (cmsg->cmsg_type == -1 + || cmsg->cmsg_level != SOL_SOCKET) { + linux_msg(curthread, + "unsupported sendmsg cmsg level %d type %d", + linux_cmsg.cmsg_level, linux_cmsg.cmsg_type); + goto bad; + } + + /* + * Some applications (e.g. pulseaudio) attempt to + * send ancillary data even if the underlying protocol + * doesn't support it which is not allowed in the + * FreeBSD system call interface. + */ + if (sa_family != AF_UNIX) + goto next; + + if (cmsg->cmsg_type == SCM_CREDS) { + len = sizeof(struct cmsgcred); + if (datalen + CMSG_SPACE(len) > MCLBYTES) + goto bad; + + /* + * The lower levels will fill in the structure + */ + memset(CMSG_DATA(data), 0, len); + } else { + len = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; + if (datalen + CMSG_SPACE(len) < datalen || + datalen + CMSG_SPACE(len) > MCLBYTES) + goto bad; + + error = copyin(LINUX_CMSG_DATA(ptr_cmsg), + CMSG_DATA(data), len); + if (error != 0) + goto bad; + } + + cmsg->cmsg_len = CMSG_LEN(len); + data = (char *)data + CMSG_SPACE(len); + datalen += CMSG_SPACE(len); + +next: + if (clen <= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)) + break; + + clen -= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len); + ptr_cmsg = (struct l_cmsghdr * __capability)((char * __capability)ptr_cmsg + + LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)); + } while(clen >= sizeof(struct l_cmsghdr)); + + control->m_len = datalen; + if (datalen == 0) { + m_freem(control); + control = NULL; + } + } + + msg.msg_iov = PTR2CAP(iov); + msg.msg_flags = 0; + error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE); + control = NULL; + +bad: + m_freem(control); + free(iov, M_IOV); + return (error); +} + +int +linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) +{ + + return (linux_sendmsg_common(td, args->s, LINUX_USER_CAP(args->msg, sizeof(struct l_msghdr)), + args->flags)); +} + +int +linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args) +{ + struct l_mmsghdr * __capability msg; + l_uint retval; + int error, datagrams; + + if (args->vlen > UIO_MAXIOV) + args->vlen = UIO_MAXIOV; + + msg = LINUX_USER_CAP_ARRAY(args->msg, args->vlen); + datagrams = 0; + while (datagrams < args->vlen) { + error = linux_sendmsg_common(td, args->s, &msg->msg_hdr, + args->flags); + if (error != 0) + break; + + retval = td->td_retval[0]; + error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); + if (error != 0) + break; + ++msg; + ++datagrams; + } + if (error == 0) + td->td_retval[0] = datagrams; + return (error); +} + +static int +recvmsg_scm_rights(struct thread *td, l_uint flags, socklen_t *datalen, + void **data, void **udata) +{ + int i, fd, fds, *fdp; + + if (flags & LINUX_MSG_CMSG_CLOEXEC) { + fds = *datalen / sizeof(int); + fdp = *data; + for (i = 0; i < fds; i++) { + fd = *fdp++; + (void)kern_fcntl(td, fd, F_SETFD, FD_CLOEXEC); + } + } + return (0); +} + + +static int +recvmsg_scm_creds(socklen_t *datalen, void **data, void **udata) +{ + struct cmsgcred *cmcred; + struct l_ucred lu; + + cmcred = *data; + lu.pid = cmcred->cmcred_pid; + lu.uid = cmcred->cmcred_uid; + lu.gid = cmcred->cmcred_gid; + memmove(*data, &lu, sizeof(lu)); + *datalen = sizeof(lu); + return (0); +} +_Static_assert(sizeof(struct cmsgcred) >= sizeof(struct l_ucred), + "scm_creds sizeof l_ucred"); + +static int +recvmsg_scm_creds2(socklen_t *datalen, void **data, void **udata) +{ + struct sockcred2 *scred; + struct l_ucred lu; + + scred = *data; + lu.pid = scred->sc_pid; + lu.uid = scred->sc_uid; + lu.gid = scred->sc_gid; + memmove(*data, &lu, sizeof(lu)); + *datalen = sizeof(lu); + return (0); +} +_Static_assert(sizeof(struct sockcred2) >= sizeof(struct l_ucred), + "scm_creds2 sizeof l_ucred"); + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +static int +recvmsg_scm_timestamp(l_int msg_type, socklen_t *datalen, void **data, + void **udata) +{ + l_sock_timeval ltv64; + l_timeval ltv; + struct timeval *tv; + socklen_t len; + void *buf; + + if (*datalen != sizeof(struct timeval)) + return (EMSGSIZE); + + tv = *data; +#if defined(COMPAT_LINUX32) + if (msg_type == LINUX_SCM_TIMESTAMPO && + (tv->tv_sec > INT_MAX || tv->tv_sec < INT_MIN)) + return (EOVERFLOW); +#endif + if (msg_type == LINUX_SCM_TIMESTAMPN) + len = sizeof(ltv64); + else + len = sizeof(ltv); + + buf = malloc(len, M_LINUX, M_WAITOK); + if (msg_type == LINUX_SCM_TIMESTAMPN) { + ltv64.tv_sec = tv->tv_sec; + ltv64.tv_usec = tv->tv_usec; + memmove(buf, <v64, len); + } else { + ltv.tv_sec = tv->tv_sec; + ltv.tv_usec = tv->tv_usec; + memmove(buf, <v, len); + } + *data = *udata = buf; + *datalen = len; + return (0); +} +#else +_Static_assert(sizeof(struct timeval) == sizeof(l_timeval), + "scm_timestamp sizeof l_timeval"); +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +static int +recvmsg_scm_timestampns(l_int msg_type, socklen_t *datalen, void **data, + void **udata) +{ + struct l_timespec64 ts64; + struct l_timespec ts32; + struct timespec ts; + socklen_t len; + void *buf; + + if (msg_type == LINUX_SCM_TIMESTAMPNSO) + len = sizeof(ts32); + else + len = sizeof(ts64); + + buf = malloc(len, M_LINUX, M_WAITOK); + bintime2timespec(*data, &ts); + if (msg_type == LINUX_SCM_TIMESTAMPNSO) { + ts32.tv_sec = ts.tv_sec; + ts32.tv_nsec = ts.tv_nsec; + memmove(buf, &ts32, len); + } else { + ts64.tv_sec = ts.tv_sec; + ts64.tv_nsec = ts.tv_nsec; + memmove(buf, &ts64, len); + } + *data = *udata = buf; + *datalen = len; + return (0); +} +#else +static int +recvmsg_scm_timestampns(l_int msg_type, socklen_t *datalen, void **data, + void **udata) +{ + struct timespec ts; + + bintime2timespec(*data, &ts); + memmove(*data, &ts, sizeof(struct timespec)); + *datalen = sizeof(struct timespec); + return (0); +} +_Static_assert(sizeof(struct bintime) >= sizeof(struct timespec), + "scm_timestampns sizeof timespec"); +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +static int +recvmsg_scm_sol_socket(struct thread *td, l_int msg_type, l_int lmsg_type, + l_uint flags, socklen_t *datalen, void **data, void **udata) +{ + int error; + + error = 0; + switch (msg_type) { + case SCM_RIGHTS: + error = recvmsg_scm_rights(td, flags, datalen, + data, udata); + break; + case SCM_CREDS: + error = recvmsg_scm_creds(datalen, data, udata); + break; + case SCM_CREDS2: + error = recvmsg_scm_creds2(datalen, data, udata); + break; + case SCM_TIMESTAMP: +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + error = recvmsg_scm_timestamp(lmsg_type, datalen, + data, udata); +#endif + break; + case SCM_BINTIME: + error = recvmsg_scm_timestampns(lmsg_type, datalen, + data, udata); + break; + } + + return (error); +} + +static int +recvmsg_scm_ip_origdstaddr(socklen_t *datalen, void **data, void **udata) +{ + struct l_sockaddr *lsa; + int error; + + error = bsd_to_linux_sockaddr(*data, &lsa, *datalen); + if (error == 0) { + *data = *udata = lsa; + *datalen = sizeof(*lsa); + } + return (error); +} + +static int +recvmsg_scm_ipproto_ip(l_int msg_type, l_int lmsg_type, socklen_t *datalen, + void **data, void **udata) +{ + int error; + + error = 0; + switch (msg_type) { + case IP_ORIGDSTADDR: + error = recvmsg_scm_ip_origdstaddr(datalen, data, + udata); + break; + } + + return (error); +} + +static int +linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr * __capability msghdr, + l_uint flags, struct msghdr *msg) +{ + struct proc *p = td->td_proc; + struct cmsghdr *cm; + struct l_cmsghdr *lcm = NULL; + socklen_t datalen, maxlen, outlen; + struct l_msghdr l_msghdr; + struct iovec *iov, * __capability uiov; + struct mbuf *m, *control = NULL; + struct mbuf **controlp; + struct sockaddr * __capability sa; + char * __capability outbuf; + void *data, *udata; + int error, skiped; + + error = copyin(msghdr, &l_msghdr, sizeof(l_msghdr)); + if (error != 0) + return (error); + + /* + * Pass user-supplied recvmsg() flags in msg_flags field, + * following sys_recvmsg() convention. + */ + l_msghdr.msg_flags = flags; + + error = linux_to_bsd_msghdr(msg, &l_msghdr); + if (error != 0) + return (error); + +#if defined(COMPAT_LINUX32) + error = freebsd32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen, + &iov, EMSGSIZE); +#elif defined(COMPAT_LINUX64) + error = linux64_copyiniov((void * __capability)msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE); +#else + error = copyiniov((void * __capability)msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE); +#endif + if (error != 0) + return (error); + + if (msg->msg_name != NULL && msg->msg_namelen > 0) { + msg->msg_namelen = min(msg->msg_namelen, SOCK_MAXADDRLEN); + sa = malloc_c(msg->msg_namelen, M_SONAME, M_WAITOK); + msg->msg_name = sa; + } else { + sa = NULL; + msg->msg_name = NULL; + } + + uiov = msg->msg_iov; + msg->msg_iov = PTR2CAP(iov); + controlp = (msg->msg_control != NULL) ? &control : NULL; + error = kern_recvit(td, s, msg, UIO_SYSSPACE, controlp); + msg->msg_iov = uiov; + if (error != 0) + goto bad; + + /* + * Note that kern_recvit() updates msg->msg_namelen. + */ + if (msg->msg_name != NULL && msg->msg_namelen > 0) { + msg->msg_name = LINUX_USER_CAP(l_msghdr.msg_name, msg->msg_namelen); + error = linux_copyout_sockaddr((__cheri_fromcap const struct sockaddr *)sa, PTRIN(l_msghdr.msg_name), + msg->msg_namelen); + if (error != 0) + goto bad; + } + + error = bsd_to_linux_msghdr(msg, &l_msghdr); + if (error != 0) + goto bad; + + skiped = outlen = 0; + maxlen = l_msghdr.msg_controllen; + if (control == NULL) + goto out; + + lcm = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO); + msg->msg_control = mtod(control, struct cmsghdr * __capability); + msg->msg_controllen = control->m_len; + outbuf = LINUX_USER_CAP(l_msghdr.msg_control, l_msghdr.msg_controllen); + for (m = control; m != NULL; m = m->m_next) { + cm = mtod(m, struct cmsghdr *); + lcm->cmsg_type = bsd_to_linux_cmsg_type(p, cm->cmsg_type, + cm->cmsg_level); + lcm->cmsg_level = bsd_to_linux_sockopt_level(cm->cmsg_level); + + if (lcm->cmsg_type == -1 || + cm->cmsg_level == -1) { + LINUX_RATELIMIT_MSG_OPT2( + "unsupported recvmsg cmsg level %d type %d", + cm->cmsg_level, cm->cmsg_type); + /* Skip unsupported messages */ + skiped++; + continue; + } + data = CMSG_DATA(cm); + datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; + udata = NULL; + error = 0; + + switch (cm->cmsg_level) { + case IPPROTO_IP: + error = recvmsg_scm_ipproto_ip(cm->cmsg_type, + lcm->cmsg_type, &datalen, &data, &udata); + break; + case SOL_SOCKET: + error = recvmsg_scm_sol_socket(td, cm->cmsg_type, + lcm->cmsg_type, flags, &datalen, &data, &udata); + break; + } + + /* The recvmsg_scm_ is responsible to free udata on error. */ + if (error != 0) + goto bad; + + if (outlen + LINUX_CMSG_LEN(datalen) > maxlen) { + if (outlen == 0) { + error = EMSGSIZE; + goto err; + } else { + l_msghdr.msg_flags |= LINUX_MSG_CTRUNC; + m_dispose_extcontrolm(control); + free(udata, M_LINUX); + goto out; + } + } + + lcm->cmsg_len = LINUX_CMSG_LEN(datalen); + error = copyout(lcm, outbuf, L_CMSG_HDRSZ); + if (error == 0) { + error = copyout(data, LINUX_CMSG_DATA(outbuf), datalen); + if (error == 0) { + outbuf += LINUX_CMSG_SPACE(datalen); + outlen += LINUX_CMSG_SPACE(datalen); + } + } +err: + free(udata, M_LINUX); + if (error != 0) + goto bad; + } + if (outlen == 0 && skiped > 0) { + error = EINVAL; + goto bad; + } + +out: + l_msghdr.msg_controllen = outlen; + error = copyout(&l_msghdr, msghdr, sizeof(l_msghdr)); + +bad: + if (control != NULL) { + if (error != 0) + m_dispose_extcontrolm(control); + m_freem(control); + } + free(iov, M_IOV); + free(lcm, M_LINUX); + free_c(sa, M_SONAME); + + return (error); +} + +int +linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) +{ + struct msghdr bsd_msg; + struct file *fp; + int error; + + error = getsock(td, args->s, &cap_recv_rights, &fp); + if (error != 0) + return (error); + fdrop(fp, td); + return (linux_recvmsg_common(td, args->s, LINUX_USER_CAP(args->msg, sizeof(struct l_msghdr)), + args->flags, &bsd_msg)); +} + +static int +linux_recvmmsg_common(struct thread *td, l_int s, struct l_mmsghdr * __capability msg, + l_uint vlen, l_uint flags, struct timespec *tts) +{ + struct msghdr bsd_msg; + struct timespec ts; + struct file *fp; + l_uint retval; + int error, datagrams; + + error = getsock(td, s, &cap_recv_rights, &fp); + if (error != 0) + return (error); + datagrams = 0; + while (datagrams < vlen) { + error = linux_recvmsg_common(td, s, &msg->msg_hdr, + flags & ~LINUX_MSG_WAITFORONE, &bsd_msg); + if (error != 0) + break; + + retval = td->td_retval[0]; + error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); + if (error != 0) + break; + ++msg; + ++datagrams; + + /* + * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet. + */ + if (flags & LINUX_MSG_WAITFORONE) + flags |= LINUX_MSG_DONTWAIT; + + /* + * See BUGS section of recvmmsg(2). + */ + if (tts) { + getnanotime(&ts); + timespecsub(&ts, tts, &ts); + if (!timespecisset(&ts) || ts.tv_sec > 0) + break; + } + /* Out of band data, return right away. */ + if (bsd_msg.msg_flags & MSG_OOB) + break; + } + if (error == 0) + td->td_retval[0] = datagrams; + fdrop(fp, td); + return (error); +} + +int +linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args) +{ + struct timespec ts, tts, *ptts; + int error; + + if (args->timeout) { + error = linux_get_timespec(&ts, args->timeout); + if (error != 0) + return (error); + getnanotime(&tts); + timespecadd(&tts, &ts, &tts); + ptts = &tts; + } + else ptts = NULL; + + return (linux_recvmmsg_common(td, args->s, LINUX_USER_CAP_OBJ(args->msg), + args->vlen, args->flags, ptts)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_recvmmsg_time64(struct thread *td, struct linux_recvmmsg_time64_args *args) +{ + struct timespec ts, tts, *ptts; + int error; + + if (args->timeout) { + error = linux_get_timespec64(&ts, args->timeout); + if (error != 0) + return (error); + getnanotime(&tts); + timespecadd(&tts, &ts, &tts); + ptts = &tts; + } + else ptts = NULL; + + return (linux_recvmmsg_common(td, args->s, PTRIN(args->msg), + args->vlen, args->flags, ptts)); +} +#endif + +int +linux_shutdown(struct thread *td, struct linux_shutdown_args *args) +{ + + return (kern_shutdown(td, args->s, args->how)); +} + +int +linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) +{ + struct proc *p = td->td_proc; + struct linux_pemuldata *pem; + l_timeval linux_tv; + struct sockaddr *sa; + struct timeval tv; + socklen_t len; + int error, level, name, val; + + level = linux_to_bsd_sockopt_level(args->level); + switch (level) { + case SOL_SOCKET: + name = linux_to_bsd_so_sockopt(args->optname); + switch (name) { + case LOCAL_CREDS_PERSISTENT: + level = SOL_LOCAL; + break; + case SO_RCVTIMEO: + /* FALLTHROUGH */ + case SO_SNDTIMEO: + error = copyin(LINUX_USER_CAP(args->optval, sizeof(linux_tv)), &linux_tv, + sizeof(linux_tv)); + if (error != 0) + return (error); + tv.tv_sec = linux_tv.tv_sec; + tv.tv_usec = linux_tv.tv_usec; + return (kern_setsockopt(td, args->s, level, + name, &tv, UIO_SYSSPACE, sizeof(tv))); + /* NOTREACHED */ + case SO_TIMESTAMP: + /* overwrite SO_BINTIME */ + val = 0; + error = kern_setsockopt(td, args->s, level, + SO_BINTIME, &val, UIO_SYSSPACE, sizeof(val)); + if (error != 0) + return (error); + pem = pem_find(p); + pem->so_timestamp = args->optname; + break; + case SO_BINTIME: + /* overwrite SO_TIMESTAMP */ + val = 0; + error = kern_setsockopt(td, args->s, level, + SO_TIMESTAMP, &val, UIO_SYSSPACE, sizeof(val)); + if (error != 0) + return (error); + pem = pem_find(p); + pem->so_timestampns = args->optname; + break; + default: + break; + } + break; + case IPPROTO_IP: + if (args->optname == LINUX_IP_RECVERR && + linux_ignore_ip_recverr) { + /* + * XXX: This is a hack to unbreak DNS resolution + * with glibc 2.30 and above. + */ + return (0); + } + name = linux_to_bsd_ip_sockopt(args->optname); + break; + case IPPROTO_IPV6: + if (args->optname == LINUX_IPV6_RECVERR && + linux_ignore_ip_recverr) { + /* + * XXX: This is a hack to unbreak DNS resolution + * with glibc 2.30 and above. + */ + return (0); + } + name = linux_to_bsd_ip6_sockopt(args->optname); + break; + case IPPROTO_TCP: + name = linux_to_bsd_tcp_sockopt(args->optname); + break; + case SOL_NETLINK: + name = args->optname; + break; + default: + name = -1; + break; + } + if (name < 0) { + if (name == -1) + linux_msg(curthread, + "unsupported setsockopt level %d optname %d", + args->level, args->optname); + return (ENOPROTOOPT); + } + + if (name == IPV6_NEXTHOP) { + len = args->optlen; + error = linux_to_bsd_sockaddr(LINUX_USER_CAP(args->optval, len), &sa, &len); + if (error != 0) + return (error); + + error = kern_setsockopt(td, args->s, level, + name, PTR2CAP(sa), UIO_SYSSPACE, len); + free(sa, M_SONAME); + } else { + error = kern_setsockopt(td, args->s, level, + name, LINUX_USER_CAP(args->optval, args->optlen), UIO_USERSPACE, args->optlen); + } + + return (error); +} + +static int +linux_sockopt_copyout(struct thread *td, void *val, socklen_t len, + struct linux_getsockopt_args *args) +{ + int error; + + error = copyout(val, LINUX_USER_CAP(args->optval, len), len); + if (error == 0) + error = copyout(&len, LINUX_USER_CAP(args->optlen, sizeof(len)), sizeof(len)); + return (error); +} + +static int +linux_getsockopt_so_peergroups(struct thread *td, + struct linux_getsockopt_args *args) +{ + struct xucred xu; + socklen_t xulen, len; + int error, i; + + xulen = sizeof(xu); + error = kern_getsockopt(td, args->s, 0, + LOCAL_PEERCRED, &xu, UIO_SYSSPACE, &xulen); + if (error != 0) + return (error); + + len = xu.cr_ngroups * sizeof(l_gid_t); + if (args->optlen < len) { + error = copyout(&len, LINUX_USER_CAP(args->optlen, sizeof(len)), sizeof(len)); + if (error == 0) + error = ERANGE; + return (error); + } + + /* + * "- 1" to skip the primary group. + */ + for (i = 0; i < xu.cr_ngroups - 1; i++) { + error = copyout(xu.cr_groups + i + 1, + LINUX_USER_CAP(args->optval + i * sizeof(l_gid_t), sizeof(l_gid_t)), + sizeof(l_gid_t)); + if (error != 0) + return (error); + } + + error = copyout(&len, LINUX_USER_CAP(args->optlen, sizeof(len)), sizeof(len)); + return (error); +} + +static int +linux_getsockopt_so_peersec(struct thread *td, + struct linux_getsockopt_args *args) +{ + socklen_t len; + int error; + + len = sizeof(SECURITY_CONTEXT_STRING); + if (args->optlen < len) { + error = copyout(&len, LINUX_USER_CAP(args->optlen, sizeof(len)), sizeof(len)); + if (error == 0) + error = ERANGE; + return (error); + } + + return (linux_sockopt_copyout(td, SECURITY_CONTEXT_STRING, + len, args)); +} + +static int +linux_getsockopt_so_linger(struct thread *td, + struct linux_getsockopt_args *args) +{ + struct linger ling; + socklen_t len; + int error; + + len = sizeof(ling); + error = kern_getsockopt(td, args->s, SOL_SOCKET, + SO_LINGER, &ling, UIO_SYSSPACE, &len); + if (error != 0) + return (error); + ling.l_onoff = ((ling.l_onoff & SO_LINGER) != 0); + return (linux_sockopt_copyout(td, &ling, len, args)); +} + +int +linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) +{ + l_timeval linux_tv; + struct timeval tv; + socklen_t tv_len, xulen, len; + struct sockaddr * __capability sa; + struct xucred xu; + struct l_ucred lxu; + int error, level, name, newval; + + level = linux_to_bsd_sockopt_level(args->level); + switch (level) { + case SOL_SOCKET: + switch (args->optname) { + case LINUX_SO_PEERGROUPS: + return (linux_getsockopt_so_peergroups(td, args)); + case LINUX_SO_PEERSEC: + return (linux_getsockopt_so_peersec(td, args)); + default: + break; + } + + name = linux_to_bsd_so_sockopt(args->optname); + switch (name) { + case LOCAL_CREDS_PERSISTENT: + level = SOL_LOCAL; + break; + case SO_RCVTIMEO: + /* FALLTHROUGH */ + case SO_SNDTIMEO: + tv_len = sizeof(tv); + error = kern_getsockopt(td, args->s, level, + name, &tv, UIO_SYSSPACE, &tv_len); + if (error != 0) + return (error); + linux_tv.tv_sec = tv.tv_sec; + linux_tv.tv_usec = tv.tv_usec; + return (linux_sockopt_copyout(td, &linux_tv, + sizeof(linux_tv), args)); + /* NOTREACHED */ + case LOCAL_PEERCRED: + if (args->optlen < sizeof(lxu)) + return (EINVAL); + /* + * LOCAL_PEERCRED is not served at the SOL_SOCKET level, + * but by the Unix socket's level 0. + */ + level = 0; + xulen = sizeof(xu); + error = kern_getsockopt(td, args->s, level, + name, &xu, UIO_SYSSPACE, &xulen); + if (error != 0) + return (error); + lxu.pid = xu.cr_pid; + lxu.uid = xu.cr_uid; + lxu.gid = xu.cr_gid; + return (linux_sockopt_copyout(td, &lxu, + sizeof(lxu), args)); + /* NOTREACHED */ + case SO_ERROR: + len = sizeof(newval); + error = kern_getsockopt(td, args->s, level, + name, &newval, UIO_SYSSPACE, &len); + if (error != 0) + return (error); + newval = -bsd_to_linux_errno(newval); + return (linux_sockopt_copyout(td, &newval, + len, args)); + /* NOTREACHED */ + case SO_DOMAIN: + len = sizeof(newval); + error = kern_getsockopt(td, args->s, level, + name, &newval, UIO_SYSSPACE, &len); + if (error != 0) + return (error); + newval = bsd_to_linux_domain((sa_family_t)newval); + if (newval == AF_UNKNOWN) + return (ENOPROTOOPT); + return (linux_sockopt_copyout(td, &newval, + len, args)); + /* NOTREACHED */ + case SO_LINGER: + return (linux_getsockopt_so_linger(td, args)); + /* NOTREACHED */ + default: + break; + } + break; + case IPPROTO_IP: + name = linux_to_bsd_ip_sockopt(args->optname); + break; + case IPPROTO_IPV6: + name = linux_to_bsd_ip6_sockopt(args->optname); + break; + case IPPROTO_TCP: + name = linux_to_bsd_tcp_sockopt(args->optname); + break; + default: + name = -1; + break; + } + if (name < 0) { + if (name == -1) + linux_msg(curthread, + "unsupported getsockopt level %d optname %d", + args->level, args->optname); + return (EINVAL); + } + + if (name == IPV6_NEXTHOP) { + error = copyin(LINUX_USER_CAP(args->optlen, sizeof(len)), &len, sizeof(len)); + if (error != 0) + return (error); + sa = malloc_c(len, M_SONAME, M_WAITOK); + + error = kern_getsockopt(td, args->s, level, + name, sa, UIO_SYSSPACE, &len); + if (error != 0) + goto out; + + error = linux_copyout_sockaddr((__cheri_fromcap const struct sockaddr *)sa, PTRIN(args->optval), len); + if (error == 0) + error = copyout(&len, LINUX_USER_CAP(args->optlen, sizeof(len)), + sizeof(len)); +out: + free_c(sa, M_SONAME); + } else { + if (args->optval) { + error = copyin(LINUX_USER_CAP(args->optlen, sizeof(len)), &len, sizeof(len)); + if (error != 0) + return (error); + } + error = kern_getsockopt(td, args->s, level, + name, LINUX_USER_CAP(args->optval, len), UIO_USERSPACE, &len); + if (error == 0) + error = copyout(&len, LINUX_USER_CAP(args->optlen, sizeof(len)), + sizeof(len)); + } + + return (error); +} + +/* + * Based on sendfile_getsock from kern_sendfile.c + * Determines whether an fd is a stream socket that can be used + * with FreeBSD sendfile. + */ +static bool +is_sendfile(struct file *fp, struct file *ofp) +{ + struct socket *so; + + /* + * FreeBSD sendfile() system call sends a regular file or + * shared memory object out a stream socket. + */ + if ((fp->f_type != DTYPE_SHM && fp->f_type != DTYPE_VNODE) || + (fp->f_type == DTYPE_VNODE && + (fp->f_vnode == NULL || fp->f_vnode->v_type != VREG))) + return (false); + /* + * The socket must be a stream socket and connected. + */ + if (ofp->f_type != DTYPE_SOCKET) + return (false); + so = ofp->f_data; + if (so->so_type != SOCK_STREAM) + return (false); + /* + * SCTP one-to-one style sockets currently don't work with + * sendfile(). + */ + if (so->so_proto->pr_protocol == IPPROTO_SCTP) + return (false); + return (!SOLISTENING(so)); +} + +static bool +is_regular_file(struct file *fp) +{ + + return (fp->f_type == DTYPE_VNODE && fp->f_vnode != NULL && + fp->f_vnode->v_type == VREG); +} + +static int +sendfile_fallback(struct thread *td, struct file *fp, l_int out, + off_t *offset, l_size_t count, off_t *sbytes) +{ + off_t current_offset, out_offset, to_send; + l_size_t bytes_sent, n_read; + struct file *ofp; + struct iovec aiov; + struct uio auio; + bool seekable; + size_t bufsz; + void * __capability buf; + int flags, error; + + if (offset == NULL) { + if ((error = fo_seek(fp, 0, SEEK_CUR, td)) != 0) + return (error); + current_offset = td->td_uretoff.tdu_off; + } else { + if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) + return (ESPIPE); + current_offset = *offset; + } + error = fget_write(td, out, &cap_pwrite_rights, &ofp); + if (error != 0) + return (error); + seekable = (ofp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0; + if (seekable) { + if ((error = fo_seek(ofp, 0, SEEK_CUR, td)) != 0) + goto drop; + out_offset = td->td_uretoff.tdu_off; + } else + out_offset = 0; + + flags = FOF_OFFSET | FOF_NOUPDATE; + bufsz = min(count, maxphys); + buf = malloc_c(bufsz, M_LINUX, M_WAITOK); + bytes_sent = 0; + while (bytes_sent < count) { + to_send = min(count - bytes_sent, bufsz); + aiov.iov_base = buf; + aiov.iov_len = bufsz; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_td = td; + auio.uio_rw = UIO_READ; + auio.uio_offset = current_offset; + auio.uio_resid = to_send; + error = fo_read(fp, &auio, fp->f_cred, flags, td); + if (error != 0) + break; + n_read = to_send - auio.uio_resid; + if (n_read == 0) + break; + aiov.iov_base = buf; + aiov.iov_len = bufsz; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_td = td; + auio.uio_rw = UIO_WRITE; + auio.uio_offset = (seekable) ? out_offset : 0; + auio.uio_resid = n_read; + error = fo_write(ofp, &auio, ofp->f_cred, flags, td); + if (error != 0) + break; + bytes_sent += n_read; + current_offset += n_read; + out_offset += n_read; + } + free_c(buf, M_LINUX); + + if (error == 0) { + *sbytes = bytes_sent; + if (offset != NULL) + *offset = current_offset; + else + error = fo_seek(fp, current_offset, SEEK_SET, td); + } + if (error == 0 && seekable) + error = fo_seek(ofp, out_offset, SEEK_SET, td); + +drop: + fdrop(ofp, td); + return (error); +} + +static int +sendfile_sendfile(struct thread *td, struct file *fp, l_int out, + off_t *offset, l_size_t count, off_t *sbytes) +{ + off_t current_offset; + int error; + + if (offset == NULL) { + if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) + return (ESPIPE); + if ((error = fo_seek(fp, 0, SEEK_CUR, td)) != 0) + return (error); + current_offset = td->td_uretoff.tdu_off; + } else + current_offset = *offset; + error = fo_sendfile(fp, out, NULL, NULL, current_offset, count, + sbytes, 0, td); + if (error == 0) { + current_offset += *sbytes; + if (offset != NULL) + *offset = current_offset; + else + error = fo_seek(fp, current_offset, SEEK_SET, td); + } + return (error); +} + +static int +linux_sendfile_common(struct thread *td, l_int out, l_int in, + off_t *offset, l_size_t count) +{ + struct file *fp, *ofp; + off_t sbytes; + int error; + + /* Linux cannot have 0 count. */ + if (count <= 0 || (offset != NULL && *offset < 0)) + return (EINVAL); + + AUDIT_ARG_FD(in); + error = fget_read(td, in, &cap_pread_rights, &fp); + if (error != 0) + return (error); + if ((fp->f_type != DTYPE_SHM && fp->f_type != DTYPE_VNODE) || + (fp->f_type == DTYPE_VNODE && + (fp->f_vnode == NULL || fp->f_vnode->v_type != VREG))) { + error = EINVAL; + goto drop; + } + error = fget_unlocked(td, out, &cap_no_rights, &ofp); + if (error != 0) + goto drop; + + if (is_regular_file(fp) && is_regular_file(ofp)) { + error = kern_copy_file_range(td, in, offset, out, NULL, count, + 0); + } else { + sbytes = 0; + if (is_sendfile(fp, ofp)) + error = sendfile_sendfile(td, fp, out, offset, count, + &sbytes); + else + error = sendfile_fallback(td, fp, out, offset, count, + &sbytes); + if (error == ENOBUFS && (ofp->f_flag & FNONBLOCK) != 0) + error = EAGAIN; + if (error == 0) + td->td_retval[0] = sbytes; + } + fdrop(ofp, td); + +drop: + fdrop(fp, td); + return (error); +} + +int +linux_sendfile(struct thread *td, struct linux_sendfile_args *arg) +{ + /* + * Differences between FreeBSD and Linux sendfile: + * - Linux doesn't send anything when count is 0 (FreeBSD uses 0 to + * mean send the whole file). + * - Linux can send to any fd whereas FreeBSD only supports sockets. + * We therefore use FreeBSD sendfile where possible for performance, + * but fall back on a manual copy (sendfile_fallback). + * - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr. + * - Linux takes an offset pointer and updates it to the read location. + * FreeBSD takes in an offset and a 'bytes read' parameter which is + * only filled if it isn't NULL. We use this parameter to update the + * offset pointer if it exists. + * - Linux sendfile returns bytes read on success while FreeBSD + * returns 0. We use the 'bytes read' parameter to get this value. + */ + + off_t offset64; + l_off_t offset; + int error; + + if (arg->offset != NULL) { + error = copyin(LINUX_USER_CAP_OBJ(arg->offset), &offset, sizeof(offset)); + if (error != 0) + return (error); + offset64 = offset; + } + + error = linux_sendfile_common(td, arg->out, arg->in, + arg->offset != NULL ? &offset64 : NULL, arg->count); + + if (error == 0 && arg->offset != NULL) { +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + if (offset64 > INT32_MAX) + return (EOVERFLOW); +#endif + offset = (l_off_t)offset64; + error = copyout(&offset, LINUX_USER_CAP_OBJ(arg->offset), sizeof(offset)); + } + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_sendfile64(struct thread *td, struct linux_sendfile64_args *arg) +{ + off_t offset; + int error; + + if (arg->offset != NULL) { + error = copyin(arg->offset, &offset, sizeof(offset)); + if (error != 0) + return (error); + } + + error = linux_sendfile_common(td, arg->out, arg->in, + arg->offset != NULL ? &offset : NULL, arg->count); + + if (error == 0 && arg->offset != NULL) + error = copyout(&offset, arg->offset, sizeof(offset)); + + return (error); +} + +/* Argument list sizes for linux_socketcall */ +static const unsigned char lxs_args_cnt[] = { + 0 /* unused*/, 3 /* socket */, + 3 /* bind */, 3 /* connect */, + 2 /* listen */, 3 /* accept */, + 3 /* getsockname */, 3 /* getpeername */, + 4 /* socketpair */, 4 /* send */, + 4 /* recv */, 6 /* sendto */, + 6 /* recvfrom */, 2 /* shutdown */, + 5 /* setsockopt */, 5 /* getsockopt */, + 3 /* sendmsg */, 3 /* recvmsg */, + 4 /* accept4 */, 5 /* recvmmsg */, + 4 /* sendmmsg */, 4 /* sendfile */ +}; +#define LINUX_ARGS_CNT (nitems(lxs_args_cnt) - 1) +#define LINUX_ARG_SIZE(x) (lxs_args_cnt[x] * sizeof(l_ulong)) + +int +linux_socketcall(struct thread *td, struct linux_socketcall_args *args) +{ + l_ulong a[6]; +#if defined(__amd64__) && defined(COMPAT_LINUX32) + register_t l_args[6]; +#endif + void *arg; + int error; + + if (args->what < LINUX_SOCKET || args->what > LINUX_ARGS_CNT) + return (EINVAL); + error = copyin(LINUX_USER_CAP(args->args, LINUX_ARG_SIZE(args->what)), a, LINUX_ARG_SIZE(args->what)); + if (error != 0) + return (error); + +#if defined(__amd64__) && defined(COMPAT_LINUX32) + for (int i = 0; i < lxs_args_cnt[args->what]; ++i) + l_args[i] = a[i]; + arg = l_args; +#else + arg = a; +#endif + switch (args->what) { + case LINUX_SOCKET: + return (linux_socket(td, arg)); + case LINUX_BIND: + return (linux_bind(td, arg)); + case LINUX_CONNECT: + return (linux_connect(td, arg)); + case LINUX_LISTEN: + return (linux_listen(td, arg)); + case LINUX_ACCEPT: + return (linux_accept(td, arg)); + case LINUX_GETSOCKNAME: + return (linux_getsockname(td, arg)); + case LINUX_GETPEERNAME: + return (linux_getpeername(td, arg)); + case LINUX_SOCKETPAIR: + return (linux_socketpair(td, arg)); + case LINUX_SEND: + return (linux_send(td, arg)); + case LINUX_RECV: + return (linux_recv(td, arg)); + case LINUX_SENDTO: + return (linux_sendto(td, arg)); + case LINUX_RECVFROM: + return (linux_recvfrom(td, arg)); + case LINUX_SHUTDOWN: + return (linux_shutdown(td, arg)); + case LINUX_SETSOCKOPT: + return (linux_setsockopt(td, arg)); + case LINUX_GETSOCKOPT: + return (linux_getsockopt(td, arg)); + case LINUX_SENDMSG: + return (linux_sendmsg(td, arg)); + case LINUX_RECVMSG: + return (linux_recvmsg(td, arg)); + case LINUX_ACCEPT4: + return (linux_accept4(td, arg)); + case LINUX_RECVMMSG: + return (linux_recvmmsg(td, arg)); + case LINUX_SENDMMSG: + return (linux_sendmmsg(td, arg)); + case LINUX_SENDFILE: + return (linux_sendfile(td, arg)); + } + + linux_msg(td, "socket type %d not implemented", args->what); + return (ENOSYS); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "kernel", +// "changes": [ +// "iovec-macros" +// ] +// } +// CHERI CHANGES END diff --git a/sys/compat/linux/linux_socket.h b/sys/compat/linux/linux_socket.h index 68176c3cc401..4f70328e2486 100644 --- a/sys/compat/linux/linux_socket.h +++ b/sys/compat/linux/linux_socket.h @@ -1,364 +1,364 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2000 Assar Westerlund - * 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 - * in this position and unchanged. - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - */ - -#ifndef _LINUX_SOCKET_H_ -#define _LINUX_SOCKET_H_ - -/* msg flags in recvfrom/recvmsg */ - -#define LINUX_MSG_OOB 0x01 -#define LINUX_MSG_PEEK 0x02 -#define LINUX_MSG_DONTROUTE 0x04 -#define LINUX_MSG_CTRUNC 0x08 -#define LINUX_MSG_PROXY 0x10 -#define LINUX_MSG_TRUNC 0x20 -#define LINUX_MSG_DONTWAIT 0x40 -#define LINUX_MSG_EOR 0x80 -#define LINUX_MSG_WAITALL 0x100 -#define LINUX_MSG_FIN 0x200 -#define LINUX_MSG_SYN 0x400 -#define LINUX_MSG_CONFIRM 0x800 -#define LINUX_MSG_RST 0x1000 -#define LINUX_MSG_ERRQUEUE 0x2000 -#define LINUX_MSG_NOSIGNAL 0x4000 -#define LINUX_MSG_WAITFORONE 0x10000 -#define LINUX_MSG_CMSG_CLOEXEC 0x40000000 - -struct l_msghdr { - l_uintptr_t msg_name; - l_int msg_namelen; - l_uintptr_t msg_iov; - l_size_t msg_iovlen; - l_uintptr_t msg_control; - l_size_t msg_controllen; - l_uint msg_flags; -}; - -struct l_mmsghdr { - struct l_msghdr msg_hdr; - l_uint msg_len; - -}; - -struct l_cmsghdr { - l_size_t cmsg_len; - l_int cmsg_level; - l_int cmsg_type; -}; - -/* Ancillary data object information macros */ - -#define LINUX_CMSG_ALIGN(len) roundup2(len, sizeof(l_ulong)) -#define LINUX_CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + \ - LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)))) -#define LINUX_CMSG_SPACE(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ - LINUX_CMSG_ALIGN(len)) -#define LINUX_CMSG_LEN(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ - (len)) -#define LINUX_CMSG_FIRSTHDR(msg) \ - ((msg)->msg_controllen >= \ - sizeof(struct l_cmsghdr) ? \ - (struct l_cmsghdr *) \ - PTRIN((msg)->msg_control) : \ - (struct l_cmsghdr *)(NULL)) -#define LINUX_CMSG_NXTHDR(msg, cmsg) \ - ((((char *)(cmsg) + \ - LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \ - sizeof(*(cmsg))) > \ - (((char *)PTRIN((msg)->msg_control)) + \ - (msg)->msg_controllen)) ? \ - (struct l_cmsghdr *) NULL : \ - (struct l_cmsghdr *)((char *)(cmsg) + \ - LINUX_CMSG_ALIGN((cmsg)->cmsg_len))) - -#define CMSG_HDRSZ CMSG_LEN(0) -#define L_CMSG_HDRSZ LINUX_CMSG_LEN(0) - -/* Supported socket types */ - -#define LINUX_SOCK_STREAM 1 -#define LINUX_SOCK_DGRAM 2 -#define LINUX_SOCK_RAW 3 -#define LINUX_SOCK_RDM 4 -#define LINUX_SOCK_SEQPACKET 5 - -#define LINUX_SOCK_MAX LINUX_SOCK_SEQPACKET - -#define LINUX_SOCK_TYPE_MASK 0xf - -/* Flags for socket, socketpair, accept4 */ - -#define LINUX_SOCK_CLOEXEC LINUX_O_CLOEXEC -#define LINUX_SOCK_NONBLOCK LINUX_O_NONBLOCK - -struct l_ucred { - uint32_t pid; - uint32_t uid; - uint32_t gid; -}; - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) - -struct linux_accept_args { - register_t s; - register_t addr; - register_t namelen; -}; - -int linux_accept(struct thread *td, struct linux_accept_args *args); - -/* Operations for socketcall */ -#define LINUX_SOCKET 1 -#define LINUX_BIND 2 -#define LINUX_CONNECT 3 -#define LINUX_LISTEN 4 -#define LINUX_ACCEPT 5 -#define LINUX_GETSOCKNAME 6 -#define LINUX_GETPEERNAME 7 -#define LINUX_SOCKETPAIR 8 -#define LINUX_SEND 9 -#define LINUX_RECV 10 -#define LINUX_SENDTO 11 -#define LINUX_RECVFROM 12 -#define LINUX_SHUTDOWN 13 -#define LINUX_SETSOCKOPT 14 -#define LINUX_GETSOCKOPT 15 -#define LINUX_SENDMSG 16 -#define LINUX_RECVMSG 17 -#define LINUX_ACCEPT4 18 -#define LINUX_RECVMMSG 19 -#define LINUX_SENDMMSG 20 -#define LINUX_SENDFILE 21 - -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -/* Socket defines */ -#define LINUX_SOL_SOCKET 1 - -#define LINUX_SO_DEBUG 1 -#define LINUX_SO_REUSEADDR 2 -#define LINUX_SO_TYPE 3 -#define LINUX_SO_ERROR 4 -#define LINUX_SO_DONTROUTE 5 -#define LINUX_SO_BROADCAST 6 -#define LINUX_SO_SNDBUF 7 -#define LINUX_SO_RCVBUF 8 -#define LINUX_SO_KEEPALIVE 9 -#define LINUX_SO_OOBINLINE 10 -#define LINUX_SO_NO_CHECK 11 -#define LINUX_SO_PRIORITY 12 -#define LINUX_SO_LINGER 13 -#define LINUX_SO_REUSEPORT 15 -#ifndef LINUX_SO_PASSCRED /* powerpc differs */ -#define LINUX_SO_PASSCRED 16 -#define LINUX_SO_PEERCRED 17 -#define LINUX_SO_RCVLOWAT 18 -#define LINUX_SO_SNDLOWAT 19 -#define LINUX_SO_RCVTIMEO 20 -#define LINUX_SO_SNDTIMEO 21 -#endif -#define LINUX_SO_TIMESTAMPO 29 -#define LINUX_SO_TIMESTAMPN 63 -#define LINUX_SO_TIMESTAMPNSO 35 -#define LINUX_SO_TIMESTAMPNSN 64 -#define LINUX_SO_ACCEPTCONN 30 -#define LINUX_SO_PEERSEC 31 -#define LINUX_SO_SNDBUFFORCE 32 -#define LINUX_SO_RCVBUFFORCE 33 -#define LINUX_SO_PROTOCOL 38 -#define LINUX_SO_DOMAIN 39 -#define LINUX_SO_PEERGROUPS 59 - -/* Socket-level control message types */ - -#define LINUX_SCM_RIGHTS 0x01 -#define LINUX_SCM_CREDENTIALS 0x02 -#define LINUX_SCM_TIMESTAMPO LINUX_SO_TIMESTAMPO -#define LINUX_SCM_TIMESTAMPN LINUX_SO_TIMESTAMPN -#define LINUX_SCM_TIMESTAMPNSO LINUX_SO_TIMESTAMPNSO -#define LINUX_SCM_TIMESTAMPNSN LINUX_SO_TIMESTAMPNSN - -/* Socket options */ -#define LINUX_IP_TOS 1 -#define LINUX_IP_TTL 2 -#define LINUX_IP_HDRINCL 3 -#define LINUX_IP_OPTIONS 4 -#define LINUX_IP_ROUTER_ALERT 5 -#define LINUX_IP_RECVOPTS 6 -#define LINUX_IP_RETOPTS 7 -#define LINUX_IP_PKTINFO 8 -#define LINUX_IP_PKTOPTIONS 9 -#define LINUX_IP_MTU_DISCOVER 10 -#define LINUX_IP_RECVERR 11 -#define LINUX_IP_RECVTTL 12 -#define LINUX_IP_RECVTOS 13 -#define LINUX_IP_MTU 14 -#define LINUX_IP_FREEBIND 15 -#define LINUX_IP_IPSEC_POLICY 16 -#define LINUX_IP_XFRM_POLICY 17 -#define LINUX_IP_PASSSEC 18 -#define LINUX_IP_TRANSPARENT 19 - -#define LINUX_IP_ORIGDSTADDR 20 -#define LINUX_IP_RECVORIGDSTADDR LINUX_IP_ORIGDSTADDR -#define LINUX_IP_MINTTL 21 -#define LINUX_IP_NODEFRAG 22 -#define LINUX_IP_CHECKSUM 23 -#define LINUX_IP_BIND_ADDRESS_NO_PORT 24 -#define LINUX_IP_RECVFRAGSIZE 25 - -#define LINUX_IP_MULTICAST_IF 32 -#define LINUX_IP_MULTICAST_TTL 33 -#define LINUX_IP_MULTICAST_LOOP 34 -#define LINUX_IP_ADD_MEMBERSHIP 35 -#define LINUX_IP_DROP_MEMBERSHIP 36 -#define LINUX_IP_UNBLOCK_SOURCE 37 -#define LINUX_IP_BLOCK_SOURCE 38 -#define LINUX_IP_ADD_SOURCE_MEMBERSHIP 39 -#define LINUX_IP_DROP_SOURCE_MEMBERSHIP 40 -#define LINUX_IP_MSFILTER 41 - -#define LINUX_MCAST_JOIN_GROUP 42 -#define LINUX_MCAST_BLOCK_SOURCE 43 -#define LINUX_MCAST_UNBLOCK_SOURCE 44 -#define LINUX_MCAST_LEAVE_GROUP 45 -#define LINUX_MCAST_JOIN_SOURCE_GROUP 46 -#define LINUX_MCAST_LEAVE_SOURCE_GROUP 47 -#define LINUX_MCAST_MSFILTER 48 -#define LINUX_IP_MULTICAST_ALL 49 -#define LINUX_IP_UNICAST_IF 50 - -#define LINUX_IPV6_ADDRFORM 1 -#define LINUX_IPV6_2292PKTINFO 2 -#define LINUX_IPV6_2292HOPOPTS 3 -#define LINUX_IPV6_2292DSTOPTS 4 -#define LINUX_IPV6_2292RTHDR 5 -#define LINUX_IPV6_2292PKTOPTIONS 6 -#define LINUX_IPV6_CHECKSUM 7 -#define LINUX_IPV6_2292HOPLIMIT 8 -#define LINUX_IPV6_NEXTHOP 9 -#define LINUX_IPV6_AUTHHDR 10 -#define LINUX_IPV6_FLOWINFO 11 - -#define LINUX_IPV6_UNICAST_HOPS 16 -#define LINUX_IPV6_MULTICAST_IF 17 -#define LINUX_IPV6_MULTICAST_HOPS 18 -#define LINUX_IPV6_MULTICAST_LOOP 19 -#define LINUX_IPV6_ADD_MEMBERSHIP 20 -#define LINUX_IPV6_DROP_MEMBERSHIP 21 -#define LINUX_IPV6_ROUTER_ALERT 22 -#define LINUX_IPV6_MTU_DISCOVER 23 -#define LINUX_IPV6_MTU 24 -#define LINUX_IPV6_RECVERR 25 -#define LINUX_IPV6_V6ONLY 26 -#define LINUX_IPV6_JOIN_ANYCAST 27 -#define LINUX_IPV6_LEAVE_ANYCAST 28 -#define LINUX_IPV6_MULTICAST_ALL 29 -#define LINUX_IPV6_ROUTER_ALERT_ISOLATE 30 - -#define LINUX_IPV6_FLOWLABEL_MGR 32 -#define LINUX_IPV6_FLOWINFO_SEND 33 - -#define LINUX_IPV6_IPSEC_POLICY 34 -#define LINUX_IPV6_XFRM_POLICY 35 -#define LINUX_IPV6_HDRINCL 36 - -#define LINUX_IPV6_RECVPKTINFO 49 -#define LINUX_IPV6_PKTINFO 50 -#define LINUX_IPV6_RECVHOPLIMIT 51 -#define LINUX_IPV6_HOPLIMIT 52 -#define LINUX_IPV6_RECVHOPOPTS 53 -#define LINUX_IPV6_HOPOPTS 54 -#define LINUX_IPV6_RTHDRDSTOPTS 55 -#define LINUX_IPV6_RECVRTHDR 56 -#define LINUX_IPV6_RTHDR 57 -#define LINUX_IPV6_RECVDSTOPTS 58 -#define LINUX_IPV6_DSTOPTS 59 -#define LINUX_IPV6_RECVPATHMTU 60 -#define LINUX_IPV6_PATHMTU 61 -#define LINUX_IPV6_DONTFRAG 62 - -#define LINUX_IPV6_AUTOFLOWLABEL 70 -#define LINUX_IPV6_ADDR_PREFERENCES 72 -#define LINUX_IPV6_MINHOPCOUNT 73 -#define LINUX_IPV6_ORIGDSTADDR 74 -#define LINUX_IPV6_TRANSPARENT 75 -#define LINUX_IPV6_UNICAST_IF 76 -#define LINUX_IPV6_RECVFRAGSIZE 77 -#define LINUX_IPV6_FREEBIND 78 - -#define LINUX_TCP_NODELAY 1 -#define LINUX_TCP_MAXSEG 2 -#define LINUX_TCP_CORK 3 -#define LINUX_TCP_KEEPIDLE 4 -#define LINUX_TCP_KEEPINTVL 5 -#define LINUX_TCP_KEEPCNT 6 -#define LINUX_TCP_INFO 11 -#define LINUX_TCP_MD5SIG 14 - -struct l_ifmap { - l_ulong mem_start; - l_ulong mem_end; - l_ushort base_addr; - u_char irq; - u_char dma; - u_char port; - /* 3 bytes spare */ -}; - -/* - * Careful changing the declaration of this structure. - * To use FreeBSD names to access the struct l_ifreq members the - * member names of struct l_ifreq should be equal to the FreeBSD. - */ -struct l_ifreq { - char ifr_name[LINUX_IFNAMSIZ]; - union { - struct l_sockaddr ifru_addr; - struct l_sockaddr ifru_dstaddr; - struct l_sockaddr ifru_broadaddr; - struct l_sockaddr ifru_netmask; - struct l_sockaddr ifru_hwaddr; - l_short ifru_flags[1]; - l_int ifru_index; - l_int ifru_mtu; - struct l_ifmap ifru_map; - char ifru_slave[LINUX_IFNAMSIZ]; - char ifru_newname[LINUX_IFNAMSIZ]; - l_uintptr_t ifru_data; - } ifr_ifru; -}; - -/* - * Define here members which are not exists in the FreeBSD struct ifreq. - */ -#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ - -#endif /* _LINUX_SOCKET_H_ */ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2000 Assar Westerlund + * 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 + * in this position and unchanged. + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#ifndef _LINUX_SOCKET_H_ +#define _LINUX_SOCKET_H_ + +/* msg flags in recvfrom/recvmsg */ + +#define LINUX_MSG_OOB 0x01 +#define LINUX_MSG_PEEK 0x02 +#define LINUX_MSG_DONTROUTE 0x04 +#define LINUX_MSG_CTRUNC 0x08 +#define LINUX_MSG_PROXY 0x10 +#define LINUX_MSG_TRUNC 0x20 +#define LINUX_MSG_DONTWAIT 0x40 +#define LINUX_MSG_EOR 0x80 +#define LINUX_MSG_WAITALL 0x100 +#define LINUX_MSG_FIN 0x200 +#define LINUX_MSG_SYN 0x400 +#define LINUX_MSG_CONFIRM 0x800 +#define LINUX_MSG_RST 0x1000 +#define LINUX_MSG_ERRQUEUE 0x2000 +#define LINUX_MSG_NOSIGNAL 0x4000 +#define LINUX_MSG_WAITFORONE 0x10000 +#define LINUX_MSG_CMSG_CLOEXEC 0x40000000 + +struct l_msghdr { + l_uintptr_t msg_name; + l_int msg_namelen; + l_uintptr_t msg_iov; + l_size_t msg_iovlen; + l_uintptr_t msg_control; + l_size_t msg_controllen; + l_uint msg_flags; +}; + +struct l_mmsghdr { + struct l_msghdr msg_hdr; + l_uint msg_len; + +}; + +struct l_cmsghdr { + l_size_t cmsg_len; + l_int cmsg_level; + l_int cmsg_type; +}; + +/* Ancillary data object information macros */ + +#define LINUX_CMSG_ALIGN(len) roundup2(len, sizeof(l_ulong)) +#define LINUX_CMSG_DATA(cmsg) ((void * __capability)((char * __capability)(cmsg) + \ + LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)))) +#define LINUX_CMSG_SPACE(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ + LINUX_CMSG_ALIGN(len)) +#define LINUX_CMSG_LEN(len) (LINUX_CMSG_ALIGN(sizeof(struct l_cmsghdr)) + \ + (len)) +#define LINUX_CMSG_FIRSTHDR(msg) \ + ((msg)->msg_controllen >= \ + sizeof(struct l_cmsghdr) ? \ + (struct l_cmsghdr *) \ + PTRIN((msg)->msg_control) : \ + (struct l_cmsghdr *)(NULL)) +#define LINUX_CMSG_NXTHDR(msg, cmsg) \ + ((((char *)(cmsg) + \ + LINUX_CMSG_ALIGN((cmsg)->cmsg_len) + \ + sizeof(*(cmsg))) > \ + (((char *)PTRIN((msg)->msg_control)) + \ + (msg)->msg_controllen)) ? \ + (struct l_cmsghdr *) NULL : \ + (struct l_cmsghdr *)((char *)(cmsg) + \ + LINUX_CMSG_ALIGN((cmsg)->cmsg_len))) + +#define CMSG_HDRSZ CMSG_LEN(0) +#define L_CMSG_HDRSZ LINUX_CMSG_LEN(0) + +/* Supported socket types */ + +#define LINUX_SOCK_STREAM 1 +#define LINUX_SOCK_DGRAM 2 +#define LINUX_SOCK_RAW 3 +#define LINUX_SOCK_RDM 4 +#define LINUX_SOCK_SEQPACKET 5 + +#define LINUX_SOCK_MAX LINUX_SOCK_SEQPACKET + +#define LINUX_SOCK_TYPE_MASK 0xf + +/* Flags for socket, socketpair, accept4 */ + +#define LINUX_SOCK_CLOEXEC LINUX_O_CLOEXEC +#define LINUX_SOCK_NONBLOCK LINUX_O_NONBLOCK + +struct l_ucred { + uint32_t pid; + uint32_t uid; + uint32_t gid; +}; + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + +struct linux_accept_args { + register_t s; + register_t addr; + register_t namelen; +}; + +int linux_accept(struct thread *td, struct linux_accept_args *args); + +/* Operations for socketcall */ +#define LINUX_SOCKET 1 +#define LINUX_BIND 2 +#define LINUX_CONNECT 3 +#define LINUX_LISTEN 4 +#define LINUX_ACCEPT 5 +#define LINUX_GETSOCKNAME 6 +#define LINUX_GETPEERNAME 7 +#define LINUX_SOCKETPAIR 8 +#define LINUX_SEND 9 +#define LINUX_RECV 10 +#define LINUX_SENDTO 11 +#define LINUX_RECVFROM 12 +#define LINUX_SHUTDOWN 13 +#define LINUX_SETSOCKOPT 14 +#define LINUX_GETSOCKOPT 15 +#define LINUX_SENDMSG 16 +#define LINUX_RECVMSG 17 +#define LINUX_ACCEPT4 18 +#define LINUX_RECVMMSG 19 +#define LINUX_SENDMMSG 20 +#define LINUX_SENDFILE 21 + +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +/* Socket defines */ +#define LINUX_SOL_SOCKET 1 + +#define LINUX_SO_DEBUG 1 +#define LINUX_SO_REUSEADDR 2 +#define LINUX_SO_TYPE 3 +#define LINUX_SO_ERROR 4 +#define LINUX_SO_DONTROUTE 5 +#define LINUX_SO_BROADCAST 6 +#define LINUX_SO_SNDBUF 7 +#define LINUX_SO_RCVBUF 8 +#define LINUX_SO_KEEPALIVE 9 +#define LINUX_SO_OOBINLINE 10 +#define LINUX_SO_NO_CHECK 11 +#define LINUX_SO_PRIORITY 12 +#define LINUX_SO_LINGER 13 +#define LINUX_SO_REUSEPORT 15 +#ifndef LINUX_SO_PASSCRED /* powerpc differs */ +#define LINUX_SO_PASSCRED 16 +#define LINUX_SO_PEERCRED 17 +#define LINUX_SO_RCVLOWAT 18 +#define LINUX_SO_SNDLOWAT 19 +#define LINUX_SO_RCVTIMEO 20 +#define LINUX_SO_SNDTIMEO 21 +#endif +#define LINUX_SO_TIMESTAMPO 29 +#define LINUX_SO_TIMESTAMPN 63 +#define LINUX_SO_TIMESTAMPNSO 35 +#define LINUX_SO_TIMESTAMPNSN 64 +#define LINUX_SO_ACCEPTCONN 30 +#define LINUX_SO_PEERSEC 31 +#define LINUX_SO_SNDBUFFORCE 32 +#define LINUX_SO_RCVBUFFORCE 33 +#define LINUX_SO_PROTOCOL 38 +#define LINUX_SO_DOMAIN 39 +#define LINUX_SO_PEERGROUPS 59 + +/* Socket-level control message types */ + +#define LINUX_SCM_RIGHTS 0x01 +#define LINUX_SCM_CREDENTIALS 0x02 +#define LINUX_SCM_TIMESTAMPO LINUX_SO_TIMESTAMPO +#define LINUX_SCM_TIMESTAMPN LINUX_SO_TIMESTAMPN +#define LINUX_SCM_TIMESTAMPNSO LINUX_SO_TIMESTAMPNSO +#define LINUX_SCM_TIMESTAMPNSN LINUX_SO_TIMESTAMPNSN + +/* Socket options */ +#define LINUX_IP_TOS 1 +#define LINUX_IP_TTL 2 +#define LINUX_IP_HDRINCL 3 +#define LINUX_IP_OPTIONS 4 +#define LINUX_IP_ROUTER_ALERT 5 +#define LINUX_IP_RECVOPTS 6 +#define LINUX_IP_RETOPTS 7 +#define LINUX_IP_PKTINFO 8 +#define LINUX_IP_PKTOPTIONS 9 +#define LINUX_IP_MTU_DISCOVER 10 +#define LINUX_IP_RECVERR 11 +#define LINUX_IP_RECVTTL 12 +#define LINUX_IP_RECVTOS 13 +#define LINUX_IP_MTU 14 +#define LINUX_IP_FREEBIND 15 +#define LINUX_IP_IPSEC_POLICY 16 +#define LINUX_IP_XFRM_POLICY 17 +#define LINUX_IP_PASSSEC 18 +#define LINUX_IP_TRANSPARENT 19 + +#define LINUX_IP_ORIGDSTADDR 20 +#define LINUX_IP_RECVORIGDSTADDR LINUX_IP_ORIGDSTADDR +#define LINUX_IP_MINTTL 21 +#define LINUX_IP_NODEFRAG 22 +#define LINUX_IP_CHECKSUM 23 +#define LINUX_IP_BIND_ADDRESS_NO_PORT 24 +#define LINUX_IP_RECVFRAGSIZE 25 + +#define LINUX_IP_MULTICAST_IF 32 +#define LINUX_IP_MULTICAST_TTL 33 +#define LINUX_IP_MULTICAST_LOOP 34 +#define LINUX_IP_ADD_MEMBERSHIP 35 +#define LINUX_IP_DROP_MEMBERSHIP 36 +#define LINUX_IP_UNBLOCK_SOURCE 37 +#define LINUX_IP_BLOCK_SOURCE 38 +#define LINUX_IP_ADD_SOURCE_MEMBERSHIP 39 +#define LINUX_IP_DROP_SOURCE_MEMBERSHIP 40 +#define LINUX_IP_MSFILTER 41 + +#define LINUX_MCAST_JOIN_GROUP 42 +#define LINUX_MCAST_BLOCK_SOURCE 43 +#define LINUX_MCAST_UNBLOCK_SOURCE 44 +#define LINUX_MCAST_LEAVE_GROUP 45 +#define LINUX_MCAST_JOIN_SOURCE_GROUP 46 +#define LINUX_MCAST_LEAVE_SOURCE_GROUP 47 +#define LINUX_MCAST_MSFILTER 48 +#define LINUX_IP_MULTICAST_ALL 49 +#define LINUX_IP_UNICAST_IF 50 + +#define LINUX_IPV6_ADDRFORM 1 +#define LINUX_IPV6_2292PKTINFO 2 +#define LINUX_IPV6_2292HOPOPTS 3 +#define LINUX_IPV6_2292DSTOPTS 4 +#define LINUX_IPV6_2292RTHDR 5 +#define LINUX_IPV6_2292PKTOPTIONS 6 +#define LINUX_IPV6_CHECKSUM 7 +#define LINUX_IPV6_2292HOPLIMIT 8 +#define LINUX_IPV6_NEXTHOP 9 +#define LINUX_IPV6_AUTHHDR 10 +#define LINUX_IPV6_FLOWINFO 11 + +#define LINUX_IPV6_UNICAST_HOPS 16 +#define LINUX_IPV6_MULTICAST_IF 17 +#define LINUX_IPV6_MULTICAST_HOPS 18 +#define LINUX_IPV6_MULTICAST_LOOP 19 +#define LINUX_IPV6_ADD_MEMBERSHIP 20 +#define LINUX_IPV6_DROP_MEMBERSHIP 21 +#define LINUX_IPV6_ROUTER_ALERT 22 +#define LINUX_IPV6_MTU_DISCOVER 23 +#define LINUX_IPV6_MTU 24 +#define LINUX_IPV6_RECVERR 25 +#define LINUX_IPV6_V6ONLY 26 +#define LINUX_IPV6_JOIN_ANYCAST 27 +#define LINUX_IPV6_LEAVE_ANYCAST 28 +#define LINUX_IPV6_MULTICAST_ALL 29 +#define LINUX_IPV6_ROUTER_ALERT_ISOLATE 30 + +#define LINUX_IPV6_FLOWLABEL_MGR 32 +#define LINUX_IPV6_FLOWINFO_SEND 33 + +#define LINUX_IPV6_IPSEC_POLICY 34 +#define LINUX_IPV6_XFRM_POLICY 35 +#define LINUX_IPV6_HDRINCL 36 + +#define LINUX_IPV6_RECVPKTINFO 49 +#define LINUX_IPV6_PKTINFO 50 +#define LINUX_IPV6_RECVHOPLIMIT 51 +#define LINUX_IPV6_HOPLIMIT 52 +#define LINUX_IPV6_RECVHOPOPTS 53 +#define LINUX_IPV6_HOPOPTS 54 +#define LINUX_IPV6_RTHDRDSTOPTS 55 +#define LINUX_IPV6_RECVRTHDR 56 +#define LINUX_IPV6_RTHDR 57 +#define LINUX_IPV6_RECVDSTOPTS 58 +#define LINUX_IPV6_DSTOPTS 59 +#define LINUX_IPV6_RECVPATHMTU 60 +#define LINUX_IPV6_PATHMTU 61 +#define LINUX_IPV6_DONTFRAG 62 + +#define LINUX_IPV6_AUTOFLOWLABEL 70 +#define LINUX_IPV6_ADDR_PREFERENCES 72 +#define LINUX_IPV6_MINHOPCOUNT 73 +#define LINUX_IPV6_ORIGDSTADDR 74 +#define LINUX_IPV6_TRANSPARENT 75 +#define LINUX_IPV6_UNICAST_IF 76 +#define LINUX_IPV6_RECVFRAGSIZE 77 +#define LINUX_IPV6_FREEBIND 78 + +#define LINUX_TCP_NODELAY 1 +#define LINUX_TCP_MAXSEG 2 +#define LINUX_TCP_CORK 3 +#define LINUX_TCP_KEEPIDLE 4 +#define LINUX_TCP_KEEPINTVL 5 +#define LINUX_TCP_KEEPCNT 6 +#define LINUX_TCP_INFO 11 +#define LINUX_TCP_MD5SIG 14 + +struct l_ifmap { + l_ulong mem_start; + l_ulong mem_end; + l_ushort base_addr; + u_char irq; + u_char dma; + u_char port; + /* 3 bytes spare */ +}; + +/* + * Careful changing the declaration of this structure. + * To use FreeBSD names to access the struct l_ifreq members the + * member names of struct l_ifreq should be equal to the FreeBSD. + */ +struct l_ifreq { + char ifr_name[LINUX_IFNAMSIZ]; + union { + struct l_sockaddr ifru_addr; + struct l_sockaddr ifru_dstaddr; + struct l_sockaddr ifru_broadaddr; + struct l_sockaddr ifru_netmask; + struct l_sockaddr ifru_hwaddr; + l_short ifru_flags[1]; + l_int ifru_index; + l_int ifru_mtu; + struct l_ifmap ifru_map; + char ifru_slave[LINUX_IFNAMSIZ]; + char ifru_newname[LINUX_IFNAMSIZ]; + l_uintptr_t ifru_data; + } ifr_ifru; +}; + +/* + * Define here members which are not exists in the FreeBSD struct ifreq. + */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ + +#endif /* _LINUX_SOCKET_H_ */ diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c index 0f33252902e8..9dbec22222ab 100644 --- a/sys/compat/linux/linux_stats.c +++ b/sys/compat/linux/linux_stats.c @@ -1,730 +1,733 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * 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 "opt_ktrace.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef KTRACE -#include -#endif - -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif - -#include -#include -#include - - -static int -linux_kern_fstat(struct thread *td, int fd, struct stat *sbp) -{ - struct vnode *vp; - struct file *fp; - int error; - - AUDIT_ARG_FD(fd); - - error = fget(td, fd, &cap_fstat_rights, &fp); - if (__predict_false(error != 0)) - return (error); - - AUDIT_ARG_FILE(td->td_proc, fp); - - error = fo_stat(fp, sbp, td->td_ucred); - if (error == 0 && (vp = fp->f_vnode) != NULL) - translate_vnhook_major_minor(vp, sbp); - fdrop(fp, td); -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - ktrstat_error(sbp, error); -#endif - return (error); -} - -static int -linux_kern_statat(struct thread *td, int flag, int fd, - const char * __capability path, enum uio_seg pathseg, struct stat *sbp) -{ - struct nameidata nd; - int error; - - if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | - AT_EMPTY_PATH)) != 0) - return (EINVAL); - - NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH | - AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF | - AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights); - - if ((error = namei(&nd)) != 0) { - if (error == ENOTDIR && - (nd.ni_resflags & NIRES_EMPTYPATH) != 0) - error = linux_kern_fstat(td, fd, sbp); - return (error); - } - error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED); - if (error == 0) - translate_vnhook_major_minor(nd.ni_vp, sbp); - NDFREE_PNBUF(&nd); - vput(nd.ni_vp); -#ifdef KTRACE - if (KTRPOINT(td, KTR_STRUCT)) - ktrstat_error(sbp, error); -#endif - return (error); -} - -#ifdef LINUX_LEGACY_SYSCALLS -static int -linux_kern_stat(struct thread *td, const char * __capability path, - enum uio_seg pathseg, struct stat *sbp) -{ - - return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp)); -} - -static int -linux_kern_lstat(struct thread *td, const char * __capability path, - enum uio_seg pathseg, struct stat *sbp) -{ - - return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path, - pathseg, sbp)); -} -#endif - -static int -newstat_copyout(struct stat *buf, void *ubuf) -{ - struct l_newstat tbuf; - - bzero(&tbuf, sizeof(tbuf)); - tbuf.st_dev = linux_new_encode_dev(buf->st_dev); - tbuf.st_ino = buf->st_ino; - tbuf.st_mode = buf->st_mode; - tbuf.st_nlink = buf->st_nlink; - tbuf.st_uid = buf->st_uid; - tbuf.st_gid = buf->st_gid; - tbuf.st_rdev = linux_new_encode_dev(buf->st_rdev); - tbuf.st_size = buf->st_size; - tbuf.st_atim.tv_sec = buf->st_atim.tv_sec; - tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; - tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; - tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; - tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; - tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; - tbuf.st_blksize = buf->st_blksize; - tbuf.st_blocks = buf->st_blocks; - - return (copyout(&tbuf, ubuf, sizeof(tbuf))); -} - - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_newstat(struct thread *td, struct linux_newstat_args *args) -{ - struct stat buf; - int error; - - error = linux_kern_stat(td, __USER_CAP_PATH(args->path), - UIO_USERSPACE, &buf); - if (error) - return (error); - return (newstat_copyout(&buf, args->buf)); -} - -int -linux_newlstat(struct thread *td, struct linux_newlstat_args *args) -{ - struct stat sb; - int error; - - error = linux_kern_lstat(td, __USER_CAP_PATH(args->path), - UIO_USERSPACE, &sb); - if (error) - return (error); - return (newstat_copyout(&sb, args->buf)); -} -#endif - -int -linux_newfstat(struct thread *td, struct linux_newfstat_args *args) -{ - struct stat buf; - int error; - - error = linux_kern_fstat(td, args->fd, &buf); - if (!error) - error = newstat_copyout(&buf, args->buf); - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) - -static __inline uint16_t -linux_old_encode_dev(dev_t _dev) -{ - - return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev))); -} - -static int -old_stat_copyout(struct stat *buf, void *ubuf) -{ - struct l_old_stat lbuf; - - bzero(&lbuf, sizeof(lbuf)); - lbuf.st_dev = linux_old_encode_dev(buf->st_dev); - lbuf.st_ino = buf->st_ino; - lbuf.st_mode = buf->st_mode; - lbuf.st_nlink = buf->st_nlink; - lbuf.st_uid = buf->st_uid; - lbuf.st_gid = buf->st_gid; - lbuf.st_rdev = linux_old_encode_dev(buf->st_rdev); - lbuf.st_size = MIN(buf->st_size, INT32_MAX); - lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; - lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; - lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; - lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; - lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; - lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; - lbuf.st_blksize = buf->st_blksize; - lbuf.st_blocks = buf->st_blocks; - lbuf.st_flags = buf->st_flags; - lbuf.st_gen = buf->st_gen; - - return (copyout(&lbuf, ubuf, sizeof(lbuf))); -} - -int -linux_stat(struct thread *td, struct linux_stat_args *args) -{ - struct stat buf; - int error; - - error = linux_kern_stat(td, __USER_CAP_PATH(args->path), - UIO_USERSPACE, &buf); - if (error) { - return (error); - } - return (old_stat_copyout(&buf, args->up)); -} - -int -linux_lstat(struct thread *td, struct linux_lstat_args *args) -{ - struct stat buf; - int error; - - error = linux_kern_lstat(td, __USER_CAP_PATH(args->path), - UIO_USERSPACE, &buf); - if (error) { - return (error); - } - return (old_stat_copyout(&buf, args->up)); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -struct l_statfs { - l_long f_type; - l_long f_bsize; - l_long f_blocks; - l_long f_bfree; - l_long f_bavail; - l_long f_files; - l_long f_ffree; - l_fsid_t f_fsid; - l_long f_namelen; - l_long f_frsize; - l_long f_flags; - l_long f_spare[4]; -}; - -#define LINUX_CODA_SUPER_MAGIC 0x73757245L -#define LINUX_EXT2_SUPER_MAGIC 0xEF53L -#define LINUX_HPFS_SUPER_MAGIC 0xf995e849L -#define LINUX_ISOFS_SUPER_MAGIC 0x9660L -#define LINUX_MSDOS_SUPER_MAGIC 0x4d44L -#define LINUX_NCP_SUPER_MAGIC 0x564cL -#define LINUX_NFS_SUPER_MAGIC 0x6969L -#define LINUX_NTFS_SUPER_MAGIC 0x5346544EL -#define LINUX_PROC_SUPER_MAGIC 0x9fa0L -#define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */ -#define LINUX_ZFS_SUPER_MAGIC 0x2FC12FC1 -#define LINUX_DEVFS_SUPER_MAGIC 0x1373L -#define LINUX_SHMFS_MAGIC 0x01021994 - -static long -bsd_to_linux_ftype(const char *fstypename) -{ - int i; - static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = { - {"ufs", LINUX_UFS_SUPER_MAGIC}, - {"zfs", LINUX_ZFS_SUPER_MAGIC}, - {"cd9660", LINUX_ISOFS_SUPER_MAGIC}, - {"nfs", LINUX_NFS_SUPER_MAGIC}, - {"ext2fs", LINUX_EXT2_SUPER_MAGIC}, - {"procfs", LINUX_PROC_SUPER_MAGIC}, - {"msdosfs", LINUX_MSDOS_SUPER_MAGIC}, - {"ntfs", LINUX_NTFS_SUPER_MAGIC}, - {"nwfs", LINUX_NCP_SUPER_MAGIC}, - {"hpfs", LINUX_HPFS_SUPER_MAGIC}, - {"coda", LINUX_CODA_SUPER_MAGIC}, - {"devfs", LINUX_DEVFS_SUPER_MAGIC}, - {"tmpfs", LINUX_SHMFS_MAGIC}, - {NULL, 0L}}; - - for (i = 0; b2l_tbl[i].bsd_name != NULL; i++) - if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0) - return (b2l_tbl[i].linux_type); - - return (0L); -} - -static int -bsd_to_linux_mnt_flags(int f_flags) -{ - int flags = LINUX_ST_VALID; - - if (f_flags & MNT_RDONLY) - flags |= LINUX_ST_RDONLY; - if (f_flags & MNT_NOEXEC) - flags |= LINUX_ST_NOEXEC; - if (f_flags & MNT_NOSUID) - flags |= LINUX_ST_NOSUID; - if (f_flags & MNT_NOATIME) - flags |= LINUX_ST_NOATIME; - if (f_flags & MNT_NOSYMFOLLOW) - flags |= LINUX_ST_NOSYMFOLLOW; - if (f_flags & MNT_SYNCHRONOUS) - flags |= LINUX_ST_SYNCHRONOUS; - - return (flags); -} - -static int -bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs) -{ - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) - statfs_scale_blocks(bsd_statfs, INT32_MAX); -#endif - linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); - linux_statfs->f_bsize = bsd_statfs->f_bsize; - linux_statfs->f_blocks = bsd_statfs->f_blocks; - linux_statfs->f_bfree = bsd_statfs->f_bfree; - linux_statfs->f_bavail = bsd_statfs->f_bavail; -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) - linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX); - linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX); -#else - linux_statfs->f_ffree = bsd_statfs->f_ffree; - linux_statfs->f_files = bsd_statfs->f_files; -#endif - linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; - linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; - linux_statfs->f_namelen = MAXNAMLEN; - linux_statfs->f_frsize = bsd_statfs->f_bsize; - linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags); - memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare)); - - return (0); -} - -int -linux_statfs(struct thread *td, struct linux_statfs_args *args) -{ - struct l_statfs linux_statfs; - struct statfs *bsd_statfs; - int error; - - bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); - error = kern_statfs(td, __USER_CAP_PATH(args->path), - UIO_USERSPACE, bsd_statfs); - if (error == 0) - error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs); - free(bsd_statfs, M_STATFS); - if (error != 0) - return (error); - return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -static void -bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs) -{ - - linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); - linux_statfs->f_bsize = bsd_statfs->f_bsize; - linux_statfs->f_blocks = bsd_statfs->f_blocks; - linux_statfs->f_bfree = bsd_statfs->f_bfree; - linux_statfs->f_bavail = bsd_statfs->f_bavail; - linux_statfs->f_ffree = bsd_statfs->f_ffree; - linux_statfs->f_files = bsd_statfs->f_files; - linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; - linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; - linux_statfs->f_namelen = MAXNAMLEN; - linux_statfs->f_frsize = bsd_statfs->f_bsize; - linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags); - memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare)); -} - -int -linux_statfs64(struct thread *td, struct linux_statfs64_args *args) -{ - struct l_statfs64 linux_statfs; - struct statfs *bsd_statfs; - int error; - - if (args->bufsize != sizeof(struct l_statfs64)) - return (EINVAL); - - bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); - error = kern_statfs(td, __USER_CAP_PATH(args->path), - UIO_USERSPACE, bsd_statfs); - if (error == 0) - bsd_to_linux_statfs64(bsd_statfs, &linux_statfs); - free(bsd_statfs, M_STATFS); - if (error != 0) - return (error); - return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); -} - -int -linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args) -{ - struct l_statfs64 linux_statfs; - struct statfs *bsd_statfs; - int error; - - if (args->bufsize != sizeof(struct l_statfs64)) - return (EINVAL); - - bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); - error = kern_fstatfs(td, args->fd, bsd_statfs); - if (error == 0) - bsd_to_linux_statfs64(bsd_statfs, &linux_statfs); - free(bsd_statfs, M_STATFS); - if (error != 0) - return (error); - return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); -} -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args) -{ - struct l_statfs linux_statfs; - struct statfs *bsd_statfs; - int error; - - bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); - error = kern_fstatfs(td, args->fd, bsd_statfs); - if (error == 0) - error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs); - free(bsd_statfs, M_STATFS); - if (error != 0) - return (error); - return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); -} - -struct l_ustat -{ - l_daddr_t f_tfree; - l_ino_t f_tinode; - char f_fname[6]; - char f_fpack[6]; -}; - -#ifdef LINUX_LEGACY_SYSCALLS -int -linux_ustat(struct thread *td, struct linux_ustat_args *args) -{ - - return (EOPNOTSUPP); -} -#endif - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) - -static int -stat64_copyout(struct stat *buf, void *ubuf) -{ - struct l_stat64 lbuf; - - bzero(&lbuf, sizeof(lbuf)); - lbuf.st_dev = linux_new_encode_dev(buf->st_dev); - lbuf.st_ino = buf->st_ino; - lbuf.st_mode = buf->st_mode; - lbuf.st_nlink = buf->st_nlink; - lbuf.st_uid = buf->st_uid; - lbuf.st_gid = buf->st_gid; - lbuf.st_rdev = linux_new_encode_dev(buf->st_rdev); - lbuf.st_size = buf->st_size; - lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; - lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; - lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; - lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; - lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; - lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; - lbuf.st_blksize = buf->st_blksize; - lbuf.st_blocks = buf->st_blocks; - - /* - * The __st_ino field makes all the difference. In the Linux kernel - * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO, - * but without the assignment to __st_ino the runtime linker refuses - * to mmap(2) any shared libraries. I guess it's broken alright :-) - */ - lbuf.__st_ino = buf->st_ino; - - return (copyout(&lbuf, ubuf, sizeof(lbuf))); -} - -int -linux_stat64(struct thread *td, struct linux_stat64_args *args) -{ - struct stat buf; - int error; - - error = linux_kern_stat(td, __USER_CAP_PATH(args->filename), - UIO_USERSPACE, &buf); - if (error) - return (error); - return (stat64_copyout(&buf, args->statbuf)); -} - -int -linux_lstat64(struct thread *td, struct linux_lstat64_args *args) -{ - struct stat sb; - int error; - - error = linux_kern_lstat(td, __USER_CAP_PATH(args->filename), - UIO_USERSPACE, &sb); - if (error) - return (error); - return (stat64_copyout(&sb, args->statbuf)); -} - -int -linux_fstat64(struct thread *td, struct linux_fstat64_args *args) -{ - struct stat buf; - int error; - - error = linux_kern_fstat(td, args->fd, &buf); - if (!error) - error = stat64_copyout(&buf, args->statbuf); - - return (error); -} - -int -linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args) -{ - int error, dfd, flag, unsupported; - struct stat buf; - - unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); - if (unsupported != 0) { - linux_msg(td, "fstatat64 unsupported flag 0x%x", unsupported); - return (EINVAL); - } - flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? - AT_SYMLINK_NOFOLLOW : 0; - flag |= (args->flag & LINUX_AT_EMPTY_PATH) ? - AT_EMPTY_PATH : 0; - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - error = linux_kern_statat(td, flag, dfd, - __USER_CAP_PATH(args->pathname), UIO_USERSPACE, &buf); - if (error == 0) - error = stat64_copyout(&buf, args->statbuf); - - return (error); -} - -#else /* __amd64__ && !COMPAT_LINUX32 */ - -int -linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args) -{ - int error, dfd, flag, unsupported; - struct stat buf; - - unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); - if (unsupported != 0) { - linux_msg(td, "fstatat unsupported flag 0x%x", unsupported); - return (EINVAL); - } - - flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? - AT_SYMLINK_NOFOLLOW : 0; - flag |= (args->flag & LINUX_AT_EMPTY_PATH) ? - AT_EMPTY_PATH : 0; - - dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; - error = linux_kern_statat(td, flag, dfd, - __USER_CAP_PATH(args->pathname), UIO_USERSPACE, &buf); - if (error == 0) - error = newstat_copyout(&buf, args->statbuf); - - return (error); -} - -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ - -int -linux_syncfs(struct thread *td, struct linux_syncfs_args *args) -{ - struct mount *mp; - struct vnode *vp; - int error, save; - - error = fgetvp(td, args->fd, &cap_fsync_rights, &vp); - if (error != 0) - /* - * Linux syncfs() returns only EBADF, however fgetvp() - * can return EINVAL in case of file descriptor does - * not represent a vnode. XXX. - */ - return (error); - - mp = vp->v_mount; - mtx_lock(&mountlist_mtx); - error = vfs_busy(mp, MBF_MNTLSTLOCK); - if (error != 0) { - /* See comment above. */ - mtx_unlock(&mountlist_mtx); - goto out; - } - if ((mp->mnt_flag & MNT_RDONLY) == 0 && - vn_start_write(NULL, &mp, V_NOWAIT) == 0) { - save = curthread_pflags_set(TDP_SYNCIO); - vfs_periodic(mp, MNT_NOWAIT); - VFS_SYNC(mp, MNT_NOWAIT); - curthread_pflags_restore(save); - vn_finished_write(mp); - } - vfs_unbusy(mp); - - out: - vrele(vp); - return (error); -} - -static int -statx_copyout(struct stat *buf, void *ubuf) -{ - struct l_statx tbuf; - - bzero(&tbuf, sizeof(tbuf)); - tbuf.stx_mask = STATX_ALL; - tbuf.stx_blksize = buf->st_blksize; - tbuf.stx_attributes = 0; - tbuf.stx_nlink = buf->st_nlink; - tbuf.stx_uid = buf->st_uid; - tbuf.stx_gid = buf->st_gid; - tbuf.stx_mode = buf->st_mode; - tbuf.stx_ino = buf->st_ino; - tbuf.stx_size = buf->st_size; - tbuf.stx_blocks = buf->st_blocks; - - tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec; - tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec; - tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec; - tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec; - tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec; - tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec; - tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec; - tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec; - tbuf.stx_rdev_major = linux_encode_major(buf->st_rdev); - tbuf.stx_rdev_minor = linux_encode_minor(buf->st_rdev); - tbuf.stx_dev_major = linux_encode_major(buf->st_dev); - tbuf.stx_dev_minor = linux_encode_minor(buf->st_dev); - - return (copyout(&tbuf, ubuf, sizeof(tbuf))); -} - -int -linux_statx(struct thread *td, struct linux_statx_args *args) -{ - int error, dirfd, flags, unsupported; - struct stat buf; - - unsupported = args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW | - LINUX_AT_EMPTY_PATH | LINUX_AT_NO_AUTOMOUNT); - if (unsupported != 0) { - linux_msg(td, "statx unsupported flags 0x%x", unsupported); - return (EINVAL); - } - - flags = (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) ? - AT_SYMLINK_NOFOLLOW : 0; - flags |= (args->flags & LINUX_AT_EMPTY_PATH) ? - AT_EMPTY_PATH : 0; - - dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd; - error = linux_kern_statat(td, flags, dirfd, args->pathname, - UIO_USERSPACE, &buf); - if (error == 0) - error = statx_copyout(&buf, args->statxbuf); - - return (error); -} -// CHERI CHANGES START -// { -// "updated": 20230509, -// "target_type": "kernel", -// "changes": [ -// "user_capabilities" -// ] -// } -// CHERI CHANGES END +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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 "opt_ktrace.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef KTRACE +#include +#endif + +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +#include +#include +#include + + +static int +linux_kern_fstat(struct thread *td, int fd, struct stat *sbp) +{ + struct vnode *vp; + struct file *fp; + int error; + + AUDIT_ARG_FD(fd); + + error = fget(td, fd, &cap_fstat_rights, &fp); + if (__predict_false(error != 0)) + return (error); + + AUDIT_ARG_FILE(td->td_proc, fp); + + error = fo_stat(fp, sbp, td->td_ucred); + if (error == 0 && (vp = fp->f_vnode) != NULL) + translate_vnhook_major_minor(vp, sbp); + fdrop(fp, td); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + ktrstat_error(sbp, error); +#endif + return (error); +} + +static int +linux_kern_statat(struct thread *td, int flag, int fd, + const char * __capability path, enum uio_seg pathseg, struct stat *sbp) +{ + struct nameidata nd; + int error; + + if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | + AT_EMPTY_PATH)) != 0) + return (EINVAL); + + NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH | + AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF | + AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights); + + if ((error = namei(&nd)) != 0) { + if (error == ENOTDIR && + (nd.ni_resflags & NIRES_EMPTYPATH) != 0) + error = linux_kern_fstat(td, fd, sbp); + return (error); + } + error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED); + if (error == 0) + translate_vnhook_major_minor(nd.ni_vp, sbp); + NDFREE_PNBUF(&nd); + vput(nd.ni_vp); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + ktrstat_error(sbp, error); +#endif + return (error); +} + +#ifdef LINUX_LEGACY_SYSCALLS +static int +linux_kern_stat(struct thread *td, const char * __capability path, + enum uio_seg pathseg, struct stat *sbp) +{ + + return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp)); +} + +static int +linux_kern_lstat(struct thread *td, const char * __capability path, + enum uio_seg pathseg, struct stat *sbp) +{ + + return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path, + pathseg, sbp)); +} +#endif + +static int +newstat_copyout(struct stat *buf, void * __capability ubuf) +{ + struct l_newstat tbuf; + + bzero(&tbuf, sizeof(tbuf)); + tbuf.st_dev = linux_new_encode_dev(buf->st_dev); + tbuf.st_ino = buf->st_ino; + tbuf.st_mode = buf->st_mode; + tbuf.st_nlink = buf->st_nlink; + tbuf.st_uid = buf->st_uid; + tbuf.st_gid = buf->st_gid; + tbuf.st_rdev = linux_new_encode_dev(buf->st_rdev); + tbuf.st_size = buf->st_size; + tbuf.st_atim.tv_sec = buf->st_atim.tv_sec; + tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; + tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; + tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; + tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; + tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; + tbuf.st_blksize = buf->st_blksize; + tbuf.st_blocks = buf->st_blocks; + + return (copyout(&tbuf, ubuf, sizeof(tbuf))); +} + + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_newstat(struct thread *td, struct linux_newstat_args *args) +{ + struct stat buf; + int error; + + error = linux_kern_stat(td, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, &buf); + if (error) + return (error); + return (newstat_copyout(&buf, LINUX_USER_CAP_OBJ(args->buf))); +} + +int +linux_newlstat(struct thread *td, struct linux_newlstat_args *args) +{ + struct stat sb; + int error; + + error = linux_kern_lstat(td, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, &sb); + if (error) + return (error); + return (newstat_copyout(&sb, LINUX_USER_CAP_OBJ(args->buf))); +} +#endif + +int +linux_newfstat(struct thread *td, struct linux_newfstat_args *args) +{ + struct stat buf; + int error; + + error = linux_kern_fstat(td, args->fd, &buf); + if (!error) + error = newstat_copyout(&buf, LINUX_USER_CAP_OBJ(args->buf)); + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + +static __inline uint16_t +linux_old_encode_dev(dev_t _dev) +{ + + return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev))); +} + +static int +old_stat_copyout(struct stat *buf, void *ubuf) +{ + struct l_old_stat lbuf; + + bzero(&lbuf, sizeof(lbuf)); + lbuf.st_dev = linux_old_encode_dev(buf->st_dev); + lbuf.st_ino = buf->st_ino; + lbuf.st_mode = buf->st_mode; + lbuf.st_nlink = buf->st_nlink; + lbuf.st_uid = buf->st_uid; + lbuf.st_gid = buf->st_gid; + lbuf.st_rdev = linux_old_encode_dev(buf->st_rdev); + lbuf.st_size = MIN(buf->st_size, INT32_MAX); + lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; + lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; + lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; + lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; + lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; + lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; + lbuf.st_blksize = buf->st_blksize; + lbuf.st_blocks = buf->st_blocks; + lbuf.st_flags = buf->st_flags; + lbuf.st_gen = buf->st_gen; + + return (copyout(&lbuf, LINUX_USER_CAP(ubuf, sizeof(lbuf)), sizeof(lbuf))); +} + +int +linux_stat(struct thread *td, struct linux_stat_args *args) +{ + struct stat buf; + int error; + + error = linux_kern_stat(td, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, &buf); + if (error) { + return (error); + } + return (old_stat_copyout(&buf, args->up)); +} + +int +linux_lstat(struct thread *td, struct linux_lstat_args *args) +{ + struct stat buf; + int error; + + error = linux_kern_lstat(td, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, &buf); + if (error) { + return (error); + } + return (old_stat_copyout(&buf, args->up)); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +struct l_statfs { + l_long f_type; + l_long f_bsize; + l_long f_blocks; + l_long f_bfree; + l_long f_bavail; + l_long f_files; + l_long f_ffree; + l_fsid_t f_fsid; + l_long f_namelen; + l_long f_frsize; + l_long f_flags; + l_long f_spare[4]; +}; + +#define LINUX_CODA_SUPER_MAGIC 0x73757245L +#define LINUX_EXT2_SUPER_MAGIC 0xEF53L +#define LINUX_HPFS_SUPER_MAGIC 0xf995e849L +#define LINUX_ISOFS_SUPER_MAGIC 0x9660L +#define LINUX_MSDOS_SUPER_MAGIC 0x4d44L +#define LINUX_NCP_SUPER_MAGIC 0x564cL +#define LINUX_NFS_SUPER_MAGIC 0x6969L +#define LINUX_NTFS_SUPER_MAGIC 0x5346544EL +#define LINUX_PROC_SUPER_MAGIC 0x9fa0L +#define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */ +#define LINUX_ZFS_SUPER_MAGIC 0x2FC12FC1 +#define LINUX_DEVFS_SUPER_MAGIC 0x1373L +#define LINUX_SHMFS_MAGIC 0x01021994 + +static long +bsd_to_linux_ftype(const char *fstypename) +{ + int i; + static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = { + {"ufs", LINUX_UFS_SUPER_MAGIC}, + {"zfs", LINUX_ZFS_SUPER_MAGIC}, + {"cd9660", LINUX_ISOFS_SUPER_MAGIC}, + {"nfs", LINUX_NFS_SUPER_MAGIC}, + {"ext2fs", LINUX_EXT2_SUPER_MAGIC}, + {"procfs", LINUX_PROC_SUPER_MAGIC}, + {"msdosfs", LINUX_MSDOS_SUPER_MAGIC}, + {"ntfs", LINUX_NTFS_SUPER_MAGIC}, + {"nwfs", LINUX_NCP_SUPER_MAGIC}, + {"hpfs", LINUX_HPFS_SUPER_MAGIC}, + {"coda", LINUX_CODA_SUPER_MAGIC}, + {"devfs", LINUX_DEVFS_SUPER_MAGIC}, + {"tmpfs", LINUX_SHMFS_MAGIC}, + {NULL, 0L}}; + + for (i = 0; b2l_tbl[i].bsd_name != NULL; i++) + if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0) + return (b2l_tbl[i].linux_type); + + return (0L); +} + +static int +bsd_to_linux_mnt_flags(int f_flags) +{ + int flags = LINUX_ST_VALID; + + if (f_flags & MNT_RDONLY) + flags |= LINUX_ST_RDONLY; + if (f_flags & MNT_NOEXEC) + flags |= LINUX_ST_NOEXEC; + if (f_flags & MNT_NOSUID) + flags |= LINUX_ST_NOSUID; + if (f_flags & MNT_NOATIME) + flags |= LINUX_ST_NOATIME; + if (f_flags & MNT_NOSYMFOLLOW) + flags |= LINUX_ST_NOSYMFOLLOW; + if (f_flags & MNT_SYNCHRONOUS) + flags |= LINUX_ST_SYNCHRONOUS; + + return (flags); +} + +static int +bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs) +{ + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + statfs_scale_blocks(bsd_statfs, INT32_MAX); +#endif + linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); + linux_statfs->f_bsize = bsd_statfs->f_bsize; + linux_statfs->f_blocks = bsd_statfs->f_blocks; + linux_statfs->f_bfree = bsd_statfs->f_bfree; + linux_statfs->f_bavail = bsd_statfs->f_bavail; +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX); + linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX); +#else + linux_statfs->f_ffree = bsd_statfs->f_ffree; + linux_statfs->f_files = bsd_statfs->f_files; +#endif + linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; + linux_statfs->f_namelen = MAXNAMLEN; + linux_statfs->f_frsize = bsd_statfs->f_bsize; + linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags); + memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare)); + + return (0); +} + +int +linux_statfs(struct thread *td, struct linux_statfs_args *args) +{ + struct l_statfs linux_statfs; + struct statfs *bsd_statfs; + int error; + + bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); + error = kern_statfs(td, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, bsd_statfs); + if (error == 0) + error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs); + free(bsd_statfs, M_STATFS); + if (error != 0) + return (error); + return (copyout(&linux_statfs, LINUX_USER_CAP(args->buf, sizeof(linux_statfs)), sizeof(linux_statfs))); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +static void +bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs) +{ + + linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); + linux_statfs->f_bsize = bsd_statfs->f_bsize; + linux_statfs->f_blocks = bsd_statfs->f_blocks; + linux_statfs->f_bfree = bsd_statfs->f_bfree; + linux_statfs->f_bavail = bsd_statfs->f_bavail; + linux_statfs->f_ffree = bsd_statfs->f_ffree; + linux_statfs->f_files = bsd_statfs->f_files; + linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; + linux_statfs->f_namelen = MAXNAMLEN; + linux_statfs->f_frsize = bsd_statfs->f_bsize; + linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags); + memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare)); +} + +int +linux_statfs64(struct thread *td, struct linux_statfs64_args *args) +{ + struct l_statfs64 linux_statfs; + struct statfs *bsd_statfs; + int error; + + if (args->bufsize != sizeof(struct l_statfs64)) + return (EINVAL); + + bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); + error = kern_statfs(td, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, bsd_statfs); + if (error == 0) + bsd_to_linux_statfs64(bsd_statfs, &linux_statfs); + free(bsd_statfs, M_STATFS); + if (error != 0) + return (error); + return (copyout(&linux_statfs, LINUX_USER_CAP(args->buf, sizeof(linux_statfs)), sizeof(linux_statfs))); +} + +int +linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args) +{ + struct l_statfs64 linux_statfs; + struct statfs *bsd_statfs; + int error; + + if (args->bufsize != sizeof(struct l_statfs64)) + return (EINVAL); + + bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); + error = kern_fstatfs(td, args->fd, bsd_statfs); + if (error == 0) + bsd_to_linux_statfs64(bsd_statfs, &linux_statfs); + free(bsd_statfs, M_STATFS); + if (error != 0) + return (error); + return (copyout(&linux_statfs, LINUX_USER_CAP(args->buf, sizeof(linux_statfs)), sizeof(linux_statfs))); +} +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args) +{ + struct l_statfs linux_statfs; + struct statfs *bsd_statfs; + int error; + + bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); + error = kern_fstatfs(td, args->fd, bsd_statfs); + if (error == 0) + error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs); + free(bsd_statfs, M_STATFS); + if (error != 0) + return (error); + return (copyout(&linux_statfs, LINUX_USER_CAP(args->buf, sizeof(linux_statfs)), sizeof(linux_statfs))); +} + +struct l_ustat +{ + l_daddr_t f_tfree; + l_ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + +#ifdef LINUX_LEGACY_SYSCALLS +int +linux_ustat(struct thread *td, struct linux_ustat_args *args) +{ + + return (EOPNOTSUPP); +} +#endif + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + +static int +stat64_copyout(struct stat *buf, void *ubuf) +{ + struct l_stat64 lbuf; + + bzero(&lbuf, sizeof(lbuf)); + lbuf.st_dev = linux_new_encode_dev(buf->st_dev); + lbuf.st_ino = buf->st_ino; + lbuf.st_mode = buf->st_mode; + lbuf.st_nlink = buf->st_nlink; + lbuf.st_uid = buf->st_uid; + lbuf.st_gid = buf->st_gid; + lbuf.st_rdev = linux_new_encode_dev(buf->st_rdev); + lbuf.st_size = buf->st_size; + lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; + lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; + lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; + lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; + lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; + lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; + lbuf.st_blksize = buf->st_blksize; + lbuf.st_blocks = buf->st_blocks; + + /* + * The __st_ino field makes all the difference. In the Linux kernel + * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO, + * but without the assignment to __st_ino the runtime linker refuses + * to mmap(2) any shared libraries. I guess it's broken alright :-) + */ + lbuf.__st_ino = buf->st_ino; + + return (copyout(&lbuf, LINUX_USER_CAP(ubuf, sizeof(lbuf)), sizeof(lbuf))); +} + +int +linux_stat64(struct thread *td, struct linux_stat64_args *args) +{ + struct stat buf; + int error; + + error = linux_kern_stat(td, LINUX_USER_CAP_PATH(args->filename), + UIO_USERSPACE, &buf); + if (error) + return (error); + return (stat64_copyout(&buf, args->statbuf)); +} + +int +linux_lstat64(struct thread *td, struct linux_lstat64_args *args) +{ + struct stat sb; + int error; + + error = linux_kern_lstat(td, LINUX_USER_CAP_PATH(args->filename), + UIO_USERSPACE, &sb); + if (error) + return (error); + return (stat64_copyout(&sb, args->statbuf)); +} + +int +linux_fstat64(struct thread *td, struct linux_fstat64_args *args) +{ + struct stat buf; + int error; + + error = linux_kern_fstat(td, args->fd, &buf); + if (!error) + error = stat64_copyout(&buf, args->statbuf); + + return (error); +} + +int +linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args) +{ + int error, dfd, flag, unsupported; + struct stat buf; + + unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); + if (unsupported != 0) { + linux_msg(td, "fstatat64 unsupported flag 0x%x", unsupported); + return (EINVAL); + } + flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? + AT_SYMLINK_NOFOLLOW : 0; + flag |= (args->flag & LINUX_AT_EMPTY_PATH) ? + AT_EMPTY_PATH : 0; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + error = linux_kern_statat(td, flag, dfd, + LINUX_USER_CAP_PATH(args->pathname), UIO_USERSPACE, &buf); + if (error == 0) + error = stat64_copyout(&buf, args->statbuf); + + return (error); +} + +#else /* __amd64__ && !COMPAT_LINUX32 */ + +int +linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args) +{ + int error, dfd, flag, unsupported; + struct stat buf; + + unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); + if (unsupported != 0) { + linux_msg(td, "fstatat unsupported flag 0x%x", unsupported); + return (EINVAL); + } + + flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? + AT_SYMLINK_NOFOLLOW : 0; + flag |= (args->flag & LINUX_AT_EMPTY_PATH) ? + AT_EMPTY_PATH : 0; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + error = linux_kern_statat(td, flag, dfd, + LINUX_USER_CAP_PATH(args->pathname), UIO_USERSPACE, &buf); + if (error == 0) + error = newstat_copyout(&buf, LINUX_USER_CAP_OBJ(args->statbuf)); + + return (error); +} + +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ + +int +linux_syncfs(struct thread *td, struct linux_syncfs_args *args) +{ + struct mount *mp; + struct vnode *vp; + int error, save; + + error = fgetvp(td, args->fd, &cap_fsync_rights, &vp); + if (error != 0) + /* + * Linux syncfs() returns only EBADF, however fgetvp() + * can return EINVAL in case of file descriptor does + * not represent a vnode. XXX. + */ + return (error); + + mp = vp->v_mount; + mtx_lock(&mountlist_mtx); + error = vfs_busy(mp, MBF_MNTLSTLOCK); + if (error != 0) { + /* See comment above. */ + mtx_unlock(&mountlist_mtx); + goto out; + } + if ((mp->mnt_flag & MNT_RDONLY) == 0 && + vn_start_write(NULL, &mp, V_NOWAIT) == 0) { + save = curthread_pflags_set(TDP_SYNCIO); + vfs_periodic(mp, MNT_NOWAIT); + VFS_SYNC(mp, MNT_NOWAIT); + curthread_pflags_restore(save); + vn_finished_write(mp); + } + vfs_unbusy(mp); + + out: + vrele(vp); + return (error); +} + +static int +statx_copyout(struct stat *buf, void * __capability ubuf) +{ + struct l_statx tbuf; + + bzero(&tbuf, sizeof(tbuf)); + tbuf.stx_mask = STATX_ALL; + tbuf.stx_blksize = buf->st_blksize; + tbuf.stx_attributes = 0; + tbuf.stx_nlink = buf->st_nlink; + tbuf.stx_uid = buf->st_uid; + tbuf.stx_gid = buf->st_gid; + tbuf.stx_mode = buf->st_mode; + tbuf.stx_ino = buf->st_ino; + tbuf.stx_size = buf->st_size; + tbuf.stx_blocks = buf->st_blocks; + + tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec; + tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec; + tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec; + tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec; + tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec; + tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec; + tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec; + tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec; + tbuf.stx_rdev_major = linux_encode_major(buf->st_rdev); + tbuf.stx_rdev_minor = linux_encode_minor(buf->st_rdev); + tbuf.stx_dev_major = linux_encode_major(buf->st_dev); + tbuf.stx_dev_minor = linux_encode_minor(buf->st_dev); + + return (copyout(&tbuf, ubuf, sizeof(tbuf))); +} + +int +linux_statx(struct thread *td, struct linux_statx_args *args) +{ + int error, dirfd, flags, unsupported; + struct stat buf; + + unsupported = args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW | + LINUX_AT_EMPTY_PATH | LINUX_AT_NO_AUTOMOUNT); + if (unsupported != 0) { + linux_msg(td, "statx unsupported flags 0x%x", unsupported); + return (EINVAL); + } + + flags = (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) ? + AT_SYMLINK_NOFOLLOW : 0; + flags |= (args->flags & LINUX_AT_EMPTY_PATH) ? + AT_EMPTY_PATH : 0; + + dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd; + error = linux_kern_statat(td, flags, dirfd, LINUX_USER_CAP_PATH(args->pathname), + UIO_USERSPACE, &buf); + if (error == 0) + error = statx_copyout(&buf, LINUX_USER_CAP(args->statxbuf, sizeof(struct l_statx))); + + return (error); +} +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "kernel", +// "changes": [ +// "user_capabilities" +// ] +// } +// CHERI CHANGES END diff --git a/sys/compat/linux/linux_sysctl.c b/sys/compat/linux/linux_sysctl.c index 97341c051af7..cabafc0683d1 100644 --- a/sys/compat/linux/linux_sysctl.c +++ b/sys/compat/linux/linux_sysctl.c @@ -1,168 +1,171 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2001 Marcel Moolenaar - * 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 -#include -#include -#include -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif - -#include -#include -#include - -#define LINUX_CTL_KERN 1 -#define LINUX_CTL_VM 2 -#define LINUX_CTL_NET 3 -#define LINUX_CTL_PROC 4 -#define LINUX_CTL_FS 5 -#define LINUX_CTL_DEBUG 6 -#define LINUX_CTL_DEV 7 -#define LINUX_CTL_BUS 8 - -/* CTL_KERN names */ -#define LINUX_KERN_OSTYPE 1 -#define LINUX_KERN_OSRELEASE 2 -#define LINUX_KERN_OSREV 3 -#define LINUX_KERN_VERSION 4 - -/* DTrace init */ -LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); - -/** - * DTrace probes in this module. - */ -LIN_SDT_PROBE_DEFINE1(sysctl, handle_string, copyout_error, "int"); -LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, copyin_error, "int"); -LIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, wrong_length, "int", "int"); -LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, unsupported_sysctl, "char *"); - -#ifdef LINUX_LEGACY_SYSCALLS -static int -handle_string(struct l___sysctl_args *la, const char *value) -{ - int error; - - if (la->oldval != 0) { - l_int len = strlen(value); - error = copyout(value, PTRIN(la->oldval), len + 1); - if (!error && la->oldlenp != 0) - error = copyout(&len, PTRIN(la->oldlenp), sizeof(len)); - if (error) { - LIN_SDT_PROBE1(sysctl, handle_string, copyout_error, - error); - return (error); - } - } - - if (la->newval != 0) - return (ENOTDIR); - - return (0); -} - -int -linux_sysctl(struct thread *td, struct linux_sysctl_args *args) -{ - struct l___sysctl_args la; - struct sbuf *sb; - l_int *mib; - char *sysctl_string; - int error, i; - - error = copyin(args->args, &la, sizeof(la)); - if (error) { - LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error); - return (error); - } - - if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME) { - LIN_SDT_PROBE2(sysctl, linux_sysctl, wrong_length, la.nlen, - LINUX_CTL_MAXNAME); - return (ENOTDIR); - } - - mib = malloc(la.nlen * sizeof(l_int), M_LINUX, M_WAITOK); - error = copyin(PTRIN(la.name), mib, la.nlen * sizeof(l_int)); - if (error) { - LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error); - free(mib, M_LINUX); - return (error); - } - - switch (mib[0]) { - case LINUX_CTL_KERN: - if (la.nlen < 2) - break; - - switch (mib[1]) { - case LINUX_KERN_VERSION: - error = handle_string(&la, version); - free(mib, M_LINUX); - return (error); - default: - break; - } - break; - default: - break; - } - - sb = sbuf_new(NULL, NULL, 20 + la.nlen * 5, SBUF_AUTOEXTEND); - if (sb == NULL) { - linux_msg(td, "sysctl is not implemented"); - LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl, - "unknown sysctl, ENOMEM during lookup"); - } else { - sbuf_printf(sb, "sysctl "); - for (i = 0; i < la.nlen; i++) - sbuf_printf(sb, "%c%d", (i) ? ',' : '{', mib[i]); - sbuf_printf(sb, "} is not implemented"); - sbuf_finish(sb); - sysctl_string = sbuf_data(sb); - linux_msg(td, "%s", sysctl_string); - LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl, - sysctl_string); - sbuf_delete(sb); - } - - free(mib, M_LINUX); - - return (ENOTDIR); -} -#endif +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Marcel Moolenaar + * 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 +#include +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +#include +#include +#include + +#define LINUX_CTL_KERN 1 +#define LINUX_CTL_VM 2 +#define LINUX_CTL_NET 3 +#define LINUX_CTL_PROC 4 +#define LINUX_CTL_FS 5 +#define LINUX_CTL_DEBUG 6 +#define LINUX_CTL_DEV 7 +#define LINUX_CTL_BUS 8 + +/* CTL_KERN names */ +#define LINUX_KERN_OSTYPE 1 +#define LINUX_KERN_OSRELEASE 2 +#define LINUX_KERN_OSREV 3 +#define LINUX_KERN_VERSION 4 + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE1(sysctl, handle_string, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, wrong_length, "int", "int"); +LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, unsupported_sysctl, "char *"); + +#ifdef LINUX_LEGACY_SYSCALLS +static int +handle_string(struct l___sysctl_args *la, const char *value) +{ + int error; + + if (la->oldval != 0) { + l_int len = strlen(value); + error = copyout(value, PTRIN(la->oldval), len + 1); + if (!error && la->oldlenp != 0) + error = copyout(&len, PTRIN(la->oldlenp), sizeof(len)); + if (error) { + LIN_SDT_PROBE1(sysctl, handle_string, copyout_error, + error); + return (error); + } + } + + if (la->newval != 0) + return (ENOTDIR); + + return (0); +} + +int +linux_sysctl(struct thread *td, struct linux_sysctl_args *args) +{ + struct l___sysctl_args la; + struct sbuf *sb; + l_int *mib; + char *sysctl_string; + int error, i; + + error = copyin(args->args, &la, sizeof(la)); + if (error) { + LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error); + return (error); + } + + if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME) { + LIN_SDT_PROBE2(sysctl, linux_sysctl, wrong_length, la.nlen, + LINUX_CTL_MAXNAME); + return (ENOTDIR); + } + + mib = malloc(la.nlen * sizeof(l_int), M_LINUX, M_WAITOK); + error = copyin(PTRIN(la.name), mib, la.nlen * sizeof(l_int)); + if (error) { + LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error); + free(mib, M_LINUX); + return (error); + } + + switch (mib[0]) { + case LINUX_CTL_KERN: + if (la.nlen < 2) + break; + + switch (mib[1]) { + case LINUX_KERN_VERSION: + error = handle_string(&la, version); + free(mib, M_LINUX); + return (error); + default: + break; + } + break; + default: + break; + } + + sb = sbuf_new(NULL, NULL, 20 + la.nlen * 5, SBUF_AUTOEXTEND); + if (sb == NULL) { + linux_msg(td, "sysctl is not implemented"); + LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl, + "unknown sysctl, ENOMEM during lookup"); + } else { + sbuf_printf(sb, "sysctl "); + for (i = 0; i < la.nlen; i++) + sbuf_printf(sb, "%c%d", (i) ? ',' : '{', mib[i]); + sbuf_printf(sb, "} is not implemented"); + sbuf_finish(sb); + sysctl_string = sbuf_data(sb); + linux_msg(td, "%s", sysctl_string); + LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl, + sysctl_string); + sbuf_delete(sb); + } + + free(mib, M_LINUX); + + return (ENOTDIR); +} +#endif diff --git a/sys/compat/linux/linux_time.c b/sys/compat/linux/linux_time.c index f4dd26dd3d2a..7f19a7cad831 100644 --- a/sys/compat/linux/linux_time.c +++ b/sys/compat/linux/linux_time.c @@ -1,805 +1,824 @@ -/* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */ - -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Emmanuel Dreyfus. - * - * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 -#if 0 -__KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif - -#include -#include -#include -#include - -/* DTrace init */ -LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); - -/** - * DTrace probes in this module. - */ -LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid, - "clockid_t"); -LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid, - "clockid_t"); -LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_gettime, conversion_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int"); -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, gettime_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, copyout_error, "int"); -#endif -LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, settime_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, conversion_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int"); -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, conversion_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, copyin_error, "int"); -#endif -LIN_SDT_PROBE_DEFINE0(time, linux_common_clock_getres, nullcall); -LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, conversion_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, getres_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int"); -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres_time64, copyout_error, "int"); -#endif -LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_flags, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_clockid, "int"); -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyout_error, "int"); -LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyin_error, "int"); -#endif - -static int linux_common_clock_gettime(struct thread *, clockid_t, - struct timespec *); -static int linux_common_clock_settime(struct thread *, clockid_t, - struct timespec *); -static int linux_common_clock_getres(struct thread *, clockid_t, - struct timespec *); -static int linux_common_clock_nanosleep(struct thread *, clockid_t, - l_int, struct timespec *, struct timespec *); - -int -native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) -{ - -#ifdef COMPAT_LINUX32 - if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN) - return (EOVERFLOW); -#endif - ltp->tv_sec = ntp->tv_sec; - ltp->tv_nsec = ntp->tv_nsec; - - return (0); -} - -int -linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp) -{ - - if (!timespecvalid_interval(ltp)) - return (EINVAL); - ntp->tv_sec = ltp->tv_sec; - ntp->tv_nsec = ltp->tv_nsec; - - return (0); -} - -int -linux_put_timespec(struct timespec *ntp, struct l_timespec *ltp) -{ - struct l_timespec lts; - int error; - - error = native_to_linux_timespec(<s, ntp); - if (error != 0) - return (error); - return (copyout(<s, ltp, sizeof(lts))); -} - -int -linux_get_timespec(struct timespec *ntp, const struct l_timespec *ultp) -{ - struct l_timespec lts; - int error; - - error = copyin(ultp, <s, sizeof(lts)); - if (error != 0) - return (error); - return (linux_to_native_timespec(ntp, <s)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -native_to_linux_timespec64(struct l_timespec64 *ltp64, struct timespec *ntp) -{ - - ltp64->tv_sec = ntp->tv_sec; - ltp64->tv_nsec = ntp->tv_nsec; - - return (0); -} - -int -linux_to_native_timespec64(struct timespec *ntp, struct l_timespec64 *ltp64) -{ - -#if defined(__i386__) - /* i386 time_t is still 32-bit */ - if (ltp64->tv_sec > INT_MAX || ltp64->tv_sec < INT_MIN) - return (EOVERFLOW); -#endif - /* Zero out the padding in compat mode. */ - ntp->tv_nsec = ltp64->tv_nsec & 0xFFFFFFFFUL; - ntp->tv_sec = ltp64->tv_sec; - - if (!timespecvalid_interval(ntp)) - return (EINVAL); - - return (0); -} - -int -linux_put_timespec64(struct timespec *ntp, struct l_timespec64 *ltp) -{ - struct l_timespec64 lts; - int error; - - error = native_to_linux_timespec64(<s, ntp); - if (error != 0) - return (error); - return (copyout(<s, ltp, sizeof(lts))); -} - -int -linux_get_timespec64(struct timespec *ntp, const struct l_timespec64 *ultp) -{ - struct l_timespec64 lts; - int error; - - error = copyin(ultp, <s, sizeof(lts)); - if (error != 0) - return (error); - return (linux_to_native_timespec64(ntp, <s)); -} -#endif - -int -native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp) -{ - int error; - - error = native_to_linux_timespec(<p->it_interval, &ntp->it_interval); - if (error == 0) - error = native_to_linux_timespec(<p->it_value, &ntp->it_value); - return (error); -} - -int -linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp) -{ - int error; - - error = linux_to_native_timespec(&ntp->it_interval, <p->it_interval); - if (error == 0) - error = linux_to_native_timespec(&ntp->it_value, <p->it_value); - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_to_native_itimerspec64(struct itimerspec *ntp, struct l_itimerspec64 *ltp) -{ - int error; - - error = linux_to_native_timespec64(&ntp->it_interval, <p->it_interval); - if (error == 0) - error = linux_to_native_timespec64(&ntp->it_value, <p->it_value); - return (error); -} - -int -native_to_linux_itimerspec64(struct l_itimerspec64 *ltp, struct itimerspec *ntp) -{ - int error; - - error = native_to_linux_timespec64(<p->it_interval, &ntp->it_interval); - if (error == 0) - error = native_to_linux_timespec64(<p->it_value, &ntp->it_value); - return (error); -} -#endif - -int -linux_to_native_clockid(clockid_t *n, clockid_t l) -{ - - if (l < 0) { - /* cpu-clock */ - if (LINUX_CPUCLOCK_WHICH(l) == LINUX_CLOCKFD) { - LIN_SDT_PROBE1(time, linux_to_native_clockid, - unsupported_clockid, l); - return (ENOTSUP); - } - if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD_MASK) - return (EINVAL); - - if (LINUX_CPUCLOCK_PERTHREAD(l)) - *n = CLOCK_THREAD_CPUTIME_ID; - else - *n = CLOCK_PROCESS_CPUTIME_ID; - return (0); - } - - switch (l) { - case LINUX_CLOCK_REALTIME: - *n = CLOCK_REALTIME; - break; - case LINUX_CLOCK_MONOTONIC: - *n = CLOCK_UPTIME; - break; - case LINUX_CLOCK_PROCESS_CPUTIME_ID: - *n = CLOCK_PROCESS_CPUTIME_ID; - break; - case LINUX_CLOCK_THREAD_CPUTIME_ID: - *n = CLOCK_THREAD_CPUTIME_ID; - break; - case LINUX_CLOCK_REALTIME_COARSE: - *n = CLOCK_REALTIME_FAST; - break; - case LINUX_CLOCK_MONOTONIC_COARSE: - case LINUX_CLOCK_MONOTONIC_RAW: - *n = CLOCK_UPTIME_FAST; - break; - case LINUX_CLOCK_BOOTTIME: - *n = CLOCK_MONOTONIC; - break; - case LINUX_CLOCK_REALTIME_ALARM: - case LINUX_CLOCK_BOOTTIME_ALARM: - case LINUX_CLOCK_SGI_CYCLE: - case LINUX_CLOCK_TAI: - LIN_SDT_PROBE1(time, linux_to_native_clockid, - unsupported_clockid, l); - return (ENOTSUP); - default: - LIN_SDT_PROBE1(time, linux_to_native_clockid, - unknown_clockid, l); - return (ENOTSUP); - } - - return (0); -} - -int -linux_to_native_timerflags(int *nflags, int flags) -{ - - if (flags & ~LINUX_TIMER_ABSTIME) - return (EINVAL); - *nflags = 0; - if (flags & LINUX_TIMER_ABSTIME) - *nflags |= TIMER_ABSTIME; - return (0); -} - -static int -linux_common_clock_gettime(struct thread *td, clockid_t which, - struct timespec *tp) -{ - struct rusage ru; - struct thread *targettd; - struct proc *p; - int error, clockwhich; - clockid_t nwhich; - pid_t pid; - lwpid_t tid; - - error = linux_to_native_clockid(&nwhich, which); - if (error != 0) { - linux_msg(curthread, - "unsupported clock_gettime clockid %d", which); - LIN_SDT_PROBE1(time, linux_common_clock_gettime, - conversion_error, error); - return (error); - } - - switch (nwhich) { - case CLOCK_PROCESS_CPUTIME_ID: - if (which < 0) { - clockwhich = LINUX_CPUCLOCK_WHICH(which); - pid = LINUX_CPUCLOCK_ID(which); - } else { - clockwhich = LINUX_CPUCLOCK_SCHED; - pid = 0; - } - if (pid == 0) { - p = td->td_proc; - PROC_LOCK(p); - } else { - error = pget(pid, PGET_CANSEE, &p); - if (error != 0) - return (EINVAL); - } - switch (clockwhich) { - case LINUX_CPUCLOCK_PROF: - PROC_STATLOCK(p); - calcru(p, &ru.ru_utime, &ru.ru_stime); - PROC_STATUNLOCK(p); - PROC_UNLOCK(p); - timevaladd(&ru.ru_utime, &ru.ru_stime); - TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); - break; - case LINUX_CPUCLOCK_VIRT: - PROC_STATLOCK(p); - calcru(p, &ru.ru_utime, &ru.ru_stime); - PROC_STATUNLOCK(p); - PROC_UNLOCK(p); - TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); - break; - case LINUX_CPUCLOCK_SCHED: - kern_process_cputime(p, tp); - PROC_UNLOCK(p); - break; - default: - PROC_UNLOCK(p); - return (EINVAL); - } - - break; - - case CLOCK_THREAD_CPUTIME_ID: - if (which < 0) { - clockwhich = LINUX_CPUCLOCK_WHICH(which); - tid = LINUX_CPUCLOCK_ID(which); - } else { - clockwhich = LINUX_CPUCLOCK_SCHED; - tid = 0; - } - p = td->td_proc; - if (tid == 0) { - targettd = td; - PROC_LOCK(p); - } else { - targettd = linux_tdfind(td, tid, p->p_pid); - if (targettd == NULL) - return (EINVAL); - } - switch (clockwhich) { - case LINUX_CPUCLOCK_PROF: - PROC_STATLOCK(p); - thread_lock(targettd); - rufetchtd(targettd, &ru); - thread_unlock(targettd); - PROC_STATUNLOCK(p); - PROC_UNLOCK(p); - timevaladd(&ru.ru_utime, &ru.ru_stime); - TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); - break; - case LINUX_CPUCLOCK_VIRT: - PROC_STATLOCK(p); - thread_lock(targettd); - rufetchtd(targettd, &ru); - thread_unlock(targettd); - PROC_STATUNLOCK(p); - PROC_UNLOCK(p); - TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); - break; - case LINUX_CPUCLOCK_SCHED: - if (td == targettd) - targettd = NULL; - kern_thread_cputime(targettd, tp); - PROC_UNLOCK(p); - break; - default: - PROC_UNLOCK(p); - return (EINVAL); - } - break; - - default: - error = kern_clock_gettime(td, nwhich, tp); - break; - } - - return (error); -} - -int -linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args) -{ - struct timespec tp; - int error; - - error = linux_common_clock_gettime(td, args->which, &tp); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); - return (error); - } - error = linux_put_timespec(&tp, args->tp); - if (error != 0) - LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error); - - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_clock_gettime64(struct thread *td, struct linux_clock_gettime64_args *args) -{ - struct timespec tp; - int error; - - error = linux_common_clock_gettime(td, args->which, &tp); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_clock_gettime64, gettime_error, error); - return (error); - } - error = linux_put_timespec64(&tp, args->tp); - if (error != 0) - LIN_SDT_PROBE1(time, linux_clock_gettime64, copyout_error, error); - - return (error); -} -#endif - -static int -linux_common_clock_settime(struct thread *td, clockid_t which, - struct timespec *ts) -{ - int error; - clockid_t nwhich; - - error = linux_to_native_clockid(&nwhich, which); - if (error != 0) { - linux_msg(curthread, - "unsupported clock_settime clockid %d", which); - LIN_SDT_PROBE1(time, linux_common_clock_settime, conversion_error, - error); - return (error); - } - - error = kern_clock_settime(td, nwhich, ts); - if (error != 0) - LIN_SDT_PROBE1(time, linux_common_clock_settime, - settime_error, error); - - return (error); -} - -int -linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args) -{ - struct timespec ts; - int error; - - error = linux_get_timespec(&ts, args->tp); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error); - return (error); - } - return (linux_common_clock_settime(td, args->which, &ts)); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_clock_settime64(struct thread *td, struct linux_clock_settime64_args *args) -{ - struct timespec ts; - int error; - - error = linux_get_timespec64(&ts, args->tp); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_clock_settime64, copyin_error, error); - return (error); - } - return (linux_common_clock_settime(td, args->which, &ts)); -} -#endif - -static int -linux_common_clock_getres(struct thread *td, clockid_t which, - struct timespec *ts) -{ - struct proc *p; - int error, clockwhich; - clockid_t nwhich; - pid_t pid; - lwpid_t tid; - - error = linux_to_native_clockid(&nwhich, which); - if (error != 0) { - linux_msg(curthread, - "unsupported clock_getres clockid %d", which); - LIN_SDT_PROBE1(time, linux_common_clock_getres, - conversion_error, error); - return (error); - } - - /* - * Check user supplied clock id in case of per-process - * or thread-specific cpu-time clock. - */ - if (which < 0) { - switch (nwhich) { - case CLOCK_THREAD_CPUTIME_ID: - tid = LINUX_CPUCLOCK_ID(which); - if (tid != 0) { - p = td->td_proc; - if (linux_tdfind(td, tid, p->p_pid) == NULL) - return (EINVAL); - PROC_UNLOCK(p); - } - break; - case CLOCK_PROCESS_CPUTIME_ID: - pid = LINUX_CPUCLOCK_ID(which); - if (pid != 0) { - error = pget(pid, PGET_CANSEE, &p); - if (error != 0) - return (EINVAL); - PROC_UNLOCK(p); - } - break; - } - } - - if (ts == NULL) { - LIN_SDT_PROBE0(time, linux_common_clock_getres, nullcall); - return (0); - } - - switch (nwhich) { - case CLOCK_THREAD_CPUTIME_ID: - case CLOCK_PROCESS_CPUTIME_ID: - clockwhich = LINUX_CPUCLOCK_WHICH(which); - /* - * In both cases (when the clock id obtained by a call to - * clock_getcpuclockid() or using the clock - * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision - * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock. - * - * See Linux posix_cpu_clock_getres() implementation. - */ - if (which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) { - ts->tv_sec = 0; - ts->tv_nsec = 1; - goto out; - } - - switch (clockwhich) { - case LINUX_CPUCLOCK_PROF: - nwhich = CLOCK_PROF; - break; - case LINUX_CPUCLOCK_VIRT: - nwhich = CLOCK_VIRTUAL; - break; - default: - return (EINVAL); - } - break; - - default: - break; - } - error = kern_clock_getres(td, nwhich, ts); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_common_clock_getres, - getres_error, error); - return (error); - } - -out: - return (error); -} - -int -linux_clock_getres(struct thread *td, - struct linux_clock_getres_args *args) -{ - struct timespec ts; - int error; - - error = linux_common_clock_getres(td, args->which, &ts); - if (error != 0 || args->tp == NULL) - return (error); - error = linux_put_timespec(&ts, args->tp); - if (error != 0) - LIN_SDT_PROBE1(time, linux_clock_getres, - copyout_error, error); - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_clock_getres_time64(struct thread *td, - struct linux_clock_getres_time64_args *args) -{ - struct timespec ts; - int error; - - error = linux_common_clock_getres(td, args->which, &ts); - if (error != 0 || args->tp == NULL) - return (error); - error = linux_put_timespec64(&ts, args->tp); - if (error != 0) - LIN_SDT_PROBE1(time, linux_clock_getres_time64, - copyout_error, error); - return (error); -} -#endif - -int -linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args) -{ - struct timespec *rmtp; - struct timespec rqts, rmts; - int error, error2; - - error = linux_get_timespec(&rqts, args->rqtp); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error); - return (error); - } - if (args->rmtp != NULL) - rmtp = &rmts; - else - rmtp = NULL; - - error = kern_nanosleep(td, &rqts, rmtp); - if (error == EINTR && args->rmtp != NULL) { - error2 = linux_put_timespec(rmtp, args->rmtp); - if (error2 != 0) { - LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, - error2); - return (error2); - } - } - - return (error); -} - -static int -linux_common_clock_nanosleep(struct thread *td, clockid_t which, - l_int lflags, struct timespec *rqtp, struct timespec *rmtp) -{ - int error, flags; - clockid_t clockid; - - error = linux_to_native_timerflags(&flags, lflags); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_common_clock_nanosleep, - unsupported_flags, lflags); - return (error); - } - - error = linux_to_native_clockid(&clockid, which); - if (error != 0) { - linux_msg(curthread, - "unsupported clock_nanosleep clockid %d", which); - LIN_SDT_PROBE1(time, linux_common_clock_nanosleep, - unsupported_clockid, which); - return (error); - } - if (clockid == CLOCK_THREAD_CPUTIME_ID) - return (ENOTSUP); - - return (kern_clock_nanosleep(td, clockid, flags, rqtp, rmtp)); -} - -int -linux_clock_nanosleep(struct thread *td, - struct linux_clock_nanosleep_args *args) -{ - struct timespec *rmtp; - struct timespec rqts, rmts; - int error, error2; - - error = linux_get_timespec(&rqts, args->rqtp); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error, - error); - return (error); - } - if (args->rmtp != NULL) - rmtp = &rmts; - else - rmtp = NULL; - - error = linux_common_clock_nanosleep(td, args->which, args->flags, - &rqts, rmtp); - if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 && - args->rmtp != NULL) { - error2 = linux_put_timespec(rmtp, args->rmtp); - if (error2 != 0) { - LIN_SDT_PROBE1(time, linux_clock_nanosleep, - copyout_error, error2); - return (error2); - } - } - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_clock_nanosleep_time64(struct thread *td, - struct linux_clock_nanosleep_time64_args *args) -{ - struct timespec *rmtp; - struct timespec rqts, rmts; - int error, error2; - - error = linux_get_timespec64(&rqts, args->rqtp); - if (error != 0) { - LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64, - copyin_error, error); - return (error); - } - if (args->rmtp != NULL) - rmtp = &rmts; - else - rmtp = NULL; - - error = linux_common_clock_nanosleep(td, args->which, args->flags, - &rqts, rmtp); - if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 && - args->rmtp != NULL) { - error2 = linux_put_timespec64(rmtp, args->rmtp); - if (error2 != 0) { - LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64, - copyout_error, error2); - return (error2); - } - } - return (error); -} -#endif +/* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Emmanuel Dreyfus. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +#if 0 +__KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $"); +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid, + "clockid_t"); +LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid, + "clockid_t"); +LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_gettime, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int"); +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, gettime_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, copyout_error, "int"); +#endif +LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, settime_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int"); +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, copyin_error, "int"); +#endif +LIN_SDT_PROBE_DEFINE0(time, linux_common_clock_getres, nullcall); +LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, getres_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int"); +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres_time64, copyout_error, "int"); +#endif +LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_flags, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_clockid, "int"); +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyin_error, "int"); +#endif + +static int linux_common_clock_gettime(struct thread *, clockid_t, + struct timespec *); +static int linux_common_clock_settime(struct thread *, clockid_t, + struct timespec *); +static int linux_common_clock_getres(struct thread *, clockid_t, + struct timespec *); +static int linux_common_clock_nanosleep(struct thread *, clockid_t, + l_int, struct timespec *, struct timespec *); + +int +native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) +{ + +#ifdef COMPAT_LINUX32 + if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN) + return (EOVERFLOW); +#endif + ltp->tv_sec = ntp->tv_sec; + ltp->tv_nsec = ntp->tv_nsec; + + return (0); +} + +int +linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp) +{ + + if (!timespecvalid_interval(ltp)) + return (EINVAL); + ntp->tv_sec = ltp->tv_sec; + ntp->tv_nsec = ltp->tv_nsec; + + return (0); +} + +int +linux_put_timespec(struct timespec *ntp, struct l_timespec * __linuxcap ltp) +{ + struct l_timespec lts; + int error; + + error = native_to_linux_timespec(<s, ntp); + if (error != 0) + return (error); + return (copyout(<s, LINUX_USER_CAP_OBJ(ltp), sizeof(lts))); +} + +int +linux_get_timespec(struct timespec *ntp, const struct l_timespec * __linuxcap ultp) +{ + struct l_timespec lts; + int error; + + error = copyin(LINUX_USER_CAP_OBJ(ultp), <s, sizeof(lts)); + if (error != 0) + return (error); + return (linux_to_native_timespec(ntp, <s)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +native_to_linux_timespec64(struct l_timespec64 *ltp64, struct timespec *ntp) +{ + + ltp64->tv_sec = ntp->tv_sec; + ltp64->tv_nsec = ntp->tv_nsec; + + return (0); +} + +int +linux_to_native_timespec64(struct timespec *ntp, struct l_timespec64 *ltp64) +{ + +#if defined(__i386__) + /* i386 time_t is still 32-bit */ + if (ltp64->tv_sec > INT_MAX || ltp64->tv_sec < INT_MIN) + return (EOVERFLOW); +#endif + /* Zero out the padding in compat mode. */ + ntp->tv_nsec = ltp64->tv_nsec & 0xFFFFFFFFUL; + ntp->tv_sec = ltp64->tv_sec; + + if (!timespecvalid_interval(ntp)) + return (EINVAL); + + return (0); +} + +int +linux_put_timespec64(struct timespec *ntp, struct l_timespec64 *ltp) +{ + struct l_timespec64 lts; + int error; + + error = native_to_linux_timespec64(<s, ntp); + if (error != 0) + return (error); + return (copyout(<s, LINUX_USER_CAP_OBJ(ltp), sizeof(lts))); +} + +int +linux_get_timespec64(struct timespec *ntp, const struct l_timespec64 *ultp) +{ + struct l_timespec64 lts; + int error; + + error = copyin(LINUX_USER_CAP_OBJ(ultp), <s, sizeof(lts)); + if (error != 0) + return (error); + return (linux_to_native_timespec64(ntp, <s)); +} +#endif + +int +native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp) +{ + int error; + + error = native_to_linux_timespec(<p->it_interval, &ntp->it_interval); + if (error == 0) + error = native_to_linux_timespec(<p->it_value, &ntp->it_value); + return (error); +} + +int +linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp) +{ + int error; + + error = linux_to_native_timespec(&ntp->it_interval, <p->it_interval); + if (error == 0) + error = linux_to_native_timespec(&ntp->it_value, <p->it_value); + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_to_native_itimerspec64(struct itimerspec *ntp, struct l_itimerspec64 *ltp) +{ + int error; + + error = linux_to_native_timespec64(&ntp->it_interval, <p->it_interval); + if (error == 0) + error = linux_to_native_timespec64(&ntp->it_value, <p->it_value); + return (error); +} + +int +native_to_linux_itimerspec64(struct l_itimerspec64 *ltp, struct itimerspec *ntp) +{ + int error; + + error = native_to_linux_timespec64(<p->it_interval, &ntp->it_interval); + if (error == 0) + error = native_to_linux_timespec64(<p->it_value, &ntp->it_value); + return (error); +} +#endif + +int +linux_to_native_clockid(clockid_t *n, clockid_t l) +{ + + if (l < 0) { + /* cpu-clock */ + if (LINUX_CPUCLOCK_WHICH(l) == LINUX_CLOCKFD) { + LIN_SDT_PROBE1(time, linux_to_native_clockid, + unsupported_clockid, l); + return (ENOTSUP); + } + if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD_MASK) + return (EINVAL); + + if (LINUX_CPUCLOCK_PERTHREAD(l)) + *n = CLOCK_THREAD_CPUTIME_ID; + else + *n = CLOCK_PROCESS_CPUTIME_ID; + return (0); + } + + switch (l) { + case LINUX_CLOCK_REALTIME: + *n = CLOCK_REALTIME; + break; + case LINUX_CLOCK_MONOTONIC: + *n = CLOCK_UPTIME; + break; + case LINUX_CLOCK_PROCESS_CPUTIME_ID: + *n = CLOCK_PROCESS_CPUTIME_ID; + break; + case LINUX_CLOCK_THREAD_CPUTIME_ID: + *n = CLOCK_THREAD_CPUTIME_ID; + break; + case LINUX_CLOCK_REALTIME_COARSE: + *n = CLOCK_REALTIME_FAST; + break; + case LINUX_CLOCK_MONOTONIC_COARSE: + case LINUX_CLOCK_MONOTONIC_RAW: + *n = CLOCK_UPTIME_FAST; + break; + case LINUX_CLOCK_BOOTTIME: + *n = CLOCK_MONOTONIC; + break; + case LINUX_CLOCK_REALTIME_ALARM: + case LINUX_CLOCK_BOOTTIME_ALARM: + case LINUX_CLOCK_SGI_CYCLE: + case LINUX_CLOCK_TAI: + LIN_SDT_PROBE1(time, linux_to_native_clockid, + unsupported_clockid, l); + return (ENOTSUP); + default: + LIN_SDT_PROBE1(time, linux_to_native_clockid, + unknown_clockid, l); + return (ENOTSUP); + } + + return (0); +} + +int +linux_to_native_timerflags(int *nflags, int flags) +{ + + if (flags & ~LINUX_TIMER_ABSTIME) + return (EINVAL); + *nflags = 0; + if (flags & LINUX_TIMER_ABSTIME) + *nflags |= TIMER_ABSTIME; + return (0); +} + +static int +linux_common_clock_gettime(struct thread *td, clockid_t which, + struct timespec *tp) +{ + struct rusage ru; + struct thread *targettd; + struct proc *p; + int error, clockwhich; + clockid_t nwhich; + pid_t pid; + lwpid_t tid; + + error = linux_to_native_clockid(&nwhich, which); + if (error != 0) { + linux_msg(curthread, + "unsupported clock_gettime clockid %d", which); + LIN_SDT_PROBE1(time, linux_common_clock_gettime, + conversion_error, error); + return (error); + } + + switch (nwhich) { + case CLOCK_PROCESS_CPUTIME_ID: + if (which < 0) { + clockwhich = LINUX_CPUCLOCK_WHICH(which); + pid = LINUX_CPUCLOCK_ID(which); + } else { + clockwhich = LINUX_CPUCLOCK_SCHED; + pid = 0; + } + if (pid == 0) { + p = td->td_proc; + PROC_LOCK(p); + } else { + error = pget(pid, PGET_CANSEE, &p); + if (error != 0) + return (EINVAL); + } + switch (clockwhich) { + case LINUX_CPUCLOCK_PROF: + PROC_STATLOCK(p); + calcru(p, &ru.ru_utime, &ru.ru_stime); + PROC_STATUNLOCK(p); + PROC_UNLOCK(p); + timevaladd(&ru.ru_utime, &ru.ru_stime); + TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); + break; + case LINUX_CPUCLOCK_VIRT: + PROC_STATLOCK(p); + calcru(p, &ru.ru_utime, &ru.ru_stime); + PROC_STATUNLOCK(p); + PROC_UNLOCK(p); + TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); + break; + case LINUX_CPUCLOCK_SCHED: + kern_process_cputime(p, tp); + PROC_UNLOCK(p); + break; + default: + PROC_UNLOCK(p); + return (EINVAL); + } + + break; + + case CLOCK_THREAD_CPUTIME_ID: + if (which < 0) { + clockwhich = LINUX_CPUCLOCK_WHICH(which); + tid = LINUX_CPUCLOCK_ID(which); + } else { + clockwhich = LINUX_CPUCLOCK_SCHED; + tid = 0; + } + p = td->td_proc; + if (tid == 0) { + targettd = td; + PROC_LOCK(p); + } else { + targettd = linux_tdfind(td, tid, p->p_pid); + if (targettd == NULL) + return (EINVAL); + } + switch (clockwhich) { + case LINUX_CPUCLOCK_PROF: + PROC_STATLOCK(p); + thread_lock(targettd); + rufetchtd(targettd, &ru); + thread_unlock(targettd); + PROC_STATUNLOCK(p); + PROC_UNLOCK(p); + timevaladd(&ru.ru_utime, &ru.ru_stime); + TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); + break; + case LINUX_CPUCLOCK_VIRT: + PROC_STATLOCK(p); + thread_lock(targettd); + rufetchtd(targettd, &ru); + thread_unlock(targettd); + PROC_STATUNLOCK(p); + PROC_UNLOCK(p); + TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); + break; + case LINUX_CPUCLOCK_SCHED: + if (td == targettd) + targettd = NULL; + kern_thread_cputime(targettd, tp); + PROC_UNLOCK(p); + break; + default: + PROC_UNLOCK(p); + return (EINVAL); + } + break; + + default: + error = kern_clock_gettime(td, nwhich, tp); + break; + } + + return (error); +} + +int +linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args) +{ + struct timespec tp; + int error; + + error = linux_common_clock_gettime(td, args->which, &tp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); + return (error); + } + error = linux_put_timespec(&tp, args->tp); + if (error != 0) + LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error); + + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_clock_gettime64(struct thread *td, struct linux_clock_gettime64_args *args) +{ + struct timespec tp; + int error; + + error = linux_common_clock_gettime(td, args->which, &tp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_gettime64, gettime_error, error); + return (error); + } + error = linux_put_timespec64(&tp, args->tp); + if (error != 0) + LIN_SDT_PROBE1(time, linux_clock_gettime64, copyout_error, error); + + return (error); +} +#endif + +static int +linux_common_clock_settime(struct thread *td, clockid_t which, + struct timespec *ts) +{ + int error; + clockid_t nwhich; + + error = linux_to_native_clockid(&nwhich, which); + if (error != 0) { + linux_msg(curthread, + "unsupported clock_settime clockid %d", which); + LIN_SDT_PROBE1(time, linux_common_clock_settime, conversion_error, + error); + return (error); + } + + error = kern_clock_settime(td, nwhich, ts); + if (error != 0) + LIN_SDT_PROBE1(time, linux_common_clock_settime, + settime_error, error); + + return (error); +} + +int +linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args) +{ + struct timespec ts; + int error; + + error = linux_get_timespec(&ts, args->tp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error); + return (error); + } + return (linux_common_clock_settime(td, args->which, &ts)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_clock_settime64(struct thread *td, struct linux_clock_settime64_args *args) +{ + struct timespec ts; + int error; + + error = linux_get_timespec64(&ts, args->tp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_settime64, copyin_error, error); + return (error); + } + return (linux_common_clock_settime(td, args->which, &ts)); +} +#endif + +static int +linux_common_clock_getres(struct thread *td, clockid_t which, + struct timespec *ts) +{ + struct proc *p; + int error, clockwhich; + clockid_t nwhich; + pid_t pid; + lwpid_t tid; + + error = linux_to_native_clockid(&nwhich, which); + if (error != 0) { + linux_msg(curthread, + "unsupported clock_getres clockid %d", which); + LIN_SDT_PROBE1(time, linux_common_clock_getres, + conversion_error, error); + return (error); + } + + /* + * Check user supplied clock id in case of per-process + * or thread-specific cpu-time clock. + */ + if (which < 0) { + switch (nwhich) { + case CLOCK_THREAD_CPUTIME_ID: + tid = LINUX_CPUCLOCK_ID(which); + if (tid != 0) { + p = td->td_proc; + if (linux_tdfind(td, tid, p->p_pid) == NULL) + return (EINVAL); + PROC_UNLOCK(p); + } + break; + case CLOCK_PROCESS_CPUTIME_ID: + pid = LINUX_CPUCLOCK_ID(which); + if (pid != 0) { + error = pget(pid, PGET_CANSEE, &p); + if (error != 0) + return (EINVAL); + PROC_UNLOCK(p); + } + break; + } + } + + if (ts == NULL) { + LIN_SDT_PROBE0(time, linux_common_clock_getres, nullcall); + return (0); + } + + switch (nwhich) { + case CLOCK_THREAD_CPUTIME_ID: + case CLOCK_PROCESS_CPUTIME_ID: + clockwhich = LINUX_CPUCLOCK_WHICH(which); + /* + * In both cases (when the clock id obtained by a call to + * clock_getcpuclockid() or using the clock + * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision + * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock. + * + * See Linux posix_cpu_clock_getres() implementation. + */ + if (which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) { + ts->tv_sec = 0; + ts->tv_nsec = 1; + goto out; + } + + switch (clockwhich) { + case LINUX_CPUCLOCK_PROF: + nwhich = CLOCK_PROF; + break; + case LINUX_CPUCLOCK_VIRT: + nwhich = CLOCK_VIRTUAL; + break; + default: + return (EINVAL); + } + break; + + default: + break; + } + error = kern_clock_getres(td, nwhich, ts); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_common_clock_getres, + getres_error, error); + return (error); + } + +out: + return (error); +} + +int +linux_clock_getres(struct thread *td, + struct linux_clock_getres_args *args) +{ + struct timespec ts; + int error; + + error = linux_common_clock_getres(td, args->which, &ts); + if (error != 0 || args->tp == NULL) + return (error); + error = linux_put_timespec(&ts, args->tp); + if (error != 0) + LIN_SDT_PROBE1(time, linux_clock_getres, + copyout_error, error); + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_clock_getres_time64(struct thread *td, + struct linux_clock_getres_time64_args *args) +{ + struct timespec ts; + int error; + + error = linux_common_clock_getres(td, args->which, &ts); + if (error != 0 || args->tp == NULL) + return (error); + error = linux_put_timespec64(&ts, args->tp); + if (error != 0) + LIN_SDT_PROBE1(time, linux_clock_getres_time64, + copyout_error, error); + return (error); +} +#endif + +int +linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args) +{ + struct timespec *rmtp; + struct timespec rqts, rmts; + int error, error2; + + error = linux_get_timespec(&rqts, args->rqtp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error); + return (error); + } + if (args->rmtp != NULL) + rmtp = &rmts; + else + rmtp = NULL; + + error = kern_nanosleep(td, &rqts, rmtp); + if (error == EINTR && args->rmtp != NULL) { + error2 = linux_put_timespec(rmtp, args->rmtp); + if (error2 != 0) { + LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, + error2); + return (error2); + } + } + + return (error); +} + +static int +linux_common_clock_nanosleep(struct thread *td, clockid_t which, + l_int lflags, struct timespec *rqtp, struct timespec *rmtp) +{ + int error, flags; + clockid_t clockid; + + error = linux_to_native_timerflags(&flags, lflags); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_common_clock_nanosleep, + unsupported_flags, lflags); + return (error); + } + + error = linux_to_native_clockid(&clockid, which); + if (error != 0) { + linux_msg(curthread, + "unsupported clock_nanosleep clockid %d", which); + LIN_SDT_PROBE1(time, linux_common_clock_nanosleep, + unsupported_clockid, which); + return (error); + } + if (clockid == CLOCK_THREAD_CPUTIME_ID) + return (ENOTSUP); + + return (kern_clock_nanosleep(td, clockid, flags, rqtp, rmtp)); +} + +int +linux_clock_nanosleep(struct thread *td, + struct linux_clock_nanosleep_args *args) +{ + struct timespec *rmtp; + struct timespec rqts, rmts; + int error, error2; + + error = linux_get_timespec(&rqts, args->rqtp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error, + error); + return (error); + } + if (args->rmtp != NULL) + rmtp = &rmts; + else + rmtp = NULL; + + error = linux_common_clock_nanosleep(td, args->which, args->flags, + &rqts, rmtp); + if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 && + args->rmtp != NULL) { + error2 = linux_put_timespec(rmtp, args->rmtp); + if (error2 != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, + copyout_error, error2); + return (error2); + } + } + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_clock_nanosleep_time64(struct thread *td, + struct linux_clock_nanosleep_time64_args *args) +{ + struct timespec *rmtp; + struct timespec rqts, rmts; + int error, error2; + + error = linux_get_timespec64(&rqts, args->rqtp); + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64, + copyin_error, error); + return (error); + } + if (args->rmtp != NULL) + rmtp = &rmts; + else + rmtp = NULL; + + error = linux_common_clock_nanosleep(td, args->which, args->flags, + &rqts, rmtp); + if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 && + args->rmtp != NULL) { + error2 = linux_put_timespec64(rmtp, args->rmtp); + if (error2 != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64, + copyout_error, error2); + return (error2); + } + } + return (error); +} +#endif + +int +linux_gettimeofday(struct thread *td, + struct linux_gettimeofday_args *args) +{ + + return (kern_gettimeofday(td, LINUX_USER_CAP_OBJ(args->tp), LINUX_USER_CAP_OBJ(args->tzp))); +} + +int +linux_settimeofday(struct thread *td, + struct linux_settimeofday_args *args) +{ + + return (user_settimeofday(td, LINUX_USER_CAP_OBJ(args->tv), LINUX_USER_CAP_OBJ(args->tzp))); +} diff --git a/sys/compat/linux/linux_time.h b/sys/compat/linux/linux_time.h index bb23105f4f23..49b62d3b8479 100644 --- a/sys/compat/linux/linux_time.h +++ b/sys/compat/linux/linux_time.h @@ -1,143 +1,143 @@ -/*- - * Copyright (c) 2014 Bjoern A. Zeeb - * All rights reserved. - * - * This software was developed by SRI International and the University of - * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 - * ("MRC2"), as part of the DARPA MRC research programme. - * - * 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. - */ - -#ifndef _LINUX_TIME_H -#define _LINUX_TIME_H - -#ifndef __LINUX_ARCH_SIGEV_PREAMBLE_SIZE -#define __LINUX_ARCH_SIGEV_PREAMBLE_SIZE \ - (sizeof(l_int) * 2 + sizeof(l_sigval_t)) -#endif - -#define LINUX_SIGEV_MAX_SIZE 64 -#define LINUX_SIGEV_PAD_SIZE \ - ((LINUX_SIGEV_MAX_SIZE - __LINUX_ARCH_SIGEV_PREAMBLE_SIZE) / \ - sizeof(l_int)) - -#define LINUX_CLOCK_REALTIME 0 -#define LINUX_CLOCK_MONOTONIC 1 -#define LINUX_CLOCK_PROCESS_CPUTIME_ID 2 -#define LINUX_CLOCK_THREAD_CPUTIME_ID 3 -#define LINUX_CLOCK_MONOTONIC_RAW 4 -#define LINUX_CLOCK_REALTIME_COARSE 5 -#define LINUX_CLOCK_MONOTONIC_COARSE 6 -#define LINUX_CLOCK_BOOTTIME 7 -#define LINUX_CLOCK_REALTIME_ALARM 8 -#define LINUX_CLOCK_BOOTTIME_ALARM 9 -#define LINUX_CLOCK_SGI_CYCLE 10 -#define LINUX_CLOCK_TAI 11 - -#define LINUX_CPUCLOCK_PERTHREAD_MASK 4 -#define LINUX_CPUCLOCK_MASK 3 -#define LINUX_CPUCLOCK_WHICH(clock) \ - ((clock) & (clockid_t) LINUX_CPUCLOCK_MASK) -#define LINUX_CPUCLOCK_PROF 0 -#define LINUX_CPUCLOCK_VIRT 1 -#define LINUX_CPUCLOCK_SCHED 2 -#define LINUX_CPUCLOCK_MAX 3 -#define LINUX_CLOCKFD LINUX_CPUCLOCK_MAX -#define LINUX_CLOCKFD_MASK \ - (LINUX_CPUCLOCK_PERTHREAD_MASK|LINUX_CPUCLOCK_MASK) - -#define LINUX_CPUCLOCK_ID(clock) ((pid_t) ~((clock) >> 3)) -#define LINUX_CPUCLOCK_PERTHREAD(clock) \ - (((clock) & (clockid_t) LINUX_CPUCLOCK_PERTHREAD_MASK) != 0) - -#define LINUX_TIMER_ABSTIME 0x01 - -#define L_SIGEV_SIGNAL 0 -#define L_SIGEV_NONE 1 -#define L_SIGEV_THREAD 2 -#define L_SIGEV_THREAD_ID 4 - -struct l_sigevent { - l_sigval_t sigev_value; - l_int sigev_signo; - l_int sigev_notify; - union { - l_int _pad[LINUX_SIGEV_PAD_SIZE]; - l_int _tid; - struct { - l_uintptr_t _function; - l_uintptr_t _attribute; - } _l_sigev_thread; - } _l_sigev_un; -} -#if defined(__amd64__) && defined(COMPAT_LINUX32) -__packed -#endif -; - -struct l_itimerspec { - struct l_timespec it_interval; - struct l_timespec it_value; -}; - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -struct l_itimerspec64 { - struct l_timespec64 it_interval; - struct l_timespec64 it_value; -}; -#endif - -int native_to_linux_timespec(struct l_timespec *, - struct timespec *); -int linux_to_native_timespec(struct timespec *, - struct l_timespec *); -int linux_put_timespec(struct timespec *, - struct l_timespec *); -int linux_get_timespec(struct timespec *, - const struct l_timespec *); -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int native_to_linux_timespec64(struct l_timespec64 *, - struct timespec *); -int linux_to_native_timespec64(struct timespec *, - struct l_timespec64 *); -int linux_put_timespec64(struct timespec *, - struct l_timespec64 *); -int linux_get_timespec64(struct timespec *, - const struct l_timespec64 *); -#endif -int linux_to_native_clockid(clockid_t *, clockid_t); -int native_to_linux_itimerspec(struct l_itimerspec *, - struct itimerspec *); -int linux_to_native_itimerspec(struct itimerspec *, - struct l_itimerspec *); -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int native_to_linux_itimerspec64(struct l_itimerspec64 *, - struct itimerspec *); -int linux_to_native_itimerspec64(struct itimerspec *, - struct l_itimerspec64 *); -#endif - -int linux_convert_l_sigevent(const struct l_sigevent *l_sig, struct sigevent *sig); -int linux_to_native_timerflags(int *, int); - -#endif /* _LINUX_TIME_H */ +/*- + * Copyright (c) 2014 Bjoern A. Zeeb + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 + * ("MRC2"), as part of the DARPA MRC research programme. + * + * 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. + */ + +#ifndef _LINUX_TIME_H +#define _LINUX_TIME_H + +#ifndef __LINUX_ARCH_SIGEV_PREAMBLE_SIZE +#define __LINUX_ARCH_SIGEV_PREAMBLE_SIZE \ + roundup((sizeof(l_int) * 2 + sizeof(l_sigval_t)), sizeof(l_uintptr_t)) +#endif + +#define LINUX_SIGEV_MAX_SIZE 64 +#define LINUX_SIGEV_PAD_SIZE \ + ((LINUX_SIGEV_MAX_SIZE - __LINUX_ARCH_SIGEV_PREAMBLE_SIZE) / \ + sizeof(l_int)) + +#define LINUX_CLOCK_REALTIME 0 +#define LINUX_CLOCK_MONOTONIC 1 +#define LINUX_CLOCK_PROCESS_CPUTIME_ID 2 +#define LINUX_CLOCK_THREAD_CPUTIME_ID 3 +#define LINUX_CLOCK_MONOTONIC_RAW 4 +#define LINUX_CLOCK_REALTIME_COARSE 5 +#define LINUX_CLOCK_MONOTONIC_COARSE 6 +#define LINUX_CLOCK_BOOTTIME 7 +#define LINUX_CLOCK_REALTIME_ALARM 8 +#define LINUX_CLOCK_BOOTTIME_ALARM 9 +#define LINUX_CLOCK_SGI_CYCLE 10 +#define LINUX_CLOCK_TAI 11 + +#define LINUX_CPUCLOCK_PERTHREAD_MASK 4 +#define LINUX_CPUCLOCK_MASK 3 +#define LINUX_CPUCLOCK_WHICH(clock) \ + ((clock) & (clockid_t) LINUX_CPUCLOCK_MASK) +#define LINUX_CPUCLOCK_PROF 0 +#define LINUX_CPUCLOCK_VIRT 1 +#define LINUX_CPUCLOCK_SCHED 2 +#define LINUX_CPUCLOCK_MAX 3 +#define LINUX_CLOCKFD LINUX_CPUCLOCK_MAX +#define LINUX_CLOCKFD_MASK \ + (LINUX_CPUCLOCK_PERTHREAD_MASK|LINUX_CPUCLOCK_MASK) + +#define LINUX_CPUCLOCK_ID(clock) ((pid_t) ~((clock) >> 3)) +#define LINUX_CPUCLOCK_PERTHREAD(clock) \ + (((clock) & (clockid_t) LINUX_CPUCLOCK_PERTHREAD_MASK) != 0) + +#define LINUX_TIMER_ABSTIME 0x01 + +#define L_SIGEV_SIGNAL 0 +#define L_SIGEV_NONE 1 +#define L_SIGEV_THREAD 2 +#define L_SIGEV_THREAD_ID 4 + +struct l_sigevent { + l_sigval_t sigev_value; + l_int sigev_signo; + l_int sigev_notify; + union { + l_int _pad[LINUX_SIGEV_PAD_SIZE]; + l_int _tid; + struct { + l_uintptr_t _function; + l_uintptr_t _attribute; + } _l_sigev_thread; + } _l_sigev_un; +} +#if defined(__amd64__) && defined(COMPAT_LINUX32) +__packed +#endif +; + +struct l_itimerspec { + struct l_timespec it_interval; + struct l_timespec it_value; +}; + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +struct l_itimerspec64 { + struct l_timespec64 it_interval; + struct l_timespec64 it_value; +}; +#endif + +int native_to_linux_timespec(struct l_timespec *, + struct timespec *); +int linux_to_native_timespec(struct timespec *, + struct l_timespec *); +int linux_put_timespec(struct timespec *, + struct l_timespec * __linuxcap); +int linux_get_timespec(struct timespec *, + const struct l_timespec * __linuxcap); +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int native_to_linux_timespec64(struct l_timespec64 *, + struct timespec *); +int linux_to_native_timespec64(struct timespec *, + struct l_timespec64 *); +int linux_put_timespec64(struct timespec *, + struct l_timespec64 *); +int linux_get_timespec64(struct timespec *, + const struct l_timespec64 *); +#endif +int linux_to_native_clockid(clockid_t *, clockid_t); +int native_to_linux_itimerspec(struct l_itimerspec *, + struct itimerspec *); +int linux_to_native_itimerspec(struct itimerspec *, + struct l_itimerspec *); +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int native_to_linux_itimerspec64(struct l_itimerspec64 *, + struct itimerspec *); +int linux_to_native_itimerspec64(struct itimerspec *, + struct l_itimerspec64 *); +#endif + +int linux_convert_l_sigevent(const struct l_sigevent *l_sig, struct sigevent *sig); +int linux_to_native_timerflags(int *, int); + +#endif /* _LINUX_TIME_H */ diff --git a/sys/compat/linux/linux_timer.c b/sys/compat/linux/linux_timer.c index ed9133359302..b56bc3160043 100644 --- a/sys/compat/linux/linux_timer.c +++ b/sys/compat/linux/linux_timer.c @@ -1,213 +1,216 @@ -/*- - * Copyright (c) 2014 Bjoern A. Zeeb - * All rights reserved. - * - * This software was developed by SRI International and the University of - * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 - * ("MRC2"), as part of the DARPA MRC research programme. - * - * 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 -#include -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif -#include - -int -linux_convert_l_sigevent(const struct l_sigevent *l_sig, struct sigevent *sig) -{ - - CP(*l_sig, *sig, sigev_notify); - switch (l_sig->sigev_notify) { - case L_SIGEV_SIGNAL: - if (!LINUX_SIG_VALID(l_sig->sigev_signo)) - return (EINVAL); - sig->sigev_notify = SIGEV_SIGNAL; - sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo); - PTRIN_CP(*l_sig, *sig, sigev_value.sival_ptr); - break; - case L_SIGEV_NONE: - sig->sigev_notify = SIGEV_NONE; - break; - case L_SIGEV_THREAD: -#if 0 - /* Seems to not be used anywhere (anymore)? */ - sig->sigev_notify = SIGEV_THREAD; - return (ENOSYS); -#else - return (EINVAL); -#endif - case L_SIGEV_THREAD_ID: - if (!LINUX_SIG_VALID(l_sig->sigev_signo)) - return (EINVAL); - sig->sigev_notify = SIGEV_THREAD_ID; - CP2(*l_sig, *sig, _l_sigev_un._tid, sigev_notify_thread_id); - sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo); - PTRIN_CP(*l_sig, *sig, sigev_value.sival_ptr); - break; - default: - return (EINVAL); - } - return (0); -} - -int -linux_timer_create(struct thread *td, struct linux_timer_create_args *uap) -{ - struct l_sigevent l_ev; - struct sigevent ev, *evp; - clockid_t nwhich; - int error, id; - - if (uap->evp == NULL) { - evp = NULL; - } else { - error = copyin(uap->evp, &l_ev, sizeof(l_ev)); - if (error != 0) - return (error); - error = linux_convert_l_sigevent(&l_ev, &ev); - if (error != 0) - return (error); - evp = &ev; - } - error = linux_to_native_clockid(&nwhich, uap->clock_id); - if (error != 0) - return (error); - error = kern_ktimer_create(td, nwhich, evp, &id, -1); - if (error == 0) { - error = copyout(&id, uap->timerid, sizeof(int)); - if (error != 0) - kern_ktimer_delete(td, id); - } - return (error); -} - -int -linux_timer_settime(struct thread *td, struct linux_timer_settime_args *uap) -{ - struct l_itimerspec l_val, l_oval; - struct itimerspec val, oval, *ovalp; - int flags, error; - - error = copyin(uap->new, &l_val, sizeof(l_val)); - if (error != 0) - return (error); - error = linux_to_native_itimerspec(&val, &l_val); - if (error != 0) - return (error); - ovalp = uap->old != NULL ? &oval : NULL; - error = linux_to_native_timerflags(&flags, uap->flags); - if (error != 0) - return (error); - error = kern_ktimer_settime(td, uap->timerid, flags, &val, ovalp); - if (error == 0 && uap->old != NULL) { - error = native_to_linux_itimerspec(&l_val, &val); - if (error == 0) - error = copyout(&l_oval, uap->old, sizeof(l_oval)); - } - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_timer_settime64(struct thread *td, struct linux_timer_settime64_args *uap) -{ - struct l_itimerspec64 l_val, l_oval; - struct itimerspec val, oval, *ovalp; - int flags, error; - - error = copyin(uap->new, &l_val, sizeof(l_val)); - if (error != 0) - return (error); - error = linux_to_native_itimerspec64(&val, &l_val); - if (error != 0) - return (error); - ovalp = uap->old != NULL ? &oval : NULL; - error = linux_to_native_timerflags(&flags, uap->flags); - if (error != 0) - return (error); - error = kern_ktimer_settime(td, uap->timerid, flags, &val, ovalp); - if (error == 0 && uap->old != NULL) { - error = native_to_linux_itimerspec64(&l_val, &val); - if (error == 0) - error = copyout(&l_oval, uap->old, sizeof(l_oval)); - } - return (error); -} -#endif - -int -linux_timer_gettime(struct thread *td, struct linux_timer_gettime_args *uap) -{ - struct l_itimerspec l_val; - struct itimerspec val; - int error; - - error = kern_ktimer_gettime(td, uap->timerid, &val); - if (error == 0) - error = native_to_linux_itimerspec(&l_val, &val); - if (error == 0) - error = copyout(&l_val, uap->setting, sizeof(l_val)); - return (error); -} - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -int -linux_timer_gettime64(struct thread *td, struct linux_timer_gettime64_args *uap) -{ - struct l_itimerspec64 l_val; - struct itimerspec val; - int error; - - error = kern_ktimer_gettime(td, uap->timerid, &val); - if (error == 0) - error = native_to_linux_itimerspec64(&l_val, &val); - if (error == 0) - error = copyout(&l_val, uap->setting, sizeof(l_val)); - return (error); -} -#endif - -int -linux_timer_getoverrun(struct thread *td, struct linux_timer_getoverrun_args *uap) -{ - - return (kern_ktimer_getoverrun(td, uap->timerid)); -} - -int -linux_timer_delete(struct thread *td, struct linux_timer_delete_args *uap) -{ - - return (kern_ktimer_delete(td, uap->timerid)); -} +/*- + * Copyright (c) 2014 Bjoern A. Zeeb + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 + * ("MRC2"), as part of the DARPA MRC research programme. + * + * 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 +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif +#include + +int +linux_convert_l_sigevent(const struct l_sigevent *l_sig, struct sigevent *sig) +{ + + CP(*l_sig, *sig, sigev_notify); + switch (l_sig->sigev_notify) { + case L_SIGEV_SIGNAL: + if (!LINUX_SIG_VALID(l_sig->sigev_signo)) + return (EINVAL); + sig->sigev_notify = SIGEV_SIGNAL; + sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo); + sig->sigev_value.sival_ptr = LINUX_USER_CODE_CAP(l_sig->sigev_value.sival_ptr); + break; + case L_SIGEV_NONE: + sig->sigev_notify = SIGEV_NONE; + break; + case L_SIGEV_THREAD: +#if 0 + /* Seems to not be used anywhere (anymore)? */ + sig->sigev_notify = SIGEV_THREAD; + return (ENOSYS); +#else + return (EINVAL); +#endif + case L_SIGEV_THREAD_ID: + if (!LINUX_SIG_VALID(l_sig->sigev_signo)) + return (EINVAL); + sig->sigev_notify = SIGEV_THREAD_ID; + CP2(*l_sig, *sig, _l_sigev_un._tid, sigev_notify_thread_id); + sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo); + sig->sigev_value.sival_ptr = LINUX_USER_CODE_CAP(l_sig->sigev_value.sival_ptr); + break; + default: + return (EINVAL); + } + return (0); +} + +int +linux_timer_create(struct thread *td, struct linux_timer_create_args *uap) +{ + struct l_sigevent l_ev; + struct sigevent ev, *evp; + clockid_t nwhich; + int error, id; + + if (uap->evp == NULL) { + evp = NULL; + } else { + error = copyincap(LINUX_USER_CAP_OBJ(uap->evp), &l_ev, sizeof(l_ev)); + if (error != 0) + return (error); + error = linux_convert_l_sigevent(&l_ev, &ev); + if (error != 0) + return (error); + evp = &ev; + } + error = linux_to_native_clockid(&nwhich, uap->clock_id); + if (error != 0) + return (error); + error = kern_ktimer_create(td, nwhich, evp, &id, -1); + if (error == 0) { + error = copyout(&id, LINUX_USER_CAP_OBJ(uap->timerid), sizeof(int)); + if (error != 0) + kern_ktimer_delete(td, id); + } + return (error); +} + +int +linux_timer_settime(struct thread *td, struct linux_timer_settime_args *uap) +{ + struct l_itimerspec l_val, l_oval; + struct itimerspec val, oval, *ovalp; + int flags, error; + + error = copyin(LINUX_USER_CAP(uap->new, sizeof(l_val)), &l_val, sizeof(l_val)); + if (error != 0) + return (error); + error = linux_to_native_itimerspec(&val, &l_val); + if (error != 0) + return (error); + ovalp = uap->old != NULL ? &oval : NULL; + error = linux_to_native_timerflags(&flags, uap->flags); + if (error != 0) + return (error); + error = kern_ktimer_settime(td, uap->timerid, flags, &val, ovalp); + if (error == 0 && uap->old != NULL) { + error = native_to_linux_itimerspec(&l_val, &val); + if (error == 0) + error = copyout(&l_oval, LINUX_USER_CAP(uap->old, sizeof(l_oval)), sizeof(l_oval)); + } + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_timer_settime64(struct thread *td, struct linux_timer_settime64_args *uap) +{ + struct l_itimerspec64 l_val, l_oval; + struct itimerspec val, oval, *ovalp; + int flags, error; + + error = copyin(LINUX_USER_CAP(uap->new, sizeof(l_val)), &l_val, sizeof(l_val)); + if (error != 0) + return (error); + error = linux_to_native_itimerspec64(&val, &l_val); + if (error != 0) + return (error); + ovalp = uap->old != NULL ? &oval : NULL; + error = linux_to_native_timerflags(&flags, uap->flags); + if (error != 0) + return (error); + error = kern_ktimer_settime(td, uap->timerid, flags, &val, ovalp); + if (error == 0 && uap->old != NULL) { + error = native_to_linux_itimerspec64(&l_val, &val); + if (error == 0) + error = copyout(&l_oval, LINUX_USER_CAP(uap->old, sizeof(l_oval)), sizeof(l_oval)); + } + return (error); +} +#endif + +int +linux_timer_gettime(struct thread *td, struct linux_timer_gettime_args *uap) +{ + struct l_itimerspec l_val; + struct itimerspec val; + int error; + + error = kern_ktimer_gettime(td, uap->timerid, &val); + if (error == 0) + error = native_to_linux_itimerspec(&l_val, &val); + if (error == 0) + error = copyout(&l_val, LINUX_USER_CAP(uap->setting, sizeof(l_val)), sizeof(l_val)); + return (error); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_timer_gettime64(struct thread *td, struct linux_timer_gettime64_args *uap) +{ + struct l_itimerspec64 l_val; + struct itimerspec val; + int error; + + error = kern_ktimer_gettime(td, uap->timerid, &val); + if (error == 0) + error = native_to_linux_itimerspec64(&l_val, &val); + if (error == 0) + error = copyout(&l_val, LINUX_USER_CAP(uap->setting, sizeof(l_val)), sizeof(l_val)); + return (error); +} +#endif + +int +linux_timer_getoverrun(struct thread *td, struct linux_timer_getoverrun_args *uap) +{ + + return (kern_ktimer_getoverrun(td, uap->timerid)); +} + +int +linux_timer_delete(struct thread *td, struct linux_timer_delete_args *uap) +{ + + return (kern_ktimer_delete(td, uap->timerid)); +} diff --git a/sys/compat/linux/linux_uid16.c b/sys/compat/linux/linux_uid16.c index 0a22c9f6ba0d..0139ef971d5b 100644 --- a/sys/compat/linux/linux_uid16.c +++ b/sys/compat/linux/linux_uid16.c @@ -1,320 +1,323 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2001 The FreeBSD Project - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif - -#include -#include - -/* DTrace init */ -LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); - -/** - * DTrace probes in this module. - */ -LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, conv_path, "char *"); -LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, conv_path, "char *"); -LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, copyin_error, "int"); -LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, priv_check_cred_error, "int"); -LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, copyout_error, "int"); - -DUMMY(setfsuid16); -DUMMY(setfsgid16); -DUMMY(getresuid16); -DUMMY(getresgid16); - -#define CAST_NOCHG(x) ((x == 0xFFFF) ? -1 : x) - -int -linux_chown16(struct thread *td, struct linux_chown16_args *args) -{ - - return (kern_fchownat(td, AT_FDCWD, __USER_CAP_PATH(args->path), - UIO_USERSPACE, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0)); -} - -int -linux_lchown16(struct thread *td, struct linux_lchown16_args *args) -{ - - return (kern_fchownat(td, AT_FDCWD, __USER_CAP_PATH(args->path), - UIO_USERSPACE, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), - AT_SYMLINK_NOFOLLOW)); -} - -int -linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args) -{ - struct ucred *newcred, *oldcred; - l_gid16_t *linux_gidset; - gid_t *bsd_gidset; - int ngrp, error; - struct proc *p; - - ngrp = args->gidsetsize; - if (ngrp < 0 || ngrp >= ngroups_max + 1) - return (EINVAL); - linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); - error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t)); - if (error) { - LIN_SDT_PROBE1(uid16, linux_setgroups16, copyin_error, error); - free(linux_gidset, M_LINUX); - return (error); - } - newcred = crget(); - p = td->td_proc; - PROC_LOCK(p); - oldcred = crcopysafe(p, newcred); - - /* - * cr_groups[0] holds egid. Setting the whole set from - * the supplied set will cause egid to be changed too. - * Keep cr_groups[0] unchanged to prevent that. - */ - - if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) { - PROC_UNLOCK(p); - crfree(newcred); - - LIN_SDT_PROBE1(uid16, linux_setgroups16, priv_check_cred_error, - error); - goto out; - } - - if (ngrp > 0) { - newcred->cr_ngroups = ngrp + 1; - - bsd_gidset = newcred->cr_groups; - ngrp--; - while (ngrp >= 0) { - bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; - ngrp--; - } - } - else - newcred->cr_ngroups = 1; - - setsugid(td->td_proc); - proc_set_cred(p, newcred); - PROC_UNLOCK(p); - crfree(oldcred); - error = 0; -out: - free(linux_gidset, M_LINUX); - - return (error); -} - -int -linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args) -{ - struct ucred *cred; - l_gid16_t *linux_gidset; - gid_t *bsd_gidset; - int bsd_gidsetsz, ngrp, error; - - cred = td->td_ucred; - bsd_gidset = cred->cr_groups; - bsd_gidsetsz = cred->cr_ngroups - 1; - - /* - * cr_groups[0] holds egid. Returning the whole set - * here will cause a duplicate. Exclude cr_groups[0] - * to prevent that. - */ - - if ((ngrp = args->gidsetsize) == 0) { - td->td_retval[0] = bsd_gidsetsz; - return (0); - } - - if (ngrp < bsd_gidsetsz) - return (EINVAL); - - ngrp = 0; - linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), - M_LINUX, M_WAITOK); - while (ngrp < bsd_gidsetsz) { - linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; - ngrp++; - } - - error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t)); - free(linux_gidset, M_LINUX); - if (error) { - LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error); - return (error); - } - - td->td_retval[0] = ngrp; - - return (0); -} - -int -linux_getgid16(struct thread *td, struct linux_getgid16_args *args) -{ - - td->td_retval[0] = td->td_ucred->cr_rgid; - - return (0); -} - -int -linux_getuid16(struct thread *td, struct linux_getuid16_args *args) -{ - - td->td_retval[0] = td->td_ucred->cr_ruid; - - return (0); -} - -int -linux_getegid16(struct thread *td, struct linux_getegid16_args *args) -{ - struct getegid_args bsd; - int error; - - error = sys_getegid(td, &bsd); - - return (error); -} - -int -linux_geteuid16(struct thread *td, struct linux_geteuid16_args *args) -{ - struct geteuid_args bsd; - int error; - - error = sys_geteuid(td, &bsd); - - return (error); -} - -int -linux_setgid16(struct thread *td, struct linux_setgid16_args *args) -{ - struct setgid_args bsd; - int error; - - bsd.gid = args->gid; - error = sys_setgid(td, &bsd); - - return (error); -} - -int -linux_setuid16(struct thread *td, struct linux_setuid16_args *args) -{ - struct setuid_args bsd; - int error; - - bsd.uid = args->uid; - error = sys_setuid(td, &bsd); - - return (error); -} - -int -linux_setregid16(struct thread *td, struct linux_setregid16_args *args) -{ - struct setregid_args bsd; - int error; - - bsd.rgid = CAST_NOCHG(args->rgid); - bsd.egid = CAST_NOCHG(args->egid); - error = sys_setregid(td, &bsd); - - return (error); -} - -int -linux_setreuid16(struct thread *td, struct linux_setreuid16_args *args) -{ - struct setreuid_args bsd; - int error; - - bsd.ruid = CAST_NOCHG(args->ruid); - bsd.euid = CAST_NOCHG(args->euid); - error = sys_setreuid(td, &bsd); - - return (error); -} - -int -linux_setresgid16(struct thread *td, struct linux_setresgid16_args *args) -{ - struct setresgid_args bsd; - int error; - - bsd.rgid = CAST_NOCHG(args->rgid); - bsd.egid = CAST_NOCHG(args->egid); - bsd.sgid = CAST_NOCHG(args->sgid); - error = sys_setresgid(td, &bsd); - - return (error); -} - -int -linux_setresuid16(struct thread *td, struct linux_setresuid16_args *args) -{ - struct setresuid_args bsd; - int error; - - bsd.ruid = CAST_NOCHG(args->ruid); - bsd.euid = CAST_NOCHG(args->euid); - bsd.suid = CAST_NOCHG(args->suid); - error = sys_setresuid(td, &bsd); - - return (error); -} -// CHERI CHANGES START -// { -// "updated": 20230509, -// "target_type": "kernel", -// "changes": [ -// "user_capabilities" -// ] -// } -// CHERI CHANGES END +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 The FreeBSD Project + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +#include +#include + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, conv_path, "char *"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, conv_path, "char *"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, priv_check_cred_error, "int"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, copyout_error, "int"); + +DUMMY(setfsuid16); +DUMMY(setfsgid16); +DUMMY(getresuid16); +DUMMY(getresgid16); + +#define CAST_NOCHG(x) ((x == 0xFFFF) ? -1 : x) + +int +linux_chown16(struct thread *td, struct linux_chown16_args *args) +{ + + return (kern_fchownat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0)); +} + +int +linux_lchown16(struct thread *td, struct linux_lchown16_args *args) +{ + + return (kern_fchownat(td, AT_FDCWD, LINUX_USER_CAP_PATH(args->path), + UIO_USERSPACE, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), + AT_SYMLINK_NOFOLLOW)); +} + +int +linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args) +{ + struct ucred *newcred, *oldcred; + l_gid16_t *linux_gidset; + gid_t *bsd_gidset; + int ngrp, error; + struct proc *p; + + ngrp = args->gidsetsize; + if (ngrp < 0 || ngrp >= ngroups_max + 1) + return (EINVAL); + linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); + error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t)); + if (error) { + LIN_SDT_PROBE1(uid16, linux_setgroups16, copyin_error, error); + free(linux_gidset, M_LINUX); + return (error); + } + newcred = crget(); + p = td->td_proc; + PROC_LOCK(p); + oldcred = crcopysafe(p, newcred); + + /* + * cr_groups[0] holds egid. Setting the whole set from + * the supplied set will cause egid to be changed too. + * Keep cr_groups[0] unchanged to prevent that. + */ + + if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) { + PROC_UNLOCK(p); + crfree(newcred); + + LIN_SDT_PROBE1(uid16, linux_setgroups16, priv_check_cred_error, + error); + goto out; + } + + if (ngrp > 0) { + newcred->cr_ngroups = ngrp + 1; + + bsd_gidset = newcred->cr_groups; + ngrp--; + while (ngrp >= 0) { + bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; + ngrp--; + } + } + else + newcred->cr_ngroups = 1; + + setsugid(td->td_proc); + proc_set_cred(p, newcred); + PROC_UNLOCK(p); + crfree(oldcred); + error = 0; +out: + free(linux_gidset, M_LINUX); + + return (error); +} + +int +linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args) +{ + struct ucred *cred; + l_gid16_t *linux_gidset; + gid_t *bsd_gidset; + int bsd_gidsetsz, ngrp, error; + + cred = td->td_ucred; + bsd_gidset = cred->cr_groups; + bsd_gidsetsz = cred->cr_ngroups - 1; + + /* + * cr_groups[0] holds egid. Returning the whole set + * here will cause a duplicate. Exclude cr_groups[0] + * to prevent that. + */ + + if ((ngrp = args->gidsetsize) == 0) { + td->td_retval[0] = bsd_gidsetsz; + return (0); + } + + if (ngrp < bsd_gidsetsz) + return (EINVAL); + + ngrp = 0; + linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), + M_LINUX, M_WAITOK); + while (ngrp < bsd_gidsetsz) { + linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; + ngrp++; + } + + error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t)); + free(linux_gidset, M_LINUX); + if (error) { + LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error); + return (error); + } + + td->td_retval[0] = ngrp; + + return (0); +} + +int +linux_getgid16(struct thread *td, struct linux_getgid16_args *args) +{ + + td->td_retval[0] = td->td_ucred->cr_rgid; + + return (0); +} + +int +linux_getuid16(struct thread *td, struct linux_getuid16_args *args) +{ + + td->td_retval[0] = td->td_ucred->cr_ruid; + + return (0); +} + +int +linux_getegid16(struct thread *td, struct linux_getegid16_args *args) +{ + struct getegid_args bsd; + int error; + + error = sys_getegid(td, &bsd); + + return (error); +} + +int +linux_geteuid16(struct thread *td, struct linux_geteuid16_args *args) +{ + struct geteuid_args bsd; + int error; + + error = sys_geteuid(td, &bsd); + + return (error); +} + +int +linux_setgid16(struct thread *td, struct linux_setgid16_args *args) +{ + struct setgid_args bsd; + int error; + + bsd.gid = args->gid; + error = sys_setgid(td, &bsd); + + return (error); +} + +int +linux_setuid16(struct thread *td, struct linux_setuid16_args *args) +{ + struct setuid_args bsd; + int error; + + bsd.uid = args->uid; + error = sys_setuid(td, &bsd); + + return (error); +} + +int +linux_setregid16(struct thread *td, struct linux_setregid16_args *args) +{ + struct setregid_args bsd; + int error; + + bsd.rgid = CAST_NOCHG(args->rgid); + bsd.egid = CAST_NOCHG(args->egid); + error = sys_setregid(td, &bsd); + + return (error); +} + +int +linux_setreuid16(struct thread *td, struct linux_setreuid16_args *args) +{ + struct setreuid_args bsd; + int error; + + bsd.ruid = CAST_NOCHG(args->ruid); + bsd.euid = CAST_NOCHG(args->euid); + error = sys_setreuid(td, &bsd); + + return (error); +} + +int +linux_setresgid16(struct thread *td, struct linux_setresgid16_args *args) +{ + struct setresgid_args bsd; + int error; + + bsd.rgid = CAST_NOCHG(args->rgid); + bsd.egid = CAST_NOCHG(args->egid); + bsd.sgid = CAST_NOCHG(args->sgid); + error = sys_setresgid(td, &bsd); + + return (error); +} + +int +linux_setresuid16(struct thread *td, struct linux_setresuid16_args *args) +{ + struct setresuid_args bsd; + int error; + + bsd.ruid = CAST_NOCHG(args->ruid); + bsd.euid = CAST_NOCHG(args->euid); + bsd.suid = CAST_NOCHG(args->suid); + error = sys_setresuid(td, &bsd); + + return (error); +} +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "kernel", +// "changes": [ +// "user_capabilities" +// ] +// } +// CHERI CHANGES END diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c index e0c010cb5e48..f7aef706f7ae 100644 --- a/sys/compat/linux/linux_util.c +++ b/sys/compat/linux/linux_util.c @@ -1,342 +1,342 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1994 Christos Zoulas - * Copyright (c) 1995 Frank van der Linden - * Copyright (c) 1995 Scott Bartram - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - * - * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); -MALLOC_DEFINE(M_EPOLL, "lepoll", "Linux events structures"); - -FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator"); -FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support in the linuxulator"); - -/** - * Special DTrace provider for the linuxulator. - * - * In this file we define the provider for the entire linuxulator. All - * modules (= files of the linuxulator) use it. - * - * We define a different name depending on the emulated bitsize, see - * ../..//linux{,32}/linux.h, e.g.: - * native bitsize = linuxulator - * amd64, 32bit emulation = linuxulator32 - */ -LIN_SDT_PROVIDER_DEFINE(linuxulator); -LIN_SDT_PROVIDER_DEFINE(linuxulator32); - -char linux_emul_path[MAXPATHLEN] = "/compat/linux"; - -SYSCTL_STRING(_compat_linux, OID_AUTO, emul_path, CTLFLAG_RWTUN, - linux_emul_path, sizeof(linux_emul_path), - "Linux runtime environment path"); - -int -linux_pwd_onexec(struct thread *td) -{ - struct nameidata nd; - int error; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path); - error = namei(&nd); - if (error != 0) { - /* Do not prevent execution if altroot is non-existent. */ - pwd_altroot(td, NULL); - return (0); - } - NDFREE_PNBUF(&nd); - pwd_altroot(td, nd.ni_vp); - vrele(nd.ni_vp); - return (0); -} - -void -linux_pwd_onexec_native(struct thread *td) -{ - - pwd_altroot(td, NULL); -} - -void -linux_msg(const struct thread *td, const char *fmt, ...) -{ - va_list ap; - struct proc *p; - - if (linux_debug == 0) - return; - - p = td->td_proc; - printf("linux: jid %d pid %d (%s): ", p->p_ucred->cr_prison->pr_id, - (int)p->p_pid, p->p_comm); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); -} - -struct device_element -{ - TAILQ_ENTRY(device_element) list; - struct linux_device_handler entry; -}; - -static TAILQ_HEAD(, device_element) devices = - TAILQ_HEAD_INITIALIZER(devices); - -static struct linux_device_handler null_handler = - { "mem", "mem", "null", "null", 1, 3, 1}; - -DATA_SET(linux_device_handler_set, null_handler); - -char * -linux_driver_get_name_dev(device_t dev) -{ - struct device_element *de; - const char *device_name = device_get_name(dev); - - if (device_name == NULL) - return (NULL); - TAILQ_FOREACH(de, &devices, list) { - if (strcmp(device_name, de->entry.bsd_driver_name) == 0) - return (de->entry.linux_driver_name); - } - - return (NULL); -} - -int -linux_driver_get_major_minor(const char *node, int *major, int *minor) -{ - struct device_element *de; - unsigned long devno; - size_t sz; - - if (node == NULL || major == NULL || minor == NULL) - return (1); - - sz = sizeof("pts/") - 1; - if (strncmp(node, "pts/", sz) == 0 && node[sz] != '\0') { - /* - * Linux checks major and minors of the slave device - * to make sure it's a pty device, so let's make him - * believe it is. - */ - devno = strtoul(node + sz, NULL, 10); - *major = 136 + (devno / 256); - *minor = devno % 256; - return (0); - } - - sz = sizeof("dri/card") - 1; - if (strncmp(node, "dri/card", sz) == 0 && node[sz] != '\0') { - devno = strtoul(node + sz, NULL, 10); - *major = 226 + (devno / 256); - *minor = devno % 256; - return (0); - } - sz = sizeof("dri/controlD") - 1; - if (strncmp(node, "dri/controlD", sz) == 0 && node[sz] != '\0') { - devno = strtoul(node + sz, NULL, 10); - *major = 226 + (devno / 256); - *minor = devno % 256; - return (0); - } - sz = sizeof("dri/renderD") - 1; - if (strncmp(node, "dri/renderD", sz) == 0 && node[sz] != '\0') { - devno = strtoul(node + sz, NULL, 10); - *major = 226 + (devno / 256); - *minor = devno % 256; - return (0); - } - sz = sizeof("drm/") - 1; - if (strncmp(node, "drm/", sz) == 0 && node[sz] != '\0') { - devno = strtoul(node + sz, NULL, 10); - *major = 226 + (devno / 256); - *minor = devno % 256; - return (0); - } - - TAILQ_FOREACH(de, &devices, list) { - if (strcmp(node, de->entry.bsd_device_name) == 0) { - *major = de->entry.linux_major; - *minor = de->entry.linux_minor; - return (0); - } - } - - return (1); -} - -int -linux_vn_get_major_minor(const struct vnode *vp, int *major, int *minor) -{ - int error; - - if (vp->v_type != VCHR) - return (ENOTBLK); - dev_lock(); - if (vp->v_rdev == NULL) { - dev_unlock(); - return (ENXIO); - } - error = linux_driver_get_major_minor(devtoname(vp->v_rdev), - major, minor); - dev_unlock(); - return (error); -} - -void -translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) -{ - int major, minor; - - if (vn_isdisk(vp)) { - sb->st_mode &= ~S_IFMT; - sb->st_mode |= S_IFBLK; - } - - /* - * Return the same st_dev for every devfs instance. The reason - * for this is to work around an idiosyncrasy of glibc getttynam() - * implementation: it checks whether st_dev returned for fd 0 - * is the same as st_dev returned for the target of /proc/self/fd/0 - * symlink, and with linux chroots having their own devfs instance, - * the check will fail if you chroot into it. - */ - if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc) - sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0]; - - if (linux_vn_get_major_minor(vp, &major, &minor) == 0) - sb->st_rdev = makedev(major, minor); -} - -char * -linux_get_char_devices(void) -{ - struct device_element *de; - char *temp, *string, *last; - char formated[256]; - int current_size = 0, string_size = 1024; - - string = malloc(string_size, M_LINUX, M_WAITOK); - string[0] = '\000'; - last = ""; - TAILQ_FOREACH(de, &devices, list) { - if (!de->entry.linux_char_device) - continue; - temp = string; - if (strcmp(last, de->entry.bsd_driver_name) != 0) { - last = de->entry.bsd_driver_name; - - snprintf(formated, sizeof(formated), "%3d %s\n", - de->entry.linux_major, - de->entry.linux_device_name); - if (strlen(formated) + current_size - >= string_size) { - string_size *= 2; - string = malloc(string_size, - M_LINUX, M_WAITOK); - bcopy(temp, string, current_size); - free(temp, M_LINUX); - } - strcat(string, formated); - current_size = strlen(string); - } - } - - return (string); -} - -void -linux_free_get_char_devices(char *string) -{ - - free(string, M_LINUX); -} - -static int linux_major_starting = 200; - -int -linux_device_register_handler(struct linux_device_handler *d) -{ - struct device_element *de; - - if (d == NULL) - return (EINVAL); - - de = malloc(sizeof(*de), M_LINUX, M_WAITOK); - if (d->linux_major < 0) { - d->linux_major = linux_major_starting++; - } - bcopy(d, &de->entry, sizeof(*d)); - - /* Add the element to the list, sorted on span. */ - TAILQ_INSERT_TAIL(&devices, de, list); - - return (0); -} - -int -linux_device_unregister_handler(struct linux_device_handler *d) -{ - struct device_element *de; - - if (d == NULL) - return (EINVAL); - - TAILQ_FOREACH(de, &devices, list) { - if (bcmp(d, &de->entry, sizeof(*d)) == 0) { - TAILQ_REMOVE(&devices, de, list); - free(de, M_LINUX); - - return (0); - } - } - - return (EINVAL); -} +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1994 Christos Zoulas + * Copyright (c) 1995 Frank van der Linden + * Copyright (c) 1995 Scott Bartram + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); +MALLOC_DEFINE(M_EPOLL, "lepoll", "Linux events structures"); + +FEATURE(linuxulator_v4l, "V4L ioctl wrapper support in the linuxulator"); +FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support in the linuxulator"); + +/** + * Special DTrace provider for the linuxulator. + * + * In this file we define the provider for the entire linuxulator. All + * modules (= files of the linuxulator) use it. + * + * We define a different name depending on the emulated bitsize, see + * ../..//linux{,32}/linux.h, e.g.: + * native bitsize = linuxulator + * amd64, 32bit emulation = linuxulator32 + */ +LIN_SDT_PROVIDER_DEFINE(linuxulator); +LIN_SDT_PROVIDER_DEFINE(linuxulator32); + +char linux_emul_path[MAXPATHLEN] = "/compat/linux"; + +SYSCTL_STRING(_compat_linux, OID_AUTO, emul_path, CTLFLAG_RWTUN, + linux_emul_path, sizeof(linux_emul_path), + "Linux runtime environment path"); + +int +linux_pwd_onexec(struct thread *td) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path); + error = namei(&nd); + if (error != 0) { + /* Do not prevent execution if altroot is non-existent. */ + pwd_altroot(td, NULL); + return (0); + } + NDFREE_PNBUF(&nd); + pwd_altroot(td, nd.ni_vp); + vrele(nd.ni_vp); + return (0); +} + +void +linux_pwd_onexec_native(struct thread *td) +{ + + pwd_altroot(td, NULL); +} + +void +linux_msg(const struct thread *td, const char *fmt, ...) +{ + va_list ap; + struct proc *p; + + if (linux_debug == 0) + return; + + p = td->td_proc; + printf("linux: jid %d pid %d (%s): ", p->p_ucred->cr_prison->pr_id, + (int)p->p_pid, p->p_comm); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); +} + +struct device_element +{ + TAILQ_ENTRY(device_element) list; + struct linux_device_handler entry; +}; + +static TAILQ_HEAD(, device_element) devices = + TAILQ_HEAD_INITIALIZER(devices); + +static struct linux_device_handler null_handler = + { "mem", "mem", "null", "null", 1, 3, 1}; + +DATA_SET(linux_device_handler_set, null_handler); + +char * +linux_driver_get_name_dev(device_t dev) +{ + struct device_element *de; + const char *device_name = device_get_name(dev); + + if (device_name == NULL) + return (NULL); + TAILQ_FOREACH(de, &devices, list) { + if (strcmp(device_name, de->entry.bsd_driver_name) == 0) + return (de->entry.linux_driver_name); + } + + return (NULL); +} + +int +linux_driver_get_major_minor(const char *node, int *major, int *minor) +{ + struct device_element *de; + unsigned long devno; + size_t sz; + + if (node == NULL || major == NULL || minor == NULL) + return (1); + + sz = sizeof("pts/") - 1; + if (strncmp(node, "pts/", sz) == 0 && node[sz] != '\0') { + /* + * Linux checks major and minors of the slave device + * to make sure it's a pty device, so let's make him + * believe it is. + */ + devno = strtoul(node + sz, NULL, 10); + *major = 136 + (devno / 256); + *minor = devno % 256; + return (0); + } + + sz = sizeof("dri/card") - 1; + if (strncmp(node, "dri/card", sz) == 0 && node[sz] != '\0') { + devno = strtoul(node + sz, NULL, 10); + *major = 226 + (devno / 256); + *minor = devno % 256; + return (0); + } + sz = sizeof("dri/controlD") - 1; + if (strncmp(node, "dri/controlD", sz) == 0 && node[sz] != '\0') { + devno = strtoul(node + sz, NULL, 10); + *major = 226 + (devno / 256); + *minor = devno % 256; + return (0); + } + sz = sizeof("dri/renderD") - 1; + if (strncmp(node, "dri/renderD", sz) == 0 && node[sz] != '\0') { + devno = strtoul(node + sz, NULL, 10); + *major = 226 + (devno / 256); + *minor = devno % 256; + return (0); + } + sz = sizeof("drm/") - 1; + if (strncmp(node, "drm/", sz) == 0 && node[sz] != '\0') { + devno = strtoul(node + sz, NULL, 10); + *major = 226 + (devno / 256); + *minor = devno % 256; + return (0); + } + + TAILQ_FOREACH(de, &devices, list) { + if (strcmp(node, de->entry.bsd_device_name) == 0) { + *major = de->entry.linux_major; + *minor = de->entry.linux_minor; + return (0); + } + } + + return (1); +} + +int +linux_vn_get_major_minor(const struct vnode *vp, int *major, int *minor) +{ + int error; + + if (vp->v_type != VCHR) + return (ENOTBLK); + dev_lock(); + if (vp->v_rdev == NULL) { + dev_unlock(); + return (ENXIO); + } + error = linux_driver_get_major_minor(devtoname(vp->v_rdev), + major, minor); + dev_unlock(); + return (error); +} + +void +translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) +{ + int major, minor; + + if (vn_isdisk(vp)) { + sb->st_mode &= ~S_IFMT; + sb->st_mode |= S_IFBLK; + } + + /* + * Return the same st_dev for every devfs instance. The reason + * for this is to work around an idiosyncrasy of glibc getttynam() + * implementation: it checks whether st_dev returned for fd 0 + * is the same as st_dev returned for the target of /proc/self/fd/0 + * symlink, and with linux chroots having their own devfs instance, + * the check will fail if you chroot into it. + */ + if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc) + sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0]; + + if (linux_vn_get_major_minor(vp, &major, &minor) == 0) + sb->st_rdev = makedev(major, minor); +} + +char * +linux_get_char_devices(void) +{ + struct device_element *de; + char *temp, *string, *last; + char formated[256]; + int current_size = 0, string_size = 1024; + + string = malloc(string_size, M_LINUX, M_WAITOK); + string[0] = '\000'; + last = ""; + TAILQ_FOREACH(de, &devices, list) { + if (!de->entry.linux_char_device) + continue; + temp = string; + if (strcmp(last, de->entry.bsd_driver_name) != 0) { + last = de->entry.bsd_driver_name; + + snprintf(formated, sizeof(formated), "%3d %s\n", + de->entry.linux_major, + de->entry.linux_device_name); + if (strlen(formated) + current_size + >= string_size) { + string_size *= 2; + string = malloc(string_size, + M_LINUX, M_WAITOK); + bcopy(temp, string, current_size); + free(temp, M_LINUX); + } + strcat(string, formated); + current_size = strlen(string); + } + } + + return (string); +} + +void +linux_free_get_char_devices(char *string) +{ + + free(string, M_LINUX); +} + +static int linux_major_starting = 200; + +int +linux_device_register_handler(struct linux_device_handler *d) +{ + struct device_element *de; + + if (d == NULL) + return (EINVAL); + + de = malloc(sizeof(*de), M_LINUX, M_WAITOK); + if (d->linux_major < 0) { + d->linux_major = linux_major_starting++; + } + bcopy(d, &de->entry, sizeof(*d)); + + /* Add the element to the list, sorted on span. */ + TAILQ_INSERT_TAIL(&devices, de, list); + + return (0); +} + +int +linux_device_unregister_handler(struct linux_device_handler *d) +{ + struct device_element *de; + + if (d == NULL) + return (EINVAL); + + TAILQ_FOREACH(de, &devices, list) { + if (bcmp(d, &de->entry, sizeof(*d)) == 0) { + TAILQ_REMOVE(&devices, de, list); + free(de, M_LINUX); + + return (0); + } + } + + return (EINVAL); +} diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h index 58f7c533d647..47ba179a7d15 100644 --- a/sys/compat/linux/linux_util.h +++ b/sys/compat/linux/linux_util.h @@ -1,179 +1,179 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1994 Christos Zoulas - * Copyright (c) 1995 Frank van der Linden - * Copyright (c) 1995 Scott Bartram - * 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. - * - * from: svr4_util.h,v 1.5 1994/11/18 02:54:31 christos Exp - * from: linux_util.h,v 1.2 1995/03/05 23:23:50 fvdl Exp - */ - -#ifndef _LINUX_UTIL_H_ -#define _LINUX_UTIL_H_ - -#include -#include - -extern int linux_debug; - -MALLOC_DECLARE(M_LINUX); -MALLOC_DECLARE(M_EPOLL); - -int linux_pwd_onexec(struct thread *); -void linux_pwd_onexec_native(struct thread *); - -#define DUMMY(s) \ -LIN_SDT_PROBE_DEFINE0(dummy, s, not_implemented); \ -int \ -linux_ ## s(struct thread *td, struct linux_ ## s ## _args *args) \ -{ \ - static pid_t pid; \ - \ - if (pid != td->td_proc->p_pid) { \ - linux_msg(td, "syscall %s not implemented", #s); \ - LIN_SDT_PROBE0(dummy, s, not_implemented); \ - pid = td->td_proc->p_pid; \ - }; \ - \ - return (ENOSYS); \ -} \ -struct __hack - -/* - * This is for the syscalls that are not even yet implemented in Linux. - * - * They're marked as UNIMPL in syscall.master so it will - * have nosys record in linux_sysent[]. - */ -#define UNIMPLEMENTED(s) - -void linux_msg(const struct thread *td, const char *fmt, ...) - __printflike(2, 3); - -struct linux_device_handler { - char *bsd_driver_name; - char *linux_driver_name; - char *bsd_device_name; - char *linux_device_name; - int linux_major; - int linux_minor; - int linux_char_device; -}; - -struct stat; - -int linux_device_register_handler(struct linux_device_handler *h); -int linux_device_unregister_handler(struct linux_device_handler *h); -char *linux_driver_get_name_dev(device_t dev); -int linux_driver_get_major_minor(const char *node, int *major, int *minor); -int linux_vn_get_major_minor(const struct vnode *vn, int *major, int *minor); -char *linux_get_char_devices(void); -void linux_free_get_char_devices(char *string); -void translate_vnhook_major_minor(struct vnode *vp, struct stat *sb); - -#if defined(KTR) - -#define KTR_LINUX KTR_SUBSYS -#define LINUX_CTRFMT(nm, fmt) #nm"("fmt")" - -#define LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) do { \ - CTR6(KTR_LINUX, LINUX_CTRFMT(f, m), \ - p1, p2, p3, p4, p5, p6); \ -} while (0) - -#define LINUX_CTR(f) LINUX_CTR6(f, "", 0, 0, 0, 0, 0, 0) -#define LINUX_CTR0(f, m) LINUX_CTR6(f, m, 0, 0, 0, 0, 0, 0) -#define LINUX_CTR1(f, m, p1) LINUX_CTR6(f, m, p1, 0, 0, 0, 0, 0) -#define LINUX_CTR2(f, m, p1, p2) LINUX_CTR6(f, m, p1, p2, 0, 0, 0, 0) -#define LINUX_CTR3(f, m, p1, p2, p3) LINUX_CTR6(f, m, p1, p2, p3, 0, 0, 0) -#define LINUX_CTR4(f, m, p1, p2, p3, p4) LINUX_CTR6(f, m, p1, p2, p3, p4, 0, 0) -#define LINUX_CTR5(f, m, p1, p2, p3, p4, p5) LINUX_CTR6(f, m, p1, p2, p3, p4, p5, 0) -#else -#define LINUX_CTR(f) -#define LINUX_CTR0(f, m) -#define LINUX_CTR1(f, m, p1) -#define LINUX_CTR2(f, m, p1, p2) -#define LINUX_CTR3(f, m, p1, p2, p3) -#define LINUX_CTR4(f, m, p1, p2, p3, p4) -#define LINUX_CTR5(f, m, p1, p2, p3, p4, p5) -#define LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) -#endif - -/* - * Some macros for rate limiting messages: - * - noisy if compat.linux.debug = 1 - * - print only once if compat.linux.debug > 1 - */ -#define LINUX_RATELIMIT_MSG_NOTTESTED(_what) \ - do { \ - static int seen = 0; \ - \ - if (seen == 0 && linux_debug >= 2) { \ - linux_msg(curthread, "%s is not tested, please report on emulation@FreeBSD.org how it works", _what); \ - \ - if (linux_debug < 3) \ - seen = 1; \ - } \ - } while (0) - -#define LINUX_RATELIMIT_MSG(_message) \ - do { \ - static int seen = 0; \ - \ - if (seen == 0) { \ - linux_msg(curthread, _message); \ - \ - if (linux_debug < 3) \ - seen = 1; \ - } \ - } while (0) - -#define LINUX_RATELIMIT_MSG_OPT1(_message, _opt1) \ - do { \ - static int seen = 0; \ - \ - if (seen == 0) { \ - linux_msg(curthread, _message, _opt1); \ - \ - if (linux_debug < 3) \ - seen = 1; \ - } \ - } while (0) - -#define LINUX_RATELIMIT_MSG_OPT2(_message, _opt1, _opt2) \ - do { \ - static int seen = 0; \ - \ - if (seen == 0) { \ - linux_msg(curthread, _message, _opt1, _opt2); \ - \ - if (linux_debug < 3) \ - seen = 1; \ - } \ - } while (0) - -#endif /* ! _LINUX_UTIL_H_ */ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1994 Christos Zoulas + * Copyright (c) 1995 Frank van der Linden + * Copyright (c) 1995 Scott Bartram + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * from: svr4_util.h,v 1.5 1994/11/18 02:54:31 christos Exp + * from: linux_util.h,v 1.2 1995/03/05 23:23:50 fvdl Exp + */ + +#ifndef _LINUX_UTIL_H_ +#define _LINUX_UTIL_H_ + +#include +#include + +extern int linux_debug; + +MALLOC_DECLARE(M_LINUX); +MALLOC_DECLARE(M_EPOLL); + +int linux_pwd_onexec(struct thread *); +void linux_pwd_onexec_native(struct thread *); + +#define DUMMY(s) \ +LIN_SDT_PROBE_DEFINE0(dummy, s, not_implemented); \ +int \ +linux_ ## s(struct thread *td, struct linux_ ## s ## _args *args) \ +{ \ + static pid_t pid; \ + \ + if (pid != td->td_proc->p_pid) { \ + linux_msg(td, "syscall %s not implemented", #s); \ + LIN_SDT_PROBE0(dummy, s, not_implemented); \ + pid = td->td_proc->p_pid; \ + }; \ + \ + return (ENOSYS); \ +} \ +struct __hack + +/* + * This is for the syscalls that are not even yet implemented in Linux. + * + * They're marked as UNIMPL in syscall.master so it will + * have nosys record in linux_sysent[]. + */ +#define UNIMPLEMENTED(s) + +void linux_msg(const struct thread *td, const char *fmt, ...) + __printflike(2, 3); + +struct linux_device_handler { + char *bsd_driver_name; + char *linux_driver_name; + char *bsd_device_name; + char *linux_device_name; + int linux_major; + int linux_minor; + int linux_char_device; +}; + +struct stat; + +int linux_device_register_handler(struct linux_device_handler *h); +int linux_device_unregister_handler(struct linux_device_handler *h); +char *linux_driver_get_name_dev(device_t dev); +int linux_driver_get_major_minor(const char *node, int *major, int *minor); +int linux_vn_get_major_minor(const struct vnode *vn, int *major, int *minor); +char *linux_get_char_devices(void); +void linux_free_get_char_devices(char *string); +void translate_vnhook_major_minor(struct vnode *vp, struct stat *sb); + +#if defined(KTR) + +#define KTR_LINUX KTR_SUBSYS +#define LINUX_CTRFMT(nm, fmt) #nm"("fmt")" + +#define LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) do { \ + CTR6(KTR_LINUX, LINUX_CTRFMT(f, m), \ + p1, p2, p3, p4, p5, p6); \ +} while (0) + +#define LINUX_CTR(f) LINUX_CTR6(f, "", 0, 0, 0, 0, 0, 0) +#define LINUX_CTR0(f, m) LINUX_CTR6(f, m, 0, 0, 0, 0, 0, 0) +#define LINUX_CTR1(f, m, p1) LINUX_CTR6(f, m, p1, 0, 0, 0, 0, 0) +#define LINUX_CTR2(f, m, p1, p2) LINUX_CTR6(f, m, p1, p2, 0, 0, 0, 0) +#define LINUX_CTR3(f, m, p1, p2, p3) LINUX_CTR6(f, m, p1, p2, p3, 0, 0, 0) +#define LINUX_CTR4(f, m, p1, p2, p3, p4) LINUX_CTR6(f, m, p1, p2, p3, p4, 0, 0) +#define LINUX_CTR5(f, m, p1, p2, p3, p4, p5) LINUX_CTR6(f, m, p1, p2, p3, p4, p5, 0) +#else +#define LINUX_CTR(f) +#define LINUX_CTR0(f, m) +#define LINUX_CTR1(f, m, p1) +#define LINUX_CTR2(f, m, p1, p2) +#define LINUX_CTR3(f, m, p1, p2, p3) +#define LINUX_CTR4(f, m, p1, p2, p3, p4) +#define LINUX_CTR5(f, m, p1, p2, p3, p4, p5) +#define LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) +#endif + +/* + * Some macros for rate limiting messages: + * - noisy if compat.linux.debug = 1 + * - print only once if compat.linux.debug > 1 + */ +#define LINUX_RATELIMIT_MSG_NOTTESTED(_what) \ + do { \ + static int seen = 0; \ + \ + if (seen == 0 && linux_debug >= 2) { \ + linux_msg(curthread, "%s is not tested, please report on emulation@FreeBSD.org how it works", _what); \ + \ + if (linux_debug < 3) \ + seen = 1; \ + } \ + } while (0) + +#define LINUX_RATELIMIT_MSG(_message) \ + do { \ + static int seen = 0; \ + \ + if (seen == 0) { \ + linux_msg(curthread, _message); \ + \ + if (linux_debug < 3) \ + seen = 1; \ + } \ + } while (0) + +#define LINUX_RATELIMIT_MSG_OPT1(_message, _opt1) \ + do { \ + static int seen = 0; \ + \ + if (seen == 0) { \ + linux_msg(curthread, _message, _opt1); \ + \ + if (linux_debug < 3) \ + seen = 1; \ + } \ + } while (0) + +#define LINUX_RATELIMIT_MSG_OPT2(_message, _opt1, _opt2) \ + do { \ + static int seen = 0; \ + \ + if (seen == 0) { \ + linux_msg(curthread, _message, _opt1, _opt2); \ + \ + if (linux_debug < 3) \ + seen = 1; \ + } \ + } while (0) + +#endif /* ! _LINUX_UTIL_H_ */ diff --git a/sys/compat/linux/linux_vdso.c b/sys/compat/linux/linux_vdso.c index 94f08246d08c..c15cf6007dab 100644 --- a/sys/compat/linux/linux_vdso.c +++ b/sys/compat/linux/linux_vdso.c @@ -1,179 +1,191 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2013-2021 Dmitry Chagin - * - * 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. - */ - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -#define __ELF_WORD_SIZE 32 -#else -#define __ELF_WORD_SIZE 64 -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -SLIST_HEAD(, linux_vdso_sym) __elfN(linux_vdso_syms) = - SLIST_HEAD_INITIALIZER(__elfN(linux_vdso_syms)); - -void -__elfN(linux_vdso_sym_init)(struct linux_vdso_sym *s) -{ - - SLIST_INSERT_HEAD(&__elfN(linux_vdso_syms), s, sym); -} - -vm_object_t -__elfN(linux_shared_page_init)(char **mapping, vm_size_t size) -{ - vm_page_t m; - vm_object_t obj; - vm_offset_t addr; - size_t n, pages; - - pages = size / PAGE_SIZE; - - addr = kva_alloc(size); - obj = vm_pager_allocate(OBJT_PHYS, 0, size, - VM_PROT_DEFAULT, 0, NULL); - VM_OBJECT_WLOCK(obj); - for (n = 0; n < pages; n++) { - m = vm_page_grab(obj, n, - VM_ALLOC_ZERO); - vm_page_valid(m); - vm_page_xunbusy(m); - pmap_qenter(addr + n * PAGE_SIZE, &m, 1); - } - VM_OBJECT_WUNLOCK(obj); - *mapping = (char *)addr; - return (obj); -} - -void -__elfN(linux_shared_page_fini)(vm_object_t obj, void *mapping, - vm_size_t size) -{ - vm_offset_t va; - - va = (vm_offset_t)mapping; - pmap_qremove(va, size / PAGE_SIZE); - kva_free(va, size); - vm_object_deallocate(obj); -} - -void -__elfN(linux_vdso_fixup)(char *base, vm_offset_t offset) -{ - struct linux_vdso_sym *lsym; - const Elf_Shdr *shdr; - Elf_Ehdr *ehdr; - Elf_Sym *dsym, *sym; - char *strtab, *symname; - int i, symcnt; - - ehdr = (Elf_Ehdr *)base; - - MPASS(IS_ELF(*ehdr)); - MPASS(ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS); - MPASS(ehdr->e_ident[EI_DATA] == ELF_TARG_DATA); - MPASS(ehdr->e_ident[EI_VERSION] == EV_CURRENT); - MPASS(ehdr->e_shentsize == sizeof(Elf_Shdr)); - MPASS(ehdr->e_shoff != 0); - MPASS(ehdr->e_type == ET_DYN); - - shdr = (const Elf_Shdr *)(base + ehdr->e_shoff); - - dsym = NULL; - for (i = 0; i < ehdr->e_shnum; i++) { - if (shdr[i].sh_size == 0) - continue; - if (shdr[i].sh_type == SHT_DYNSYM) { - dsym = (Elf_Sym *)(base + shdr[i].sh_offset); - strtab = base + shdr[shdr[i].sh_link].sh_offset; - symcnt = shdr[i].sh_size / sizeof(*dsym); - break; - } - } - MPASS(dsym != NULL); - - ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX; - - /* - * VDSO is readonly mapped to the process VA and - * can't be relocated by rtld. - */ - SLIST_FOREACH(lsym, &__elfN(linux_vdso_syms), sym) { - for (i = 0, sym = dsym; i < symcnt; i++, sym++) { - symname = strtab + sym->st_name; - if (strncmp(lsym->symname, symname, lsym->size) == 0) { - sym->st_value += offset; - *lsym->ptr = sym->st_value; - break; - - } - } - } -} - -int -linux_map_vdso(struct proc *p, vm_object_t obj, vm_offset_t base, - vm_offset_t size, struct image_params *imgp) -{ - struct vmspace *vmspace; - vm_map_t map; - vm_pointer_t addr; - int error; - - MPASS((imgp->sysent->sv_flags & SV_ABI_MASK) == SV_ABI_LINUX); - MPASS(obj != NULL); - - vmspace = p->p_vmspace; - map = &vmspace->vm_map; - - vm_object_reference(obj); - error = vm_map_fixed(map, obj, 0, base, &addr, size, - VM_PROT_READ | VM_PROT_EXECUTE, - VM_PROT_READ | VM_PROT_EXECUTE, - MAP_INHERIT_SHARE | MAP_ACC_NO_CHARGE); - if (error != KERN_SUCCESS) { - vm_object_deallocate(obj); - return (vm_mmap_to_errno(error)); - } - return (0); -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2013-2021 Dmitry Chagin + * + * 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. + */ + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +#define __ELF_WORD_SIZE 32 +#else +#define __ELF_WORD_SIZE 64 +#if __has_feature(capabilities) && !defined(COMPAT_LINUX64) +#define __ELF_CHERI +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#elif defined(COMPAT_LINUX64) +#include +#else +#include +#endif + +#include +#include + +SLIST_HEAD(, linux_vdso_sym) __elfN(linux_vdso_syms) = + SLIST_HEAD_INITIALIZER(__elfN(linux_vdso_syms)); + +void +__elfN(linux_vdso_sym_init)(struct linux_vdso_sym *s) +{ + + SLIST_INSERT_HEAD(&__elfN(linux_vdso_syms), s, sym); +} + +vm_object_t +__elfN(linux_shared_page_init)(char **mapping, vm_size_t size) +{ + vm_page_t m; + vm_object_t obj; + vm_pointer_t addr; + size_t n, pages; + + pages = size / PAGE_SIZE; + + addr = kva_alloc(size); + obj = vm_pager_allocate(OBJT_PHYS, 0, size, + VM_PROT_DEFAULT, 0, NULL); + VM_OBJECT_WLOCK(obj); + for (n = 0; n < pages; n++) { + m = vm_page_grab(obj, n, + VM_ALLOC_ZERO); + vm_page_valid(m); + vm_page_xunbusy(m); + pmap_qenter(addr + n * PAGE_SIZE, &m, 1); + } + VM_OBJECT_WUNLOCK(obj); + *mapping = (char *)addr; + return (obj); +} + +void +__elfN(linux_shared_page_fini)(vm_object_t obj, void *mapping, + vm_size_t size) +{ + vm_pointer_t va; + + va = (vm_pointer_t)mapping; + pmap_qremove((vm_offset_t)va, size / PAGE_SIZE); + kva_free(va, size); + vm_object_deallocate(obj); +} + +void +__elfN(linux_vdso_fixup)(char *base, vm_offset_t offset) +{ + struct linux_vdso_sym *lsym; + const Elf_Shdr *shdr; + Elf_Ehdr *ehdr; + Elf_Sym *dsym, *sym; + char *strtab, *symname; + int i, symcnt; + + ehdr = (Elf_Ehdr *)base; + + MPASS(IS_ELF(*ehdr)); + MPASS(ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS); + MPASS(ehdr->e_ident[EI_DATA] == ELF_TARG_DATA); + MPASS(ehdr->e_ident[EI_VERSION] == EV_CURRENT); + MPASS(ehdr->e_shentsize == sizeof(Elf_Shdr)); + MPASS(ehdr->e_shoff != 0); + MPASS(ehdr->e_type == ET_DYN); + + shdr = (const Elf_Shdr *)(base + ehdr->e_shoff); + + dsym = NULL; + for (i = 0; i < ehdr->e_shnum; i++) { + if (shdr[i].sh_size == 0) + continue; + if (shdr[i].sh_type == SHT_DYNSYM) { + dsym = (Elf_Sym *)(base + shdr[i].sh_offset); + strtab = base + shdr[shdr[i].sh_link].sh_offset; + symcnt = shdr[i].sh_size / sizeof(*dsym); + break; + } + } + MPASS(dsym != NULL); + + ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX; + + /* + * VDSO is readonly mapped to the process VA and + * can't be relocated by rtld. + */ + SLIST_FOREACH(lsym, &__elfN(linux_vdso_syms), sym) { + for (i = 0, sym = dsym; i < symcnt; i++, sym++) { + symname = strtab + sym->st_name; + if (strncmp(lsym->symname, symname, lsym->size) == 0) { + sym->st_value += offset; + *lsym->ptr = (uintptr_t)sym->st_value; + break; + + } + } + } +} + +int +linux_map_vdso(struct proc *p, vm_object_t obj, vm_offset_t base, + vm_offset_t size, struct image_params *imgp) +{ + struct vmspace *vmspace; + vm_map_t map; + vm_pointer_t addr; + int error; + + MPASS((imgp->sysent->sv_flags & SV_ABI_MASK) == SV_ABI_LINUX); + MPASS(obj != NULL); + + vmspace = p->p_vmspace; + map = &vmspace->vm_map; + + vm_object_reference(obj); + error = vm_map_fixed(map, obj, 0, base, &addr, size, + VM_PROT_READ | VM_PROT_EXECUTE, + VM_PROT_READ | VM_PROT_EXECUTE, + MAP_INHERIT_SHARE | MAP_ACC_NO_CHARGE); + if (error != KERN_SUCCESS) { + vm_object_deallocate(obj); + return (vm_mmap_to_errno(error)); + } + return (0); +} diff --git a/sys/compat/linux/linux_vdso.h b/sys/compat/linux/linux_vdso.h index e7f45f38c662..7012723dbef8 100644 --- a/sys/compat/linux/linux_vdso.h +++ b/sys/compat/linux/linux_vdso.h @@ -1,64 +1,64 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2013-2021 Dmitry Chagin - * - * 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. - */ - -#ifndef _LINUX_VDSO_H_ -#define _LINUX_VDSO_H_ - -struct linux_vdso_sym { - SLIST_ENTRY(linux_vdso_sym) sym; - uint32_t size; - uintptr_t * ptr; - char symname[]; -}; - -vm_object_t __elfN(linux_shared_page_init)(char **, vm_size_t); -void __elfN(linux_shared_page_fini)(vm_object_t, void *, vm_size_t); -void __elfN(linux_vdso_fixup)(char *, vm_offset_t); -void __elfN(linux_vdso_sym_init)(struct linux_vdso_sym *); - -int linux_map_vdso(struct proc *, vm_object_t, vm_offset_t, - vm_offset_t, struct image_params *); - -#define LINUX_VDSO_SYM_INTPTR(name) \ -uintptr_t name; \ -LINUX_VDSO_SYM_DEFINE(name) - -#define LINUX_VDSO_SYM_CHAR(name) \ -const char * name; \ -LINUX_VDSO_SYM_DEFINE(name) - -#define LINUX_VDSO_SYM_DEFINE(name) \ -static struct linux_vdso_sym name ## sym = { \ - .symname = #name, \ - .size = sizeof(#name), \ - .ptr = (uintptr_t *)&name \ -}; \ -SYSINIT(__elfN(name ## _sym_init), SI_SUB_EXEC, \ - SI_ORDER_FIRST, __elfN(linux_vdso_sym_init), &name ## sym); \ -struct __hack - -#endif /* _LINUX_VDSO_H_ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2013-2021 Dmitry Chagin + * + * 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. + */ + +#ifndef _LINUX_VDSO_H_ +#define _LINUX_VDSO_H_ + +struct linux_vdso_sym { + SLIST_ENTRY(linux_vdso_sym) sym; + uint32_t size; + uintptr_t * ptr; + char symname[]; +}; + +vm_object_t __elfN(linux_shared_page_init)(char **, vm_size_t); +void __elfN(linux_shared_page_fini)(vm_object_t, void *, vm_size_t); +void __elfN(linux_vdso_fixup)(char *, vm_offset_t); +void __elfN(linux_vdso_sym_init)(struct linux_vdso_sym *); + +int linux_map_vdso(struct proc *, vm_object_t, vm_offset_t, + vm_offset_t, struct image_params *); + +#define LINUX_VDSO_SYM_INTPTR(name) \ +uintptr_t name; \ +LINUX_VDSO_SYM_DEFINE(name) + +#define LINUX_VDSO_SYM_CHAR(name) \ +const char *name; \ +LINUX_VDSO_SYM_DEFINE(name) + +#define LINUX_VDSO_SYM_DEFINE(name) \ +static struct linux_vdso_sym name ## sym = { \ + .symname = #name, \ + .size = sizeof(#name), \ + .ptr = (uintptr_t *)&name \ +}; \ +SYSINIT(__elfN(name ## _sym_init), SI_SUB_EXEC, \ + SI_ORDER_FIRST, __elfN(linux_vdso_sym_init), &name ## sym); \ +struct __hack + +#endif /* _LINUX_VDSO_H_ */ diff --git a/sys/compat/linux/linux_vdso_gtod.inc b/sys/compat/linux/linux_vdso_gtod.inc index e508f821725d..7df355963cdf 100644 --- a/sys/compat/linux/linux_vdso_gtod.inc +++ b/sys/compat/linux/linux_vdso_gtod.inc @@ -1,393 +1,393 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2012 Konstantin Belousov - * Copyright (c) 2021 Dmitry Chagin - * - * 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. - */ - -#if defined(__aarch64__) -#define __VDSO_PREFIX __kernel -#else -#define __VDSO_PREFIX __vdso -#endif - -#define __vdsoN(x) __CONCAT(__CONCAT(__VDSO_PREFIX,_),x) - -static int -fls(int mask) -{ - - if (mask == 0) - return (0); - return ((__builtin_clz(mask) ^ 0x1f) + 1); -} - -#ifdef _LP64 -static int -flsl(long mask) -{ - int bit; - - if (mask == 0) - return (0); - for (bit = 1; mask != 1; bit++) - mask = (unsigned long)mask >> 1; - return (bit); -} -#else -static int -flsll(long long mask) -{ - int bit; - - if (mask == 0) - return (0); - for (bit = 1; mask != 1; bit++) - mask = (unsigned long long)mask >> 1; - return (bit); -} -#endif - -static int -__vdso_native_to_linux_timespec(struct l_timespec *lts, - struct timespec *nts) -{ - -#ifdef COMPAT_LINUX32 - if (nts->tv_sec > INT_MAX || nts->tv_sec < INT_MIN) - return (LINUX_EOVERFLOW); -#endif - lts->tv_sec = nts->tv_sec; - lts->tv_nsec = nts->tv_nsec; - return (0); -} - -static int -__vdso_native_to_linux_timeval(l_timeval *ltv, - struct timeval *ntv) -{ - -#ifdef COMPAT_LINUX32 - if (ntv->tv_sec > INT_MAX || ntv->tv_sec < INT_MIN) - return (LINUX_EOVERFLOW); -#endif - ltv->tv_sec = ntv->tv_sec; - ltv->tv_usec = ntv->tv_usec; - return (0); -} - - -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) -static int -__vdso_native_to_linux_timespec64(struct l_timespec64 *lts, - struct timespec *nts) -{ - - lts->tv_sec = nts->tv_sec; - lts->tv_nsec = nts->tv_nsec; - return (0); -} -#endif - -static int -__vdso_linux_to_native_clockid(clockid_t *n, clockid_t l) -{ - - switch (l) { - case LINUX_CLOCK_REALTIME: - *n = CLOCK_REALTIME; - break; - case LINUX_CLOCK_MONOTONIC: - *n = CLOCK_MONOTONIC; - break; - case LINUX_CLOCK_REALTIME_COARSE: - *n = CLOCK_REALTIME_FAST; - break; - case LINUX_CLOCK_MONOTONIC_COARSE: - case LINUX_CLOCK_MONOTONIC_RAW: - *n = CLOCK_MONOTONIC_FAST; - break; - case LINUX_CLOCK_BOOTTIME: - *n = CLOCK_UPTIME; - break; - default: - return (LINUX_EINVAL); - } - return (0); -} - -/* - * The code below adapted from - * lib/libc/sys/__vdso_gettimeofday.c - */ - -static inline void -__vdso_gettimekeep(struct vdso_timekeep **tk) -{ - - *tk = (struct vdso_timekeep *)kern_timekeep_base; -} - -static int -tc_delta(const struct vdso_timehands *th, u_int *delta) -{ - int error; - u_int tc; - - error = __vdso_gettc(th, &tc); - if (error == 0) - *delta = (tc - th->th_offset_count) & th->th_counter_mask; - return (error); -} - -/* - * Calculate the absolute or boot-relative time from the - * machine-specific fast timecounter and the published timehands - * structure read from the shared page. - * - * The lockless reading scheme is similar to the one used to read the - * in-kernel timehands, see sys/kern/kern_tc.c:binuptime(). This code - * is based on the kernel implementation. - */ -static int -freebsd_binuptime(struct bintime *bt, struct vdso_timekeep *tk, bool abs) -{ - struct vdso_timehands *th; - uint32_t curr, gen; - uint64_t scale, x; - u_int delta, scale_bits; - int error; - - do { - if (!tk->tk_enabled) - return (ENOSYS); - - curr = atomic_load_acq_32(&tk->tk_current); - th = &tk->tk_th[curr]; - gen = atomic_load_acq_32(&th->th_gen); - *bt = th->th_offset; - error = tc_delta(th, &delta); - if (error == EAGAIN) - continue; - if (error != 0) - return (error); - scale = th->th_scale; -#ifdef _LP64 - scale_bits = flsl(scale); -#else - scale_bits = flsll(scale); -#endif - if (__predict_false(scale_bits + fls(delta) > 63)) { - x = (scale >> 32) * delta; - scale &= 0xffffffff; - bt->sec += x >> 32; - bintime_addx(bt, x << 32); - } - bintime_addx(bt, scale * delta); - if (abs) - bintime_add(bt, &th->th_boottime); - - /* - * Ensure that the load of th_offset is completed - * before the load of th_gen. - */ - atomic_thread_fence_acq(); - } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); - return (0); -} - -static int -freebsd_getnanouptime(struct bintime *bt, struct vdso_timekeep *tk) -{ - struct vdso_timehands *th; - uint32_t curr, gen; - - do { - if (!tk->tk_enabled) - return (ENOSYS); - - curr = atomic_load_acq_32(&tk->tk_current); - th = &tk->tk_th[curr]; - gen = atomic_load_acq_32(&th->th_gen); - *bt = th->th_offset; - - /* - * Ensure that the load of th_offset is completed - * before the load of th_gen. - */ - atomic_thread_fence_acq(); - } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); - return (0); -} - -static int -freebsd_gettimeofday(struct timeval *tv, struct timezone *tz) -{ - struct vdso_timekeep *tk; - struct bintime bt; - int error; - - if (tz != NULL) - return (ENOSYS); - __vdso_gettimekeep(&tk); - if (tk == NULL) - return (ENOSYS); - if (tk->tk_ver != VDSO_TK_VER_CURR) - return (ENOSYS); - error = freebsd_binuptime(&bt, tk, true); - if (error == 0) - bintime2timeval(&bt, tv); - return (error); -} - -static int -freebsd_clock_gettime(clockid_t clock_id, struct timespec *ts) -{ - struct vdso_timekeep *tk; - struct bintime bt; - int error; - - __vdso_gettimekeep(&tk); - if (tk == NULL) - return (ENOSYS); - if (tk->tk_ver != VDSO_TK_VER_CURR) - return (ENOSYS); - switch (clock_id) { - case CLOCK_REALTIME: - case CLOCK_REALTIME_PRECISE: - case CLOCK_REALTIME_FAST: - error = freebsd_binuptime(&bt, tk, true); - break; - case CLOCK_MONOTONIC: - case CLOCK_MONOTONIC_PRECISE: - case CLOCK_UPTIME: - case CLOCK_UPTIME_PRECISE: - error = freebsd_binuptime(&bt, tk, false); - break; - case CLOCK_MONOTONIC_FAST: - case CLOCK_UPTIME_FAST: - error = freebsd_getnanouptime(&bt, tk); - break; - default: - error = ENOSYS; - break; - } - if (error == 0) - bintime2timespec(&bt, ts); - return (error); -} - -/* - * Linux vDSO interfaces - * - */ -int -__vdsoN(clock_gettime)(clockid_t clock_id, struct l_timespec *lts) -{ - struct timespec ts; - clockid_t which; - int error; - - error = __vdso_linux_to_native_clockid(&which, clock_id); - if (error != 0) - return (__vdso_clock_gettime_fallback(clock_id, lts)); - error = freebsd_clock_gettime(which, &ts); - if (error == 0) - return (-__vdso_native_to_linux_timespec(lts, &ts)); - else - return (__vdso_clock_gettime_fallback(clock_id, lts)); -} - -int -__vdsoN(gettimeofday)(l_timeval *ltv, struct timezone *tz) -{ - struct timeval tv; - int error; - - error = freebsd_gettimeofday(&tv, tz); - if (error != 0) - return (__vdso_gettimeofday_fallback(ltv, tz)); - return (-__vdso_native_to_linux_timeval(ltv, &tv)); -} - -int -__vdsoN(clock_getres)(clockid_t clock_id, struct l_timespec *lts) -{ - - return (__vdso_clock_getres_fallback(clock_id, lts)); -} - -#if defined(__i386__) || defined(COMPAT_LINUX32) -int -__vdso_clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts) -{ - struct timespec ts; - clockid_t which; - int error; - - error = __vdso_linux_to_native_clockid(&which, clock_id); - if (error != 0) - return (__vdso_clock_gettime64_fallback(clock_id, lts)); - error = freebsd_clock_gettime(which, &ts); - if (error == 0) - return(-__vdso_native_to_linux_timespec64(lts, &ts)); - else - return(__vdso_clock_gettime64_fallback(clock_id, lts)); -} - -int clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts) - __attribute__((weak, alias("__vdso_clock_gettime64"))); -#endif - -#if defined(__i386__) || defined(__amd64__) -int -__vdso_getcpu(uint32_t *cpu, uint32_t *node, void *cache) -{ - int ret; - - if (node != NULL) - return (__vdso_getcpu_fallback(cpu, node, cache)); - ret = __vdso_getcpu_try(); - if (ret < 0) - return (__vdso_getcpu_fallback(cpu, node, cache)); - *cpu = ret; - return (0); -} -#endif - -#if defined(__i386__) || defined(__amd64__) -int -__vdso_time(long *tm) -{ - struct timeval tv; - int error; - - error = freebsd_gettimeofday(&tv, NULL); - if (error != 0) - return (__vdso_time_fallback(tm)); - if (tm != NULL) - *tm = tv.tv_sec; - return (tv.tv_sec); -} -#endif +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2012 Konstantin Belousov + * Copyright (c) 2021 Dmitry Chagin + * + * 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. + */ + +#if defined(__aarch64__) +#define __VDSO_PREFIX __kernel +#else +#define __VDSO_PREFIX __vdso +#endif + +#define __vdsoN(x) __CONCAT(__CONCAT(__VDSO_PREFIX,_),x) + +static int +fls(int mask) +{ + + if (mask == 0) + return (0); + return ((__builtin_clz(mask) ^ 0x1f) + 1); +} + +#ifdef _LP64 +static int +flsl(long mask) +{ + int bit; + + if (mask == 0) + return (0); + for (bit = 1; mask != 1; bit++) + mask = (unsigned long)mask >> 1; + return (bit); +} +#else +static int +flsll(long long mask) +{ + int bit; + + if (mask == 0) + return (0); + for (bit = 1; mask != 1; bit++) + mask = (unsigned long long)mask >> 1; + return (bit); +} +#endif + +static int +__vdso_native_to_linux_timespec(struct l_timespec *lts, + struct timespec *nts) +{ + +#ifdef COMPAT_LINUX32 + if (nts->tv_sec > INT_MAX || nts->tv_sec < INT_MIN) + return (LINUX_EOVERFLOW); +#endif + lts->tv_sec = nts->tv_sec; + lts->tv_nsec = nts->tv_nsec; + return (0); +} + +static int +__vdso_native_to_linux_timeval(l_timeval *ltv, + struct timeval *ntv) +{ + +#ifdef COMPAT_LINUX32 + if (ntv->tv_sec > INT_MAX || ntv->tv_sec < INT_MIN) + return (LINUX_EOVERFLOW); +#endif + ltv->tv_sec = ntv->tv_sec; + ltv->tv_usec = ntv->tv_usec; + return (0); +} + + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +static int +__vdso_native_to_linux_timespec64(struct l_timespec64 *lts, + struct timespec *nts) +{ + + lts->tv_sec = nts->tv_sec; + lts->tv_nsec = nts->tv_nsec; + return (0); +} +#endif + +static int +__vdso_linux_to_native_clockid(clockid_t *n, clockid_t l) +{ + + switch (l) { + case LINUX_CLOCK_REALTIME: + *n = CLOCK_REALTIME; + break; + case LINUX_CLOCK_MONOTONIC: + *n = CLOCK_MONOTONIC; + break; + case LINUX_CLOCK_REALTIME_COARSE: + *n = CLOCK_REALTIME_FAST; + break; + case LINUX_CLOCK_MONOTONIC_COARSE: + case LINUX_CLOCK_MONOTONIC_RAW: + *n = CLOCK_MONOTONIC_FAST; + break; + case LINUX_CLOCK_BOOTTIME: + *n = CLOCK_UPTIME; + break; + default: + return (LINUX_EINVAL); + } + return (0); +} + +/* + * The code below adapted from + * lib/libc/sys/__vdso_gettimeofday.c + */ + +static inline void +__vdso_gettimekeep(struct vdso_timekeep **tk) +{ + + *tk = (struct vdso_timekeep *)kern_timekeep_base; +} + +static int +tc_delta(const struct vdso_timehands *th, u_int *delta) +{ + int error; + u_int tc; + + error = __vdso_gettc(th, &tc); + if (error == 0) + *delta = (tc - th->th_offset_count) & th->th_counter_mask; + return (error); +} + +/* + * Calculate the absolute or boot-relative time from the + * machine-specific fast timecounter and the published timehands + * structure read from the shared page. + * + * The lockless reading scheme is similar to the one used to read the + * in-kernel timehands, see sys/kern/kern_tc.c:binuptime(). This code + * is based on the kernel implementation. + */ +static int +freebsd_binuptime(struct bintime *bt, struct vdso_timekeep *tk, bool abs) +{ + struct vdso_timehands *th; + uint32_t curr, gen; + uint64_t scale, x; + u_int delta, scale_bits; + int error; + + do { + if (!tk->tk_enabled) + return (ENOSYS); + + curr = atomic_load_acq_32(&tk->tk_current); + th = &tk->tk_th[curr]; + gen = atomic_load_acq_32(&th->th_gen); + *bt = th->th_offset; + error = tc_delta(th, &delta); + if (error == EAGAIN) + continue; + if (error != 0) + return (error); + scale = th->th_scale; +#ifdef _LP64 + scale_bits = flsl(scale); +#else + scale_bits = flsll(scale); +#endif + if (__predict_false(scale_bits + fls(delta) > 63)) { + x = (scale >> 32) * delta; + scale &= 0xffffffff; + bt->sec += x >> 32; + bintime_addx(bt, x << 32); + } + bintime_addx(bt, scale * delta); + if (abs) + bintime_add(bt, &th->th_boottime); + + /* + * Ensure that the load of th_offset is completed + * before the load of th_gen. + */ + atomic_thread_fence_acq(); + } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); + return (0); +} + +static int +freebsd_getnanouptime(struct bintime *bt, struct vdso_timekeep *tk) +{ + struct vdso_timehands *th; + uint32_t curr, gen; + + do { + if (!tk->tk_enabled) + return (ENOSYS); + + curr = atomic_load_acq_32(&tk->tk_current); + th = &tk->tk_th[curr]; + gen = atomic_load_acq_32(&th->th_gen); + *bt = th->th_offset; + + /* + * Ensure that the load of th_offset is completed + * before the load of th_gen. + */ + atomic_thread_fence_acq(); + } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); + return (0); +} + +static int +freebsd_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + struct vdso_timekeep *tk; + struct bintime bt; + int error; + + if (tz != NULL) + return (ENOSYS); + __vdso_gettimekeep(&tk); + if (tk == NULL) + return (ENOSYS); + if (tk->tk_ver != VDSO_TK_VER_CURR) + return (ENOSYS); + error = freebsd_binuptime(&bt, tk, true); + if (error == 0) + bintime2timeval(&bt, tv); + return (error); +} + +static int +freebsd_clock_gettime(clockid_t clock_id, struct timespec *ts) +{ + struct vdso_timekeep *tk; + struct bintime bt; + int error; + + __vdso_gettimekeep(&tk); + if (tk == NULL) + return (ENOSYS); + if (tk->tk_ver != VDSO_TK_VER_CURR) + return (ENOSYS); + switch (clock_id) { + case CLOCK_REALTIME: + case CLOCK_REALTIME_PRECISE: + case CLOCK_REALTIME_FAST: + error = freebsd_binuptime(&bt, tk, true); + break; + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_PRECISE: + case CLOCK_UPTIME: + case CLOCK_UPTIME_PRECISE: + error = freebsd_binuptime(&bt, tk, false); + break; + case CLOCK_MONOTONIC_FAST: + case CLOCK_UPTIME_FAST: + error = freebsd_getnanouptime(&bt, tk); + break; + default: + error = ENOSYS; + break; + } + if (error == 0) + bintime2timespec(&bt, ts); + return (error); +} + +/* + * Linux vDSO interfaces + * + */ +int +__vdsoN(clock_gettime)(clockid_t clock_id, struct l_timespec *lts) +{ + struct timespec ts; + clockid_t which; + int error; + + error = __vdso_linux_to_native_clockid(&which, clock_id); + if (error != 0) + return (__vdso_clock_gettime_fallback(clock_id, lts)); + error = freebsd_clock_gettime(which, &ts); + if (error == 0) + return (-__vdso_native_to_linux_timespec(lts, &ts)); + else + return (__vdso_clock_gettime_fallback(clock_id, lts)); +} + +int +__vdsoN(gettimeofday)(l_timeval *ltv, struct timezone *tz) +{ + struct timeval tv; + int error; + + error = freebsd_gettimeofday(&tv, tz); + if (error != 0) + return (__vdso_gettimeofday_fallback(ltv, tz)); + return (-__vdso_native_to_linux_timeval(ltv, &tv)); +} + +int +__vdsoN(clock_getres)(clockid_t clock_id, struct l_timespec *lts) +{ + + return (__vdso_clock_getres_fallback(clock_id, lts)); +} + +#if defined(__i386__) || defined(COMPAT_LINUX32) +int +__vdso_clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts) +{ + struct timespec ts; + clockid_t which; + int error; + + error = __vdso_linux_to_native_clockid(&which, clock_id); + if (error != 0) + return (__vdso_clock_gettime64_fallback(clock_id, lts)); + error = freebsd_clock_gettime(which, &ts); + if (error == 0) + return(-__vdso_native_to_linux_timespec64(lts, &ts)); + else + return(__vdso_clock_gettime64_fallback(clock_id, lts)); +} + +int clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts) + __attribute__((weak, alias("__vdso_clock_gettime64"))); +#endif + +#if defined(__i386__) || defined(__amd64__) +int +__vdso_getcpu(uint32_t *cpu, uint32_t *node, void *cache) +{ + int ret; + + if (node != NULL) + return (__vdso_getcpu_fallback(cpu, node, cache)); + ret = __vdso_getcpu_try(); + if (ret < 0) + return (__vdso_getcpu_fallback(cpu, node, cache)); + *cpu = ret; + return (0); +} +#endif + +#if defined(__i386__) || defined(__amd64__) +int +__vdso_time(long *tm) +{ + struct timeval tv; + int error; + + error = freebsd_gettimeofday(&tv, NULL); + if (error != 0) + return (__vdso_time_fallback(tm)); + if (tm != NULL) + *tm = tv.tv_sec; + return (tv.tv_sec); +} +#endif diff --git a/sys/compat/linux/linux_vdso_inc.S b/sys/compat/linux/linux_vdso_inc.S index 44cc357b4a4a..79773d79b2dd 100644 --- a/sys/compat/linux/linux_vdso_inc.S +++ b/sys/compat/linux/linux_vdso_inc.S @@ -1,39 +1,41 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (C) 2020 Arm Ltd - * - * 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. - */ - - .section .data - .globl _binary_linux_vdso_so_o_start -_binary_linux_vdso_so_o_start: - .incbin "linux_vdso.so.o" - .globl _binary_linux_vdso_so_o_end -_binary_linux_vdso_so_o_end: - -#if defined(__aarch64__) -#include -#include -GNU_PROPERTY_AARCH64_FEATURE_1_NOTE(GNU_PROPERTY_AARCH64_FEATURE_1_VAL) -#endif +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2020 Arm Ltd + * + * 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. + */ + + .section .data + .globl _binary_linux_vdso_so_o_start + .type _binary_linux_vdso_so_o_start, #object +_binary_linux_vdso_so_o_start: + .incbin "linux_vdso.so.o" + .size _binary_linux_vdso_so_o_start, . - _binary_linux_vdso_so_o_start + .globl _binary_linux_vdso_so_o_end +_binary_linux_vdso_so_o_end: + +#if defined(__aarch64__) +#include +#include +GNU_PROPERTY_AARCH64_FEATURE_1_NOTE(GNU_PROPERTY_AARCH64_FEATURE_1_VAL) +#endif diff --git a/sys/compat/linux/linux_videodev2_compat.h b/sys/compat/linux/linux_videodev2_compat.h index cd7ca5f002e1..52e86e5f84bc 100644 --- a/sys/compat/linux/linux_videodev2_compat.h +++ b/sys/compat/linux/linux_videodev2_compat.h @@ -1,133 +1,133 @@ -/* - * This file defines compatibility versions of several video structures - * defined in the Linux videodev2.h header (linux_videodev2.h). The - * structures defined in this file are the ones that have been determined - * to have 32- to 64-bit size dependencies. - */ - -#ifndef _LINUX_VIDEODEV2_COMPAT_H_ -#define _LINUX_VIDEODEV2_COMPAT_H_ - -struct l_v4l2_buffer { - uint32_t index; - enum v4l2_buf_type type; - uint32_t bytesused; - uint32_t flags; - enum v4l2_field field; - l_timeval timestamp; - struct v4l2_timecode timecode; - uint32_t sequence; - - /* memory location */ - enum v4l2_memory memory; - union { - uint32_t offset; - l_ulong userptr; - } m; - uint32_t length; - uint32_t input; - uint32_t reserved; -}; - -struct l_v4l2_framebuffer { - uint32_t capability; - uint32_t flags; -/* FIXME: in theory we should pass something like PCI device + memory - * region + offset instead of some physical address */ - l_uintptr_t base; - struct v4l2_pix_format fmt; -}; - -struct l_v4l2_clip { - struct v4l2_rect c; - l_uintptr_t next; -}; - -struct l_v4l2_window { - struct v4l2_rect w; - enum v4l2_field field; - uint32_t chromakey; - l_uintptr_t clips; - uint32_t clipcount; - l_uintptr_t bitmap; - uint8_t global_alpha; -}; - -struct l_v4l2_standard { - uint32_t index; - v4l2_std_id id; - uint8_t name[24]; - struct v4l2_fract frameperiod; /* Frames, not fields */ - uint32_t framelines; - uint32_t reserved[4]; -} -#ifdef COMPAT_LINUX32 /* 32bit linuxolator */ -__attribute__ ((packed)) -#endif -; - -struct l_v4l2_ext_control { - uint32_t id; - uint32_t size; - uint32_t reserved2[1]; - union { - int32_t value; - int64_t value64; - l_uintptr_t string; - } u; -} __attribute__ ((packed)); - -struct l_v4l2_ext_controls { - uint32_t ctrl_class; - uint32_t count; - uint32_t error_idx; - uint32_t reserved[2]; - l_uintptr_t controls; -}; - -struct l_v4l2_format { - enum v4l2_buf_type type; - union { - struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ - struct l_v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ - struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ - struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ - uint8_t raw_data[200]; /* user-defined */ - } fmt; -} -#ifdef COMPAT_LINUX32 /* 32bit linuxolator */ -__attribute__ ((packed)) -#endif -; - -#ifdef VIDIOC_DQEVENT -struct l_v4l2_event { - uint32_t type; - union { - struct v4l2_event_vsync vsync; - uint8_t data[64]; - } u; - uint32_t pending; - uint32_t sequence; - struct l_timespec timestamp; - uint32_t reserved[9]; -}; -#endif - -struct l_v4l2_input { - uint32_t index; /* Which input */ - uint8_t name[32]; /* Label */ - uint32_t type; /* Type of input */ - uint32_t audioset; /* Associated audios (bitfield) */ - uint32_t tuner; /* Associated tuner */ - v4l2_std_id std; - uint32_t status; - uint32_t capabilities; - uint32_t reserved[3]; -} -#ifdef COMPAT_LINUX32 /* 32bit linuxolator */ -__attribute__ ((packed)) -#endif -; - -#endif /* _LINUX_VIDEODEV2_COMPAT_H_ */ +/* + * This file defines compatibility versions of several video structures + * defined in the Linux videodev2.h header (linux_videodev2.h). The + * structures defined in this file are the ones that have been determined + * to have 32- to 64-bit size dependencies. + */ + +#ifndef _LINUX_VIDEODEV2_COMPAT_H_ +#define _LINUX_VIDEODEV2_COMPAT_H_ + +struct l_v4l2_buffer { + uint32_t index; + enum v4l2_buf_type type; + uint32_t bytesused; + uint32_t flags; + enum v4l2_field field; + l_timeval timestamp; + struct v4l2_timecode timecode; + uint32_t sequence; + + /* memory location */ + enum v4l2_memory memory; + union { + uint32_t offset; + l_ulong userptr; + } m; + uint32_t length; + uint32_t input; + uint32_t reserved; +}; + +struct l_v4l2_framebuffer { + uint32_t capability; + uint32_t flags; +/* FIXME: in theory we should pass something like PCI device + memory + * region + offset instead of some physical address */ + l_uintptr_t base; + struct v4l2_pix_format fmt; +}; + +struct l_v4l2_clip { + struct v4l2_rect c; + l_uintptr_t next; +}; + +struct l_v4l2_window { + struct v4l2_rect w; + enum v4l2_field field; + uint32_t chromakey; + l_uintptr_t clips; + uint32_t clipcount; + l_uintptr_t bitmap; + uint8_t global_alpha; +}; + +struct l_v4l2_standard { + uint32_t index; + v4l2_std_id id; + uint8_t name[24]; + struct v4l2_fract frameperiod; /* Frames, not fields */ + uint32_t framelines; + uint32_t reserved[4]; +} +#ifdef COMPAT_LINUX32 /* 32bit linuxolator */ +__attribute__ ((packed)) +#endif +; + +struct l_v4l2_ext_control { + uint32_t id; + uint32_t size; + uint32_t reserved2[1]; + union { + int32_t value; + int64_t value64; + l_uintptr_t string; + } u; +}; + +struct l_v4l2_ext_controls { + uint32_t ctrl_class; + uint32_t count; + uint32_t error_idx; + uint32_t reserved[2]; + l_uintptr_t controls; +}; + +struct l_v4l2_format { + enum v4l2_buf_type type; + union { + struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ + struct l_v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ + struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ + struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ + uint8_t raw_data[200]; /* user-defined */ + } fmt; +} +#ifdef COMPAT_LINUX32 /* 32bit linuxolator */ +__attribute__ ((packed)) +#endif +; + +#ifdef VIDIOC_DQEVENT +struct l_v4l2_event { + uint32_t type; + union { + struct v4l2_event_vsync vsync; + uint8_t data[64]; + } u; + uint32_t pending; + uint32_t sequence; + struct l_timespec timestamp; + uint32_t reserved[9]; +}; +#endif + +struct l_v4l2_input { + uint32_t index; /* Which input */ + uint8_t name[32]; /* Label */ + uint32_t type; /* Type of input */ + uint32_t audioset; /* Associated audios (bitfield) */ + uint32_t tuner; /* Associated tuner */ + v4l2_std_id std; + uint32_t status; + uint32_t capabilities; + uint32_t reserved[3]; +} +#ifdef COMPAT_LINUX32 /* 32bit linuxolator */ +__attribute__ ((packed)) +#endif +; + +#endif /* _LINUX_VIDEODEV2_COMPAT_H_ */ diff --git a/sys/compat/linux/linux_videodev_compat.h b/sys/compat/linux/linux_videodev_compat.h index c35a59d2ecf8..1146a9064069 100644 --- a/sys/compat/linux/linux_videodev_compat.h +++ b/sys/compat/linux/linux_videodev_compat.h @@ -1,55 +1,55 @@ -/* - * This file defines compatibility versions of several video structures - * defined in the Linux videodev.h header (linux_videodev.h). The - * structures defined in this file are the ones that have been determined - * to have 32- to 64-bit size dependencies. - */ - -#ifndef _LINUX_VIDEODEV_COMPAT_H_ -#define _LINUX_VIDEODEV_COMPAT_H_ - -struct l_video_tuner -{ - l_int tuner; -#define LINUX_VIDEO_TUNER_NAME_SIZE 32 - char name[LINUX_VIDEO_TUNER_NAME_SIZE]; - l_ulong rangelow, rangehigh; - uint32_t flags; - uint16_t mode; - uint16_t signal; -}; - -struct l_video_clip -{ - int32_t x, y; - int32_t width, height; - l_uintptr_t next; -}; - -struct l_video_window -{ - uint32_t x, y; - uint32_t width, height; - uint32_t chromakey; - uint32_t flags; - l_uintptr_t clips; - l_int clipcount; -}; - -struct l_video_buffer -{ - l_uintptr_t base; - l_int height, width; - l_int depth; - l_int bytesperline; -}; - -struct l_video_code -{ -#define LINUX_VIDEO_CODE_LOADWHAT_SIZE 16 - char loadwhat[LINUX_VIDEO_CODE_LOADWHAT_SIZE]; - l_int datasize; - l_uintptr_t data; -}; - -#endif /* !_LINUX_VIDEODEV_COMPAT_H_ */ +/* + * This file defines compatibility versions of several video structures + * defined in the Linux videodev.h header (linux_videodev.h). The + * structures defined in this file are the ones that have been determined + * to have 32- to 64-bit size dependencies. + */ + +#ifndef _LINUX_VIDEODEV_COMPAT_H_ +#define _LINUX_VIDEODEV_COMPAT_H_ + +struct l_video_tuner +{ + l_int tuner; +#define LINUX_VIDEO_TUNER_NAME_SIZE 32 + char name[LINUX_VIDEO_TUNER_NAME_SIZE]; + l_ulong rangelow, rangehigh; + uint32_t flags; + uint16_t mode; + uint16_t signal; +}; + +struct l_video_clip +{ + int32_t x, y; + int32_t width, height; + l_uintptr_t next; +}; + +struct l_video_window +{ + uint32_t x, y; + uint32_t width, height; + uint32_t chromakey; + uint32_t flags; + l_uintptr_t clips; + l_int clipcount; +}; + +struct l_video_buffer +{ + l_uintptr_t base; + l_int height, width; + l_int depth; + l_int bytesperline; +}; + +struct l_video_code +{ +#define LINUX_VIDEO_CODE_LOADWHAT_SIZE 16 + char loadwhat[LINUX_VIDEO_CODE_LOADWHAT_SIZE]; + l_int datasize; + l_uintptr_t data; +}; + +#endif /* !_LINUX_VIDEODEV_COMPAT_H_ */ diff --git a/sys/compat/linux/linux_xattr.c b/sys/compat/linux/linux_xattr.c index 6979fff9c82d..b92442651f63 100644 --- a/sys/compat/linux/linux_xattr.c +++ b/sys/compat/linux/linux_xattr.c @@ -1,460 +1,463 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2023 Dmitry Chagin - * - * 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 -#include -#include -#include -#include -#include - -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif - -#include - -#define LINUX_XATTR_SIZE_MAX 65536 -#define LINUX_XATTR_LIST_MAX 65536 -#define LINUX_XATTR_NAME_MAX 255 - -#define LINUX_XATTR_CREATE 0x1 -#define LINUX_XATTR_REPLACE 0x2 -#define LINUX_XATTR_FLAGS LINUX_XATTR_CREATE|LINUX_XATTR_REPLACE - -struct listxattr_args { - int fd; - const char *path; - char *list; - l_size_t size; - int follow; -}; - -struct setxattr_args { - int fd; - const char *path; - const char *name; - void *value; - l_size_t size; - l_int flags; - int follow; -}; - -struct getxattr_args { - int fd; - const char *path; - const char *name; - void *value; - l_size_t size; - int follow; -}; - -struct removexattr_args { - int fd; - const char *path; - const char *name; - int follow; -}; - -static char *extattr_namespace_names[] = EXTATTR_NAMESPACE_NAMES; - - -static int -error_to_xattrerror(int attrnamespace, int error) -{ - - if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM && error == EPERM) - return (ENOTSUP); - else - return (error); -} - -static int -xatrr_to_extattr(const char *uattrname, int *attrnamespace, char *attrname) -{ - char uname[LINUX_XATTR_NAME_MAX + 1], *dot; - size_t len, cplen; - int error; - - error = copyinstr(uattrname, uname, sizeof(uname), &cplen); - if (error != 0) - return (error); - if (cplen == sizeof(uname)) - return (ERANGE); - dot = strchr(uname, '.'); - if (dot == NULL) - return (ENOTSUP); - *dot = '\0'; - for (*attrnamespace = EXTATTR_NAMESPACE_USER; - *attrnamespace < nitems(extattr_namespace_names); - (*attrnamespace)++) { - if (bcmp(uname, extattr_namespace_names[*attrnamespace], - dot - uname + 1) == 0) { - dot++; - len = strlen(dot) + 1; - bcopy(dot, attrname, len); - return (0); - } - } - return (ENOTSUP); -} - -static int -listxattr(struct thread *td, struct listxattr_args *args) -{ - char attrname[LINUX_XATTR_NAME_MAX + 1]; - char *data, *prefix, *key; - struct uio auio; - struct iovec aiov; - unsigned char keylen; - size_t sz, cnt, rs, prefixlen, pairlen; - int attrnamespace, error; - - if (args->size != 0) - sz = min(LINUX_XATTR_LIST_MAX, args->size); - else - sz = LINUX_XATTR_LIST_MAX; - - data = malloc(sz, M_LINUX, M_WAITOK); - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_td = td; - cnt = 0; - for (attrnamespace = EXTATTR_NAMESPACE_USER; - attrnamespace < nitems(extattr_namespace_names); - attrnamespace++) { - aiov.iov_base = data; - aiov.iov_len = sz; - auio.uio_resid = sz; - auio.uio_offset = 0; - - if (args->path != NULL) - error = kern_extattr_list_path(td, args->path, - attrnamespace, &auio, args->follow, UIO_USERSPACE); - else - error = kern_extattr_list_fd(td, args->fd, - attrnamespace, &auio); - rs = sz - auio.uio_resid; - if (error == EPERM) - break; - if (error != 0 || rs == 0) - continue; - prefix = extattr_namespace_names[attrnamespace]; - prefixlen = strlen(prefix); - key = data; - while (rs > 0) { - keylen = (unsigned char)key[0]; - pairlen = prefixlen + 1 + keylen + 1; - cnt += pairlen; - if (cnt > LINUX_XATTR_LIST_MAX) { - error = E2BIG; - break; - } - /* - * If size is specified as zero, return the current size - * of the list of extended attribute names. - */ - if ((args->size > 0 && cnt > args->size) || - pairlen >= sizeof(attrname)) { - error = ERANGE; - break; - } - ++key; - if (args->list != NULL && args->size > 0) { - sprintf(attrname, "%s.%.*s", prefix, keylen, key); - error = copyout(attrname, args->list, pairlen); - if (error != 0) - break; - args->list += pairlen; - } - key += keylen; - rs -= (keylen + 1); - } - } - if (error == 0) - td->td_retval[0] = cnt; - free(data, M_LINUX); - return (error_to_xattrerror(attrnamespace, error)); -} - -int -linux_listxattr(struct thread *td, struct linux_listxattr_args *args) -{ - struct listxattr_args eargs = { - .fd = -1, - .path = args->path, - .list = args->list, - .size = args->size, - .follow = FOLLOW, - }; - - return (listxattr(td, &eargs)); -} - -int -linux_llistxattr(struct thread *td, struct linux_llistxattr_args *args) -{ - struct listxattr_args eargs = { - .fd = -1, - .path = args->path, - .list = args->list, - .size = args->size, - .follow = NOFOLLOW, - }; - - return (listxattr(td, &eargs)); -} - -int -linux_flistxattr(struct thread *td, struct linux_flistxattr_args *args) -{ - struct listxattr_args eargs = { - .fd = args->fd, - .path = NULL, - .list = args->list, - .size = args->size, - .follow = 0, - }; - - return (listxattr(td, &eargs)); -} - -static int -removexattr(struct thread *td, struct removexattr_args *args) -{ - char attrname[LINUX_XATTR_NAME_MAX + 1]; - int attrnamespace, error; - - error = xatrr_to_extattr(args->name, &attrnamespace, attrname); - if (error != 0) - return (error); - if (args->path != NULL) - error = kern_extattr_delete_path(td, args->path, attrnamespace, - attrname, args->follow, UIO_USERSPACE); - else - error = kern_extattr_delete_fd(td, args->fd, attrnamespace, - attrname); - return (error_to_xattrerror(attrnamespace, error)); -} - -int -linux_removexattr(struct thread *td, struct linux_removexattr_args *args) -{ - struct removexattr_args eargs = { - .fd = -1, - .path = args->path, - .name = args->name, - .follow = FOLLOW, - }; - - return (removexattr(td, &eargs)); -} - -int -linux_lremovexattr(struct thread *td, struct linux_lremovexattr_args *args) -{ - struct removexattr_args eargs = { - .fd = -1, - .path = args->path, - .name = args->name, - .follow = NOFOLLOW, - }; - - return (removexattr(td, &eargs)); -} - -int -linux_fremovexattr(struct thread *td, struct linux_fremovexattr_args *args) -{ - struct removexattr_args eargs = { - .fd = args->fd, - .path = NULL, - .name = args->name, - .follow = 0, - }; - - return (removexattr(td, &eargs)); -} - -static int -getxattr(struct thread *td, struct getxattr_args *args) -{ - char attrname[LINUX_XATTR_NAME_MAX + 1]; - int attrnamespace, error; - - error = xatrr_to_extattr(args->name, &attrnamespace, attrname); - if (error != 0) - return (error); - if (args->path != NULL) - error = kern_extattr_get_path(td, args->path, attrnamespace, - attrname, args->value, args->size, args->follow, UIO_USERSPACE); - else - error = kern_extattr_get_fd(td, args->fd, attrnamespace, - attrname, args->value, args->size); - return (error == EPERM ? ENOATTR : error); -} - -int -linux_getxattr(struct thread *td, struct linux_getxattr_args *args) -{ - struct getxattr_args eargs = { - .fd = -1, - .path = args->path, - .name = args->name, - .value = args->value, - .size = args->size, - .follow = FOLLOW, - }; - - return (getxattr(td, &eargs)); -} - -int -linux_lgetxattr(struct thread *td, struct linux_lgetxattr_args *args) -{ - struct getxattr_args eargs = { - .fd = -1, - .path = args->path, - .name = args->name, - .value = args->value, - .size = args->size, - .follow = NOFOLLOW, - }; - - return (getxattr(td, &eargs)); -} - -int -linux_fgetxattr(struct thread *td, struct linux_fgetxattr_args *args) -{ - struct getxattr_args eargs = { - .fd = args->fd, - .path = NULL, - .name = args->name, - .value = args->value, - .size = args->size, - .follow = 0, - }; - - return (getxattr(td, &eargs)); -} - -static int -setxattr(struct thread *td, struct setxattr_args *args) -{ - char attrname[LINUX_XATTR_NAME_MAX + 1]; - int attrnamespace, error; - - if ((args->flags & ~(LINUX_XATTR_FLAGS)) != 0 || - args->flags == (LINUX_XATTR_FLAGS)) - return (EINVAL); - error = xatrr_to_extattr(args->name, &attrnamespace, attrname); - if (error != 0) - return (error); - - if ((args->flags & (LINUX_XATTR_FLAGS)) != 0 ) { - if (args->path != NULL) - error = kern_extattr_get_path(td, args->path, - attrnamespace, attrname, NULL, args->size, - args->follow, UIO_USERSPACE); - else - error = kern_extattr_get_fd(td, args->fd, - attrnamespace, attrname, NULL, args->size); - if ((args->flags & LINUX_XATTR_CREATE) != 0) { - if (error == 0) - error = EEXIST; - else if (error == ENOATTR) - error = 0; - } - if (error != 0) - goto out; - } - if (args->path != NULL) - error = kern_extattr_set_path(td, args->path, attrnamespace, - attrname, args->value, args->size, args->follow, - UIO_USERSPACE); - else - error = kern_extattr_set_fd(td, args->fd, attrnamespace, - attrname, args->value, args->size); -out: - td->td_retval[0] = 0; - return (error_to_xattrerror(attrnamespace, error)); -} - -int -linux_setxattr(struct thread *td, struct linux_setxattr_args *args) -{ - struct setxattr_args eargs = { - .fd = -1, - .path = args->path, - .name = args->name, - .value = args->value, - .size = args->size, - .flags = args->flags, - .follow = FOLLOW, - }; - - return (setxattr(td, &eargs)); -} - -int -linux_lsetxattr(struct thread *td, struct linux_lsetxattr_args *args) -{ - struct setxattr_args eargs = { - .fd = -1, - .path = args->path, - .name = args->name, - .value = args->value, - .size = args->size, - .flags = args->flags, - .follow = NOFOLLOW, - }; - - return (setxattr(td, &eargs)); -} - -int -linux_fsetxattr(struct thread *td, struct linux_fsetxattr_args *args) -{ - struct setxattr_args eargs = { - .fd = args->fd, - .path = NULL, - .name = args->name, - .value = args->value, - .size = args->size, - .flags = args->flags, - .follow = 0, - }; - - return (setxattr(td, &eargs)); -} +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Dmitry Chagin + * + * 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 +#include +#include +#include +#include +#include + +#if defined(COMPAT_LINUX32) +#include +#include +#elif defined(COMPAT_LINUX64) +#include +#include +#else +#include +#include +#endif + +#include + +#define LINUX_XATTR_SIZE_MAX 65536 +#define LINUX_XATTR_LIST_MAX 65536 +#define LINUX_XATTR_NAME_MAX 255 + +#define LINUX_XATTR_CREATE 0x1 +#define LINUX_XATTR_REPLACE 0x2 +#define LINUX_XATTR_FLAGS LINUX_XATTR_CREATE|LINUX_XATTR_REPLACE + +struct listxattr_args { + int fd; + const char * __kerncap path; + char * __kerncap list; + l_size_t size; + int follow; +}; + +struct setxattr_args { + int fd; + const char * __kerncap path; + const char * __kerncap name; + void * __kerncap value; + l_size_t size; + l_int flags; + int follow; +}; + +struct getxattr_args { + int fd; + const char * __kerncap path; + const char * __kerncap name; + void * __kerncap value; + l_size_t size; + int follow; +}; + +struct removexattr_args { + int fd; + const char * __kerncap path; + const char * __kerncap name; + int follow; +}; + +static char *extattr_namespace_names[] = EXTATTR_NAMESPACE_NAMES; + + +static int +error_to_xattrerror(int attrnamespace, int error) +{ + + if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM && error == EPERM) + return (ENOTSUP); + else + return (error); +} + +static int +xatrr_to_extattr(const char * __capability uattrname, int *attrnamespace, char *attrname) +{ + char uname[LINUX_XATTR_NAME_MAX + 1], *dot; + size_t len, cplen; + int error; + + error = copyinstr(uattrname, uname, sizeof(uname), &cplen); + if (error != 0) + return (error); + if (cplen == sizeof(uname)) + return (ERANGE); + dot = strchr(uname, '.'); + if (dot == NULL) + return (ENOTSUP); + *dot = '\0'; + for (*attrnamespace = EXTATTR_NAMESPACE_USER; + *attrnamespace < nitems(extattr_namespace_names); + (*attrnamespace)++) { + if (bcmp(uname, extattr_namespace_names[*attrnamespace], + dot - uname + 1) == 0) { + dot++; + len = strlen(dot) + 1; + bcopy(dot, attrname, len); + return (0); + } + } + return (ENOTSUP); +} + +static int +listxattr(struct thread *td, struct listxattr_args *args) +{ + char attrname[LINUX_XATTR_NAME_MAX + 1]; + char * __capability data, *prefix, * __capability key; + struct uio auio; + struct iovec aiov; + unsigned char keylen; + size_t sz, cnt, rs, prefixlen, pairlen; + int attrnamespace, error; + + if (args->size != 0) + sz = min(LINUX_XATTR_LIST_MAX, args->size); + else + sz = LINUX_XATTR_LIST_MAX; + + data = malloc_c(sz, M_LINUX, M_WAITOK); + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_td = td; + cnt = 0; + for (attrnamespace = EXTATTR_NAMESPACE_USER; + attrnamespace < nitems(extattr_namespace_names); + attrnamespace++) { + aiov.iov_base = data; + aiov.iov_len = sz; + auio.uio_resid = sz; + auio.uio_offset = 0; + + if (args->path != NULL) + error = kern_extattr_list_path(td, args->path, + attrnamespace, &auio, args->follow, UIO_USERSPACE); + else + error = kern_extattr_list_fd(td, args->fd, + attrnamespace, &auio); + rs = sz - auio.uio_resid; + if (error == EPERM) + break; + if (error != 0 || rs == 0) + continue; + prefix = extattr_namespace_names[attrnamespace]; + prefixlen = strlen(prefix); + key = data; + while (rs > 0) { + keylen = (unsigned char)key[0]; + pairlen = prefixlen + 1 + keylen + 1; + cnt += pairlen; + if (cnt > LINUX_XATTR_LIST_MAX) { + error = E2BIG; + break; + } + /* + * If size is specified as zero, return the current size + * of the list of extended attribute names. + */ + if ((args->size > 0 && cnt > args->size) || + pairlen >= sizeof(attrname)) { + error = ERANGE; + break; + } + ++key; + if (args->list != NULL && args->size > 0) { + sprintf(attrname, "%s.%.*s", prefix, keylen, (__cheri_fromcap char *)key); + error = copyout(attrname, args->list, pairlen); + if (error != 0) + break; + args->list += pairlen; + } + key += keylen; + rs -= (keylen + 1); + } + } + if (error == 0) + td->td_retval[0] = cnt; + free_c(data, M_LINUX); + return (error_to_xattrerror(attrnamespace, error)); +} + +int +linux_listxattr(struct thread *td, struct linux_listxattr_args *args) +{ + struct listxattr_args eargs = { + .fd = -1, + .path = LINUX_USER_CAP_PATH(args->path), + .list = LINUX_USER_CAP(args->list, args->size), + .size = args->size, + .follow = FOLLOW, + }; + + return (listxattr(td, &eargs)); +} + +int +linux_llistxattr(struct thread *td, struct linux_llistxattr_args *args) +{ + struct listxattr_args eargs = { + .fd = -1, + .path = LINUX_USER_CAP_PATH(args->path), + .list = LINUX_USER_CAP(args->list, args->size), + .size = args->size, + .follow = NOFOLLOW, + }; + + return (listxattr(td, &eargs)); +} + +int +linux_flistxattr(struct thread *td, struct linux_flistxattr_args *args) +{ + struct listxattr_args eargs = { + .fd = args->fd, + .path = NULL, + .list = LINUX_USER_CAP(args->list, args->size), + .size = args->size, + .follow = 0, + }; + + return (listxattr(td, &eargs)); +} + +static int +removexattr(struct thread *td, struct removexattr_args *args) +{ + char attrname[LINUX_XATTR_NAME_MAX + 1]; + int attrnamespace, error; + + error = xatrr_to_extattr(args->name, &attrnamespace, attrname); + if (error != 0) + return (error); + if (args->path != NULL) + error = kern_extattr_delete_path(td, args->path, attrnamespace, + attrname, args->follow, UIO_USERSPACE); + else + error = kern_extattr_delete_fd(td, args->fd, attrnamespace, + attrname); + return (error_to_xattrerror(attrnamespace, error)); +} + +int +linux_removexattr(struct thread *td, struct linux_removexattr_args *args) +{ + struct removexattr_args eargs = { + .fd = -1, + .path = LINUX_USER_CAP_PATH(args->path), + .name = LINUX_USER_CAP_STR(args->name), + .follow = FOLLOW, + }; + + return (removexattr(td, &eargs)); +} + +int +linux_lremovexattr(struct thread *td, struct linux_lremovexattr_args *args) +{ + struct removexattr_args eargs = { + .fd = -1, + .path = LINUX_USER_CAP_PATH(args->path), + .name = LINUX_USER_CAP_STR(args->name), + .follow = NOFOLLOW, + }; + + return (removexattr(td, &eargs)); +} + +int +linux_fremovexattr(struct thread *td, struct linux_fremovexattr_args *args) +{ + struct removexattr_args eargs = { + .fd = args->fd, + .path = NULL, + .name = LINUX_USER_CAP_STR(args->name), + .follow = 0, + }; + + return (removexattr(td, &eargs)); +} + +static int +getxattr(struct thread *td, struct getxattr_args *args) +{ + char attrname[LINUX_XATTR_NAME_MAX + 1]; + int attrnamespace, error; + + error = xatrr_to_extattr(args->name, &attrnamespace, attrname); + if (error != 0) + return (error); + if (args->path != NULL) + error = kern_extattr_get_path(td, args->path, attrnamespace, + attrname, args->value, args->size, args->follow, UIO_USERSPACE); + else + error = kern_extattr_get_fd(td, args->fd, attrnamespace, + attrname, args->value, args->size); + return (error == EPERM ? ENOATTR : error); +} + +int +linux_getxattr(struct thread *td, struct linux_getxattr_args *args) +{ + struct getxattr_args eargs = { + .fd = -1, + .path = LINUX_USER_CAP_PATH(args->path), + .name = LINUX_USER_CAP_STR(args->name), + .value = LINUX_USER_CAP(args->value, args->size), + .size = args->size, + .follow = FOLLOW, + }; + + return (getxattr(td, &eargs)); +} + +int +linux_lgetxattr(struct thread *td, struct linux_lgetxattr_args *args) +{ + struct getxattr_args eargs = { + .fd = -1, + .path = LINUX_USER_CAP_PATH(args->path), + .name = LINUX_USER_CAP_STR(args->name), + .value = LINUX_USER_CAP(args->value, args->size), + .size = args->size, + .follow = NOFOLLOW, + }; + + return (getxattr(td, &eargs)); +} + +int +linux_fgetxattr(struct thread *td, struct linux_fgetxattr_args *args) +{ + struct getxattr_args eargs = { + .fd = args->fd, + .path = NULL, + .name = LINUX_USER_CAP_STR(args->name), + .value = LINUX_USER_CAP(args->value, args->size), + .size = args->size, + .follow = 0, + }; + + return (getxattr(td, &eargs)); +} + +static int +setxattr(struct thread *td, struct setxattr_args *args) +{ + char attrname[LINUX_XATTR_NAME_MAX + 1]; + int attrnamespace, error; + + if ((args->flags & ~(LINUX_XATTR_FLAGS)) != 0 || + args->flags == (LINUX_XATTR_FLAGS)) + return (EINVAL); + error = xatrr_to_extattr(args->name, &attrnamespace, attrname); + if (error != 0) + return (error); + + if ((args->flags & (LINUX_XATTR_FLAGS)) != 0 ) { + if (args->path != NULL) + error = kern_extattr_get_path(td, args->path, + attrnamespace, attrname, NULL, args->size, + args->follow, UIO_USERSPACE); + else + error = kern_extattr_get_fd(td, args->fd, + attrnamespace, attrname, NULL, args->size); + if ((args->flags & LINUX_XATTR_CREATE) != 0) { + if (error == 0) + error = EEXIST; + else if (error == ENOATTR) + error = 0; + } + if (error != 0) + goto out; + } + if (args->path != NULL) + error = kern_extattr_set_path(td, args->path, attrnamespace, + attrname, args->value, args->size, args->follow, + UIO_USERSPACE); + else + error = kern_extattr_set_fd(td, args->fd, attrnamespace, + attrname, args->value, args->size); +out: + td->td_retval[0] = 0; + return (error_to_xattrerror(attrnamespace, error)); +} + +int +linux_setxattr(struct thread *td, struct linux_setxattr_args *args) +{ + struct setxattr_args eargs = { + .fd = -1, + .path = LINUX_USER_CAP_PATH(args->path), + .name = LINUX_USER_CAP_STR(args->name), + .value = LINUX_USER_CAP(args->value, args->size), + .size = args->size, + .flags = args->flags, + .follow = FOLLOW, + }; + + return (setxattr(td, &eargs)); +} + +int +linux_lsetxattr(struct thread *td, struct linux_lsetxattr_args *args) +{ + struct setxattr_args eargs = { + .fd = -1, + .path = LINUX_USER_CAP_PATH(args->path), + .name = LINUX_USER_CAP_STR(args->name), + .value = LINUX_USER_CAP(args->value, args->size), + .size = args->size, + .flags = args->flags, + .follow = NOFOLLOW, + }; + + return (setxattr(td, &eargs)); +} + +int +linux_fsetxattr(struct thread *td, struct linux_fsetxattr_args *args) +{ + struct setxattr_args eargs = { + .fd = args->fd, + .path = NULL, + .name = LINUX_USER_CAP_STR(args->name), + .value = LINUX_USER_CAP(args->value, args->size), + .size = args->size, + .flags = args->flags, + .follow = 0, + }; + + return (setxattr(td, &eargs)); +} diff --git a/sys/compat/linux/stats_timing.d b/sys/compat/linux/stats_timing.d index f0aa291e2155..50e7a63df18b 100644 --- a/sys/compat/linux/stats_timing.d +++ b/sys/compat/linux/stats_timing.d @@ -1,91 +1,91 @@ -#!/usr/sbin/dtrace -qs - -/*- - * Copyright (c) 2008-2012 Alexander Leidinger - * 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 - * in this position and unchanged. - * 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 ``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 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. - */ - -/** - * Some statistics (all per provider): - * - number of calls to a function per executable binary (not per PID!) - * - allows to see where an optimization would be beneficial for a given - * application - * - graph of CPU time spend in functions per executable binary - * - together with the number of calls to this function this allows - * to determine if a kernel optimization would be beneficial / is - * possible for a given application - * - graph of longest running (CPU-time!) function in total - * - may help finding problem cases in the kernel code - * - graph of longest held (CPU-time!) locks - */ - -#pragma D option dynvarsize=32m - -linuxulator*:::entry -{ - self->time[probefunc] = vtimestamp; - @calls[probeprov, execname, probefunc] = count(); -} - -linuxulator*:::return -/self->time[probefunc] != 0/ -{ - this->timediff = self->time[probefunc] - vtimestamp; - - @stats[probeprov, execname, probefunc] = quantize(this->timediff); - @longest[probeprov, probefunc] = max(this->timediff); - - self->time[probefunc] = 0; -} - -linuxulator*:::locked -{ - self->lock[arg0] = vtimestamp; -} - -linuxulator*:::unlock -/self->lock[arg0] != 0/ -{ - this->timediff = self->lock[arg0] - vtimestamp; - - @lockstats[probefunc] = quantize(this->timediff); - @longlock[probefunc] = max(this->timediff); - - self->lock[arg0] = 0; -} - -END -{ - printf("Number of calls per provider/application/kernel function:"); - printa(@calls); - printf("CPU-timing statistics per provider/application/kernel function (in ns):"); - printa(@stats); - printf("Longest running (CPU-time!) functions per provider (in ns):"); - printa(@longest); - printf("Lock CPU-timing statistics:"); - printa(@lockstats); - printf("Longest running (CPU-time!) locks:"); - printa(@longlock); -} - +#!/usr/sbin/dtrace -qs + +/*- + * Copyright (c) 2008-2012 Alexander Leidinger + * 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 + * in this position and unchanged. + * 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 ``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 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. + */ + +/** + * Some statistics (all per provider): + * - number of calls to a function per executable binary (not per PID!) + * - allows to see where an optimization would be beneficial for a given + * application + * - graph of CPU time spend in functions per executable binary + * - together with the number of calls to this function this allows + * to determine if a kernel optimization would be beneficial / is + * possible for a given application + * - graph of longest running (CPU-time!) function in total + * - may help finding problem cases in the kernel code + * - graph of longest held (CPU-time!) locks + */ + +#pragma D option dynvarsize=32m + +linuxulator*:::entry +{ + self->time[probefunc] = vtimestamp; + @calls[probeprov, execname, probefunc] = count(); +} + +linuxulator*:::return +/self->time[probefunc] != 0/ +{ + this->timediff = self->time[probefunc] - vtimestamp; + + @stats[probeprov, execname, probefunc] = quantize(this->timediff); + @longest[probeprov, probefunc] = max(this->timediff); + + self->time[probefunc] = 0; +} + +linuxulator*:::locked +{ + self->lock[arg0] = vtimestamp; +} + +linuxulator*:::unlock +/self->lock[arg0] != 0/ +{ + this->timediff = self->lock[arg0] - vtimestamp; + + @lockstats[probefunc] = quantize(this->timediff); + @longlock[probefunc] = max(this->timediff); + + self->lock[arg0] = 0; +} + +END +{ + printf("Number of calls per provider/application/kernel function:"); + printa(@calls); + printf("CPU-timing statistics per provider/application/kernel function (in ns):"); + printa(@stats); + printf("Longest running (CPU-time!) functions per provider (in ns):"); + printa(@longest); + printf("Lock CPU-timing statistics:"); + printa(@lockstats); + printf("Longest running (CPU-time!) locks:"); + printa(@longlock); +} + diff --git a/sys/compat/linux/trace_futexes.d b/sys/compat/linux/trace_futexes.d index 0827cf78aa8f..1e7834f258b2 100644 --- a/sys/compat/linux/trace_futexes.d +++ b/sys/compat/linux/trace_futexes.d @@ -1,180 +1,180 @@ -#!/usr/sbin/dtrace -qs - -/*- - * Copyright (c) 2011-2012 Alexander Leidinger - * 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 - * in this position and unchanged. - * 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 ``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 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. - */ - -/** - * Trace futex operations: - * - internal locks - * - size of the futex list - * - report error conditions (emulation errors, kernel errors, - * programming errors) - * - execution time (wallclock) of futex related functions - */ - -#pragma D option specsize=32m - -/* Error conditions */ -linuxulator*:futex:futex_get:error, -linuxulator*:futex:futex_sleep:requeue_error, -linuxulator*:futex:futex_sleep:sleep_error, -linuxulator*:futex:futex_wait:copyin_error, -linuxulator*:futex:futex_wait:itimerfix_error, -linuxulator*:futex:futex_wait:sleep_error, -linuxulator*:futex:futex_atomic_op:missing_access_check, -linuxulator*:futex:futex_atomic_op:unimplemented_op, -linuxulator*:futex:futex_atomic_op:unimplemented_cmp, -linuxulator*:futex:linux_sys_futex:unimplemented_clockswitch, -linuxulator*:futex:linux_sys_futex:copyin_error, -linuxulator*:futex:linux_sys_futex:unhandled_efault, -linuxulator*:futex:linux_sys_futex:unimplemented_lock_pi, -linuxulator*:futex:linux_sys_futex:unimplemented_unlock_pi, -linuxulator*:futex:linux_sys_futex:unimplemented_trylock_pi, -linuxulator*:futex:linux_sys_futex:unimplemented_wait_requeue_pi, -linuxulator*:futex:linux_sys_futex:unimplemented_cmp_requeue_pi, -linuxulator*:futex:linux_sys_futex:unknown_operation, -linuxulator*:futex:linux_get_robust_list:copyout_error, -linuxulator*:futex:handle_futex_death:copyin_error, -linuxulator*:futex:fetch_robust_entry:copyin_error, -linuxulator*:futex:release_futexes:copyin_error -{ - printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod, - probefunc); - stack(); - ustack(); -} - -linuxulator*:futex:linux_sys_futex:invalid_cmp_requeue_use, -linuxulator*:futex:linux_sys_futex:deprecated_requeue, -linuxulator*:futex:linux_set_robust_list:size_error -{ - printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n", - probename, probeprov, probemod, probefunc, execname); - stack(); - ustack(); -} - - -/* Per futex checks/statistics */ - -linuxulator*:futex:futex:create -{ - ++futex_count; - @max_futexes = max(futex_count); -} - -linuxulator*:futex:futex:destroy -/futex_count == 0/ -{ - printf("ERROR: Request to destroy a futex which was not created,\n"); - printf(" or this script was started after some futexes where\n"); - printf(" created. Stack trace:\n"); - stack(); - ustack(); -} - -linuxulator*:futex:futex:destroy -{ - --futex_count; -} - - -/* Internal locks */ - -linuxulator*:locks:futex_mtx:locked -{ - ++check[probefunc, arg0]; - @stats[probefunc] = count(); - - ts[probefunc] = timestamp; - spec[probefunc] = speculation(); - printf("Stacktrace of last lock operation of the %s:\n", probefunc); - stack(); -} - -linuxulator*:locks:futex_mtx:unlock -/check[probefunc, arg0] == 0/ -{ - printf("ERROR: unlock attempt of unlocked %s (%p),", probefunc, arg0); - printf(" missing SDT probe in kernel, or dtrace program started"); - printf(" while the %s was already held (race condition).", probefunc); - printf(" Stack trace follows:"); - stack(); -} - -linuxulator*:locks:futex_mtx:unlock -{ - discard(spec[probefunc]); - spec[probefunc] = 0; - --check[probefunc, arg0]; -} - -/* Timeout handling for internal locks */ - -tick-10s -/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/ -{ - commit(spec["futex_mtx"]); - spec["futex_mtx"] = 0; -} - - -/* Timing statistings */ - -linuxulator*:futex::entry -{ - self->time[probefunc] = timestamp; - @calls[probeprov, execname, probefunc] = count(); -} - -linuxulator*:futex::return -/self->time[probefunc] != 0/ -{ - this->timediff = self->time[probefunc] - timestamp; - - @timestats[probeprov, execname, probefunc] = quantize(this->timediff); - @longest[probeprov, probefunc] = max(this->timediff); - - self->time[probefunc] = 0; -} - - -/* Statistics */ - -END -{ - printf("Number of locks per type:"); - printa(@stats); - printf("Number of maximum number of futexes in the futex list:"); - printa(@max_futexes); - printf("Number of futexes still existing: %d", futex_count); - printf("Number of calls per provider/application/kernel function:"); - printa(@calls); - printf("Wallclock-timing statistics per provider/application/kernel function (in ns):"); - printa(@timestats); - printf("Longest running (wallclock!) functions per provider (in ns):"); - printa(@longest); -} +#!/usr/sbin/dtrace -qs + +/*- + * Copyright (c) 2011-2012 Alexander Leidinger + * 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 + * in this position and unchanged. + * 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 ``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 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. + */ + +/** + * Trace futex operations: + * - internal locks + * - size of the futex list + * - report error conditions (emulation errors, kernel errors, + * programming errors) + * - execution time (wallclock) of futex related functions + */ + +#pragma D option specsize=32m + +/* Error conditions */ +linuxulator*:futex:futex_get:error, +linuxulator*:futex:futex_sleep:requeue_error, +linuxulator*:futex:futex_sleep:sleep_error, +linuxulator*:futex:futex_wait:copyin_error, +linuxulator*:futex:futex_wait:itimerfix_error, +linuxulator*:futex:futex_wait:sleep_error, +linuxulator*:futex:futex_atomic_op:missing_access_check, +linuxulator*:futex:futex_atomic_op:unimplemented_op, +linuxulator*:futex:futex_atomic_op:unimplemented_cmp, +linuxulator*:futex:linux_sys_futex:unimplemented_clockswitch, +linuxulator*:futex:linux_sys_futex:copyin_error, +linuxulator*:futex:linux_sys_futex:unhandled_efault, +linuxulator*:futex:linux_sys_futex:unimplemented_lock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_unlock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_trylock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_wait_requeue_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_cmp_requeue_pi, +linuxulator*:futex:linux_sys_futex:unknown_operation, +linuxulator*:futex:linux_get_robust_list:copyout_error, +linuxulator*:futex:handle_futex_death:copyin_error, +linuxulator*:futex:fetch_robust_entry:copyin_error, +linuxulator*:futex:release_futexes:copyin_error +{ + printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod, + probefunc); + stack(); + ustack(); +} + +linuxulator*:futex:linux_sys_futex:invalid_cmp_requeue_use, +linuxulator*:futex:linux_sys_futex:deprecated_requeue, +linuxulator*:futex:linux_set_robust_list:size_error +{ + printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n", + probename, probeprov, probemod, probefunc, execname); + stack(); + ustack(); +} + + +/* Per futex checks/statistics */ + +linuxulator*:futex:futex:create +{ + ++futex_count; + @max_futexes = max(futex_count); +} + +linuxulator*:futex:futex:destroy +/futex_count == 0/ +{ + printf("ERROR: Request to destroy a futex which was not created,\n"); + printf(" or this script was started after some futexes where\n"); + printf(" created. Stack trace:\n"); + stack(); + ustack(); +} + +linuxulator*:futex:futex:destroy +{ + --futex_count; +} + + +/* Internal locks */ + +linuxulator*:locks:futex_mtx:locked +{ + ++check[probefunc, arg0]; + @stats[probefunc] = count(); + + ts[probefunc] = timestamp; + spec[probefunc] = speculation(); + printf("Stacktrace of last lock operation of the %s:\n", probefunc); + stack(); +} + +linuxulator*:locks:futex_mtx:unlock +/check[probefunc, arg0] == 0/ +{ + printf("ERROR: unlock attempt of unlocked %s (%p),", probefunc, arg0); + printf(" missing SDT probe in kernel, or dtrace program started"); + printf(" while the %s was already held (race condition).", probefunc); + printf(" Stack trace follows:"); + stack(); +} + +linuxulator*:locks:futex_mtx:unlock +{ + discard(spec[probefunc]); + spec[probefunc] = 0; + --check[probefunc, arg0]; +} + +/* Timeout handling for internal locks */ + +tick-10s +/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/ +{ + commit(spec["futex_mtx"]); + spec["futex_mtx"] = 0; +} + + +/* Timing statistings */ + +linuxulator*:futex::entry +{ + self->time[probefunc] = timestamp; + @calls[probeprov, execname, probefunc] = count(); +} + +linuxulator*:futex::return +/self->time[probefunc] != 0/ +{ + this->timediff = self->time[probefunc] - timestamp; + + @timestats[probeprov, execname, probefunc] = quantize(this->timediff); + @longest[probeprov, probefunc] = max(this->timediff); + + self->time[probefunc] = 0; +} + + +/* Statistics */ + +END +{ + printf("Number of locks per type:"); + printa(@stats); + printf("Number of maximum number of futexes in the futex list:"); + printa(@max_futexes); + printf("Number of futexes still existing: %d", futex_count); + printf("Number of calls per provider/application/kernel function:"); + printa(@calls); + printf("Wallclock-timing statistics per provider/application/kernel function (in ns):"); + printa(@timestats); + printf("Longest running (wallclock!) functions per provider (in ns):"); + printa(@longest); +} diff --git a/sys/contrib/v4l/videodev2.h b/sys/contrib/v4l/videodev2.h index 47904ba299e5..d1e12a6e22ae 100644 --- a/sys/contrib/v4l/videodev2.h +++ b/sys/contrib/v4l/videodev2.h @@ -928,7 +928,7 @@ struct v4l2_ext_control { __s64 value64; char *string; } x; -} __attribute__ ((packed)); +}; struct v4l2_ext_controls { __u32 ctrl_class; diff --git a/sys/fs/ext2fs/ext2_htree.c b/sys/fs/ext2fs/ext2_htree.c index 02a5fd93cb5b..02759a41bda8 100644 --- a/sys/fs/ext2fs/ext2_htree.c +++ b/sys/fs/ext2fs/ext2_htree.c @@ -300,7 +300,8 @@ ext2_htree_find_leaf(struct inode *ip, const char *name, int namelen, if ((levels = rootp->h_info.h_ind_levels) > 1) goto error; - entp = (struct ext2fs_htree_entry *)(((char *)&rootp->h_info) + + // Preserve capability bound here + entp = (struct ext2fs_htree_entry *)(((char *)rootp) + offsetof(struct ext2fs_htree_root, h_info) + rootp->h_info.h_info_len); if (ext2_htree_get_limit(entp) != diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 70af56c7e99d..cf9c9316a192 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1331,8 +1331,12 @@ exec_map_stack(struct image_params *imgp) error = vm_mmap_object(map, &strings_addr, 0, strings_size, VM_PROT_RW_CAP, VM_PROT_RW_CAP, MAP_ANON | MAP_FIXED | MAP_RESERVATION_CREATE, NULL, 0, FALSE, curthread); - if (error != KERN_SUCCESS) + if (error != KERN_SUCCESS) { + uprintf("%s: Create separate space for strings failed" + " mach error %d errno %d", + __func__, error, vm_mmap_to_errno(error)); return (vm_mmap_to_errno(error)); + } #ifdef __CHERI_PURE_CAPABILITY__ imgp->strings = (void *)strings_addr; #else @@ -1357,11 +1361,15 @@ exec_map_stack(struct image_params *imgp) * XXX This almost surely belongs elsewhere, but I don't immediately * see a per-sv hook here. */ - if (sv->sv_flags & SV_CHERI) { + if (sv->sv_flags & SV_CHERI && (sv->sv_flags & SV_ABI_MASK) != SV_ABI_LINUX) { error = vm_map_install_cheri_revoke_shadow(map, sv); - if (error != KERN_SUCCESS) + if (error != KERN_SUCCESS) { + uprintf("%s: vm_map_install_cheri_revoke_shadow failed" + " mach error %d errno %d", + __func__, error, vm_mmap_to_errno(error)); return (vm_mmap_to_errno(error)); + } } #endif diff --git a/sys/libkern/gsb_crc32.c b/sys/libkern/gsb_crc32.c index 58bd3e720278..02f0c52fb818 100644 --- a/sys/libkern/gsb_crc32.c +++ b/sys/libkern/gsb_crc32.c @@ -761,7 +761,7 @@ table_crc32c(uint32_t crc32c, const unsigned char *buffer, unsigned int length) } } -#if defined(_KERNEL) && defined(__aarch64__) +#if defined(_KERNEL) && defined(__aarch64__) && !__has_feature(capabilities) DEFINE_IFUNC(, uint32_t, calculate_crc32c, (uint32_t crc32c, const unsigned char *buffer, unsigned int length)) { diff --git a/sys/modules/Makefile b/sys/modules/Makefile index ca340e4d480b..e10111286a1e 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -537,6 +537,9 @@ SUBDIR+= linux .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" SUBDIR+= linux64 SUBDIR+= linux_common +.if ${MACHINE_CPU:Mcheri} +SUBDIR+= linux64c +.endif .endif .if ${MACHINE_CPUARCH} != "arm" @@ -928,7 +931,6 @@ BROKEN_MODULES+=armv8crypto BROKEN_MODULES+=bnxt BROKEN_MODULES+=dpaa2 BROKEN_MODULES+=ena -BROKEN_MODULES+=linprocfs linux64 linux_common BROKEN_MODULES+=mlx4 mlx4en mlx5 mlx5en .endif diff --git a/sys/modules/linux64/Makefile b/sys/modules/linux64/Makefile index beed5ec59c4b..3cbaf08245ff 100644 --- a/sys/modules/linux64/Makefile +++ b/sys/modules/linux64/Makefile @@ -1,11 +1,17 @@ +.include "${SYSDIR}/conf/kern.opts.mk" -.PATH: ${SRCTOP}/sys/compat/linux ${SRCTOP}/sys/${MACHINE}/linux +.if ${MACHINE_CPU:Mcheri} +SFX= 64 +CFLAGS+= -DCOMPAT_FREEBSD64 -DCOMPAT_LINUX64 +.endif + +.PATH: ${SRCTOP}/sys/compat/linux ${SRCTOP}/sys/${MACHINE}/linux${SFX} .if ${MACHINE_CPUARCH} == "amd64" .PATH: ${SRCTOP}/sys/x86/linux .endif KMOD= linux64 -SRCS= linux_dummy_machdep.c \ +SRCS= linux${SFX}_dummy_machdep.c \ linux_elf64.c \ linux_event.c \ linux_file.c \ @@ -14,17 +20,17 @@ SRCS= linux_dummy_machdep.c \ linux_getcwd.c \ linux_ioctl.c \ linux_ipc.c \ - linux_machdep.c \ + linux${SFX}_machdep.c \ linux_misc.c \ linux_ptrace.c \ linux_rseq.c \ linux_signal.c \ linux_socket.c \ linux_stats.c \ - linux_syscalls.c \ + linux${SFX}_syscalls.c \ linux_sysctl.c \ - linux_sysent.c \ - linux_sysvec.c \ + linux${SFX}_sysent.c \ + linux${SFX}_sysvec.c \ linux_time.c \ linux_vdso.c \ linux_timer.c \ @@ -35,22 +41,22 @@ SRCS= linux_dummy_machdep.c \ bus_if.h \ device_if.h \ vnode_if.h \ - linux_support.S \ + linux${SFX}_support.S \ linux_vdso_inc.S .if ${MACHINE_CPUARCH} == "amd64" SRCS+= linux_dummy_x86.c .endif -DPSRCS= assym.inc linux_genassym.c +DPSRCS= assym.inc linux${SFX}_genassym.c # XXX: for assym.inc SRCS+= opt_kstack_pages.h opt_nfs.h opt_hwpmc_hooks.h -CLEANFILES= linux_assym.h linux_genassym.o linux_locore.o \ - genassym.o linux_vdso_gtod.o linux_vdso.so.o +CLEANFILES= linux${SFX}_assym.h linux${SFX}_genassym.o linux${SFX}_locore.o \ + genassym.o linux${SFX}_vdso_gtod.o linux${SFX}_vdso.so.o -linux_assym.h: linux_genassym.o - sh ${SYSDIR}/kern/genassym.sh linux_genassym.o > ${.TARGET} +linux${SFX}_assym.h: linux${SFX}_genassym.o + sh ${SYSDIR}/kern/genassym.sh linux${SFX}_genassym.o > ${.TARGET} .if ${MACHINE_CPUARCH} == "amd64" VDSOFLAGS=-mcmodel=small -msoft-float @@ -61,7 +67,7 @@ VDSODEPS=linux_vdso_gettc_x86.inc VDSOFLAGS=-mgeneral-regs-only -mcmodel=small -ffixed-x18 .endif -linux_locore.o: linux_assym.h assym.inc +linux${SFX}_locore.o: linux${SFX}_assym.h assym.inc ${CC} -c -x assembler-with-cpp -DLOCORE \ -fPIC -pipe -O2 -Werror ${VDSOFLAGS} \ -nostdinc -fasynchronous-unwind-tables \ @@ -69,27 +75,27 @@ linux_locore.o: linux_assym.h assym.inc -fno-stack-protector -I. -I${SYSDIR} -I${SRCTOP}/include \ ${.IMPSRC} -o ${.TARGET} -linux_vdso_gtod.o: linux_vdso_gtod.inc ${VDSODEPS} +linux${SFX}_vdso_gtod.o: linux${SFX}_vdso_gtod.inc ${VDSODEPS} ${CC} -c -fPIC -pipe -O2 -Werror ${VDSOFLAGS} \ -nostdinc -fasynchronous-unwind-tables \ -fno-omit-frame-pointer -foptimize-sibling-calls \ -fno-stack-protector -I. -I${SYSDIR} -I${SRCTOP}/include \ ${.IMPSRC} -o ${.TARGET} -linux_vdso.so.o: linux_locore.o linux_vdso_gtod.o - ${LD} --shared --eh-frame-hdr -soname=linux-vdso.so.1 \ +linux${SFX}_vdso.so.o: linux${SFX}_locore.o linux${SFX}_vdso_gtod.o + ${LD} --shared --eh-frame-hdr -soname=linux${SFX}-vdso.so.1 \ --no-undefined --hash-style=both -warn-common -nostdlib \ --strip-debug -s --build-id=sha1 -Bsymbolic \ - -T${SRCTOP}/sys/${MACHINE}/linux/linux_vdso.lds.s \ + -T${SRCTOP}/sys/${MACHINE}/linux${SFX}/linux${SFX}_vdso.lds.s \ -o ${.TARGET} ${.ALLSRC:M*.o} -linux_vdso_inc.o: linux_vdso.so.o +linux${SFX}_vdso_inc.o: linux${SFX}_vdso.so.o -linux_support.o: linux_support.S assym.inc linux_assym.h +linux${SFX}_support.o: linux${SFX}_support.S assym.inc linux${SFX}_assym.h ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \ ${.ALLSRC:M*.S:u} -o ${.TARGET} -linux_genassym.o: offset.inc +linux${SFX}_genassym.o: offset.inc ${CC} -c ${CFLAGS:N-flto*:N-fno-common:N-fsanitize*:N-fno-sanitize*} \ -fcommon ${.IMPSRC} diff --git a/sys/modules/linux64c/Makefile b/sys/modules/linux64c/Makefile new file mode 100755 index 000000000000..fdeabebfec1e --- /dev/null +++ b/sys/modules/linux64c/Makefile @@ -0,0 +1,103 @@ +.include "${SYSDIR}/conf/kern.opts.mk" + +.PATH: ${SRCTOP}/sys/compat/linux ${SRCTOP}/sys/${MACHINE}/linux +.if ${MACHINE_CPUARCH} == "amd64" +.PATH: ${SRCTOP}/sys/x86/linux +.endif + +KMOD= linux64c +SRCS= linux_dummy_machdep.c \ + linux_elf64.c \ + linux_event.c \ + linux_file.c \ + linux_fork.c \ + linux_futex.c \ + linux_getcwd.c \ + linux_ioctl.c \ + linux_ipc.c \ + linux_machdep.c \ + linux_misc.c \ + linux_ptrace.c \ + linux_rseq.c \ + linux_signal.c \ + linux_socket.c \ + linux_stats.c \ + linux_syscalls.c \ + linux_sysctl.c \ + linux_sysent.c \ + linux_sysvec.c \ + linux_time.c \ + linux_vdso.c \ + linux_timer.c \ + linux_xattr.c \ + opt_ktrace.h \ + opt_inet6.h \ + opt_posix.h \ + bus_if.h \ + device_if.h \ + vnode_if.h \ + linux_support.S \ + linux_vdso_inc.S +.if ${MACHINE_CPUARCH} == "amd64" +SRCS+= linux_dummy_x86.c +.endif +DPSRCS= assym.inc linux_genassym.c + +# XXX: for assym.inc +SRCS+= opt_kstack_pages.h opt_nfs.h opt_hwpmc_hooks.h + +CLEANFILES= linux_assym.h linux_genassym.o linux_locore.o \ + genassym.o linux_vdso_gtod.o linux_vdso.so.o + + +linux_assym.h: linux_genassym.o + sh ${SYSDIR}/kern/genassym.sh linux_genassym.o > ${.TARGET} + +.if ${MACHINE_CPUARCH} == "amd64" +VDSOFLAGS=-mcmodel=small -msoft-float +VDSODEPS=linux_vdso_gettc_x86.inc +.elif ${MACHINE_CPUARCH} == "aarch64" +# The Linux uses tiny memory model, but our ld does not know about +# some of relocation types which is generated by cc +VDSOFLAGS=-mgeneral-regs-only -mcmodel=small -ffixed-x18 +.endif + +linux_locore.o: linux_assym.h assym.inc + ${CC} -c -x assembler-with-cpp -DLOCORE \ + -fPIC -pipe -O2 -Werror ${VDSOFLAGS} \ + -nostdinc -fasynchronous-unwind-tables \ + -fno-omit-frame-pointer -foptimize-sibling-calls \ + -fno-stack-protector -I. -I${SYSDIR} -I${SRCTOP}/include \ + ${.IMPSRC} -o ${.TARGET} + +linux_vdso_gtod.o: linux_vdso_gtod.inc ${VDSODEPS} + ${CC} -c -fPIC -pipe -O2 -Werror ${VDSOFLAGS} \ + -nostdinc -fasynchronous-unwind-tables \ + -fno-omit-frame-pointer -foptimize-sibling-calls \ + -fno-stack-protector -I. -I${SYSDIR} -I${SRCTOP}/include \ + ${.IMPSRC} -o ${.TARGET} + +linux_vdso.so.o: linux_locore.o linux_vdso_gtod.o + ${LD} --shared --eh-frame-hdr -soname=linux-vdso.so.1 \ + --no-undefined --hash-style=both -warn-common -nostdlib \ + --strip-debug -s --build-id=sha1 -Bsymbolic \ + -T${SRCTOP}/sys/${MACHINE}/linux/linux_vdso.lds.s \ + -o ${.TARGET} ${.ALLSRC:M*.o} + +linux_vdso_inc.o: linux_vdso.so.o + +linux_support.o: linux_support.S assym.inc linux_assym.h + ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \ + ${.ALLSRC:M*.S:u} -o ${.TARGET} + +linux_genassym.o: offset.inc + ${CC} -c ${CFLAGS:N-flto*:N-fno-common:N-fsanitize*:N-fno-sanitize*} \ + -fcommon ${.IMPSRC} + +.if !defined(KERNBUILDDIR) +.warning Building Linuxulator outside of a kernel does not make sense +.endif + +EXPORT_SYMS= YES + +.include diff --git a/sys/sys/gsb_crc32.h b/sys/sys/gsb_crc32.h index 9a5e59bd3cf2..220bda7e6032 100644 --- a/sys/sys/gsb_crc32.h +++ b/sys/sys/gsb_crc32.h @@ -38,7 +38,7 @@ uint32_t calculate_crc32c(uint32_t crc32c, const unsigned char *buffer, #if defined(__amd64__) || defined(__i386__) uint32_t sse42_crc32c(uint32_t, const unsigned char *, unsigned); #endif -#if defined(__aarch64__) +#if defined(__aarch64__) && !__has_feature(capabilities) uint32_t armv8_crc32c(uint32_t, const unsigned char *, unsigned int); #endif diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 6cf6c083ebfb..a0ca3e7e3b5e 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -751,7 +751,7 @@ struct proc { void *p_elf_brandinfo; /* (x) Elf_Brandinfo, NULL for non ELF binaries. */ sbintime_t p_umtx_min_timeout; - vm_offset_t p_psstrings; + vm_pointer_t p_psstrings; #if __has_feature(capabilities) struct cheri_c18n_info *p_c18n_info; /* (x) Compartment info block */ #endif diff --git a/tests/sys/kern/libkern_crc32.c b/tests/sys/kern/libkern_crc32.c index f386f565bb06..04db4228e444 100644 --- a/tests/sys/kern/libkern_crc32.c +++ b/tests/sys/kern/libkern_crc32.c @@ -58,7 +58,7 @@ check_crc32c(uint32_t expected, uint32_t crc32c, const void *buffer, ATF_CHECK_EQ_MSG(expected, act, "sse42_crc32c expected 0x%08x, got 0x%08x", expected, act); } -#elif defined(__aarch64__) +#elif defined(__aarch64__) && !__has_feature(capabilities) act = armv8_crc32c(crc32c, buffer, length); ATF_CHECK_EQ_MSG(expected, act, "armv8_crc32c expected 0x%08x, got 0x%08x", expected, act); diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c index f1af84101f7e..75baa31e8248 100644 --- a/usr.bin/truss/setup.c +++ b/usr.bin/truss/setup.c @@ -109,11 +109,21 @@ static struct procabi freebsd64 = { static struct procabi linux = { .type = "Linux", .abi = SYSDECODE_ABI_LINUX, - .pointer_size = sizeof(ptraddr_t), + .pointer_size = sizeof(void * __capability), .extra_syscalls = STAILQ_HEAD_INITIALIZER(linux.extra_syscalls), .syscalls = { NULL } }; +#if __has_feature(capabilities) +static struct procabi linux64 = { + .type = "Linux64", + .abi = SYSDECODE_ABI_LINUX64, + .pointer_size = sizeof(uint64_t), + .extra_syscalls = STAILQ_HEAD_INITIALIZER(linux64.extra_syscalls), + .syscalls = { NULL } +}; +#endif + #if __SIZEOF_POINTER__ > 4 static struct procabi linux32 = { .type = "Linux32", @@ -150,7 +160,12 @@ static struct procabi_table abis[] = { { "FreeBSD a.out", &freebsd }, #endif #if __SIZEOF_POINTER__ >= 8 +#if __has_feature(capabilities) + { "Linux ELF64C", &linux }, + { "Linux ELF64", &linux64 }, +#else { "Linux ELF64", &linux }, +#endif { "Linux ELF32", &linux32 }, #else { "Linux ELF32", &linux },