diff --git a/lib/Makefile b/lib/Makefile index 38fff4c5a6e0..4c393c7a8b67 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,186 +1,187 @@ .include # The SUBDIR_BOOTSTRAP list is a small set of libraries which are used by many # of the other libraries. These are built first with a .WAIT between them # and the main list to avoid needing a SUBDIR_DEPEND line on every library # naming just these few items. SUBDIR_BOOTSTRAP= \ csu \ .WAIT \ libc \ libc_nonshared \ libcompiler_rt \ ${_libclang_rt} \ libc++ \ libc++experimental \ libcxxrt \ libder \ libdiff \ libelf \ libssp \ libssp_nonshared \ libsys \ msun # The main list; please keep these sorted alphabetically. # The only exception is sqlite3: we place it at the start of the list since it # takes a long time to build and starting it first improves parallelism. SUBDIR= ${SUBDIR_BOOTSTRAP} \ .WAIT \ libsqlite3 \ geom \ lib9p \ libalias \ libarchive \ libbegemot \ libblocksruntime \ libbsddialog \ libbsdstat \ libbsm \ libbz2 \ libcalendar \ libcam \ libcapsicum \ libcasper \ libcompat \ libcrypt \ libdevctl \ libdevdctl \ libdevinfo \ libdevstat \ libdl \ libdwarf \ libedit \ libelftc \ libevent1 \ libexecinfo \ libexpat \ libfetch \ libgcc_eh \ libgcc_s \ libgeom \ libifconfig \ libipsec \ libiscsiutil \ libjail \ libkiconv \ libkldelf \ libkvm \ liblattzfs \ liblua \ liblzma \ libmemstat \ libmd \ libmt \ lib80211 \ libnetbsd \ libnetmap \ libnv \ libnvmf \ libopenbsd \ libpam \ libpathconv \ libpcap \ libpjdlog \ + libpledge \ libproc \ libprocstat \ libregex \ librpcsvc \ librss \ librt \ librtld_db \ libsbuf \ libsmb \ libstdbuf \ libstdthreads \ libsysdecode \ libtacplus \ libthr \ libthread_db \ libucl \ libufs \ libugidfw \ libulog \ libutil \ libutil++ \ libuvmem \ ${_libvgl} \ libwrap \ libxo \ liby \ libyaml \ libz \ libzstd \ ncurses \ nss_tacplus # Inter-library dependencies. When the makefile for a library contains LDADD # libraries, those libraries should be listed as build order dependencies here. SUBDIR_DEPEND_geom= libufs SUBDIR_DEPEND_googletest= libregex SUBDIR_DEPEND_libarchive= libz libbz2 libexpat liblzma libmd libzstd SUBDIR_DEPEND_libauditdm= libbsm SUBDIR_DEPEND_libbsddialog= ncurses SUBDIR_DEPEND_libbsnmp= ${_libnetgraph} SUBDIR_DEPEND_libc++:= libcxxrt # libssp_nonshared doesn't need to be linked into libc on every arch, but it is # small enough to build that this bit of serialization is likely insignificant. SUBDIR_DEPEND_libc= libsys libcompiler_rt libssp_nonshared SUBDIR_DEPEND_libcam= libsbuf SUBDIR_DEPEND_libcasper= libnv SUBDIR_DEPEND_libcrypt= libmd SUBDIR_DEPEND_libdevstat= libkvm SUBDIR_DEPEND_libdpv= libfigpar ncurses libutil SUBDIR_DEPEND_libedit= ncurses SUBDIR_DEPEND_libgeom= libexpat libsbuf .if ${MK_MITKRB5} == "no" SUBDIR_DEPEND_librpcsec_gss= libgssapi .endif SUBDIR_DEPEND_libmagic= libz SUBDIR_DEPEND_libmemstat= libkvm SUBDIR_DEPEND_libpam= libcrypt ${_libradius} librpcsvc libtacplus libutil ${_libypclnt} ${_libcom_err} SUBDIR_DEPEND_libpjdlog= libutil SUBDIR_DEPEND_libprocstat= libkvm libutil SUBDIR_DEPEND_libradius= libmd SUBDIR_DEPEND_libsmb= libkiconv # See comment above about libssp_nonshared SUBDIR_DEPEND_libsys= libcompiler_rt libssp_nonshared SUBDIR_DEPEND_libtacplus= libmd SUBDIR_DEPEND_libulog= libmd SUBDIR_DEPEND_libunbound= ${_libldns} SUBDIR_DEPEND_liblzma= libthr .if ${MK_OFED} != "no" SUBDIR_DEPEND_libpcap= ofed .endif SUBDIR_DEPEND_nss_tacplus= libtacplus SUBDIR_DEPEND_virtual_oss= libsamplerate # NB: keep these sorted by MK_* knobs SUBDIR.${MK_BEARSSL}+= libbearssl libsecureboot SUBDIR.${MK_BLACKLIST}+=libblacklist SUBDIR.${MK_BLOCKLIST}+=libblocklist SUBDIR.${MK_BLUETOOTH}+=libbluetooth libsdp SUBDIR.${MK_BSNMP}+= libbsnmp .if !defined(COMPAT_LIBCOMPAT) .if ${MK_CLANG} != "no" || ${MK_LLD} != "no" || \ ${MK_LLDB} != "no" || ${MK_LLVM_BINUTILS} != "no" SUBDIR+= clang .endif .endif SUBDIR.${MK_AUDIT}+= libauditd SUBDIR.${MK_CUSE}+= libcuse SUBDIR.${MK_TOOLCHAIN}+=libpe SUBDIR.${MK_DIALOG}+= libdpv libfigpar SUBDIR.${MK_FDT}+= libfdt SUBDIR.${MK_FILE}+= libmagic SUBDIR.${MK_GPIO}+= libgpio SUBDIR.${MK_HBSDCONTROL}+= libhbsdcontrol .if ${MK_MITKRB5} == "no" SUBDIR.${MK_KERBEROS}+= libgssapi .endif diff --git a/lib/libpledge/Makefile b/lib/libpledge/Makefile new file mode 100644 index 000000000000..fadf7c9a2504 --- /dev/null +++ b/lib/libpledge/Makefile @@ -0,0 +1,20 @@ +# $FreeBSD$ + +.include + +PACKAGE=lib${LIB} +LIB= pledge + +SHLIB_MAJOR= 5 + +SRCS= pledge.c +INCS= pledge.h + +MAN= pledge.3 +MLINKS+= pledge.3 pledge_bitmask_to_string.3 +MLINKS+= pledge.3 pledge_string_to_bitmask.3 +MLINKS+= pledge.3 pledge_string.3 + +CFLAGS+=-I${.CURDIR} + +.include diff --git a/lib/libpledge/pledge.3 b/lib/libpledge/pledge.3 new file mode 100644 index 000000000000..9d197cb7df1e --- /dev/null +++ b/lib/libpledge/pledge.3 @@ -0,0 +1,144 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. +.\" +.\" @(#)pause.3 8.1 (Berkeley) 6/4/93 +.\" $FreeBSD$ +.\" +.Dd August 16, 2018 +.Dt PLEDGE 3 +.Os +.Sh NAME +.Nm pledge +.Nd Reduce thread's pledge sandbox permission flags +.Nm pledge_string +.Nm pledge_string_to_bitmask +.Nm pledge_bitmask_to_string +.Sh LIBRARY +.Lb libpledge +.Sh SYNOPSIS +.In pledge.h +.Ft int +.Fo pledge +.Fa "uint64_t mask" +.Fc +.Ft int +.Fo pledge_string +.Fa "const char *policy" +.Fc +.Ft int +.Fo pledge_string_to_bitmask +.Fa "const char *policy" "uint64_t *result_mask" +.Fc +.Ft char * +.Fn pledge_bitmask_to_string "uint64_t mask" +.Sh DESCRIPTION +.Pp +The +.Fn pledge +function +reduces the set of operations the current thread is allow to perform. +The current pledge mask for a thread is copied on execve and thus inherited +to subsequent children, but it does NOT modify the pledge masks of children +existing prior to the call. +.\" this whole thing is a TODO +.Sh RETURN VALUES +.Ex -std +.Sh ERRORS +The +.Fn pledge +function +always returns: +.Bl -tag -width Er +.It Bq Er EINTR +The call was interrupted. TODO obv not +.El +.\" +.\" +.\" +.Sh FUNCTIONS +.\" +.Ft int +.Fo pledge_string_to_bitmask +.Fa "const char *policy" "uint64_t *result_mask" +.Fc +Convert a string policy to a mask. +On success, the parsed mask is written to _result_mask. +Negations using a prefix of '!' is supported, and they take precedence +over the whitelisting flags. +.Bd -literal -offset indent + BNF-syntax, which should go in the `man pledge` + SEPARATOR ::= ' ' | '\t' | '\n' | '\r' | '\v' | '\f' + NEGATION ::= '!' + FLAG ::= "&" | "none" | "stdio" | "rpath" | "wpath" + | <... see pledge_string_map in sys/pledge.h> + TERM ::= ( NEGATION | "") FLAG + TERM-LIST ::= TERM (SEPARATOR TERM-LIST | "" ) + POLICY ::= (TERM-LIST | "" ) (SEPARATOR | "" ) EOF +.Ed +.\" +.\" +.\" +.Sh EXAMPLES +.Ss Reducing privileges with Fn pledge +.Bd -literal -offset indent +#include +.Pp +if (pledge(PLEDGE_STDIO)) + errx("Dropping privileges failed."); +.Pp +/* Process is now limited to operations permitted by the "stdio" permission. */ +printf("Hello from the sandbox!\n"); +.Ed +.\" +.Ss Reducing privileges with Fn pledge_string +.Bd -literal -offset indent +#include +#include +.Pp +int my_fd = mkstemp("myfile"); +write(my_fd, "Good content"); +if (pledge_string("stdio rpath softfail")) + errx("Dropping privileges failed."); +if (-1 == write(my_fd, "Bad content")) { + printf("Failed to write the bad content; we lack the [wpath] flag\n"); +} +if (pledge_string("wildcard !softfail")) + errx("Failed to turn off softfail"); +.Ed +.\" +.Ss TODO document the other functions +.Ed +.\" +.Sh SEE ALSO +.Xr pledge 4 , +.Xr pledgectl 8 , +.Sh HISTORY +A +.Fn pause +syscall +appeared in +.At v6 . diff --git a/lib/libpledge/pledge.c b/lib/libpledge/pledge.c new file mode 100644 index 000000000000..7466b5ed9449 --- /dev/null +++ b/lib/libpledge/pledge.c @@ -0,0 +1,217 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pledge.h" + +/* Cached security.pledge.flags MIB */ +static int security_pledge_flags[3] = {0}; + +__attribute__ ((constructor)) static void +libpledge_initialize(void) +{ + size_t len = 3; + _Static_assert((sizeof(security_pledge_flags)/sizeof(int) == 3), + "pledge MIB != 3"); + if (sysctlnametomib("security.pledge.flags", + (int *) &security_pledge_flags, &len)) + { + //perror("pledgectl"); + fprintf(stderr, + "libpledge: failed to resolve pledge sysctl MIB\n"); + exit(1); + } +} + +/* + * Wrapper for the security.pledge.flags sysctl. + * On error, errno is set to indicate the error. + */ +int +pledge(const uint64_t mask) +{ + return (sysctl(security_pledge_flags, 3, NULL, NULL, + &mask, sizeof(mask))); +} + +/* + * State machine for pledge_str() below + */ +enum pledge_str_state { LOOK_FOR_WHITESPACE, TERM, NEGATED_TERM }; + +/* + * TODO + * Convert a human-readable string to a pledge bitmask. + * (output_mask) is only modified if the parsing was successful. + * On success returns 0, on error returns either -1, or an offset to the + * the first character not recognized by the parser. + */ +intptr_t +pledge_string_to_bitmask(const char *const policy, uint64_t *output_mask) +{ + uint64_t whitelist = PLEDGE_NONE; + uint64_t blacklist = PLEDGE_NONE; + enum pledge_str_state state = TERM; + + if (!policy || !output_mask) + return (-1); + + { /* Raw integer mask */ + char *invalid = NULL; + errno = 0; + uint64_t raw = strtoull(policy, &invalid, 0); + if ( !errno && '\0' == *invalid) { + *output_mask = raw; + return (0); + } + } + + const char *const stop = policy + strlen(policy); + for (const char *ptr = policy; ptr < stop; ptr++) { + + switch (state) { + case NEGATED_TERM: + if (isspace(*ptr)) continue; + break; + case TERM: + if ('!' == *ptr) { + state = NEGATED_TERM; + continue; + } else if (isspace(*ptr)) continue; + break; + case LOOK_FOR_WHITESPACE: + if (isspace(ptr[0])) { + state = TERM; + continue; + } + /* Expecting whitespace, got something else: */ + /* TODO if we returned the index of the invalid char + * this function would be a lot more useful to people + * having issues with the syntax. */ + return (ptr - policy); + } + + for (size_t idx = 0; + idx < sizeof(pledge_string_map) + / sizeof(pledge_string_map[0]); idx++) { + + size_t namelen = strlen(pledge_string_map[idx].name); + // TODO locale-dependent, use C locale instead: + /* + * Test for common prefix and termination with + * either space or \0 : + */ + if (0 != strncasecmp(ptr, + pledge_string_map[idx].name, namelen) + || (*(ptr + namelen) | ' ') != ' ') + continue; + + if (NEGATED_TERM == state) { + blacklist |= pledge_string_map[idx].constant; + } else { + assert(TERM == state); + whitelist |= pledge_string_map[idx].constant; + } + /* -1 because ptr++ at end of loop: */ + ptr += namelen - 1; + state = LOOK_FOR_WHITESPACE; + break; + } + + /* If we are still looking for a term, we didn't find + * a match in pledge_string_map: */ + if (LOOK_FOR_WHITESPACE != state) + return (ptr - policy); + } + + /* + * Let blacklist take precedence over whitelist by applying the + * intersection of the whitelist and the inverse of the blacklist: + */ + *output_mask = (whitelist & ~blacklist); + return (0); +} + +/* + * Parse and apply a pledge() policy from a string. + * Returns 0 on success and an error otherwise. + * See sys/pledge.h + */ +int pledge_string(const char *policy) +{ + uint64_t mask = PLEDGE_NONE; + int err = pledge_string_to_bitmask(policy, &mask); + if (err) { + return (err); + } + return (pledge(mask)); +} + +/* + * Pretty-prints the string representation of _mask into a newly allocated + * string and returns a pointer. + * Returns NULL if not enough memory is available. + * The caller is responsible for free()'ing the returned buffer. + */ +char * +pledge_bitmask_to_string(const uint64_t mask) +{ + size_t length = 1; /* At least the trailing \0 */ + char *ret = NULL; + char *off = NULL; + + /* Compute size required for the returned buffer: */ + + uint64_t space_mask = mask; + for (size_t i = 0; + i < sizeof(pledge_string_map) + / sizeof(pledge_string_map[0]); i++) { + const uint64_t target = pledge_string_map[i].constant; + if ((target & space_mask) == target) { + /* Reserve space for ' ' (space) + name: */ + length += 1 + strlen(pledge_string_map[i].name); + /* Unset all bits covered by this mask to prevent + * double matches: */ + space_mask &= ~target; + /* Do not emit "none" if we have other flags: */ + if (!space_mask) break; + } + } + + if (length > 1) --length; /* Adjust space prefix for first element */ + + off = ret = calloc(1, length); + if (NULL == ret) { + return (NULL); + } + + /* Set string: */ + + uint64_t string_mask = mask; + for (size_t i = 0; + i < sizeof(pledge_string_map) + / sizeof(pledge_string_map[0]); i++) { + const uint64_t target = pledge_string_map[i].constant; + if ((target & string_mask) == target) { + off = stpcpy(off, pledge_string_map[i].name); + /* Unset all bits covered by this mask to prevent + * double matches: */ + string_mask &= ~target; + /* If all flags decoded and at least one outputted: */ + if (!string_mask) break; + /* We have more flags left, append space separator: */ + *off++ = ' '; + } + } + + return (ret); +} diff --git a/lib/libpledge/pledge.h b/lib/libpledge/pledge.h new file mode 100644 index 000000000000..a2334d84c2af --- /dev/null +++ b/lib/libpledge/pledge.h @@ -0,0 +1,67 @@ +#ifndef _LIB_PLEDGE_H +#define _LIB_PLEDGE_H + +/* TODO BSD LICENSE */ + +// TODO should this file be called libpledge.h instead to avoid colliding with +// ? + +/* + * Pledge constants and other data types shared between kernel and userland + * are defined in + */ + +#include + + +/* + * Pledge to use a subset of system call functionality. + */ +int +pledge(const uint64_t _mask); + +/* + * Convert a string policy to a mask. + * On success, the parsed mask is written to _result_mask. + * Returns 0 on success, and an error otherwise. + * + * Negations using a prefix of '!' is supported, and they take precedence + * over the whitelisting flags. + * + * BNF-syntax, which should go in the `man pledge` + * SEPARATOR ::= ' ' | '\t' | '\n' | '\r' | '\v' | '\f' + * NEGATION ::= '!' + * FLAG ::= "pf" | "rpath" | "wpath" | <... see pledge_string_map in pledge.h> + * TERM ::= ( NEGATION | "") FLAG + * TERM-LIST ::= TERM (SEPARATOR TERM-LIST | "" ) + * POLICY ::= (TERM-LIST | "" ) (SEPARATOR | "" ) EOF + */ +intptr_t +pledge_string_to_bitmask(const char *_policy, uint64_t *_result_mask); + + +/* + * Parse and apply a pledge() policy from a string. + * Returns 0 on success and an error otherwise. + * See pledge_string_to_bitmask(). + */ +int +pledge_string(const char *_policy); + + +/* + * Pretty-prints the string representation of _mask into a newly allocated + * string and returns a pointer. + * Returns NULL if not enough memory is available. + * The caller is responsible for free()'ing the returned buffer. + * Note that if you're using this from userspace, you might want to use + * libsysdecode's sysdecode_pledge_flags(), like kdump(1) does, which + * prints the mask to a FILE *fp instead of malloc()'ing. + * Also note that at the moment this resides in libc, + * so good luck calling it from elsewhere. TODO + */ +char * +pledge_bitmask_to_string(const uint64_t _mask); + + +#endif /* _LIB_PLEDGE_H */ diff --git a/lib/libsysdecode/Makefile b/lib/libsysdecode/Makefile index 85c76bcffd8e..e7b383722f74 100644 --- a/lib/libsysdecode/Makefile +++ b/lib/libsysdecode/Makefile @@ -1,159 +1,160 @@ .include LIB= sysdecode SRCS= errno.c flags.c ioctl.c netlink.c signal.c syscallnames.c utrace.c support.c .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" || \ ${MACHINE_CPUARCH} == "i386" SRCS+= linux.c .endif INCS= sysdecode.h CFLAGS+= -I${.OBJDIR} CFLAGS+= -I${SRCTOP}/sys CFLAGS+= -I${SRCTOP}/libexec/rtld-elf MAN= sysdecode.3 \ sysdecode_abi_to_freebsd_errno.3 \ sysdecode_cap_rights.3 \ sysdecode_cmsg_type.3 \ sysdecode_enum.3 \ sysdecode_fcntl_arg.3 \ sysdecode_kevent.3 \ sysdecode_ioctlname.3 \ sysdecode_mask.3 \ sysdecode_quotactl_cmd.3 \ sysdecode_sctp_sinfo_flags.3 \ sysdecode_sigcode.3 \ sysdecode_sockopt_name.3 \ sysdecode_socket_protocol.3 \ sysdecode_syscallname.3 \ sysdecode_utrace.3 MLINKS= sysdecode_abi_to_freebsd_errno.3 sysdecode_freebsd_to_abi_errno.3 MLINKS+=sysdecode_enum.3 sysdecode_acltype.3 \ sysdecode_enum.3 sysdecode_atfd.3 \ sysdecode_enum.3 sysdecode_extattrnamespace.3 \ sysdecode_enum.3 sysdecode_fadvice.3 \ sysdecode_enum.3 sysdecode_fcntl_cmd.3 \ sysdecode_enum.3 sysdecode_getfsstat_mode.3 \ sysdecode_enum.3 sysdecode_getrusage_who.3 \ sysdecode_enum.3 sysdecode_idtype.3 \ sysdecode_enum.3 sysdecode_ipproto.3 \ sysdecode_enum.3 sysdecode_kldsym_cmd.3 \ sysdecode_enum.3 sysdecode_kldunload_flags.3 \ sysdecode_enum.3 sysdecode_lio_listio_mode.3 \ sysdecode_enum.3 sysdecode_madvice.3 \ sysdecode_enum.3 sysdecode_minherit_flags.3 \ sysdecode_enum.3 sysdecode_msgctl_cmd.3 \ sysdecode_enum.3 sysdecode_nfssvc_flags.3 \ sysdecode_enum.3 sysdecode_pathconf_name.3 \ sysdecode_enum.3 sysdecode_prio_which.3 \ sysdecode_enum.3 sysdecode_procctl_cmd.3 \ sysdecode_enum.3 sysdecode_ptrace_request.3 \ sysdecode_enum.3 sysdecode_rlimit.3 \ sysdecode_enum.3 sysdecode_rtprio_function.3 \ sysdecode_enum.3 sysdecode_scheduler_policy.3 \ sysdecode_enum.3 sysdecode_sctp_pr_policy.3 \ sysdecode_enum.3 sysdecode_semctl_cmd.3 \ sysdecode_enum.3 sysdecode_shmctl_cmd.3 \ sysdecode_enum.3 sysdecode_shutdown_how.3 \ sysdecode_enum.3 sysdecode_sigbus_code.3 \ sysdecode_enum.3 sysdecode_sigchld_code.3 \ sysdecode_enum.3 sysdecode_sigfpe_code.3 \ sysdecode_enum.3 sysdecode_sigill_code.3 \ sysdecode_enum.3 sysdecode_signal.3 \ sysdecode_enum.3 sysdecode_sigprocmask_how.3 \ sysdecode_enum.3 sysdecode_sigsegv_code.3 \ sysdecode_enum.3 sysdecode_sigtrap_code.3 \ sysdecode_enum.3 sysdecode_sockaddr_family.3 \ sysdecode_enum.3 sysdecode_socketdomain.3 \ sysdecode_enum.3 sysdecode_sockettype.3 \ sysdecode_enum.3 sysdecode_sockopt_level.3 \ sysdecode_enum.3 sysdecode_sysarch_number.3 \ sysdecode_enum.3 sysdecode_umtx_op.3 \ sysdecode_enum.3 sysdecode_vmresult.3 \ sysdecode_enum.3 sysdecode_whence.3 MLINKS+=sysdecode_fcntl_arg.3 sysdecode_fcntl_arg_p.3 MLINKS+=sysdecode_kevent.3 sysdecode_kevent_fflags.3 \ sysdecode_kevent.3 sysdecode_kevent_filter.3 \ sysdecode_kevent.3 sysdecode_kevent_flags.3 MLINKS+=sysdecode_mask.3 sysdecode_accessmode.3 \ sysdecode_mask.3 sysdecode_atflags.3 \ sysdecode_mask.3 sysdecode_capfcntlrights.3 \ sysdecode_mask.3 sysdecode_fcntl_fileflags.3 \ sysdecode_mask.3 sysdecode_fileflags.3 \ sysdecode_mask.3 sysdecode_filemode.3 \ sysdecode_mask.3 sysdecode_flock_operation.3 \ sysdecode_mask.3 sysdecode_inotifyflags.3 \ sysdecode_mask.3 sysdecode_mlockall_flags.3 \ sysdecode_mask.3 sysdecode_mmap_flags.3 \ sysdecode_mask.3 sysdecode_mmap_prot.3 \ sysdecode_mask.3 sysdecode_mount_flags.3 \ sysdecode_mask.3 sysdecode_msg_flags.3 \ sysdecode_mask.3 sysdecode_msync_flags.3 \ sysdecode_mask.3 sysdecode_open_flags.3 \ sysdecode_mask.3 sysdecode_pipe2_flags.3 \ + sysdecode_mask.3 sysdecode_pledge_flags.3 \ sysdecode_mask.3 sysdecode_pollfd_events.3 \ sysdecode_mask.3 sysdecode_reboot_howto.3 \ sysdecode_mask.3 sysdecode_rfork_flags.3 \ sysdecode_mask.3 sysdecode_semget_flags.3 \ sysdecode_mask.3 sysdecode_sendfile_flags.3 \ sysdecode_mask.3 sysdecode_shmat_flags.3 \ sysdecode_mask.3 sysdecode_sctp_nxt_flags.3 \ sysdecode_mask.3 sysdecode_sctp_rcv_flags.3 \ sysdecode_mask.3 sysdecode_sctp_snd_flags.3 \ sysdecode_mask.3 sysdecode_socket_type.3 \ sysdecode_mask.3 sysdecode_thr_create_flags.3 \ sysdecode_mask.3 sysdecode_umtx_cvwait_flags.3 \ sysdecode_mask.3 sysdecode_umtx_rwlock_flags.3 \ sysdecode_mask.3 sysdecode_vmprot.3 \ sysdecode_mask.3 sysdecode_wait4_options.3 \ sysdecode_mask.3 sysdecode_wait6_options.3 CLEANFILES= ioctl.c ioctl.c.tmp tables.h tables_linux.h # XXX: The flags should come from bsd.compat.mk / Makefile.libcompat .if ${COMPAT_LIBCOMPAT:U} == "32" CPP+= -m32 .endif .if ${MK_PF} != "no" CFLAGS+=-DPF .endif # Workaround duplicate declarations in CFLAGS.gcc.ioctl.c+= -Wno-redundant-decls CFLAGS.gcc+= ${CFLAGS.gcc.${.IMPSRC}} DEPENDOBJS+= tables.h tables_linux.h .if ${MK_DIRDEPS_BUILD} == "yes" MKTABLES_INCLUDEDIR= ${STAGE_INCLUDEDIR} .else MKTABLES_INCLUDEDIR= ${SYSROOT:U${DESTDIR}}${INCLUDEDIR} .endif tables.h: mktables sh ${.CURDIR}/mktables ${MKTABLES_INCLUDEDIR} ${.TARGET} tables_linux.h: mklinuxtables sh ${.CURDIR}/mklinuxtables ${SRCTOP}/sys ${.TARGET} # mkioctls runs find(1) for headers so needs to rebuild every time. This used # to be a hack only done in buildworld. .if !defined(_SKIP_BUILD) ioctl.c.tmp: .PHONY .endif ioctl.c.tmp: mkioctls .META env CPP="${CPP}" MK_PF="${MK_PF}" \ /bin/sh ${.CURDIR}/mkioctls ${MKTABLES_INCLUDEDIR} > ${.TARGET} ioctl.c: ioctl.c.tmp if [ ! -e ${.TARGET} ] || ! cmp -s ${.TARGET} ${.TARGET}.tmp; then \ mv -f ${.TARGET}.tmp ${.TARGET}; \ fi beforedepend: ioctl.c tables.h tables_linux.h HAS_TESTS= SUBDIR.${MK_TESTS}+= tests .include diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c index 8009a7a2f97e..86328fe36981 100644 --- a/lib/libsysdecode/flags.c +++ b/lib/libsysdecode/flags.c @@ -1,136 +1,137 @@ /* * Copyright (c) 2006 "David Kirchner" . 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. */ #define L2CAP_SOCKET_CHECKED #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 #include #include #include #include #include #include #include #include #include #include #include #include #include "support.h" #define X(a) { a, #a }, #define XEND { 0, NULL } #define TABLE_START(n) static struct name_table n[] = { #define TABLE_ENTRY X #define TABLE_END XEND }; #include "tables.h" #undef TABLE_START #undef TABLE_ENTRY #undef TABLE_END const char * sysdecode_atfd(int fd) { if (fd == AT_FDCWD) return ("AT_FDCWD"); return (NULL); } bool sysdecode_atflags(FILE *fp, int flag, int *rem) { return (print_mask_int(fp, atflags, flag, rem)); } static struct name_table semctlops[] = { X(GETNCNT) X(GETPID) X(GETVAL) X(GETALL) X(GETZCNT) X(SETVAL) X(SETALL) X(IPC_RMID) X(IPC_SET) X(IPC_STAT) XEND }; const char * sysdecode_semctl_cmd(int cmd) { return (lookup_value(semctlops, cmd)); } static struct name_table shmctlops[] = { X(IPC_RMID) X(IPC_SET) X(IPC_STAT) XEND }; const char * sysdecode_shmctl_cmd(int cmd) { return (lookup_value(shmctlops, cmd)); } const char * sysdecode_msgctl_cmd(int cmd) { return (sysdecode_shmctl_cmd(cmd)); } static struct name_table semgetflags[] = { X(IPC_CREAT) X(IPC_EXCL) X(SEM_R) X(SEM_A) X((SEM_R>>3)) X((SEM_A>>3)) @@ -478,200 +479,207 @@ sysdecode_kldsym_cmd(int cmd) } const char * sysdecode_kldunload_flags(int flags) { return (lookup_value(kldunloadfflags, flags)); } const char * sysdecode_lio_listio_mode(int mode) { return (lookup_value(lio_listiomodes, mode)); } const char * sysdecode_madvice(int advice) { return (lookup_value(madvisebehav, advice)); } const char * sysdecode_minherit_inherit(int inherit) { return (lookup_value(minheritflags, inherit)); } bool sysdecode_mlockall_flags(FILE *fp, int flags, int *rem) { return (print_mask_int(fp, mlockallflags, flags, rem)); } bool sysdecode_mmap_prot(FILE *fp, int prot, int *rem) { int protm; bool printed; printed = false; protm = PROT_MAX_EXTRACT(prot); prot &= ~PROT_MAX(protm); if (protm != 0) { fputs("PROT_MAX(", fp); printed = print_mask_int(fp, mmapprot, protm, rem); fputs(")|", fp); } return (print_mask_int(fp, mmapprot, prot, rem) || printed); } bool sysdecode_fileflags(FILE *fp, fflags_t flags, fflags_t *rem) { return (print_mask_0(fp, fileflags, flags, rem)); } bool sysdecode_filemode(FILE *fp, int mode, int *rem) { return (print_mask_0(fp, filemode, mode, rem)); } bool sysdecode_mount_flags(FILE *fp, int flags, int *rem) { return (print_mask_int(fp, mountflags, flags, rem)); } bool sysdecode_msync_flags(FILE *fp, int flags, int *rem) { return (print_mask_int(fp, msyncflags, flags, rem)); } const char * sysdecode_nfssvc_flags(int flags) { return (lookup_value(nfssvcflags, flags)); } static struct name_table pipe2flags[] = { X(O_CLOEXEC) X(O_CLOFORK) X(O_NONBLOCK) XEND }; bool sysdecode_pipe2_flags(FILE *fp, int flags, int *rem) { return (print_mask_0(fp, pipe2flags, flags, rem)); } +bool +sysdecode_pledge_flags(FILE *fp, u_long flags, u_long *rem) +{ + + return (print_mask_0ul(fp, pledgeflags, flags, rem)); +} + bool sysdecode_pollfd_events(FILE *fp, int flags, int *rem) { return (print_mask_int(fp, pollfdevents, flags, rem)); } const char * sysdecode_prio_which(int which) { return (lookup_value(prio, which)); } const char * sysdecode_procctl_cmd(int cmd) { return (lookup_value(procctlcmd, cmd)); } const char * sysdecode_ptrace_request(int request) { return (lookup_value(ptraceop, request)); } static struct name_table quotatypes[] = { X(GRPQUOTA) X(USRQUOTA) XEND }; bool sysdecode_quotactl_cmd(FILE *fp, int cmd) { const char *primary, *type; primary = lookup_value(quotactlcmds, cmd >> SUBCMDSHIFT); if (primary == NULL) return (false); fprintf(fp, "QCMD(%s,", primary); type = lookup_value(quotatypes, cmd & SUBCMDMASK); if (type != NULL) fprintf(fp, "%s", type); else fprintf(fp, "%#x", cmd & SUBCMDMASK); fprintf(fp, ")"); return (true); } bool sysdecode_reboot_howto(FILE *fp, int howto, int *rem) { bool printed; /* * RB_AUTOBOOT is special in that its value is zero, but it is * also an implied argument if a different operation is not * requested via RB_HALT, RB_POWERCYCLE, RB_POWEROFF, or * RB_REROOT. */ if (howto != 0 && (howto & (RB_HALT | RB_POWEROFF | RB_REROOT | RB_POWERCYCLE)) == 0) { fputs("RB_AUTOBOOT|", fp); printed = true; } else printed = false; return (print_mask_int(fp, rebootopt, howto, rem) || printed); } bool sysdecode_rfork_flags(FILE *fp, int flags, int *rem) { return (print_mask_int(fp, rforkflags, flags, rem)); } const char * sysdecode_rlimit(int resource) { return (lookup_value(rlimit, resource)); } const char * sysdecode_scheduler_policy(int policy) { return (lookup_value(schedpolicy, policy)); } bool sysdecode_sendfile_flags(FILE *fp, int flags, int *rem) { return (print_mask_int(fp, sendfileflags, flags, rem)); } bool sysdecode_shmat_flags(FILE *fp, int flags, int *rem) @@ -880,201 +888,201 @@ static struct name_table fcntl_fd_arg[] = { bool sysdecode_fcntl_arg_p(int cmd) { switch (cmd) { case F_GETFD: case F_GETFL: case F_GETOWN: return (false); default: return (true); } } void sysdecode_fcntl_arg(FILE *fp, int cmd, uintptr_t arg, int base) { int rem; switch (cmd) { case F_SETFD: if (!print_value(fp, fcntl_fd_arg, arg)) print_integer(fp, arg, base); break; case F_SETFL: if (!sysdecode_fcntl_fileflags(fp, arg, &rem)) fprintf(fp, "%#x", rem); else if (rem != 0) fprintf(fp, "|%#x", rem); break; case F_GETLK: case F_SETLK: case F_SETLKW: fprintf(fp, "%p", (void *)arg); break; default: print_integer(fp, arg, base); break; } } bool sysdecode_mmap_flags(FILE *fp, int flags, int *rem) { uintmax_t val; bool printed; int align; /* * MAP_ALIGNED can't be handled directly by print_mask_int(). */ printed = false; align = flags & MAP_ALIGNMENT_MASK; val = (unsigned)flags & ~MAP_ALIGNMENT_MASK; print_mask_part(fp, mmapflags, &val, &printed); if (align != 0) { if (printed) fputc('|', fp); if (align == MAP_ALIGNED_SUPER) fputs("MAP_ALIGNED_SUPER", fp); else fprintf(fp, "MAP_ALIGNED(%d)", align >> MAP_ALIGNMENT_SHIFT); printed = true; } if (rem != NULL) *rem = val; return (printed); } const char * sysdecode_pathconf_name(int name) { return (lookup_value(pathconfname, name)); } const char * sysdecode_rtprio_function(int function) { return (lookup_value(rtpriofuncs, function)); } bool sysdecode_msg_flags(FILE *fp, int flags, int *rem) { return (print_mask_0(fp, msgflags, flags, rem)); } const char * sysdecode_sigcode(int sig, int si_code) { const char *str; str = lookup_value(sigcode, si_code); if (str != NULL) return (str); - + switch (sig) { case SIGILL: return (sysdecode_sigill_code(si_code)); case SIGBUS: return (sysdecode_sigbus_code(si_code)); case SIGSEGV: return (sysdecode_sigsegv_code(si_code)); case SIGFPE: return (sysdecode_sigfpe_code(si_code)); case SIGTRAP: return (sysdecode_sigtrap_code(si_code)); case SIGCHLD: return (sysdecode_sigchld_code(si_code)); default: return (NULL); } } const char * sysdecode_sysarch_number(int number) { return (lookup_value(sysarchnum, number)); } bool sysdecode_umtx_cvwait_flags(FILE *fp, u_long flags, u_long *rem) { return (print_mask_0ul(fp, umtxcvwaitflags, flags, rem)); } bool sysdecode_umtx_rwlock_flags(FILE *fp, u_long flags, u_long *rem) { return (print_mask_0ul(fp, umtxrwlockflags, flags, rem)); } void sysdecode_cap_rights(FILE *fp, cap_rights_t *rightsp) { cap_rights_t diff, sum, zero; const struct name_table *t; int i; bool comma; for (i = 0; i < CAPARSIZE(rightsp); i++) { if (CAPIDXBIT(rightsp->cr_rights[i]) != 1 << i) { fprintf(fp, "invalid cap_rights_t"); return; } } cap_rights_init(&sum); diff = *rightsp; for (t = caprights, comma = false; t->str != NULL; t++) { if (cap_rights_is_set(rightsp, t->val)) { cap_rights_clear(&diff, t->val); if (cap_rights_is_set(&sum, t->val)) { /* Don't print redundant rights. */ continue; } cap_rights_set(&sum, t->val); fprintf(fp, "%s%s", comma ? "," : "", t->str); comma = true; } } if (!comma) fprintf(fp, "CAP_NONE"); /* * Provide a breadcrumb if some of the provided rights are not included * in the table, likely due to a bug in the mktables script. */ CAP_NONE(&zero); if (!cap_rights_contains(&zero, &diff)) fprintf(fp, ",unknown rights"); } /* * Pre-sort the set of rights, which has a partial ordering defined by the * subset relation. This lets sysdecode_cap_rights() print a list of minimal * length with a single pass over the "caprights" table. */ static void __attribute__((constructor)) sysdecode_cap_rights_init(void) { cap_rights_t tr, qr; struct name_table *t, *q, tmp; bool swapped; do { for (t = caprights, swapped = false; t->str != NULL; t++) { cap_rights_init(&tr, t->val); for (q = t + 1; q->str != NULL; q++) { cap_rights_init(&qr, q->val); if (cap_rights_contains(&qr, &tr)) { tmp = *t; *t = *q; diff --git a/lib/libsysdecode/mktables b/lib/libsysdecode/mktables index 2bfbaf529f44..deb9f005623e 100644 --- a/lib/libsysdecode/mktables +++ b/lib/libsysdecode/mktables @@ -57,134 +57,135 @@ gen_table() local name grep file excl filter name=$1 grep=$2 file=$3 excl=$4 if [ -z "$excl" ]; then filter="cat" else filter="egrep -v" fi cat <<_EOF_ TABLE_START(${name}) _EOF_ if [ -e "${include_dir}/${file}" ]; then all_headers="${all_headers:+${all_headers} }${file}" egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \ $include_dir/$file | ${filter} ${excl} | \ awk '{ for (i = 1; i <= NF; i++) \ if ($i ~ /define/) \ break; \ ++i; \ printf "TABLE_ENTRY(%s)\n", $i }' fi cat <<_EOF_ TABLE_END _EOF_ } cat <<_EOF_ /* This file is auto-generated. */ _EOF_ gen_table "accessmode" "[A-Z]_OK[[:space:]]+0?x?[0-9A-Fa-f]+" "sys/unistd.h" gen_table "acltype" "ACL_TYPE_[A-Z4_]+[[:space:]]+0x[0-9]+" "sys/acl.h" gen_table "atflags" "AT_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/fcntl.h" gen_table "capfcntl" "CAP_FCNTL_[A-Z]+[[:space:]]+\(1" "sys/capsicum.h" gen_table "closerangeflags" "CLOSE_RANGE_[A-Z]+[[:space:]]+\([0-9]+<<[0-9]+\)" "sys/unistd.h" gen_table "extattrns" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/extattr.h" gen_table "fadvisebehav" "POSIX_FADV_[A-Z]+[[:space:]]+[0-9]+" "sys/fcntl.h" gen_table "openflags" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h" "O_RDONLY|O_RDWR|O_WRONLY" gen_table "flockops" "LOCK_[A-Z]+[[:space:]]+0x[0-9]+" "sys/fcntl.h" gen_table "inotifyflags" "IN_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/inotify.h" "IN_CLOEXEC|IN_NONBLOCK" gen_table "kldsymcmd" "KLDSYM_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h" gen_table "kldunloadfflags" "LINKER_UNLOAD_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h" gen_table "lio_listiomodes" "LIO_(NO)?WAIT[[:space:]]+[0-9]+" "aio.h" gen_table "madvisebehav" "_?MADV_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h" gen_table "minheritflags" "INHERIT_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h" gen_table "mlockallflags" "MCL_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h" gen_table "mmapprot" "PROT_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h" gen_table "ngbtsolevel" "SOL_[A-Z0-9]+[[:space:]]+0x[0-9A-Fa-f]+" "netgraph/bluetooth/include/ng_btsocket.h" gen_table "fileflags" "[SU]F_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/stat.h" "UF_COMPRESSED|UF_TRACKED|UF_SETTABLE|SF_SETTABLE" gen_table "filemode" "S_[A-Z]+[[:space:]]+[0-6]{7}" "sys/stat.h" gen_table "keventflags" "EV_[A-Z]+[[:space:]]+0x[0-9]+" "sys/event.h" "EV_SYSFLAGS|EV_DROP|EV_FLAG[12]" gen_table "keventfilters" "EVFILT_[A-Z]+[[:space:]]+\(-[0-9]+\)" "sys/event.h" gen_table "mountflags" "MNT_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mount.h" gen_table "msyncflags" "MS_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h" gen_table "nfssvcflags" "NFSSVC_[A-Z0-9]+[[:space:]]+0x[0-9]+" "nfs/nfssvc.h" gen_table "pathconfname" "_PC_[A-Z4_]+[[:space:]]+[0-9]+" "sys/unistd.h" gen_table "pollfdevents" "POLL[A-Z]+[[:space:]]+" "sys/poll.h" gen_table "prio" "PRIO_[A-Z]+[[:space:]]+[0-9]" "sys/resource.h" gen_table "procctlcmd" "PROC_[A-Z_]+[[:space:]]+[0-9]" "sys/procctl.h" "PROC_TRACE_CTL_" gen_table "ptraceop" "PT_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/ptrace.h" gen_table "quotactlcmds" "Q_[A-Z]+[[:space:]]+0x[0-9]+" "ufs/ufs/quota.h" gen_table "rebootopt" "RB_[A-Z]+[[:space:]]+0x[0-9]+" "sys/reboot.h" gen_table "rforkflags" "RF[A-Z]+[[:space:]]+\([0-9]+[uU]?<<[0-9]+\)" "sys/unistd.h" "RFPPWAIT" gen_table "rlimit" "RLIMIT_[A-Z]+[[:space:]]+[0-9]+" "sys/resource.h" gen_table "rusage" "RUSAGE_[A-Z]+[[:space:]]+[-0-9]+" "sys/resource.h" gen_table "schedpolicy" "SCHED_[A-Z]+[[:space:]]+[0-9]+" "sys/sched.h" gen_table "sendfileflags" "SF_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h" gen_table "shmatflags" "SHM_[A-Z]+[[:space:]]+[0-9]{6}" "sys/shm.h" gen_table "shutdownhow" "SHUT_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h" gen_table "sigbuscode" "BUS_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" gen_table "sigchldcode" "CLD_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" gen_table "sigfpecode" "FPE_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" gen_table "sigprocmaskhow" "SIG_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" gen_table "sigillcode" "ILL_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" gen_table "sigsegvcode" "SEGV_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" gen_table "sigtrapcode" "TRAP_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" gen_table "sockdomain" "PF_[[:alnum:]]+[[:space:]]+" "sys/socket.h" gen_table "sockfamily" "AF_[[:alnum:]]+[[:space:]]+" "sys/socket.h" gen_table "sockipproto" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h" gen_table "sockopt" "SO_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/socket.h" gen_table "sockoptip" "(IP_[[:alnum:]_]+|MCAST_[[:alnum:]_]+_GROUP)[[:space:]]+" "netinet/in.h" "IP_DEFAULT|IP_MIN|IP_MAX|IP_PORTRANGE" gen_table "sockoptipv6" "IPV6_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet6/in6.h" "IPV6_ADDR_|IPV6_TAG_DIRECT|IPV6_OPTIONS|IPV6_RECVOPTS|IPV6_RECVRETOPTS|IPV6_RECVDSTADDR|IPV6_RETOPTS|IPV6_2292|IPV6_RECVRTHDRDSTOPTS|IPV6_REACHCONF|IPV6_PKTOPTIONS" gen_table "sockoptsctp" "SCTP_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet/sctp.h" gen_table "sockopttcp" "TCP_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet/tcp.h" "TCP_MIN|TCP_MAX[^S]|TCP_MSS|TCP_[[:alnum:]_]+_MAX|TCP_FASTOPEN_MIN_COOKIE_LEN|TCP_FASTOPEN_PSK_LEN|TCP_USE_DDP" gen_table "sockoptudp" "UDP_[[:alnum:]]+[[:space:]]+[0-9]+" "netinet/udp.h" "UDP_ENCAP_" gen_table "sockoptudplite" "UDPLITE_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet/udplite.h" gen_table "socktype" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h" gen_table "thrcreateflags" "THR_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/thr.h" gen_table "umtxop" "UMTX_OP_[[:alnum:]][[:alnum:]_]*[[:space:]]+[0-9]+" "sys/umtx.h" gen_table "umtxopflags" "UMTX_OP__[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/umtx.h" gen_table "vmprot" "VM_PROT_[A-Z_]+[[:space:]]+\(\(vm_prot_t\)[[:space:]]+0x[0-9]+\)" "vm/vm.h" gen_table "vmresult" "KERN_[A-Z_]+[[:space:]]+[0-9]+" "vm/vm_param.h" gen_table "wait6opt" "W[A-Z]+[[:space:]]+[0-9]+" "sys/wait.h" gen_table "seekwhence" "SEEK_[A-Z]+[[:space:]]+[0-9]+" "sys/unistd.h" gen_table "fcntlcmd" "F_[A-Z0-9_]+[[:space:]]+[0-9]+[[:space:]]+" "sys/fcntl.h" "F_CANCEL|F_..LCK" +gen_table "pledgeflags" "PLEDGE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/pledge.h" gen_table "mmapflags" "MAP_[2-3A-Z_]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h" gen_table "rtpriofuncs" "RTP_[A-Z]+[[:space:]]+[0-9]+" "sys/rtprio.h" gen_table "msgflags" "MSG_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/socket.h" "MSG_SOCALLBCK|MSG_MORETOCOME|MSG_TLSAPPDATA" gen_table "sigcode" "SI_[A-Z]+[[:space:]]+0(x[0-9abcdef]+)?" "sys/signal.h" gen_table "umtxcvwaitflags" "CVWAIT_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/umtx.h" gen_table "umtxrwlockflags" "URWLOCK_PREFER_READER[[:space:]]+0x[0-9]+" "sys/umtx.h" gen_table "caprights" "CAP_[A-Z_]+[[:space:]]+((CAPRIGHT\([0-9],[[:space:]]+0x[0-9]{16}ULL\))|(\(CAP_[A-Z_]+[[:space:]]*\|.*\)))" "sys/capsicum.h" gen_table "sctpprpolicy" "SCTP_PR_SCTP_[A-Z_]+[[:space:]]+0x[0-9]+" "netinet/sctp_uio.h" "SCTP_PR_SCTP_ALL" gen_table "cmsgtypesocket" "SCM_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/socket.h" if [ -e "${include_dir}/x86/sysarch.h" ]; then gen_table "sysarchnum" "(AMD64|I386)_[A-Z86_]+[[:space:]]+[0-9]+" "x86/sysarch.h" else gen_table "sysarchnum" "[A-Z_]+[[:space:]]+[0-9]+" "machine/sysarch.h" fi gen_table "shmflags" "SHM_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/mman.h" "SHM_ANON" gen_table "itimerwhich" "ITIMER_[A-Z]+[[:space:]]+[0-9]+" "sys/time.h" gen_table "pfnl_cmd" "PFNL_CMD_[A-Z_]+[[:space:]]+[0-9]+" "netpfil/pf/pf_nl.h" # Generate a .depend file for our output file if [ -n "$output_file" ]; then depend_tmp=$(mktemp -u) { echo "$output_file: \\" echo "$all_headers" | tr ' ' '\n' | sort -u | sed -e "s,^, $include_dir/," -e 's,$, \\,' echo } > "$depend_tmp" if cmp -s "$output_tmp" "$output_file"; then rm -f "$output_tmp" "$depend_tmp" else mv -f "$depend_tmp" ".depend.${output_file}" mv -f "$output_tmp" "$output_file" fi fi diff --git a/lib/libsysdecode/sysdecode.h b/lib/libsysdecode/sysdecode.h index 4675b1e3c463..9f466603f0b6 100644 --- a/lib/libsysdecode/sysdecode.h +++ b/lib/libsysdecode/sysdecode.h @@ -1,154 +1,155 @@ /*- * Copyright (c) 2015 John H. Baldwin * * 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 __SYSDECODE_H__ #define __SYSDECODE_H__ #include #include #include enum sysdecode_abi { SYSDECODE_ABI_UNKNOWN = 0, SYSDECODE_ABI_FREEBSD, SYSDECODE_ABI_FREEBSD32, SYSDECODE_ABI_LINUX, SYSDECODE_ABI_LINUX32, }; int sysdecode_abi_to_freebsd_errno(enum sysdecode_abi _abi, int _error); bool sysdecode_access_mode(FILE *_fp, int _mode, int *_rem); const char *sysdecode_acltype(int _type); const char *sysdecode_atfd(int _fd); bool sysdecode_atflags(FILE *_fp, int _flags, int *_rem); bool sysdecode_cap_fcntlrights(FILE *_fp, uint32_t _rights, uint32_t *_rem); void sysdecode_cap_rights(FILE *_fp, cap_rights_t *_rightsp); bool sysdecode_close_range_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_cmsg_type(int _cmsg_level, int _cmsg_type); const char *sysdecode_extattrnamespace(int _namespace); const char *sysdecode_fadvice(int _advice); void sysdecode_fcntl_arg(FILE *_fp, int _cmd, uintptr_t _arg, int _base); bool sysdecode_fcntl_arg_p(int _cmd); const char *sysdecode_fcntl_cmd(int _cmd); bool sysdecode_fcntl_fileflags(FILE *_fp, int _flags, int *_rem); bool sysdecode_fileflags(FILE *_fp, fflags_t _flags, fflags_t *_rem); bool sysdecode_filemode(FILE *_fp, int _mode, int *_rem); bool sysdecode_flock_operation(FILE *_fp, int _operation, int *_rem); int sysdecode_freebsd_to_abi_errno(enum sysdecode_abi _abi, int _error); const char *sysdecode_getfsstat_mode(int _mode); const char *sysdecode_getrusage_who(int _who); const char *sysdecode_idtype(int _idtype); const char *sysdecode_ioctlname(unsigned long _val); bool sysdecode_inotifyflags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_ipproto(int _protocol); void sysdecode_kevent_fflags(FILE *_fp, short _filter, int _fflags, int _base); const char *sysdecode_itimer(int _which); const char *sysdecode_pfnl_cmd(int cmd); const char *sysdecode_kevent_filter(int _filter); bool sysdecode_kevent_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_kldsym_cmd(int _cmd); const char *sysdecode_kldunload_flags(int _flags); const char *sysdecode_lio_listio_mode(int _mode); const char *sysdecode_madvice(int _advice); const char *sysdecode_minherit_inherit(int _inherit); const char *sysdecode_msgctl_cmd(int _cmd); bool sysdecode_mlockall_flags(FILE *_fp, int _flags, int *_rem); bool sysdecode_mmap_flags(FILE *_fp, int _flags, int *_rem); bool sysdecode_mmap_prot(FILE *_fp, int _prot, int *_rem); bool sysdecode_mount_flags(FILE *_fp, int _flags, int *_rem); bool sysdecode_msg_flags(FILE *_fp, int _flags, int *_rem); bool sysdecode_msync_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_nfssvc_flags(int _flags); bool sysdecode_open_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_pathconf_name(int _name); bool sysdecode_pipe2_flags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_pledge_flags(FILE *_fp, u_long flags, u_long *_rem); bool sysdecode_pollfd_events(FILE *fp, int flags, int *rem); const char *sysdecode_prio_which(int _which); const char *sysdecode_procctl_cmd(int _cmd); const char *sysdecode_ptrace_request(int _request); bool sysdecode_quotactl_cmd(FILE *_fp, int _cmd); bool sysdecode_reboot_howto(FILE *_fp, int _howto, int *_rem); bool sysdecode_rfork_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_rlimit(int _resource); const char *sysdecode_rtprio_function(int _function); const char *sysdecode_scheduler_policy(int _policy); bool sysdecode_sctp_nxt_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_sctp_pr_policy(int _policy); bool sysdecode_sctp_rcv_flags(FILE *_fp, int _flags, int *_rem); void sysdecode_sctp_sinfo_flags(FILE *_fp, int _sinfo_flags); bool sysdecode_sctp_snd_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_semctl_cmd(int _cmd); bool sysdecode_semget_flags(FILE *_fp, int _flag, int *_rem); bool sysdecode_sendfile_flags(FILE *_fp, int _flags, int *_rem); bool sysdecode_shmat_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_shmctl_cmd(int _cmd); const char *sysdecode_shutdown_how(int _how); const char *sysdecode_sigbus_code(int _si_code); const char *sysdecode_sigchld_code(int _si_code); const char *sysdecode_sigcode(int _sig, int _si_code); const char *sysdecode_sigfpe_code(int _si_code); const char *sysdecode_sigill_code(int _si_code); const char *sysdecode_signal(int _sig); const char *sysdecode_sigprocmask_how(int _how); const char *sysdecode_sigsegv_code(int _si_code); const char *sysdecode_sigtrap_code(int _si_code); const char *sysdecode_sockaddr_family(int _sa_family); const char *sysdecode_socketdomain(int _domain); const char *sysdecode_socket_protocol(int _domain, int _protocol); bool sysdecode_socket_type(FILE *_fp, int _type, int *_rem); const char *sysdecode_sockopt_level(int _level); const char *sysdecode_sockopt_name(int _level, int _optname); const char *sysdecode_syscallname(enum sysdecode_abi _abi, unsigned int _code); const char *sysdecode_sysarch_number(int _number); bool sysdecode_thr_create_flags(FILE *_fp, int _flags, int *_rem); bool sysdecode_umtx_cvwait_flags(FILE *_fp, u_long _flags, u_long *_rem); const char *sysdecode_umtx_op(int _op); bool sysdecode_umtx_op_flags(FILE *_fp, int op, int *_rem); bool sysdecode_umtx_rwlock_flags(FILE *_fp, u_long _flags, u_long *_rem); int sysdecode_utrace(FILE *_fp, void *_buf, size_t _len); bool sysdecode_vmprot(FILE *_fp, int _type, int *_rem); const char *sysdecode_vmresult(int _result); bool sysdecode_wait4_options(FILE *_fp, int _options, int *_rem); bool sysdecode_wait6_options(FILE *_fp, int _options, int *_rem); const char *sysdecode_whence(int _whence); bool sysdecode_shmflags(FILE *_fp, int _flags, int *_rem); bool sysdecode_netlink(FILE *_fp, const void *_buf, size_t _len); #if defined(__i386__) || defined(__amd64__) || defined(__aarch64__) #define SYSDECODE_HAVE_LINUX bool sysdecode_linux_atflags(FILE *_fp, int _flag, int *_rem); void sysdecode_linux_clockid(FILE *_fp, clockid_t _which); bool sysdecode_linux_clock_flags(FILE *_fp, int _flags, int *_rem); bool sysdecode_linux_clone_flags(FILE *_fp, int _flags, int *_rem); bool sysdecode_linux_open_flags(FILE *_fp, int _flags, int *_rem); const char *sysdecode_linux_signal(int _sig); const char *sysdecode_linux_sigprocmask_how(int _how); #endif /* __i386__ || __amd64__ || __aarch64__ */ #endif /* !__SYSDECODE_H__ */ diff --git a/lib/libsysdecode/sysdecode_mask.3 b/lib/libsysdecode/sysdecode_mask.3 index efcab331fe29..bfe5122e0935 100644 --- a/lib/libsysdecode/sysdecode_mask.3 +++ b/lib/libsysdecode/sysdecode_mask.3 @@ -1,250 +1,252 @@ .\" .\" Copyright (c) 2016 John Baldwin .\" .\" 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. .\" .Dd February 29, 2024 .Dt sysdecode_mask 3 .Os .Sh NAME .Nm sysdecode_mask , .Nm sysdecode_accessmode , .Nm sysdecode_atflags , .Nm sysdecode_capfcntlrights , .Nm sysdecode_close_range_flags , .Nm sysdecode_fcntl_fileflags , .Nm sysdecode_fileflags , .Nm sysdecode_filemode , .Nm sysdecode_flock_operation , .Nm sysdecode_mlockall_flags , .Nm sysdecode_mmap_flags , .Nm sysdecode_mmap_prot , .Nm sysdecode_mount_flags , .Nm sysdecode_msg_flags , .Nm sysdecode_msync_flags , .Nm sysdecode_open_flags , .Nm sysdecode_pipe2_flags , .Nm sysdecode_pollfd_events , .Nm sysdecode_reboot_howto , .Nm sysdecode_rfork_flags , .Nm sysdecode_semget_flags , .Nm sysdecode_sendfile_flags , .Nm sysdecode_shmat_flags , .Nm sysdecode_sctp_nxt_flags , .Nm sysdecode_sctp_rcv_flags , .Nm sysdecode_sctp_snd_flags , .Nm sysdecode_socket_type , .Nm sysdecode_thr_create_flags , .Nm sysdecode_umtx_cvwait_flags , .Nm sysdecode_umtx_rwlock_flags , .Nm sysdecode_vmprot , .Nm sysdecode_wait4_options , .Nm sysdecode_wait6_options .Nd print name of various bitmask values .Sh LIBRARY .Lb libsysdecode .Sh SYNOPSIS .In sysdecode.h .Ft bool .Fn sysdecode_access_mode "FILE *fp" "int mode" "int *rem" .Ft bool .Fn sysdecode_atflags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_cap_fcntlrights "FILE *fp" "uint32_t rights" "uint32_t *rem" .Ft bool .Fn sysdecode_close_range_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_fcntl_fileflags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_fileflags "FILE *fp" "fflags_t flags" "fflags_t *rem" .Ft bool .Fn sysdecode_filemode "FILE *fp" "int mode" "int *rem" .Ft bool .Fn sysdecode_flock_operation "FILE *fp" "int operation" "int *rem" .Ft bool .Fn sysdecode_mlockall_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_mmap_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_mmap_prot "FILE *fp" "int prot" "int *rem" .Ft bool .Fn sysdecode_mount_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_msg_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_msync_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_open_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_pipe2_flags "FILE *fp" "int flags" "int *rem" .Ft bool +.Fn sysdecode_pledge_flags "uint64_t mask" .Fn sysdecode_pollfd_events "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_reboot_howto "FILE *fp" "int howto" "int *rem" .Ft bool .Fn sysdecode_rfork_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_sctp_nxt_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_sctp_rcv_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_sctp_snd_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_semget_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_sendfile_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_shmat_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_socket_type "FILE *fp" "int type" "int *rem" .Ft bool .Fn sysdecode_thr_create_flags "FILE *fp" "int flags" "int *rem" .Ft bool .Fn sysdecode_umtx_cvwait_flags "FILE *fp" "u_long flags" "u_long *rem" .Ft bool .Fn sysdecode_umtx_rwlock_flags "FILE *fp" "u_long flags" "u_long *rem" .Ft bool .Fn sysdecode_vmprot "FILE *fp" "int type" "int *rem" .Ft bool .Fn sysdecode_wait4_options "FILE *fp" "int options" "int *rem" .Ft bool .Fn sysdecode_wait6_options "FILE *fp" "int options" "int *rem" .Sh DESCRIPTION The .Nm functions are used to generate a text description of an integer value built from a mask of bitfields. The text description lists the C macros for field values joined by pipe .Sq | characters matching the format used in C source code. Most of the values decoded by these functions are passed as arguments to system calls, though some of these values are used internally in the kernel. .Pp Each function writes the text description to .Fa fp . The second argument should contain the integer value to be decoded. The .Fa rem argument is set to the value of any bits that were not decoded .Pq bit fields that do not have a corresponding C macro . .Fa rem may be set to .Dv NULL if the caller does not need this value. Each function returns .Dv true if any bit fields in the value were decoded and .Dv false if no bit fields were decoded. .Pp Most of these functions decode an argument passed to a system call: .Bl -column "Fn sysdecode_flock_operation" "Xr cap_fcntls_limit 2" .It Sy Function Ta Sy System Call Ta Sy Argument .It Fn sysdecode_access_mode Ta Xr access 2 Ta Fa mode .It Fn sysdecode_atflags Ta Xr chflagsat 2 , Xr fstatat 2 Ta Fa atflag , Fa flag .It Fn sysdecode_cap_fcntlrights Ta Xr cap_fcntls_limit 2 Ta Fa fcntlrights .It Fn sysdecode_fileflags Ta Xr chflags 2 Ta Fa flags .It Fn sysdecode_filemode Ta Xr chmod 2 , Xr open 2 Ta mode .It Fn sysdecode_flock_operation Ta Xr flock 2 Ta Fa operation .It Fn sysdecode_mlockall_flags Ta Xr mlockall 2 Ta Fa flags .It Fn sysdecode_mmap_flags Ta Xr mmap 2 Ta Fa flags .It Fn sysdecode_mmap_prot Ta Xr mmap 2 Ta Fa prot .It Fn sysdecode_mount_flags Ta Xr mount 2 Ta Fa flags .It Fn sysdecode_msg_flags Ta Xr recv 2 , Xr send 2 Ta Fa flags .It Fn sysdecode_msync_flags Ta Xr msync 2 Ta Fa flags .It Fn sysdecode_open_flags Ta Xr open 2 Ta Fa flags .It Fn sysdecode_pipe2_flags Ta Xr pipe2 Ta Fa flags +.It Fn sysdecode_pledge_flags Ta Xr pledge Ta Fa flags .It Fn sysdecode_reboot_howto Ta Xr reboot 2 Ta Fa howto .It Fn sysdecode_rfork_flags Ta Xr rfork 2 Ta Fa flags .It Fn sysdecode_semget_flags Ta Xr semget 2 Ta Fa flags .It Fn sysdecode_sendfile_flags Ta Xr sendfile 2 Ta Fa flags .It Fn sysdecode_shmat_flags Ta Xr shmat 2 Ta Fa flags .It Fn sysdecode_socket_type Ta Xr socket 2 Ta Fa type .It Fn sysdecode_thr_create_flags Ta Xr thr_create 2 Ta Fa flags .It Fn sysdecode_wait4_options Ta Xr wait4 2 Ta Fa options .It Fn sysdecode_wait6_options Ta Xr wait6 2 Ta Fa options .El .Pp Other functions decode the values described below: .Bl -tag -width ".Fn sysdecode_umtx_cvwait_flags" .It Fn sysdecode_fcntl_fileflags The file flags used with the .Dv F_GETFL and .Dv F_SETFL .Xr fcntl 2 commands. .It Fn sysdecode_pollfd_events The .Fa events and .Fa revents members of a .Vt struct pollfd . .It Fn sysdecode_sctp_nxt_flags The .Fa nxt_flags member of a .Vt struct sctp_nxtinfo . .It Fn sysdecode_sctp_rcv_flags The .Fa rcv_flags member of a .Vt struct sctp_rcvinfo . .It Fn sysdecode_sctp_snd_flags The .Fa snd_flags member of a .Vt struct sctp_sndinfo . .It Fn sysdecode_umtx_cvwait_flags The .Fa val argument to .Xr _umtx_op 2 for .Dv UMTX_OP_CV_WAIT operations. .It Fn sysdecode_umtx_rwlock_flags The .Fa val argument to .Xr _umtx_op 2 for .Dv UMTX_OP_RW_RDLOCK operations. .It Fn sysdecode_vmprot The memory protection flags stored in .Vt vm_prot_t variables. .El .Sh RETURN VALUES The .Nm functions return .Dv true if any bit fields in the value were decoded and .Dv false if no bit fields were decoded. .Sh SEE ALSO .Xr sysdecode 3 , .Xr sysdecode_enum 3 diff --git a/pledge-dlearn.d b/pledge-dlearn.d new file mode 100755 index 000000000000..4dd726590f13 --- /dev/null +++ b/pledge-dlearn.d @@ -0,0 +1,94 @@ +#!/usr/bin/env -S /usr/sbin/dtrace -C -s +/* + * dtrace -s ./dlearn.d -c ncal + * TODO consider -q to produce parseable output + */ + +/* we want temporal ordering of trace in order to determine + * temporal ordering of pledge flags: */ +#pragma D option temporal + +/* + +// /pid == $target || progenyof($target)/ + +// https://wiki.freebsd.org/DTrace/One-Liners +// only trace from jail: +// # pragma D option zone=dhcpd + +// dwatch -R ... // show parents of execs +// see 'pproc' in dwatch script +// basically curthread->td_proc->p_pptr + +// http://dtrace.org/blogs/dap/2013/11/20/understanding-dtrace-ustack-helpers/ + +// dwatch -j myjail .... + +// stack(stackdepth) +*/ + +BEGIN +{ + calls = 0ULL; +} + +/* + * pledge:kern:kern_pledge:masks + * pid, 0, 0, possessed, new mask + */ +pledge:kern:kern_pledge:masks +/ pid == $target || progenyof($target) / +{ + printf("%s pid:%i pos:%#lx new:%l#x", probefunc, + arg0, arg3, arg4 + ); + trace("aaa"); + ustack(50); + trace("ccc"); +} + +/* trace pledge() application */ +/****************** consider -Z to enable tracing when target is not +***** built with libpledge +pid$target::pledge_string:entry +{ + self->pledge_str = arg0; +} + +pid$target::pledge_string:return +{ + printf("pledge_string(\"%s\") == %ull;", copyinstr(self->pledge_str), arg0); + self->pledge_str = 0; + ustack(50); +} + +pid$target::pledge:entry +{ + printf("pledge(%#lx);", arg1); + ustack(50); +} +******************/ + + + +/* pledge:learning:insert:masks + * pid, fsid, inode, syscall no, possessed, violated, used + */ +pledge:learning:insert:masks +/ 1==0 && pid == $target || progenyof($target) / +{ + printf("%s pid:%i fsid:%#lx ino:%i sysno:%d cur:%#lx vio:%#lx used: %#lx progenyof:%d", probefunc, + arg0, arg1, arg2, arg3, + arg4, arg5, arg6, progenyof(pid)); + /* Userland backtrace for context: */ + ustack(50); +} + +/* +END +{ + printf("calls %ull\n", calls); +} +*/ + +/* dtrace at boot: http://dtrace.org/guide/chp-anon.html#chp-anon */ diff --git a/pledge-measure.d b/pledge-measure.d new file mode 100644 index 000000000000..a1450294a855 --- /dev/null +++ b/pledge-measure.d @@ -0,0 +1 @@ +dtrace -n 'pledge_check_bitmap:entry { self->begin=timestamp} pledge_check_bitmap:return { @mit = quantize(timestamp - self->begin); self->begin = 0}' diff --git a/pledge-parselearn.awk b/pledge-parselearn.awk new file mode 100644 index 000000000000..981bfc222330 --- /dev/null +++ b/pledge-parselearn.awk @@ -0,0 +1,85 @@ +#!/usr/bin/env -S awk -f +# ./dlearn.d -o yo.trace -c 'look azyme' +# awk -f parselearn.awk < yo.trace >dotty.dot +# dot dotty.dot -Tpng > yo.png + +BEGIN { + collapse_libc=0; +} + +/insert pid/ { + point++; + # if the process forks the layout changes, TODO + # figure out how to get dtrace to give us something + # consistent here: + if ($12 ~ /[0-9]/) { + used_mask = $12; + } else { + used_mask = $9; + } + # inherit parent's least privileges, in the end used_temporal[-1] + # should be the starting requirements for the process: + used_temporal[point] = used_mask; + funcidx[point] =0; + next +} + +/^CPU/ { next } +/YYY/ { next } +/:END/ { next } + +/`/ { + points[point, funcidx[point]] = $1; + used[$1] = or(used_mask, used[$1]); + previous_func = points[point, funcidx[point]-1] + used_trans[previous_func, $1] = or(used_mask, used_trans[previous_func, $1]) + funcidx[point]++; + next +} + // or($12, used[$1]) + +{ next } +END { + initial_learned_mask = 0; + for (p = point; p ; p--) { + min_hereafter[p] = or(min_hereafter[p+1], used_temporal[p]); + printf("# %d: ", p); print(min_hereafter[p]); + } + print "digraph G {\n"; + print "node [shape=box];" + for(p = 1; p <= point ; p++) { + initial_learned_mask = or(initial_learned_mask, used_temporal[p]); + first_in_chain = 1; + for(; funcidx[p]-- ;) { + if (collapse_libc && points[p, funcidx[p]] ~ /^libc\.so/) { + name = "libc"; + } else { + name = points[p, funcidx[p]]; + } + if (points[p,funcidx[p]+1]) { + printf " -> \"%s\"", name + last = or(used[points[p,funcidx[p]+1]], min_hereafter[p]); + this = or(used[points[p,funcidx[p]]], min_hereafter[p+1]); + if (first_in_chain && used[funcidx[p+1]] <= min_hereafter[p+1]) { + printf " [label=\"%s\\n%d/%d pledge(%d->%d)\"]", name, used_temporal[p], p, min_hereafter[p+1], min_hereafter[p]; + first_in_chain = 0; + } else { + printf " [label=\"%d//%d/%d:%d==%d,%d\"]", or(used_temporal[p], used[points[p,funcidx[p]]], min_hereafter[p]), or(used_trans[points[p,funcidx[p]-1],points[p,funcidx[p]]], min_hereafter[p], used[points[p,funcidx[p]]]), p, funcidx[p], last, this + } + } else { + printf "\"%s\"", name; + } + if ((! funcidx[p]-1) && (min_hereafter[p] < min_hereafter[p-1])) { + printf "; \"%s\"", name + printf " [fillcolor=\"yellow\",style=filled]" + } + if (name == "libc") { break; } + printf "; \"%s\"", name + } + printf ";\n" + } + print "}\n"; + printf("# initial mask needed: "); print(initial_learned_mask); +} +# sysno == 1 && used = 0 -> we're calling exit(), silly to pledge() after that. +# diff --git a/share/man/man4/pledge.4 b/share/man/man4/pledge.4 new file mode 100644 index 000000000000..6d5376ecf54c --- /dev/null +++ b/share/man/man4/pledge.4 @@ -0,0 +1,113 @@ +.\" Hello this is the documentation for the pledge mechanism. +.\" TODO turn this into a valid man page format. + +.Dd March 1, 2020 +.Dt PLEDGE 4 +.Os +.Sh NAME +.Nm pledge +.Nd TODO Process sandbox mechanism +.Sh SYNOPSIS +.\" +.Ss Sysctls +.Bd -offset indent +.Nm security.pledge.flags=\fIuint64\fR +Set (and retrieve) the permissions for the calling process +.It Nm security.pledge.enforcing=\fIbool\fR +Turn on/off the enforcing of pledge policies globally. +.It Nm security.pledge.violations=\fIuint64\fR +.It Nm security.pledge.kills=\fIuint64\fR +.It Nm security.pledge.softfails=\fIuint64\fR +.It Nm security.pledge.learning=\fIbool\fR +.It Nm security.pledge.learning_count=\fIuint64l\fR +yooo +.Ei +.Ed +.Ss Permissions +.\" +See +.Cm pledgectl -v +for the set of flags supported by your copy of +.Nm "libpledge". +.\" +Here we should list each PLEDGE_ flag, and its consequences. +.\" +PLEDGE_ID Change user id, group id, effective etc. +PLEDGE_SOFTFAIL TODO +PLEDGE_NOLEARN Do not record the mask in "used" if no violation occurred. +.\" +.Sh DESCRIPTION +Note: To avoid synchronization overhead, the uint64 counters +(violations, kills, softfails, learning) are kept per-CPU, and +only eventually convergent, so the retrieved values are conservative estimates +rather than exact values. When requesting data for security.pledge.learning you +should ask for more than security.pledge.learning_count entries +TODO . + +The security mechanism is implemented by starting +.Fn +init(1) +with a pledge mask of +PLEDGE_WILDCARD +, and allowing threads to remove flags by calling +.Fn +pledge(3) +with the complete set of desired of flags. +.\" +.\" +To enable enforcing of the pledge mechanism, this sysctl must be set to one: +.\" +.Cd security.pledge.enforcing = 1 +.\" +.\" +To avoid clashing with syscalls, the kernel interface for +.Fn +pledge(3) +is currently implemented as a sysctl node, +.Fn +security.pledge.flags +.\" +.\" +A "learning mode" is available, but disabled by default due to +the performance overhead it might incur on the system. +It can be enabled with the command: +.Cm sysctl security.pledge.learning=1 +.\" +.\" +The learning mode will keep track of which executables trigger violations of +their respective pledge masks, and keep track of the flags actively utilized by +the executables, enabling the system administrator to identify executables +that are equipped with excessively permissive flags, or to identify the set +flags that programs require. +Learning mode works independently of +.Fn +security.pledge.enforcing +and thus can be used to create a baseline for normal operation of a system while +enforcement is turned off. +.\" +Regardless of the configuration of +.Fn +security.pledge.learning +and +.Fn +security.pledge.enforcing +a counter of all encountered policy violations since boot is maintained +under sysctl node +.Nm "security.pledge.violations". +The system administrator can overwrite this when necessary, for instance +after making policy changes. +.\" +The +.Xr pledgectl 1 +utility can be used to extract the data gathered by the learning mode and +display it to the system administrator. +.Sh BUGS +.Li +The learning mode currently records 'possessed' only when a process ends up +requiring privileges, so if it starts with PLEDGE_WILDCARD and proceeds to drop +privileges before any system call, this is not reflected anywhere. Maybe that's +sensible, but it is probably not good for e.g. suid binaries that could have +flaws in the argument/environment variable parsing. The way to prevent such +stuff would be to have either extattr or the ELF loader apply flags before +execution starts, and record the initial set of flags after that process +has taken place. diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk index bf6564afee38..f4f1efecb21d 100644 --- a/share/mk/bsd.libnames.mk +++ b/share/mk/bsd.libnames.mk @@ -40,200 +40,201 @@ LIBCAM?= ${LIBDESTDIR}${LIBDIR_BASE}/libcam.a LIBCOMPAT?= ${LIBDESTDIR}${LIBDIR_BASE}/libcompat.a LIBCOMPILER_RT?=${LIBDESTDIR}${LIBDIR_BASE}/libcompiler_rt.a LIBCOM_ERR?= ${LIBDESTDIR}${LIBDIR_BASE}/libcom_err.a LIBCPLUSPLUS?= ${LIBDESTDIR}${LIBDIR_BASE}/libc++.a LIBCRYPT?= ${LIBDESTDIR}${LIBDIR_BASE}/libcrypt.a LIBCRYPTO?= ${LIBDESTDIR}${LIBDIR_BASE}/libcrypto.a LIBCTF?= ${LIBDESTDIR}${LIBDIR_BASE}/libctf.a LIBCURSES?= ${LIBDESTDIR}${LIBDIR_BASE}/libcurses.a LIBCUSE?= ${LIBDESTDIR}${LIBDIR_BASE}/libcuse.a LIBCXGB4?= ${LIBDESTDIR}${LIBDIR_BASE}/libcxgb4.a LIBCXXRT?= ${LIBDESTDIR}${LIBDIR_BASE}/libcxxrt.a LIBC_PIC?= ${LIBDESTDIR}${LIBDIR_BASE}/libc_pic.a LIBDEVCTL?= ${LIBDESTDIR}${LIBDIR_BASE}/libdevctl.a LIBDEVDCTL?= ${LIBDESTDIR}${LIBDIR_BASE}/libdevdctl.a LIBDEVINFO?= ${LIBDESTDIR}${LIBDIR_BASE}/libdevinfo.a LIBDEVSTAT?= ${LIBDESTDIR}${LIBDIR_BASE}/libdevstat.a LIBDIALOG?= ${LIBDESTDIR}${LIBDIR_BASE}/libdialog.a LIBDL?= ${LIBDESTDIR}${LIBDIR_BASE}/libdl.a LIBDNS?= ${LIBDESTDIR}${LIBDIR_BASE}/libdns.a LIBDPV?= ${LIBDESTDIR}${LIBDIR_BASE}/libdpv.a LIBDTRACE?= ${LIBDESTDIR}${LIBDIR_BASE}/libdtrace.a LIBDWARF?= ${LIBDESTDIR}${LIBDIR_BASE}/libdwarf.a LIBEDIT?= ${LIBDESTDIR}${LIBDIR_BASE}/libedit.a LIBEFIVAR?= ${LIBDESTDIR}${LIBDIR_BASE}/libefivar.a LIBELF?= ${LIBDESTDIR}${LIBDIR_BASE}/libelf.a LIBEXECINFO?= ${LIBDESTDIR}${LIBDIR_BASE}/libexecinfo.a LIBFETCH?= ${LIBDESTDIR}${LIBDIR_BASE}/libfetch.a LIBFIGPAR?= ${LIBDESTDIR}${LIBDIR_BASE}/libfigpar.a LIBFL?= "don't use LIBFL, use LIBL" LIBFORMW?= ${LIBDESTDIR}${LIBDIR_BASE}/libformw.a LIBG2C?= ${LIBDESTDIR}${LIBDIR_BASE}/libg2c.a LIBGEOM?= ${LIBDESTDIR}${LIBDIR_BASE}/libgeom.a LIBGPIO?= ${LIBDESTDIR}${LIBDIR_BASE}/libgpio.a LIBGSSAPI?= ${LIBDESTDIR}${LIBDIR_BASE}/libgssapi.a LIBGSSAPI_KRB5?= ${LIBDESTDIR}${LIBDIR_BASE}/libgssapi_krb5.a LIBGSSRPC?= ${LIBDESTDIR}${LIBDIR_BASE}/libgssrpc.a LIBHDB?= ${LIBDESTDIR}${LIBDIR_BASE}/libhdb.a LIBHEIMBASE?= ${LIBDESTDIR}${LIBDIR_BASE}/libheimbase.a LIBHEIMNTLM?= ${LIBDESTDIR}${LIBDIR_BASE}/libheimntlm.a LIBHEIMSQLITE?= ${LIBDESTDIR}${LIBDIR_BASE}/libheimsqlite.a LIBHX509?= ${LIBDESTDIR}${LIBDIR_BASE}/libhx509.a LIBIBCM?= ${LIBDESTDIR}${LIBDIR_BASE}/libibcm.a LIBIBMAD?= ${LIBDESTDIR}${LIBDIR_BASE}/libibmad.a LIBIBNETDISC?= ${LIBDESTDIR}${LIBDIR_BASE}/libibnetdisc.a LIBIBUMAD?= ${LIBDESTDIR}${LIBDIR_BASE}/libibumad.a LIBIBVERBS?= ${LIBDESTDIR}${LIBDIR_BASE}/libibverbs.a LIBICP?= ${LIBDESTDIR}${LIBDIR_BASE}/libicp.a LIBIPSEC?= ${LIBDESTDIR}${LIBDIR_BASE}/libipsec.a LIBIPT?= ${LIBDESTDIR}${LIBDIR_BASE}/libipt.a LIBIRDMA?= ${LIBDESTDIR}${LIBDIR_BASE}/libirdma.a LIBISCSIUTIL?= ${LIBDESTDIR}${LIBDIR_BASE}/libiscsiutil.a LIBJAIL?= ${LIBDESTDIR}${LIBDIR_BASE}/libjail.a LIBKADM5CLNT?= ${LIBDESTDIR}${LIBDIR_BASE}/libkadm5clnt.a LIBKADM5SRV?= ${LIBDESTDIR}${LIBDIR_BASE}/libkadm5srv.a LIBK5CRYPTO?= ${LIBDESTDIR}${LIBDIR_BASE}/libk5crypto.a LIBKADMIN_COMMON?= ${LIBDESTDIR}${LIBDIR_BASE}/libkadmin_common.a LIBKADM5CLNT_MIT?= ${LIBDESTDIR}${LIBDIR_BASE}/libkadm5clnt_mit.a LIBKADM5SRV_MIT?= ${LIBDESTDIR}${LIBDIR_BASE}/libkadm5srv_mit.a LIBKAFS5?= ${LIBDESTDIR}${LIBDIR_BASE}/libkafs5.a LIBKDB5?= ${LIBDESTDIR}${LIBDIR_BASE}/libkdb5.a LIBKDC?= ${LIBDESTDIR}${LIBDIR_BASE}/libkdc.a LIBKEYCAP?= ${LIBDESTDIR}${LIBDIR_BASE}/libkeycap.a LIBKICONV?= ${LIBDESTDIR}${LIBDIR_BASE}/libkiconv.a LIBKPROP_UTIL?= ${LIBDESTDIR}${LIBDIR_BASE}/libkprop_util.a LIBKRAD?= ${LIBDESTDIR}${LIBDIR_BASE}/libkrad.a LIBKRB5?= ${LIBDESTDIR}${LIBDIR_BASE}/libkrb5.a LIBKRB5PROFILE?= ${LIBDESTDIR}${LIBDIR_BASE}/libkrb5profile.a LIBKRB5SS?= ${LIBDESTDIR}${LIBDIR_BASE}/libkrb5ss.a LIBKRB5SUPPORT?= ${LIBDESTDIR}${LIBDIR_BASE}/libkrb5support.a LIBKVM?= ${LIBDESTDIR}${LIBDIR_BASE}/libkvm.a LIBL?= ${LIBDESTDIR}${LIBDIR_BASE}/libl.a LIBLN?= "don't use LIBLN, use LIBL" LIBLZMA?= ${LIBDESTDIR}${LIBDIR_BASE}/liblzma.a LIBM?= ${LIBDESTDIR}${LIBDIR_BASE}/libm.a LIBMAGIC?= ${LIBDESTDIR}${LIBDIR_BASE}/libmagic.a LIBMD?= ${LIBDESTDIR}${LIBDIR_BASE}/libmd.a LIBMEMSTAT?= ${LIBDESTDIR}${LIBDIR_BASE}/libmemstat.a LIBMENU?= ${LIBDESTDIR}${LIBDIR_BASE}/libmenu.a LIBMILTER?= ${LIBDESTDIR}${LIBDIR_BASE}/libmilter.a LIBMLX4?= ${LIBDESTDIR}${LIBDIR_BASE}/libmlx4.a LIBMLX5?= ${LIBDESTDIR}${LIBDIR_BASE}/libmlx5.a LIBBNXTRE?= ${LIBDESTDIR}${LIBDIR_BASE}/libbnxtre.a LIBMP?= ${LIBDESTDIR}${LIBDIR_BASE}/libmp.a LIBMT?= ${LIBDESTDIR}${LIBDIR_BASE}/libmt.a LIBNCURSES?= ${LIBDESTDIR}${LIBDIR_BASE}/libncurses.a LIBNCURSESW?= ${LIBDESTDIR}${LIBDIR_BASE}/libncursesw.a LIBNETGRAPH?= ${LIBDESTDIR}${LIBDIR_BASE}/libnetgraph.a LIBNETMAP?= ${LIBDESTDIR}${LIBDIR_BASE}/libnetmap.a LIBNGATM?= ${LIBDESTDIR}${LIBDIR_BASE}/libngatm.a LIBNV?= ${LIBDESTDIR}${LIBDIR_BASE}/libnv.a LIBNVPAIR?= ${LIBDESTDIR}${LIBDIR_BASE}/libnvpair.a LIBOPENCSD?= ${LIBDESTDIR}${LIBDIR_BASE}/libopencsd.a LIBOPENSM?= ${LIBDESTDIR}${LIBDIR_BASE}/libopensm.a LIBOSMCOMP?= ${LIBDESTDIR}${LIBDIR_BASE}/libosmcomp.a LIBOSMVENDOR?= ${LIBDESTDIR}${LIBDIR_BASE}/libosmvendor.a LIBPAM?= ${LIBDESTDIR}${LIBDIR_BASE}/libpam.a LIBPANEL?= ${LIBDESTDIR}${LIBDIR_BASE}/libpanel.a LIBPANELW?= ${LIBDESTDIR}${LIBDIR_BASE}/libpanelw.a LIBPCAP?= ${LIBDESTDIR}${LIBDIR_BASE}/libpcap.a LIBPJDLOG?= ${LIBDESTDIR}${LIBDIR_BASE}/libpjdlog.a +LIBPLEDGE?= ${LIBDESTDIR}${LIBDIR_BASE}/libpledge.a LIBPKGCONF?= ${LIBDESTDIR}${LIBDIR_BASE}/libpkgconf.a LIBPMC?= ${LIBDESTDIR}${LIBDIR_BASE}/libpmc.a LIBPROC?= ${LIBDESTDIR}${LIBDIR_BASE}/libproc.a LIBPROCSTAT?= ${LIBDESTDIR}${LIBDIR_BASE}/libprocstat.a LIBPTHREAD?= ${LIBDESTDIR}${LIBDIR_BASE}/libpthread.a LIBRADIUS?= ${LIBDESTDIR}${LIBDIR_BASE}/libradius.a LIBRDMACM?= ${LIBDESTDIR}${LIBDIR_BASE}/librdmacm.a LIBREGEX?= ${LIBDESTDIR}${LIBDIR_BASE}/libregex.a LIBROKEN?= ${LIBDESTDIR}${LIBDIR_BASE}/libroken.a LIBRPCSEC_GSS?= ${LIBDESTDIR}${LIBDIR_BASE}/librpcsec_gss.a LIBRPCSVC?= ${LIBDESTDIR}${LIBDIR_BASE}/librpcsvc.a LIBRT?= ${LIBDESTDIR}${LIBDIR_BASE}/librt.a LIBRTLD_DB?= ${LIBDESTDIR}${LIBDIR_BASE}/librtld_db.a LIBSBUF?= ${LIBDESTDIR}${LIBDIR_BASE}/libsbuf.a LIBSDP?= ${LIBDESTDIR}${LIBDIR_BASE}/libsdp.a LIBSMB?= ${LIBDESTDIR}${LIBDIR_BASE}/libsmb.a LIBSPL?= ${LIBDESTDIR}${LIBDIR_BASE}/libspl.a LIBSSL?= ${LIBDESTDIR}${LIBDIR_BASE}/libssl.a LIBSSP_NONSHARED?= ${LIBDESTDIR}${LIBDIR_BASE}/libssp_nonshared.a LIBSTATS?= ${LIBDESTDIR}${LIBDIR_BASE}/libstats.a LIBSTDTHREADS?= ${LIBDESTDIR}${LIBDIR_BASE}/libstdthreads.a LIBSYSDECODE?= ${LIBDESTDIR}${LIBDIR_BASE}/libsysdecode.a LIBTACPLUS?= ${LIBDESTDIR}${LIBDIR_BASE}/libtacplus.a LIBTERMCAP?= ${LIBDESTDIR}${LIBDIR_BASE}/libtermcap.a LIBTERMCAPW?= ${LIBDESTDIR}${LIBDIR_BASE}/libtermcapw.a LIBTERMLIB?= "don't use LIBTERMLIB, use LIBTERMCAP" LIBTINFOW= ${LIBDESTDIR}${LIBDIR_BASE}/libtinfow.a LIBUFS?= ${LIBDESTDIR}${LIBDIR_BASE}/libufs.a LIBUGIDFW?= ${LIBDESTDIR}${LIBDIR_BASE}/libugidfw.a LIBULOG?= ${LIBDESTDIR}${LIBDIR_BASE}/libulog.a LIBUMEM?= ${LIBDESTDIR}${LIBDIR_BASE}/libumem.a LIBUSB?= ${LIBDESTDIR}${LIBDIR_BASE}/libusb.a LIBUSBHID?= ${LIBDESTDIR}${LIBDIR_BASE}/libusbhid.a LIBUTIL?= ${LIBDESTDIR}${LIBDIR_BASE}/libutil.a LIBUVMEM?= ${LIBDESTDIR}${LIBDIR_BASE}/libuvmem.a LIBVERTO?= ${LIBDESTDIR}${LIBDIR_BASE}/libverto.a LIBVGL?= ${LIBDESTDIR}${LIBDIR_BASE}/libvgl.a LIBVMMAPI?= ${LIBDESTDIR}${LIBDIR_BASE}/libvmmapi.a LIBWIND?= ${LIBDESTDIR}${LIBDIR_BASE}/libwind.a LIBWRAP?= ${LIBDESTDIR}${LIBDIR_BASE}/libwrap.a LIBXO?= ${LIBDESTDIR}${LIBDIR_BASE}/libxo.a LIBXPG4?= ${LIBDESTDIR}${LIBDIR_BASE}/libxpg4.a LIBY?= ${LIBDESTDIR}${LIBDIR_BASE}/liby.a LIBYPCLNT?= ${LIBDESTDIR}${LIBDIR_BASE}/libypclnt.a LIBZ?= ${LIBDESTDIR}${LIBDIR_BASE}/libz.a LIBZDB?= ${LIBDESTDIR}${LIBDIR_BASE}/libzdb.a LIBZFS?= ${LIBDESTDIR}${LIBDIR_BASE}/libzfs.a LIBZFS_CORE?= ${LIBDESTDIR}${LIBDIR_BASE}/libzfs_core.a LIBZFSBOOTENV?= ${LIBDESTDIR}${LIBDIR_BASE}/libzfsbootenv.a LIBZPOOL?= ${LIBDESTDIR}${LIBDIR_BASE}/libzpool.a LIBZUTIL?= ${LIBDESTDIR}${LIBDIR_BASE}/libzutil.a # enforce -lpthread, -lc, and -lsys to always be the last in that exact order .if defined(LDADD) .if ${LDADD:M-lpthread} LDADD:= ${LDADD:N-lpthread} -lpthread .endif .if ${LDADD:M-lc} LDADD:= ${LDADD:N-lc} -lc .endif .if ${LDADD:M-lsys} LDADD:= ${LDADD:N-lsys} -lsys .endif .endif # Only do this for src builds. .if defined(SRCTOP) .if defined(_LIBRARIES) && defined(LIB) && \ ${_LIBRARIES:M${LIB}} != "" .if !defined(LIB${LIB:tu}) .error ${.CURDIR}: Missing value for LIB${LIB:tu} in ${_this:T}. Likely should be: LIB${LIB:tu}?= $${LIBDESTDIR}$${LIBDIR_BASE}/lib${LIB}.a .endif .endif # Derive LIB*SRCDIR from LIB*DIR .for lib in ${_LIBRARIES} LIB${lib:tu}SRCDIR?= ${SRCTOP}/${LIB${lib:tu}DIR:S,^${OBJTOP}/,,} .endfor .else # Out of tree builds # There are LIBADD defined in an out-of-tree build. Are they *all* # in-tree libraries? If so convert them to LDADD to support # partial checkouts. .if !empty(LIBADD) _convert_libadd= 1 .for l in ${LIBADD} .if empty(LIB${l:tu}) _convert_libadd= 0 .endif .endfor .if ${_convert_libadd} == 1 .warning Converting out-of-tree build LIBADDs into LDADD. This is not fully supported. .for l in ${LIBADD} LDADD+= -l${l} .endfor .endif .endif diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk index 5361c771fc5a..25bd18d5195a 100644 --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -109,200 +109,201 @@ _LIBRARIES= \ ${_INTERNALLIBS} \ ${LOCAL_LIBRARIES} \ 80211 \ 9p \ alias \ archive \ asn1 \ avl \ BlocksRuntime \ be \ begemot \ bluetooth \ bsdxml \ bsm \ bsnmp \ bz2 \ c \ c_pic \ calendar \ cam \ casper \ cap_dns \ cap_fileargs \ cap_grp \ cap_net \ cap_netdb \ cap_pwd \ cap_sysctl \ cap_syslog \ com_err \ compiler_rt \ crypt \ crypto \ ctf \ cuse \ cxxrt \ devctl \ devdctl \ devinfo \ devstat \ dialog \ dl \ dpv \ dtrace \ dwarf \ edit \ efivar \ elf \ execinfo \ fetch \ figpar \ formw \ geom \ gpio \ gssapi \ gssapi_krb5 \ gssrpc \ hdb \ heimbase \ heimntlm \ heimsqlite \ hx509 \ icp \ ipsec \ ipt \ jail \ k5crypto \ kadm5 \ kadmin_common \ kafs5 \ kdb5 \ kdc \ kiconv \ krad \ krb5 \ krb5profile \ krb5support \ kvm \ l \ lattzfs \ lzma \ m \ magic \ md \ memstat \ mp \ mt \ ncursesw \ netgraph \ netmap \ ngatm \ nv \ nvpair \ opencsd \ pam \ panel \ panelw \ pcap \ pcsclite \ pjdlog \ + pledge \ pmc \ proc \ procstat \ pthread \ radius \ regex \ roken \ rpcsec_gss \ rpcsvc \ rt \ rtld_db \ sbuf \ sdp \ sm \ smb \ spl \ ssl \ ssp_nonshared \ stats \ stdthreads \ supcplusplus \ sys \ sysdecode \ tacplus \ termcapw \ tinfow \ ufs \ ugidfw \ ulog \ umem \ usb \ usbhid \ util \ uvmem \ verto \ vmmapi \ wind \ wrap \ xo \ y \ ypclnt \ z \ zdb \ zfs_core \ zfs \ zfsbootenv \ zpool \ zutil .if ${MK_KERBEROS} != "no" && ${MK_MITKRB5} != "no" _LIBRARIES+= \ kadm5clnt_mit \ kadm5srv_mit .else _LIBRARIES+= \ kadm5clnt \ kadm5srv .endif .if ${MK_BLACKLIST} != "no" _LIBRARIES+= \ blacklist .endif .if ${MK_BLOCKLIST} != "no" _LIBRARIES+= \ blocklist .endif .if ${MK_HBSDCONTROL} != "no" _LIBRARIES+= hbsdcontrol _DP_hbsdcontrol+= pthread _DP_hbsdcontrol+= util .endif .if ${MK_OFED} != "no" _LIBRARIES+= \ cxgb4 \ ibcm \ ibmad \ ibnetdisc \ ibumad \ ibverbs \ irdma \ mlx4 \ mlx5 \ bnxtre \ rdmacm \ osmcomp \ opensm \ osmvendor .endif .if ${MK_BEARSSL} == "yes" _LIBRARIES+= \ bearssl \ secureboot \ LIBBEARSSL?= ${LIBBEARSSLDIR}/libbearssl.a LIBSECUREBOOT?= ${LIBSECUREBOOTDIR}/libsecureboot.a diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 2fc7ddf9e3fd..dd84ee8e4671 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2747,135 +2747,137 @@ options DEBUG # Kernel filelock debugging. options LOCKF_DEBUG # System V compatible message queues # Please note that the values provided here are used to test kernel # building. The defaults in the sources provide almost the same numbers. # MSGSSZ must be a power of 2 between 8 and 1024. options MSGMNB=2049 # Max number of chars in queue options MSGMNI=41 # Max number of message queue identifiers options MSGSEG=2049 # Max number of message segments options MSGSSZ=16 # Size of a message segment options MSGTQL=41 # Max number of messages in system options NBUF=512 # Number of buffer headers options SC_DEBUG_LEVEL=5 # Syscons debug level options SC_RENDER_DEBUG # syscons rendering debugging options VFS_BIO_DEBUG # VFS buffer I/O debugging options KSTACK_MAX_PAGES=32 # Maximum pages to give the kernel stack options KSTACK_USAGE_PROF # Adaptec Array Controller driver options options AAC_DEBUG # Debugging levels: # 0 - quiet, only emit warnings # 1 - noisy, emit major function # points and things done # 2 - extremely noisy, emit trace # items in loops, etc. # Resource Accounting options RACCT # Resource Limits options RCTL # Yet more undocumented options for linting. options MAXFILES=999 # Random number generator # Alternative algorithm. options RANDOM_FENESTRASX # Allow the CSPRNG algorithm to be loaded as a module. #options RANDOM_LOADABLE # Select this to allow high-rate but potentially expensive # harvesting of Slab-Allocator entropy. In very high-rate # situations the value of doing this is dubious at best. options RANDOM_ENABLE_UMA # slab allocator # Select this to allow high-rate but potentially expensive # harvesting of the m_next pointer in the mbuf. Note that # the m_next pointer is NULL except when receiving > 4K # jumbo frames or sustained bursts by way of LRO. Thus in # the common case it is stirring zero in to the entropy # pool. In cases where it is not NULL it is pointing to one # of a small (in the thousands to 10s of thousands) number # of 256 byte aligned mbufs. Hence it is, even in the best # case, a poor source of entropy. And in the absence of actual # runtime analysis of entropy collection may mislead the user in # to believe that substantially more entropy is being collected # than in fact is - leading to a different class of security # risk. In high packet rate situations ethernet entropy # collection is also very expensive, possibly leading to as # much as a 50% drop in packets received. # This option is present to maintain backwards compatibility # if desired, however it cannot be recommended for use in any # environment. options RANDOM_ENABLE_ETHER # ether_input options RANDOM_ENABLE_KBD options RANDOM_ENABLE_MOUSE options RANDOM_ENABLE_TPM # implies TPM_HARVEST # Module to enable execution of application via emulators like QEMU options IMGACT_BINMISC # zlib I/O stream support # This enables support for compressed core dumps. options GZIO # PAX and HardenedBSD related knobs options PAX # Enable the PAX framework options PAX_CONTROL_ACL # PaX MAC framework, required for secadm options PAX_CONTROL_ACL_OVERRIDE_SUPPORT # Allow to override hbsdcontrol settings with ACLs options PAX_CONTROL_EXTATTR # extattr based control framework for hbsdcontrol options PAX_ASLR # Address Space Layout Randomization options PAX_HARDENING # Other hardening features options PAX_NOEXEC # Remove WX pages from user-space and enforce W^X options PAX_SEGVGUARD # Track and ban failing process options PAX_SYSCTLS # Run-time settings for PAX and Hardening options PAX_JAIL_SUPPORT # Allow to override PAX settings per jail options PAX_INSECURE_MODE # Allow to override INVARIANTS enforcements options HBSD_DEBUG # zstd support # This enables support for Zstandard compression for core dumps, # kernel dumps, GEOM_UZIP images, and tarfs, and is required by zfs. options ZSTDIO +options HBSD_PLEDGE # Enable pledge(2) syscall whitelisting mechanism + # BHND(4) drivers options BHND_LOGLEVEL # Logging threshold level # evdev interface device evdev # input event device support options EVDEV_SUPPORT # evdev support in legacy drivers options EVDEV_DEBUG # enable event debug msgs device uinput # install /dev/uinput cdev options UINPUT_DEBUG # enable uinput debug msgs # Encrypted kernel crash dumps. options EKCD # Serial Peripheral Interface (SPI) support. device spibus # Bus support. device at45d # DataFlash driver device cqspi # device mx25l # SPIFlash driver device n25q # device spigen # Generic access to SPI devices from userland. # Enable legacy /dev/spigenN name aliases for /dev/spigenX.Y devices. options SPIGEN_LEGACY_CDEVNAME # legacy device names for spigen # Compression supports. device zlib # gzip/zlib compression/decompression library device xz # xz_embedded LZMA de-compression library # Kernel support for stats(3). options STATS # File system monitoring device filemon # file monitoring for make(1) meta-mode # Options for the Intel QuickAssist (QAT) driver. options QAT_DISABLE_SAFE_DC_MODE # Disable QAT safe data compression mode (only for 4940 devices). diff --git a/sys/conf/files b/sys/conf/files index e57037d28518..3b9753083f41 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3731,200 +3731,202 @@ geom/eli/g_eli_integrity.c optional geom_eli geom/eli/g_eli_key.c optional geom_eli geom/eli/g_eli_key_cache.c optional geom_eli geom/eli/g_eli_privacy.c optional geom_eli geom/eli/pkcs5v2.c optional geom_eli geom/gate/g_gate.c optional geom_gate geom/geom_bsd_enc.c optional geom_part_bsd geom/geom_ccd.c optional ccd | geom_ccd geom/geom_ctl.c standard geom/geom_dev.c standard geom/geom_disk.c standard geom/geom_dump.c standard geom/geom_event.c standard geom/geom_flashmap.c optional fdt cfi | fdt mx25l | mmcsd | fdt n25q | fdt at45d geom/geom_io.c standard geom/geom_kern.c standard geom/geom_slice.c standard geom/geom_subr.c standard geom/geom_vfs.c standard geom/journal/g_journal.c optional geom_journal geom/journal/g_journal_ufs.c optional geom_journal geom/label/g_label.c optional geom_label | geom_label_gpt geom/label/g_label_ext2fs.c optional geom_label geom/label/g_label_flashmap.c optional geom_label geom/label/g_label_iso9660.c optional geom_label geom/label/g_label_msdosfs.c optional geom_label geom/label/g_label_ntfs.c optional geom_label geom/label/g_label_ufs.c optional geom_label geom/label/g_label_gpt.c optional geom_label | geom_label_gpt geom/label/g_label_disk_ident.c optional geom_label geom/label/g_label_swaplinux.c optional geom_label geom/linux_lvm/g_linux_lvm.c optional geom_linux_lvm geom/mirror/g_mirror.c optional geom_mirror geom/mirror/g_mirror_ctl.c optional geom_mirror geom/mountver/g_mountver.c optional geom_mountver geom/multipath/g_multipath.c optional geom_multipath geom/nop/g_nop.c optional geom_nop geom/part/g_part.c standard geom/part/g_part_if.m standard geom/part/g_part_apm.c optional geom_part_apm geom/part/g_part_bsd.c optional geom_part_bsd geom/part/g_part_bsd64.c optional geom_part_bsd64 geom/part/g_part_ebr.c optional geom_part_ebr geom/part/g_part_gpt.c optional geom_part_gpt geom/part/g_part_ldm.c optional geom_part_ldm geom/part/g_part_mbr.c optional geom_part_mbr geom/raid/g_raid.c optional geom_raid geom/raid/g_raid_ctl.c optional geom_raid geom/raid/g_raid_md_if.m optional geom_raid geom/raid/g_raid_tr_if.m optional geom_raid geom/raid/md_ddf.c optional geom_raid geom/raid/md_intel.c optional geom_raid geom/raid/md_jmicron.c optional geom_raid geom/raid/md_nvidia.c optional geom_raid geom/raid/md_promise.c optional geom_raid geom/raid/md_sii.c optional geom_raid geom/raid/tr_concat.c optional geom_raid geom/raid/tr_raid0.c optional geom_raid geom/raid/tr_raid1.c optional geom_raid geom/raid/tr_raid1e.c optional geom_raid geom/raid/tr_raid5.c optional geom_raid geom/raid3/g_raid3.c optional geom_raid3 geom/raid3/g_raid3_ctl.c optional geom_raid3 geom/shsec/g_shsec.c optional geom_shsec geom/stripe/g_stripe.c optional geom_stripe geom/union/g_union.c optional geom_union geom/uzip/g_uzip.c optional geom_uzip geom/uzip/g_uzip_lzma.c optional geom_uzip geom/uzip/g_uzip_wrkthr.c optional geom_uzip geom/uzip/g_uzip_zlib.c optional geom_uzip geom/uzip/g_uzip_zstd.c optional geom_uzip zstdio \ compile-with "${NORMAL_C} -I$S/contrib/zstd/lib/freebsd" geom/virstor/binstream.c optional geom_virstor geom/virstor/g_virstor.c optional geom_virstor geom/virstor/g_virstor_md.c optional geom_virstor geom/zero/g_zero.c optional geom_zero fs/ext2fs/ext2_acl.c optional ext2fs fs/ext2fs/ext2_alloc.c optional ext2fs fs/ext2fs/ext2_balloc.c optional ext2fs fs/ext2fs/ext2_bmap.c optional ext2fs fs/ext2fs/ext2_csum.c optional ext2fs fs/ext2fs/ext2_extattr.c optional ext2fs fs/ext2fs/ext2_extents.c optional ext2fs fs/ext2fs/ext2_inode.c optional ext2fs fs/ext2fs/ext2_inode_cnv.c optional ext2fs fs/ext2fs/ext2_hash.c optional ext2fs fs/ext2fs/ext2_htree.c optional ext2fs fs/ext2fs/ext2_lookup.c optional ext2fs fs/ext2fs/ext2_subr.c optional ext2fs fs/ext2fs/ext2_vfsops.c optional ext2fs fs/ext2fs/ext2_vnops.c optional ext2fs # hardenedbsd/hbsd_grsec_tpe.c optional pax pax_hardening hardenedbsd/hbsd_pax_common.c optional pax hardenedbsd/hbsd_pax_log.c optional pax hardenedbsd/hbsd_pax_aslr.c optional pax pax_aslr hardenedbsd/hbsd_pax_hardening.c optional pax pax_hardening hardenedbsd/hbsd_pax_noexec.c optional pax pax_noexec hardenedbsd/hbsd_pax_segvguard.c optional pax pax_segvguard hardenedbsd/hbsd_control_acl.c optional pax pax_control_acl hardenedbsd/hbsd_control_extattr.c optional pax pax_control_extattr +hardenedbsd/hbsd_pledge.c standard +# TODO make hbsd_pledge.c inclusion optional? # isa/isa_if.m standard isa/isa_common.c optional isa isa/isahint.c optional isa isa/pnp.c optional isa isapnp isa/pnpparse.c optional isa isapnp fs/cd9660/cd9660_bmap.c optional cd9660 fs/cd9660/cd9660_lookup.c optional cd9660 fs/cd9660/cd9660_node.c optional cd9660 fs/cd9660/cd9660_rrip.c optional cd9660 fs/cd9660/cd9660_util.c optional cd9660 fs/cd9660/cd9660_vfsops.c optional cd9660 fs/cd9660/cd9660_vnops.c optional cd9660 fs/cd9660/cd9660_iconv.c optional cd9660_iconv gnu/gcov/gcc_4_7.c optional gcov \ warning "kernel contains GPL licensed gcov support" gnu/gcov/gcov_fs.c optional gcov lindebugfs \ compile-with "${LINUXKPI_C}" gnu/gcov/gcov_subr.c optional gcov kern/bus_if.m standard kern/clock_if.m standard kern/coredump_vnode.c standard kern/cpufreq_if.m standard kern/device_if.m standard kern/imgact_binmisc.c optional imgact_binmisc kern/imgact_elf.c standard kern/imgact_elf32.c optional compat_freebsd32 kern/imgact_shell.c standard kern/init_main.c standard kern/init_sysent.c standard kern/ksched.c optional _kposix_priority_scheduling kern/kern_acct.c standard kern/kern_alq.c optional alq kern/kern_boottrace.c standard kern/kern_clock.c standard kern/kern_clocksource.c standard kern/kern_condvar.c standard kern/kern_conf.c standard kern/kern_cons.c standard kern/kern_cpu.c standard kern/kern_cpuset.c standard kern/kern_context.c standard kern/kern_descrip.c standard kern/kern_devctl.c standard kern/kern_dtrace.c optional kdtrace_hooks kern/kern_dump.c standard kern/kern_environment.c standard kern/kern_et.c standard kern/kern_event.c standard kern/kern_exec.c standard kern/kern_exit.c standard kern/kern_fail.c standard kern/kern_ffclock.c standard kern/kern_fork.c standard kern/kern_hhook.c standard kern/kern_idle.c standard kern/kern_intr.c standard kern/kern_jail.c standard kern/kern_jaildesc.c standard kern/kern_jailmeta.c standard kern/kern_kcov.c optional kcov \ compile-with "${NOSAN_C} ${MSAN_CFLAGS}" kern/kern_kexec.c standard kern/kern_khelp.c standard kern/kern_kthread.c standard kern/kern_ktr.c optional ktr kern/kern_ktrace.c standard kern/kern_linker.c standard kern/kern_lock.c standard kern/kern_lockf.c standard kern/kern_lockstat.c optional kdtrace_hooks kern/kern_loginclass.c standard kern/kern_malloc.c standard kern/kern_mbuf.c standard kern/kern_membarrier.c standard kern/kern_mib.c standard kern/kern_module.c standard kern/kern_mtxpool.c standard kern/kern_mutex.c standard kern/kern_ntptime.c standard kern/kern_osd.c standard kern/kern_physio.c standard kern/kern_pmc.c standard kern/kern_poll.c optional device_polling kern/kern_priv.c standard kern/kern_proc.c standard kern/kern_procctl.c standard kern/kern_prot.c standard kern/kern_racct.c optional racct kern/kern_rangelock.c standard kern/kern_rctl.c standard kern/kern_resource.c standard kern/kern_rmlock.c standard kern/kern_rwlock.c standard kern/kern_sdt.c optional kdtrace_hooks kern/kern_sema.c standard kern/kern_sendfile.c standard kern/kern_sharedpage.c standard kern/kern_shutdown.c standard diff --git a/sys/conf/options b/sys/conf/options index 9b15fbb134db..9dc772abe3af 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -880,176 +880,178 @@ HWPMC_HOOKS # Hardware Trace (HWT) framework options HWT_HOOKS # 802.11 support layer IEEE80211_DEBUG opt_wlan.h IEEE80211_DEBUG_REFCNT opt_wlan.h IEEE80211_SUPPORT_MESH opt_wlan.h IEEE80211_SUPPORT_SUPERG opt_wlan.h IEEE80211_SUPPORT_TDMA opt_wlan.h IEEE80211_ALQ opt_wlan.h IEEE80211_DFS_DEBUG opt_wlan.h # 802.11 TDMA support TDMA_SLOTLEN_DEFAULT opt_tdma.h TDMA_SLOTCNT_DEFAULT opt_tdma.h TDMA_BINTVAL_DEFAULT opt_tdma.h TDMA_TXRATE_11B_DEFAULT opt_tdma.h TDMA_TXRATE_11G_DEFAULT opt_tdma.h TDMA_TXRATE_11A_DEFAULT opt_tdma.h TDMA_TXRATE_TURBO_DEFAULT opt_tdma.h TDMA_TXRATE_HALF_DEFAULT opt_tdma.h TDMA_TXRATE_QUARTER_DEFAULT opt_tdma.h TDMA_TXRATE_11NA_DEFAULT opt_tdma.h TDMA_TXRATE_11NG_DEFAULT opt_tdma.h # VideoMode PICKMODE_DEBUG opt_videomode.h # Network stack virtualization options VIMAGE opt_global.h VNET_DEBUG opt_global.h # Common Flash Interface (CFI) options CFI_SUPPORT_STRATAFLASH opt_cfi.h CFI_ARMEDANDDANGEROUS opt_cfi.h CFI_HARDWAREBYTESWAP opt_cfi.h # Sound options SND_DIAGNOSTIC opt_snd.h SND_FEEDER_RATE_HP opt_snd.h SND_PCM_64 opt_snd.h X86BIOS # Flattened device tree options FDT opt_platform.h FDT_DTB_STATIC opt_platform.h # OFED Infiniband stack OFED opt_ofed.h OFED_DEBUG_INIT opt_ofed.h SDP opt_ofed.h SDP_DEBUG opt_ofed.h IPOIB opt_ofed.h IPOIB_DEBUG opt_ofed.h IPOIB_CM opt_ofed.h # Resource Accounting RACCT opt_global.h RACCT_DEFAULT_TO_DISABLED opt_global.h # Resource Limits RCTL opt_global.h # HardenedBSD general hardening features HARDEN_KLD opt_pax.h # PaX-inspired hardening features PAX opt_pax.h PAX_ASLR opt_pax.h PAX_SYSCTLS opt_pax.h PAX_SEGVGUARD opt_pax.h PAX_HARDENING opt_pax.h PAX_HARDEN_KMALLOC opt_pax.h PAX_NOEXEC opt_pax.h PAX_INSECURE_MODE opt_pax.h PAX_CONTROL_ACL opt_pax.h PAX_CONTROL_ACL_OVERRIDE_SUPPORT opt_pax.h PAX_CONTROL_EXTATTR opt_pax.h PAX_JAIL_SUPPORT opt_pax.h HBSD_DEBUG opt_pax.h HBSD_RESIST_FINGERPRINTING opt_pax.h HBSD_EXPERIMENTAL opt_pax.h # ASLR overwritable defaults PAX_ASLR_DELTA_MMAP_DEF_LEN opt_pax.h PAX_ASLR_DELTA_STACK_DEF_LEN opt_pax.h PAX_ASLR_DELTA_VDSO_DEF_LEN opt_pax.h PAX_ASLR_DELTA_EXEC_DEF_LEN opt_pax.h PAX_ASLR_DELTA_RTLD_DEF_LEN opt_pax.h PAX_ASLR_COMPAT_DELTA_MMAP_DEF_LEN opt_pax.h PAX_ASLR_COMPAT_DELTA_STACK_DEF_LEN opt_pax.h PAX_ASLR_COMPAT_DELTA_EXEC_DEF_LEN opt_pax.h PAX_ASLR_COMPAT_DELTA_VDSO_DEF_LEN opt_pax.h PAX_ASLR_DELTA_MMAP_LSB opt_pax.h PAX_ASLR_DELTA_STACK_LSB opt_pax.h PAX_ASLR_DELTA_STACK_WITH_GAP_LSB opt_pax.h PAX_ASLR_DELTA_EXEC_LSB opt_pax.h PAX_ASLR_DELTA_VDSO_LSB opt_pax.h +# pledge() system call whitelisting inspired by OpenBSD +HBSD_PLEDGE opt_pledge.h # Random number generator(s) # Alternative RNG algorithm RANDOM_FENESTRASX opt_global.h # With this, no entropy processor is loaded, but the entropy # harvesting infrastructure is present. This means an entropy # processor may be loaded as a module. RANDOM_LOADABLE opt_global.h # This turns on high-rate and potentially expensive harvesting in # the uma slab allocator. RANDOM_ENABLE_UMA opt_global.h RANDOM_ENABLE_ETHER opt_global.h RANDOM_ENABLE_KBD opt_global.h RANDOM_ENABLE_MOUSE opt_global.h RANDOM_ENABLE_TPM opt_global.h # This options turns TPM into entropy source. TPM_HARVEST opt_tpm.h # BHND(4) driver BHND_LOGLEVEL opt_global.h # GPIO and child devices GPIO_SPI_DEBUG opt_gpio.h # SPI devices SPIGEN_LEGACY_CDEVNAME opt_spi.h # etherswitch(4) driver RTL8366_SOFT_RESET opt_etherswitch.h # evdev protocol support EVDEV_SUPPORT opt_evdev.h EVDEV_DEBUG opt_evdev.h UINPUT_DEBUG opt_evdev.h # Hyper-V network driver HN_DEBUG opt_hn.h # CAM-based MMC stack MMCCAM # Encrypted kernel crash dumps EKCD opt_ekcd.h # NVME options NVME_USE_NVD opt_nvme.h # amdsbwd options AMDSBWD_DEBUG opt_amdsbwd.h # gcov support GCOV opt_global.h LINDEBUGFS # options for HID support HID_DEBUG opt_hid.h IICHID_DEBUG opt_hid.h IICHID_SAMPLING opt_hid.h HKBD_DFLT_KEYMAP opt_hkbd.h HIDRAW_MAKE_UHID_ALIAS opt_hid.h U2F_DROP_UHID_ALIAS opt_hid.h # kenv options # The early kernel environment (loader environment, config(8)-provided static) # is typically cleared after the dynamic environment comes up to ensure that # we're not inadvertently holding on to 'secret' values in these stale envs. # This option is insecure except in controlled environments where the static # environment's contents are known to be safe. PRESERVE_EARLY_KENV opt_global.h # Options for the Intel QuickAssist (QAT) driver QAT_DISABLE_SAFE_DC_MODE opt_qat.h # EARLY_PRINTF specific options fo NS8250 uart UART_NS8250_EARLY_REG_IO_WIDTH opt_uart.h UART_NS8250_EARLY_REG_SHIFT opt_uart.h diff --git a/sys/hardenedbsd/hbsd_pledge.c b/sys/hardenedbsd/hbsd_pledge.c new file mode 100644 index 000000000000..12f1d21e3bda --- /dev/null +++ b/sys/hardenedbsd/hbsd_pledge.c @@ -0,0 +1,1538 @@ +#include +__FBSDID("$FreeBSD$"); + +#include "opt_pledge.h" + +#ifdef HBSD_PLEDGE + +/* TOOD determine overlap with man 9 priv, + which defaults to checking euid/jail status when determining + allowed privileges + a good place to patch in overlapping things would + probably be priv_check()/priv_check_cred() +*/ + +#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 // TODO this requires some additional includes for module_t etc +#include +#include + +FEATURE(hbsd_hardening, "Pledge sandbox mechanism"); + +SDT_PROVIDER_DECLARE(pledge); +SDT_PROVIDER_DEFINE(pledge); + + +/* DTrace probe for recording privilege transitions (drops). + pid, 0, 0, td->td_pledge, requested_mask. + The zeroes are placeholders for fsid/inode, which unfortunately are expensive to obtain. + TODO consider thread generation or similar identifying information, + alternatively we could trace the vnode pointer to the executable, which + could then be paired with a DTrace probe on process creation to obtain + the path of the executable. +*/ +SDT_PROBE_DEFINE5(pledge, kern, kern_pledge, masks, + "pid_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t"); + +/* + * TODO dwatch tooling + * DTrace SDT probe for recording violations of the pledge mask. + * This provides a live view of the data available through the + * security.pledge.learning_data sysctl. + * reference: man 9 SDT + * The arguments are (in this order): + * - pid + * - fsid + * - inode + * - syscall number + * - the current pledge mask possessed by thread + * - the violated mask. + * - the used mask + * - TODO we should add additional fields like zfs txgid + */ +SDT_PROBE_DEFINE7(pledge, learning, insert, masks, + "pid_t", "uint64_t", "ino_t", "int", "uint64_t", "uint64_t", "uint64_t"); + +/* + * Global exported symbols + */ + +bool pledge_learning = 0; +bool pledge_enforcing = 0; /* TODO: = HBSD_PLEDGE; */ + + +/* + * Forward declarations for static functions and variables in this file: + */ + +static int sysctl_pledge_flags(SYSCTL_HANDLER_ARGS); +static int sysctl_pledge_learning_data(SYSCTL_HANDLER_ARGS); + +static unsigned int pledge_jail_osd_slot; +static int pledge_jail_osd_create(void *_obj, void *_data); +static int pledge_jail_osd_remove(void *_obj, void *_data); + +static void pledge_learning_init(const void *_unused); +static void pledge_learning_record(const struct thread *, + const uint64_t, const uint64_t); + +static PLEDGE_LEARNING_COMPARE_PROTOTYPE + +/* see pledge.h for: + * - splay element type learning_splay_t + */ + +/* comparison function */ +static PLEDGE_LEARNING_COMPARE_IMPL + +/* + * DPCPU(9)-sized array of tree root structs + * TODO should we have __aligned(CACHE_LINE_SIZE) on RB_HEAD here and in the splay_entries array? + */ +typedef RB_HEAD(learning_tree, pledge_splay_t) learning_tree_t; +DPCPU_DEFINE_STATIC(learning_tree_t, learning_tree); + +/* + * Lock controlling insertion (write) and foreach/find (read) access to + * the learning_tree array: + */ +DPCPU_DEFINE_STATIC(struct rmlock, learning_rm_lock); + +RB_PROTOTYPE_STATIC(learning_tree, + pledge_splay_t, tree_link, learning_tree_compare); + +RB_GENERATE_STATIC(learning_tree, + pledge_splay_t, tree_link, learning_tree_compare); + + +/* Initialize the learning mode structure before SI_SUB_CREATE_INIT + * so we are ready for the first /sbin/init process: + */ + +SYSINIT(pledge_sysinit_learning, SI_SUB_AUDIT, SI_ORDER_ANY, + pledge_learning_init, NULL); + + +/* + * sysctl declarations for security.pledge.*: + * security.pledge.learning - toggle learning mode + * security.pledge.learning_data - retrieve learning data + * security.pledge.violations - violation counter + * security.pledge.kills - counter of killed processes + * security.pledge.softfails - counter of softfailed syscalls + * security.pledge.enforcing - toggle enforcing mode + * security.pledge.flags - get/set thread pledge bitmap + */ + +SYSCTL_NODE(_security, OID_AUTO, pledge, 0, 0, + "pledge policy controls"); + +SYSCTL_NODE(_security_pledge, OID_AUTO, jail, 0, 0, + "jail-specific pledge policy controls"); + +SYSCTL_BOOL(_security_pledge, OID_AUTO, learning, +#ifdef CTLFLAG_ROOTONLY + CTLFLAG_ROOTONLY | /* HardenedBSD-specific */ +#endif + CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_RWTUN, + &pledge_learning, 0, + "record pledge violations (0: off, 1: learning)"); + +SYSCTL_PROC(_security_pledge, OID_AUTO, learning_data, +#ifdef CTLFLAG_ROOTONLY + CTLFLAG_ROOTONLY | +#endif + CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_MPSAFE, + NULL, 0, /* TODO args ??? */ + sysctl_pledge_learning_data, "S,pledge_learning_entry_t", + "Retrieve the learning data entries"); + +static counter_u64_t learning_count = NULL; +SYSCTL_COUNTER_U64(_security_pledge, OID_AUTO, learning_count, +#ifdef CTLFLAG_ROOTONLY + CTLFLAG_ROOTONLY | +#endif + CTLFLAG_RD | CTLFLAG_STATS, + &learning_count, "Amount of recorded learning entries (for all CPUs)"); + +static counter_u64_t violation_count = NULL; +SYSCTL_COUNTER_U64(_security_pledge, OID_AUTO, violations, +#ifdef CTLFLAG_ROOTONLY + CTLFLAG_ROOTONLY | +#endif + CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_STATS, + &violation_count, "# of policy violations (enforced+learning)"); + +static counter_u64_t kill_count = NULL; +SYSCTL_COUNTER_U64(_security_pledge, OID_AUTO, kills, +#ifdef CTLFLAG_ROOTONLY + CTLFLAG_ROOTONLY | +#endif + CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_STATS, + &kill_count, "# of policy violations resulting in process kill"); + +static counter_u64_t softfail_count = NULL; +SYSCTL_COUNTER_U64(_security_pledge, OID_AUTO, softfails, +#ifdef CTLFLAG_ROOTONLY + CTLFLAG_ROOTONLY | +#endif + CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_STATS, + &softfail_count, "# of policy violations resulting in soft-fail"); + +/* TODO are proc nodes with CTLFLAG_SECURE generally accessible to + * all users in the system? */ +SYSCTL_BOOL(_security_pledge, OID_AUTO, enforcing, +#ifdef CTLFLAG_ROOTONLY + CTLFLAG_ROOTONLY | +#endif + CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_RWTUN, + &pledge_enforcing, 0, + "enforce pledge violations (0: off, 1: enforcing)"); + +SYSCTL_PROC(_security_pledge, OID_AUTO, flags, + CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_ANYBODY + | CTLFLAG_PRISON | CTLFLAG_CAPWR | CTLFLAG_CAPRD | CTLFLAG_MPSAFE, + NULL, 0, /* arg1, arg2 */ + sysctl_pledge_flags, "S,uint64_t", /* function, format*/ + "Reduce pledge flags for the calling thread and return previous flags."); + +SYSCTL_NODE(_security_pledge, OID_AUTO, override, 0, 0, + "Override required flags for a given syscall."); + +/* + * sysctl proc node for applying a new pledge mask to the calling thread. + * The supplied mask is AND'ed with the thread's current mask, permitting + * only reductions. + */ +static int +sysctl_pledge_flags(SYSCTL_HANDLER_ARGS) +{ + int error = 0; + uint64_t new_flags = req->td->td_pledge; + + error = sysctl_handle_64(oidp, &new_flags, 0, req); + + if (!error && req->newptr) { + kern_pledge(req->td, new_flags); + } + + return error; +} + +static int +pledge_jail_osd_create(void *obj, void *data __unused) +{ + struct prison *pr = obj; + //struct vfsoptlist *vfsopts = (struct vfsoptlist *)data; + struct pledge_jail_data *pjd = NULL; + + /* vfsopts contains jail options in case we want to do + * something with those. TODO. */ + + /* + * TODO we could walk + * while ((parent = pr->pr_parent)) { + * inherit from parent + * } + */ + + pjd = malloc(sizeof(struct pledge_jail_data), M_PRISON, M_ZERO|M_WAITOK); + pjd->is_enforcing = pledge_enforcing; /* inherit from global */ + pjd->violations = counter_u64_alloc(M_WAITOK); + + sysctl_ctx_init(&pjd->sysctl_ctx); + + char jail_id_str[16] = {0}; + snprintf(jail_id_str, sizeof(jail_id_str), "%u", pr->pr_id); + /* add under security.pledge: */ + struct sysctl_oid *oidp = SYSCTL_ADD_NODE(&pjd->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_security_pledge_jail), + OID_AUTO, + jail_id_str, CTLFLAG_RW, NULL, "controls for this jid"); + /* add under oidp */ + SYSCTL_ADD_BOOL(&pjd->sysctl_ctx, SYSCTL_CHILDREN(oidp), OID_AUTO, + "enforcing", CTLFLAG_RW, &pjd->is_enforcing, 0, + "enforcing for this jail"); + SYSCTL_ADD_COUNTER_U64(&pjd->sysctl_ctx, SYSCTL_CHILDREN(oidp), + OID_AUTO, + "violations", CTLFLAG_RW, &pjd->violations, + "violation count for this jail"); + + void **rsv = osd_reserve(pledge_jail_osd_slot); + for (int retry = 1; retry;) + { + prison_lock(pr); + retry = osd_jail_set_reserved(pr, + pledge_jail_osd_slot, rsv, pjd); + prison_unlock(pr); + } + + return 0; +} + +static int +pledge_jail_osd_remove(void *obj, void *data __unused) +{ + struct prison *pr = obj; + //struct vfsoptlist *vfsopts = data; + + prison_lock(pr); + struct pledge_jail_data *pjd = osd_jail_get(pr, pledge_jail_osd_slot); + prison_unlock(pr); + + if (NULL == pjd) { + printf("pledge_jail_remove: pjd == NULL (pr == prison0: %d)\n", + (pr == &prison0)); + return 0; /* TODO shouldn't happen? */ + } + + /* Cleanup sysctls: */ + sysctl_ctx_free(&pjd->sysctl_ctx); + counter_u64_free(pjd->violations); + free(pjd, M_PRISON); + + return 0; +} + +/* + * Learning mode + * pledge_learning_init() - allocate table + * pledge_learning_hash() - hash (fsid,inode) tuple to int + * pledge_learning_insert() - update entry with used/violated flags + * pledge_learning_record() - find (fsid,inode) and insert if learning enabled + */ + +static MALLOC_DEFINE(M_PLEDGE_LEARNING, "pledge learning data", + "pledge(8) learning mode data points."); + +/* + * Initialize learning mode memory structures + */ +static void +pledge_learning_init(const void *_unused) +{ + violation_count = counter_u64_alloc(M_WAITOK); + learning_count = counter_u64_alloc(M_WAITOK); + kill_count = counter_u64_alloc(M_WAITOK); + softfail_count = counter_u64_alloc(M_WAITOK); + + /* + * These are small; we INIT them regardless of learning==1 + * to avoid the headache of having to check for initialization later on: + */ + u_int cpu = 0; + CPU_FOREACH(cpu) { + rm_init(DPCPU_ID_PTR(cpu, learning_rm_lock), + "security.pledge.learning"); + RB_INIT(DPCPU_ID_PTR(cpu, learning_tree)); + } + + /* TODO add a tunable for each system call. + * This should modify the pledge_permission_map to allow overriding + * the pledge permission mask for syscalls to enable troubleshooting + * when new syscalls are added without having to recompile the kernel. + struct sysctl_oid *mynode = SYSCTL_ADD_U64(_security_pledge_override, + TODOTODO CTLFLAG_RWTUN | CTLFLAG_SECURE | CTLFLAG_RD + ); + */ + + /* + * Install per-jail osd.h hooks. + * The PR_* constants are from jail.h + */ + osd_method_t osdmethods[PR_MAXMETHOD] = {NULL}; + osdmethods[PR_METHOD_CREATE] = pledge_jail_osd_create; + osdmethods[PR_METHOD_REMOVE] = pledge_jail_osd_remove; + + /* + * Go through existing jails, taking the allprison_lock before + * registering our slot to ensure we don't trigger two calls + * to pledge_jail_osd_create for any given jail (one from osd, + * and one here). + * That might be overly careful, not sure how realistic jails + * being spawned at this point is. + */ + sx_slock(&allprison_lock); + pledge_jail_osd_slot = osd_jail_register(NULL, osdmethods); + struct prison *pr = &prison0; + (void)pledge_jail_osd_create(pr, NULL); + TAILQ_FOREACH(pr, &allprison, pr_list) { + (void)pledge_jail_osd_create(pr, NULL); + } + sx_sunlock(&allprison_lock); +} + +/* + * Erase learning entries. + * Returns the number of bytes the erased entries would have required to dump + * to userspace, in multiples of sizeof(pledge_learning_entry_t). + */ +size_t +kern_pledge_learning_data_erase(void) +{ + size_t erased_bytes = 0; + u_int cpu = 0; + CPU_FOREACH(cpu) { + struct rmlock * const rm = DPCPU_ID_PTR(cpu, learning_rm_lock); + rm_wlock(rm); + learning_tree_t * const tree = DPCPU_ID_PTR(cpu, learning_tree); + pledge_splay_t *el = NULL, *el_tmp = NULL; + RB_FOREACH_SAFE(el, learning_tree, tree, el_tmp) { + learning_tree_RB_REMOVE(tree, el); + free(el, M_PLEDGE_LEARNING); + erased_bytes += sizeof(pledge_learning_entry_t); + } + rm_wunlock(rm); + } + return erased_bytes; +} + +/* + * Records the utilized and violated pledge privileges for a given executable + * as identified by (fsid,inode) tuple. + */ +static inline void +pledge_learning_insert(const struct thread*thread, + const dev_t fsid, const ino_t inode, + const uint64_t used_mask, const uint64_t violated_mask){ + + SDT_PROBE7(pledge, learning, insert, masks, + thread->td_proc->p_pid, fsid, inode, thread->td_sa.code, + thread->td_pledge, violated_mask, used_mask); + + /* Skip if learning mode is disabled: */ + if (!pledge_learning) + return; + + u_int tree_idx = curcpu; + struct rmlock * const rm = DPCPU_ID_PTR(tree_idx, learning_rm_lock); + struct rm_priotracker rm_tracker = { 0 }; + rm_rlock(rm, &rm_tracker); + learning_tree_t *tree = DPCPU_ID_PTR(tree_idx, learning_tree); + + /* Allocate member on the stack used to find existing entry + * with this inode/fsid combination. If there isn't one, + * we will need to copy this data to a proper allocation + * before inserting. + */ + pledge_splay_t stack_el = { + .inode = inode, + .fs_id = fsid, + /* zero-initialize the remaining members + * since we may later want to add it to the tree */ + 0 + }; + + /* check if we already have an entry */ + pledge_splay_t *el = + learning_tree_RB_FIND(tree, &stack_el); + + if (el) { + el->used |= used_mask; + el->violated |= violated_mask; + el->possessed |= thread->td_pledge; + + rm_runlock(rm, &rm_tracker); + + return; + } + + /* the executable did not already have an entry, + so we need to add one. */ + + /* drop lock so we can malloc our new entry: */ + rm_runlock(rm, &rm_tracker); + /* would it make sense to use malloc_domainset here? */ + el = malloc(sizeof(stack_el), + M_PLEDGE_LEARNING, M_WAITOK | M_ZERO); + memcpy(el, &stack_el, sizeof(stack_el)); + + rm_wlock(rm); + + pledge_splay_t * const inserted = learning_tree_RB_INSERT(tree, el); + if (__builtin_expect((long)inserted, false)) { + /* while we were busy malloc'ing, + * we were preempted, and the same + * element was inserted into this tree. + * use that instead of the newly malloc'ed entry that did not + * make it into the tree: + */ + free(el, M_PLEDGE_LEARNING); + el = inserted; + } else { + counter_u64_add(learning_count, 1); + } + + el->used |= used_mask; + el->violated |= violated_mask; + el->possessed |= thread->td_pledge; + + rm_wunlock(rm); +} + +/* + * TODO. ideally we would not call VOP_GETATTR on *each* call to this... + */ +static inline void +pledge_learning_record(const struct thread *thread, + const uint64_t used_mask, + const uint64_t violated_mask) +{ + if (!pledge_learning) { /* check sysctl */ + return; + } + + int err = 0; + + /* seems like this would be a great place to have a LRU cache + of vnode/inode to avoid having to take all these locks...*/ + + /* pointer to vnode for thread's executable */ + /* locks: thread->td_proc (*) not yet protected + * td_proc->p_textvp (b) created at fork, never changes + */ + PROC_LOCK(thread->td_proc); + struct vnode * const exec_vnode = thread->td_proc->p_textvp; + PROC_UNLOCK(thread->td_proc); + + /* assert that we have a vnode, and that it is a regular file: */ + if (!exec_vnode || VREG != exec_vnode->v_type) { + /* in this case should probably have an ERROR entry + * that contains the appropriate mask for things we + * failed to look up? */ + printf("pledge not exec_vnode OR not vreg TODO\n"); + goto proc_unlock_and_return; + } + + struct vattr exec_vattr = {0}; + err = VOP_GETATTR(exec_vnode, &exec_vattr, NOCRED); + if (__builtin_expect(err, 0)) { + printf("pledge VOP_GETATTR failed, locked:%d\n", VOP_ISLOCKED(exec_vnode)); + goto proc_unlock_and_return; + } + + const dev_t exec_fsid = exec_vattr.va_fsid; + const ino_t exec_fileid = exec_vattr.va_fileid; + _Static_assert(sizeof(exec_vattr.va_fileid) == sizeof(ino_t), "va_fileid<>ino_t"); + /* TODO consider grouping by exec_vattr.va_filerev also? + * for ZFS that seems like it contains txgid ? + * https://github.com/freebsd/freebsd/blob/45d716be60e3806a85a0822cec12b8ce2321003b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c#L2668 + * Alternatively we could do something like track modification time + * and clear the recorded flags upon modification (or just store + * duplicate entries where userland will have to decide with outdated + * recordings. Finally we could let that be up to the user through + * sysctl configuration. ) + */ + + pledge_learning_insert(thread, exec_fsid, exec_fileid, + used_mask, violated_mask); + + goto proc_unlock_and_return; + + + printf("pledge TODO proc_unlock_and_return: not good.\n"); +proc_unlock_and_return: + //PROC_UNLOCK(thread->td_proc); + return; +} + +/* + * sysctl proc node that copies (to userspace) the learning data. + * newptr newlen oldptr oldlen outcome + * * !0 * * EINVAL, reserved + * !NULL 0 !NULL * EINVAL, reserved + * !NULL 0 NULL * Erase learning data + * NULL 0 !NULL * Put learning data in oldptr (up to oldlen bytes) + * NULL 0 NULL * Retrieve bufsize required for learning entries + */ +static int +sysctl_pledge_learning_data(SYSCTL_HANDLER_ARGS) +{ + /* TODO it's unfortunate that only sum(dpcpu counter array) is exposed; + * being able to retrieve max(dpcpu counter array) would be useful. */ + const uint64_t entries_num_max = counter_u64_fetch(learning_count); + uint64_t entries_bytes_max = + entries_num_max * sizeof(pledge_learning_entry_t); + + if (req->newlen) { + /* rew->newlen is reserved for now. */ + printf("pledge: trying to set learning data," + " not implemented.\n"); + return EINVAL; + } + + if (NULL == req->oldptr) { + if (NULL != req->newptr) { + entries_bytes_max = kern_pledge_learning_data_erase(); + } + /* if userspace provided req->newptr, we returned the space + * required by the erased entries. + * Otherwise, userspace did not provide a place to put entries; + * and is only interested in space required to dump data. + */ + return SYSCTL_OUT(req, NULL, entries_bytes_max); + } + + if (req->newptr) { + printf("sysctl_pledge_learning_data: newptr && oldptr\n"); + return EINVAL; + } + + const size_t idx_max = req->oldlen / sizeof(pledge_learning_entry_t); + + if (idx_max * sizeof(pledge_learning_entry_t) != req->oldlen) { + /* userland should ask for at least one entry and give + * us exactly the space we need to store them: */ + printf("pledge: learning_data %zd EINVAL TODO\n", req->oldlen); + return (EINVAL); + } + + /* Allocate contiguous buffer so we can attempt one big copyout(). + * User can potentially request a very large amount of memory, so we + * allow the malloc to fail. + * One big buffer seemed better than doing copyouts for each element, + * but it scales poorly with a large number of CPUs. + * Could also consider a copyout per CPU node, or to merge the data in-kernel. + * TODO also consider returning EINVAL if + * req->oldlen > entries_num_max + (n) * mp_ncpus + * where (n) is some sensible constant (since we don't have a + * synced upper bound to compare against). + * It seemed unclean, so I did not include that here. */ + pledge_learning_entry_t * const entry_arr = + malloc(req->oldlen, M_PLEDGE_LEARNING, M_ZERO | M_WAITOK); + + size_t idx = 0; + int err = 0; + + u_int cpu = 0; + CPU_FOREACH(cpu) { + if (idx >= idx_max) break; + struct rmlock * const rm = DPCPU_ID_PTR(cpu, learning_rm_lock); + struct rm_priotracker rm_tracker = { 0 }; + rm_rlock(rm, &rm_tracker); + learning_tree_t * const tree = DPCPU_ID_PTR(cpu, learning_tree); + pledge_splay_t *el = NULL; + RB_FOREACH(el, learning_tree, tree) { + if (idx >= idx_max) break; + /* printf("pledge el: inode %lu fs_id: %lu" + " used:0x%0lx viol:0x%0lx pos:0x%0lx\n", + el->inode, el->fs_id, + el->used, el->violated, el->possessed); */ + pledge_learning_entry_t * const user_entry = + entry_arr + idx; + user_entry->is_populated = true; + user_entry->used_flags = el->used; + user_entry->violated_flags = el->violated; + user_entry->possessed = el->possessed; + user_entry->inode = el->inode; + user_entry->fsid = el->fs_id; + idx++; + } + rm_runlock(rm, &rm_tracker); + } + + err = SYSCTL_OUT(req, entry_arr, idx*sizeof(pledge_learning_entry_t)); + if (err) { + printf("pledge:SYSCTL_OUT failed err %d idx %zd\n", err, idx); + } + + free(entry_arr, M_PLEDGE_LEARNING); + + return (err); +} + + +/* + * Generic function to handle a permission check. + * By default it checks if ONE of the flags is set, this behaviour can be + * changed to compare against all the flags by OR'ing with PLEDGE_AND. + * Returns ENOTCAPABLE or exits() the process, this function MAY NOT RETURN. + */ +int +pledge_check_bitmap(struct thread * const thread, const uint64_t flags) +{ + + /* Assume we need to match ALL the flags: */ + uint64_t violated = + (flags & PLEDGE_WILDCARD) + & (~(thread->td_pledge)); + + /* used_mask is the intersection between required and possessed: */ + // TODO atm we over-report a little bit since if AND is not set + // we really only need one of them, not all of the target flags. + // Potential solution would be to just pick the lowest. + uint64_t used_mask = + (flags & PLEDGE_WILDCARD & thread->td_pledge); + + /* Retain (violated) if one or more constraints are met: + * 1) the PLEDGE_AND bit is set in (flags) + * 2) the permission intersection of (flags) and (td_pledge) is empty + * Conversely this clears (violated) by multiplying it with 0 + * when !PLEDGE_AND && at least one required permission is possessed. + */ + violated *= + !!( (PLEDGE_AND & flags) + | !used_mask); + + /* Record the lacking permissions unless there is no violation + * and PLEDGE_NOLEARN was supplied in (flags). + * TODO document this in the manpages + * TODO document in pledgectl + */ + if (violated || !(PLEDGE_NOLEARN & flags)) { + pledge_learning_record(thread, used_mask, violated); + } + + if (violated & PLEDGE_WILDCARD) + counter_u64_add(violation_count, 1); + + if (violated) { + /* Consult the jail-specific entry.*/ + /* TODO: is (thread) always (curthread) here? */ + struct prison *pr = thread->td_ucred->cr_prison; + prison_lock(pr); + struct pledge_jail_data *pjd = osd_jail_get(pr, + pledge_jail_osd_slot); + if (pjd) { + if (violated) { + counter_u64_add(pjd->violations, 1); + } + if ( !(pledge_enforcing || pjd->is_enforcing) ) { + violated = 0; + } + } else { + // TODO just assert that pjd != NULL + counter_u64_add(softfail_count, 10); + } + prison_unlock(pr); + } + + if (violated) { + /* return a permission error if the wanted syscall_no is not + * permitted by the thread's current pledge bitmap: */ + + tprintf(thread->td_proc, 0, + "pledge: %s pid %d syscall %d due to td_pledge=0x%0lx " + "; relevant=0x%0lx\n", + ((thread->td_pledge & PLEDGE_SOFTFAIL) ? + "soft-failing" : "crashing"), + thread->td_proc->p_pid, thread->td_sa.code, + thread->td_pledge, flags); + + if (0 == (thread->td_pledge & PLEDGE_SOFTFAIL)) { + /* crash process: + * 2nd arg is exit code + * 3rd arg is signo + * TODO maybe call sys_abort2 instead to produce + * inspectable core? */ + counter_u64_add(kill_count, 1); + exit1(thread, 0, SIGKILL); + // TODO misunderstood exit1? + counter_u64_add(kill_count, 1337); + } + + counter_u64_add(softfail_count, 1); + return (ENOTCAPABLE); + } + + return 0; +} + +/* + * Apply intersection of new permission mask and the current mask. + * Always succeeds. + */ +int +kern_pledge(struct thread *td, const uint64_t mask) +{ + /* Would probably be a good place for a DTrace probe.*/ + /* TODO do we need to lock td? */ + SDT_PROBE5(pledge, kern, kern_pledge, masks, + td->td_proc->p_pid, 0, 0, td->td_pledge, mask); + td->td_pledge &= (mask & ~PLEDGE_AND); + return 0; +} + +/* + * Look up pledge bitmask for binary stored in the + * "system:pledge" and "user:pledge" extattrs, + * applying the associated masks (if they exist) to the + * thread's current pledge mask. + * The bitmasks are always stored in little-endian byte order. + * Returns 0 on success (including if the extattrs do not exist), + * and nonzero on error. + */ +int +pledge_apply_extattr(struct thread *td, struct vnode *ni_vp) +{ + int err = 0; + + uint64_t retrieved_mask = PLEDGE_NONE; + + for (int namespace = 0; namespace < 2; ++namespace) { + struct uio uio = {0}; + struct iovec iov = {0}; + + /* + * Read the system:pledge extattr on the file in question. + */ + + iov.iov_base = &retrieved_mask; + iov.iov_len = sizeof(retrieved_mask); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = 0; + uio.uio_rw = UIO_READ; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_td = td; + uio.uio_resid = sizeof(retrieved_mask); + + err = VOP_GETEXTATTR(ni_vp, + (namespace == 0 + ? EXTATTR_NAMESPACE_SYSTEM + : EXTATTR_NAMESPACE_USER), + "pledge", + &uio, NULL, NOCRED, td); + + // uio.uio_resid holds "remaining" counter, this should drop to 0 once read? + + + /* TODO maybe this should be EXTATTR_NAMESPACE_USER to permit + people to pledge their own binaries */ + + /* TODO I guess we need to bypass read permissions iff (td->ucred) has + * execute permission to the binary seeing as execution has gotten + * this far, we assume this is the case. + * Using td->td_ucred resulted in EPERM errors. + * Need to evaluate NOCRED vs td->td_ucred, also in other VOP_ ops + * in hbsd_pledge.c + */ + + if (ENOATTR == err || EOPNOTSUPP == err) { + /* it doesn't have a "pledge" extattr: */ + continue; + } else if (err) { + printf("pledge_getmask_extattr: VOP_GETEXTATTR on vnode %p " + "for attribute system:'pledge' failed with error (%d)\n", + ni_vp, err); + return 1; + } else if (0 == uio.uio_resid) { + /* + * TODO excellent place for a DTrace probe + */ + printf("pledge_getmask_extattr: vnode %p pledgemask 0x%lx\n", + ni_vp, retrieved_mask); + retrieved_mask = le64toh(retrieved_mask); + int err = kern_pledge(td, retrieved_mask); + if (err) return err; + } + else { + /* + * If there's more data in here, something is wrong. + */ + tprintf(td->td_proc, 0, "pledge_getmask_extattr: " + "size of system.pledge extattr is %zd, expected == %zd\n", + uio.uio_resid, sizeof(retrieved_mask)); + return 1; + } + } + return 0; +} + +/* + * Validate open() access. + * May not return, so care should be taken to free structures prior to calling. + */ +int inline +pledge_openat(struct thread *thread, const int fd, const char *path, + const int flags, const int mode) +{ + + uint64_t required_mask = PLEDGE_AND | PLEDGE_RPATH | PLEDGE_WPATH + | PLEDGE_CPATH | PLEDGE_FLOCK; + + /* TODO this would probably be a good point for path validation + * and whitelisting of /dev/null, /dev/urandom, etc. + * it would however feel better to check major/minor dev number + * to avoid problems with symlinks and whathaveyou. + */ + + /* determine required capabilities depending on the open() flags:*/ + + if (0 == (FFLAGS(flags) & FREAD)) + required_mask ^= PLEDGE_RPATH; + + if (0 == (FFLAGS(flags) & (FWRITE | FAPPEND))) + required_mask ^= PLEDGE_WPATH; + + if (0 == (flags & O_CREAT)) { + required_mask ^= PLEDGE_CPATH; + } + + if (0 == (flags & (O_SHLOCK | O_EXLOCK))) + required_mask ^= PLEDGE_FLOCK; + + if (PLEDGE_WILDCARD != (PLEDGE_WILDCARD & thread->td_pledge)) { + /* TODO consider DTrace probe + printf("pledge: openat: flags:0x%0x vs req:0x%0lx\n", + flags, required_mask); + */ + } + + return (pledge_check_bitmap(thread, required_mask)); +} + +/* + * This map is used in pledge_syscall() to determine which pledge flags are + * relevant to determine access to a given syscall. + * The syscall is allowed if ONE OR MORE flags match the thread's bitmap. + * + * The syscalls we do not filter using pledge are permitted by + * initializing the entry in this table to PLEDGE_WILDCARD. + * + * The rationale for listing all of the system calls here is the philosophy + * that even though it requires more maintenance, it is better to deny an + * attempt to call an unhandled system call than permitting it. + * + * NOTE that there is a special case in that function that grants access if + * pledge is turned off for that thread (when it is PLEDGE_WILDCARD), which is + * the default defined in sys/kern/init_main.c + * + * These are listed in numerical, ascending order (see sys/sys/syscalls.h): + */ +static +uint64_t pledge_permission_map[SYS_MAXSYSCALL] = { + /* 0: */ + [SYS_syscall] = PLEDGE_NONE, // TODO + [SYS_exit] = PLEDGE_NONE, + [SYS_fork] = PLEDGE_PROC, + [SYS_read] = PLEDGE_NONE, + [SYS_write] = PLEDGE_NONE, + [SYS_open] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_CPATH | PLEDGE_NOLEARN, /* NOLEARN: handled in pledge_openat */ + [SYS_close] = PLEDGE_STDIO, + [SYS_wait4] = PLEDGE_PROC, + [SYS_link] = PLEDGE_CPATH, + /* 10: */ + [SYS_unlink] = PLEDGE_CPATH, + [SYS_chdir] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_RPATH, + [SYS_fchdir] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_RPATH, +#ifdef SYS_freebsd11_mknod + [SYS_freebsd11_mknod] = PLEDGE_AND | PLEDGE_CPATH | PLEDGE_DEVICE, +#else + [SYS_mknod] = PLEDGE_AND | PLEDGE_CPATH | PLEDGE_DEVICE, +#endif + [SYS_chmod] = PLEDGE_FATTR, + [SYS_chown] = PLEDGE_AND | PLEDGE_CHOWN | PLEDGE_CPATH, // chown + [SYS_break] = PLEDGE_STDIO, + /* 20: */ + [SYS_getpid] = PLEDGE_NONE, + [SYS_mount] = PLEDGE_DEVICE, + [SYS_unmount] = PLEDGE_DEVICE, + [SYS_setuid] = PLEDGE_ID, + [SYS_getuid] = PLEDGE_NONE, + [SYS_geteuid] = PLEDGE_NONE, + [SYS_ptrace] = PLEDGE_PROC, + [SYS_recvmsg] = PLEDGE_STDIO, + [SYS_sendmsg] = PLEDGE_STDIO, + [SYS_recvfrom] = PLEDGE_STDIO, + /* 30: */ + [SYS_accept] = PLEDGE_INET | PLEDGE_UNIX, + [SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX, + [SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX, + [SYS_access] = PLEDGE_RPATH, + [SYS_chflags] = PLEDGE_AND | PLEDGE_FATTR | PLEDGE_CPATH, + [SYS_fchflags] = PLEDGE_AND | PLEDGE_FATTR | PLEDGE_CPATH, + [SYS_sync] = PLEDGE_STDIO, + [SYS_kill] = PLEDGE_PROC, + [SYS_getppid] = PLEDGE_STDIO, + [SYS_dup] = PLEDGE_STDIO, + [SYS_freebsd10_pipe] = PLEDGE_STDIO, + [SYS_getegid] = PLEDGE_STDIO, + [SYS_profil] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, // TODO?? + [SYS_ktrace] = PLEDGE_AND | PLEDGE_WPATH | PLEDGE_PROC, + [SYS_getgid] = PLEDGE_NONE, + [SYS_getlogin] = PLEDGE_STDIO, + /* 50: */ + [SYS_setlogin] = PLEDGE_ID, + [SYS_acct] = PLEDGE_PROC, + [SYS_sigaltstack] = PLEDGE_STDIO, + [SYS_ioctl] = PLEDGE_IOCTL, + [SYS_reboot] = PLEDGE_PROC, + [SYS_revoke] = PLEDGE_AND | PLEDGE_PROC | PLEDGE_RPATH, + [SYS_symlink] = PLEDGE_CPATH, + [SYS_readlink] = PLEDGE_RPATH, + [SYS_execve] = PLEDGE_AND | PLEDGE_EXEC | PLEDGE_PROC, + /* 60: */ + [SYS_umask] = PLEDGE_STDIO, + [SYS_chroot] = PLEDGE_STDIO, + [SYS_msync] = PLEDGE_STDIO, + [SYS_vfork] = PLEDGE_PROC, + [SYS_sbrk] = PLEDGE_STDIO, + /* 70: */ + [SYS_sstk] = PLEDGE_STDIO, +#ifndef SYS_vadvise +#define SYS_vadvise SYS_freebsd11_vadvise +#endif + [SYS_vadvise] = PLEDGE_STDIO, + [SYS_munmap] = PLEDGE_STDIO, + [SYS_mprotect] = PLEDGE_STDIO, + [SYS_madvise] = PLEDGE_STDIO, + [SYS_mincore] = PLEDGE_STDIO, + [SYS_getgroups] = PLEDGE_STDIO, + /* 80: */ + [SYS_setgroups] = PLEDGE_ID, + [SYS_getpgrp] = PLEDGE_STDIO, + [SYS_setpgid] = PLEDGE_STDIO, + [SYS_setitimer] = PLEDGE_STDIO, + [SYS_swapon] = PLEDGE_DEVICE, + [SYS_getitimer] = PLEDGE_STDIO, + [SYS_getdtablesize] = PLEDGE_DEVICE, // TODO + /* 90: */ + [SYS_dup2] = PLEDGE_STDIO, + [SYS_fcntl] = PLEDGE_STDIO, + [SYS_select] = PLEDGE_STDIO, + [SYS_fsync] = PLEDGE_STDIO, + [SYS_setpriority] = PLEDGE_STDIO, + [SYS_socket] = PLEDGE_DNS | PLEDGE_INET | PLEDGE_UNIX, + [SYS_connect] = PLEDGE_DNS | PLEDGE_INET | PLEDGE_UNIX, + /* 100: */ + [SYS_getpriority] = PLEDGE_STDIO, + [SYS_bind] = PLEDGE_DNS | PLEDGE_INET | PLEDGE_UNIX, + [SYS_setsockopt] = PLEDGE_DNS | PLEDGE_INET | PLEDGE_UNIX, // TODO + [SYS_listen] = PLEDGE_INET | PLEDGE_UNIX, + [SYS_gettimeofday] = PLEDGE_NONE, + [SYS_getrusage] = PLEDGE_STDIO, + [SYS_getsockopt] = PLEDGE_STDIO, // TODO? + /* 120: */ + [SYS_readv] = PLEDGE_STDIO, + [SYS_writev] = PLEDGE_STDIO, + [SYS_settimeofday] = PLEDGE_SETTIME, + [SYS_fchown] = PLEDGE_CHOWN, + [SYS_fchmod] = PLEDGE_FATTR, + [SYS_setreuid] = PLEDGE_ID, + [SYS_setregid] = PLEDGE_ID, + [SYS_rename] = PLEDGE_CPATH, + [SYS_flock] = PLEDGE_FLOCK, + [SYS_mkfifo] = PLEDGE_DPATH, + [SYS_sendto] = PLEDGE_STDIO, + [SYS_shutdown] = PLEDGE_PROC, + [SYS_socketpair] = PLEDGE_STDIO, + [SYS_mkdir] = PLEDGE_CPATH, + [SYS_rmdir] = PLEDGE_CPATH, + [SYS_utimes] = PLEDGE_FATTR, + /* 140: */ + [SYS_adjtime] = PLEDGE_SETTIME, + [SYS_setsid] = PLEDGE_STDIO, + [SYS_quotactl] = PLEDGE_STDIO, /* TODO */ + [SYS_nlm_syscall] = PLEDGE_STDIO, /* TODO */ + [SYS_nfssvc] = PLEDGE_STDIO, + /* 160: */ + [SYS_lgetfh] = PLEDGE_WPATH | PLEDGE_RPATH, /* TODO */ + [SYS_getfh] = PLEDGE_WPATH | PLEDGE_RPATH, /* TODO */ + [SYS_sysarch] = PLEDGE_STDIO, /* TODO */ + [SYS_rtprio] = PLEDGE_STDIO, + [SYS_semsys] = PLEDGE_STDIO, + /* 170: */ + [SYS_msgsys] = PLEDGE_STDIO, /* TODO */ + [SYS_shmsys] = PLEDGE_STDIO, + [SYS_setfib] = PLEDGE_ROUTE, + [SYS_ntp_adjtime] = PLEDGE_SETTIME, + [SYS_setgid] = PLEDGE_ID, + [SYS_setegid] = PLEDGE_ID, + [SYS_seteuid] = PLEDGE_ID, + [SYS_freebsd11_stat] = PLEDGE_RPATH, +#ifdef SYS_freebsd11_fstat + [SYS_freebsd11_fstat] = PLEDGE_RPATH, +#endif + /* 190: */ + [SYS_freebsd11_lstat] = PLEDGE_RPATH, + [SYS_pathconf] = PLEDGE_STDIO, // NONE? + [SYS_fpathconf] = PLEDGE_STDIO, + /* TODO what happened to 193? */ + [SYS_getrlimit] = PLEDGE_STDIO, + [SYS_setrlimit] = PLEDGE_STDIO, + [SYS_freebsd11_getdirentries] = PLEDGE_STDIO, + [SYS___syscall] = PLEDGE_STDIO, // TODO does this allow bypass? + [SYS___sysctl] = PLEDGE_SYSCTL, // TODO + [SYS_mlock] = PLEDGE_STDIO, + [SYS_munlock] = PLEDGE_STDIO, + [SYS_undelete] = PLEDGE_CPATH, // TODO + [SYS_futimes] = PLEDGE_FATTR, + [SYS_getpgid] = PLEDGE_STDIO, + [SYS_poll] = PLEDGE_STDIO, + /* 220: */ + [SYS_freebsd7___semctl] = PLEDGE_STDIO, + [SYS_semget] = PLEDGE_UNIX, + [SYS_semop] = PLEDGE_STDIO, + [SYS_freebsd7_msgctl] = PLEDGE_STDIO, + [SYS_msgget] = PLEDGE_STDIO, + [SYS_msgsnd] = PLEDGE_STDIO, + [SYS_msgrcv] = PLEDGE_STDIO, + [SYS_shmat] = PLEDGE_STDIO, + [SYS_freebsd7_shmctl] = PLEDGE_STDIO, + /* 230: */ + [SYS_shmdt] = PLEDGE_STDIO, /* TODO */ + [SYS_shmget] = PLEDGE_STDIO, + [SYS_clock_gettime] = PLEDGE_STDIO, + [SYS_clock_settime] = PLEDGE_SETTIME, + [SYS_clock_getres] = PLEDGE_STDIO, + [SYS_ktimer_create] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_UNIX, + [SYS_ktimer_delete] = PLEDGE_STDIO, + [SYS_ktimer_settime] = PLEDGE_STDIO, + [SYS_ktimer_gettime] = PLEDGE_STDIO, + [SYS_ktimer_getoverrun] = PLEDGE_STDIO, + /* 240: */ + [SYS_nanosleep] = PLEDGE_NONE, + [SYS_ffclock_getcounter] = PLEDGE_STDIO, + [SYS_ffclock_setestimate] = PLEDGE_STDIO, + [SYS_ffclock_getestimate] = PLEDGE_STDIO, + [SYS_clock_nanosleep] = PLEDGE_NONE, + [SYS_clock_getcpuclockid2] = PLEDGE_STDIO, + [SYS_ntp_gettime] = PLEDGE_STDIO, + /* 250: */ + [SYS_minherit] = PLEDGE_STDIO, + [SYS_rfork] = PLEDGE_PROC | PLEDGE_STDIO, + [SYS_issetugid] = PLEDGE_NONE, + [SYS_lchown] = PLEDGE_CHOWN, // chown + [SYS_aio_read] = PLEDGE_AND | PLEDGE_AIO, // TODO + [SYS_aio_write] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, // TODO + [SYS_lio_listio] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, // like preadv/pwritev for aio? + /* 272 */ + [SYS_freebsd11_getdents] = PLEDGE_RPATH, + [SYS_lchmod] = PLEDGE_FATTR, +#ifdef SYS_netbsd_lchown + [SYS_netbsd_lchown] = PLEDGE_CHOWN, // chown +#endif + [SYS_lutimes] = PLEDGE_FATTR, +#ifdef SYS_netbsd_msync + [SYS_netbsd_msync] = PLEDGE_STDIO, // TODO +#endif + [SYS_freebsd11_nstat] = PLEDGE_STDIO, + [SYS_freebsd11_nfstat] = PLEDGE_STDIO, // TODO + /* 280: */ + [SYS_freebsd11_nlstat] = PLEDGE_STDIO, + [SYS_preadv] = PLEDGE_STDIO, + /* 290: */ + [SYS_pwritev] = PLEDGE_STDIO, + [SYS_fhopen] = PLEDGE_RPATH | PLEDGE_WPATH, + [SYS_freebsd11_fhstat] = PLEDGE_RPATH | PLEDGE_WPATH, + /* 300: */ + [SYS_modnext] = PLEDGE_KLD, + [SYS_modstat] = PLEDGE_KLD, + [SYS_modfnext] = PLEDGE_KLD, + [SYS_modfind] = PLEDGE_KLD, + [SYS_kldload] = PLEDGE_AND | PLEDGE_EXEC | PLEDGE_KLD | PLEDGE_RPATH, + [SYS_kldunload] = PLEDGE_KLD, + [SYS_kldfind] = PLEDGE_KLD, + [SYS_kldnext] = PLEDGE_KLD, + [SYS_kldstat] = PLEDGE_KLD, + [SYS_kldfirstmod] = PLEDGE_KLD, + /* 310: */ + [SYS_getsid] = PLEDGE_STDIO, + [SYS_setresuid] = PLEDGE_ID, + [SYS_setresgid] = PLEDGE_ID, + [SYS_aio_return] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, + [SYS_aio_suspend] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, + [SYS_aio_cancel] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, + [SYS_aio_error] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, + [SYS_yield] = PLEDGE_NONE, + [SYS_mlockall] = PLEDGE_STDIO, + [SYS_munlockall] = PLEDGE_STDIO, + [SYS___getcwd] = PLEDGE_STDIO, + [SYS_sched_setparam] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, + [SYS_sched_getparam] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, + [SYS_sched_setscheduler]= PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, + /* 330: */ + [SYS_sched_getscheduler]= PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, + [SYS_sched_yield] = PLEDGE_NONE, + [SYS_sched_get_priority_max] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, + [SYS_sched_get_priority_min] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, + [SYS_sched_rr_get_interval] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, + [SYS_utrace] = PLEDGE_KLD, + [SYS_kldsym] = PLEDGE_KLD, + [SYS_jail] = PLEDGE_PROC, + [SYS_nnpfs_syscall] = PLEDGE_KLD, + /* 340: */ + [SYS_sigprocmask] = PLEDGE_STDIO, + [SYS_sigsuspend] = PLEDGE_STDIO, + [SYS_sigpending] = PLEDGE_STDIO, + [SYS_sigtimedwait] = PLEDGE_STDIO, + [SYS_sigwaitinfo] = PLEDGE_STDIO, + [SYS___acl_get_file] = PLEDGE_AND | PLEDGE_RPATH | PLEDGE_FATTR, + [SYS___acl_set_file] = PLEDGE_AND | PLEDGE_WPATH | PLEDGE_FATTR, + [SYS___acl_get_fd] = PLEDGE_FATTR, + /* 350: */ + [SYS___acl_set_fd] = PLEDGE_AND | PLEDGE_WPATH | PLEDGE_FATTR, + [SYS___acl_delete_file] = PLEDGE_AND | PLEDGE_CPATH | PLEDGE_FATTR, + [SYS___acl_delete_fd] = PLEDGE_AND | PLEDGE_CPATH | PLEDGE_FATTR, + [SYS___acl_aclcheck_file] = PLEDGE_AND | PLEDGE_RPATH | PLEDGE_FATTR, + [SYS___acl_aclcheck_fd] = PLEDGE_AND | PLEDGE_RPATH | PLEDGE_FATTR, + [SYS_extattrctl] = PLEDGE_STDIO, // TODO + [SYS_extattr_set_file] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_FATTR, + [SYS_extattr_get_file] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_RPATH, + [SYS_extattr_delete_file] = PLEDGE_CPATH, + [SYS_aio_waitcomplete] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, + /* 360: */ + [SYS_getresuid] = PLEDGE_STDIO, + [SYS_getresgid] = PLEDGE_STDIO, + [SYS_kqueue] = PLEDGE_STDIO, /* TODO */ + [SYS_freebsd11_kevent] = PLEDGE_STDIO, /* 363, TODO */ + [SYS_extattr_set_fd] = PLEDGE_AND | PLEDGE_FATTR | PLEDGE_WPATH, + [SYS_extattr_get_fd] = PLEDGE_RPATH, + [SYS_extattr_delete_fd] = PLEDGE_AND | PLEDGE_FATTR | PLEDGE_CPATH, + [SYS___setugid] = PLEDGE_ID, + [SYS_eaccess] = PLEDGE_RPATH, + [SYS_afs3_syscall] = PLEDGE_STDIO, /* TODO */ + [SYS_nmount] = PLEDGE_DEVICE, + [SYS___mac_get_proc] = PLEDGE_STDIO, + [SYS___mac_set_proc] = PLEDGE_STDIO, /* TODO */ + [SYS___mac_get_fd] = PLEDGE_STDIO, + [SYS___mac_get_file] = PLEDGE_FATTR, + [SYS___mac_set_fd] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_FATTR, /* TODO */ + [SYS___mac_set_file] = PLEDGE_FATTR, /* TODO */ + /* 390: */ + [SYS_kenv] = PLEDGE_STDIO, + [SYS_lchflags] = PLEDGE_FATTR, + [SYS_uuidgen] = PLEDGE_STDIO, // leaks mac address so... + [SYS_sendfile] = PLEDGE_STDIO, + [SYS_mac_syscall] = PLEDGE_STDIO, /* TODO */ + [SYS_freebsd11_getfsstat] = PLEDGE_STDIO, + [SYS_freebsd11_statfs] = PLEDGE_STDIO, + [SYS_freebsd11_fstatfs] = PLEDGE_STDIO, + [SYS_freebsd11_fhstatfs] = PLEDGE_STDIO, + /* 400: */ + [SYS_ksem_close] = PLEDGE_STDIO, + [SYS_ksem_post] = PLEDGE_STDIO, /* TODO */ + [SYS_ksem_wait] = PLEDGE_STDIO, + [SYS_ksem_trywait] = PLEDGE_STDIO, + [SYS_ksem_init] = PLEDGE_STDIO, + [SYS_ksem_open] = PLEDGE_STDIO, + [SYS_ksem_unlink] = PLEDGE_STDIO, + [SYS_ksem_getvalue] = PLEDGE_STDIO, + [SYS_ksem_destroy] = PLEDGE_STDIO, + [SYS___mac_get_pid] = PLEDGE_STDIO, + /* 410: */ + [SYS___mac_get_link] = PLEDGE_FATTR, + [SYS___mac_set_link] = PLEDGE_FATTR, + [SYS_extattr_set_link] = PLEDGE_CPATH, + [SYS_extattr_get_link] = PLEDGE_RPATH, + [SYS_extattr_delete_link] = PLEDGE_CPATH, + [SYS___mac_execve] = PLEDGE_FATTR, /* TODO */ + [SYS_sigaction] = PLEDGE_STDIO, + [SYS_sigreturn] = PLEDGE_STDIO, + [SYS_getcontext] = PLEDGE_STDIO, + [SYS_setcontext] = PLEDGE_STDIO, + [SYS_swapcontext] = PLEDGE_STDIO, + [SYS___acl_get_link] = PLEDGE_FATTR, + [SYS___acl_set_link] = PLEDGE_FATTR, + [SYS___acl_delete_link] = PLEDGE_FATTR, + [SYS___acl_aclcheck_link] = PLEDGE_FATTR, + [SYS_sigwait] = PLEDGE_STDIO, + /* 430: */ + [SYS_thr_create] = PLEDGE_PROC, // TODO + [SYS_thr_exit] = PLEDGE_NONE, + [SYS_thr_self] = PLEDGE_STDIO, + [SYS_thr_kill] = PLEDGE_PROC, + [SYS_jail_attach] = PLEDGE_STDIO, // TODO + [SYS_extattr_list_fd] = PLEDGE_STDIO, /* TODO */ + [SYS_extattr_list_file] = PLEDGE_STDIO, + [SYS_extattr_list_link] = PLEDGE_STDIO, + [SYS_ksem_timedwait] = PLEDGE_STDIO, + [SYS_thr_suspend] = PLEDGE_PROC, + [SYS_thr_wake] = PLEDGE_PROC, + [SYS_kldunloadf] = PLEDGE_KLD, + [SYS_audit] = PLEDGE_STDIO, + [SYS_auditon] = PLEDGE_STDIO, + [SYS_getauid] = PLEDGE_STDIO, + [SYS_setauid] = PLEDGE_ID, + [SYS_getaudit] = PLEDGE_STDIO, + /* 450: */ + [SYS_setaudit] = PLEDGE_STDIO, + [SYS_getaudit_addr] = PLEDGE_STDIO, + [SYS_setaudit_addr] = PLEDGE_STDIO, + [SYS_auditctl] = PLEDGE_AND | PLEDGE_WPATH | PLEDGE_DEVICE, /* TODO */ + [SYS__umtx_op] = PLEDGE_STDIO, + [SYS_thr_new] = PLEDGE_STDIO, + [SYS_sigqueue] = PLEDGE_STDIO, + [SYS_kmq_open] = PLEDGE_STDIO, + [SYS_kmq_setattr] = PLEDGE_STDIO, + [SYS_kmq_timedreceive] = PLEDGE_STDIO, + /* 460: */ + [SYS_kmq_timedsend] = PLEDGE_STDIO, + [SYS_kmq_notify] = PLEDGE_STDIO, + [SYS_kmq_unlink] = PLEDGE_STDIO, + [SYS_abort2] = PLEDGE_STDIO, + [SYS_thr_set_name] = PLEDGE_STDIO, + [SYS_aio_fsync] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, + [SYS_rtprio_thread] = PLEDGE_STDIO, + [SYS_sctp_peeloff] = PLEDGE_INET, /* TODO ... */ + [SYS_sctp_generic_sendmsg] = PLEDGE_INET, + [SYS_sctp_generic_sendmsg_iov] = PLEDGE_INET, + [SYS_sctp_generic_recvmsg] = PLEDGE_INET, + [SYS_pread] = PLEDGE_NONE, + [SYS_pwrite] = PLEDGE_NONE, + [SYS_mmap] = PLEDGE_STDIO, + [SYS_lseek] = PLEDGE_STDIO, // TODO consider append-only? + [SYS_truncate] = PLEDGE_WPATH, + /* 480: */ + [SYS_ftruncate] = PLEDGE_NONE, /* that is openat's problem */ + [SYS_thr_kill2] = PLEDGE_STDIO, +#ifdef SYS_freebsd12_shm_open + [SYS_freebsd12_shm_open] = PLEDGE_RPATH | PLEDGE_WPATH, /* TODO */ +#elif SYS_shm_open + [SYS_shm_open] = PLEDGE_RPATH | PLEDGE_WPATH, /* TODO */ +#endif + [SYS_shm_unlink] = PLEDGE_CPATH, + [SYS_cpuset] = PLEDGE_STDIO, + [SYS_cpuset_setid] = PLEDGE_STDIO, + [SYS_cpuset_getid] = PLEDGE_STDIO, + [SYS_cpuset_getaffinity] = PLEDGE_STDIO, + [SYS_cpuset_setaffinity] = PLEDGE_STDIO, + [SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_CPATH | PLEDGE_NOLEARN, // TODO this should probably softfail? + /* 490: */ + [SYS_fchmodat] = PLEDGE_FATTR, + [SYS_fchownat] = PLEDGE_CHOWN, // chown + [SYS_fexecve] = PLEDGE_PROC, // TODO openbsd have PLEDGE_EXEC because they distinguish between fork an execve +#ifdef SYS_freebsd11_fstatat + /* this is a bit ugly, we have a definition for + SYS_fstatat further below. would be nice to have + them in the same place. TODO */ + [SYS_freebsd11_fstatat] = PLEDGE_RPATH, // TODO also STDIO +#endif + [SYS_futimesat] = PLEDGE_FATTR, + [SYS_linkat] = PLEDGE_CPATH, + [SYS_mkdirat] = PLEDGE_CPATH, + [SYS_mkfifoat] = PLEDGE_CPATH, +#ifdef SYS_freebsd11_mknodat + [SYS_freebsd11_mknodat] = PLEDGE_AND | PLEDGE_CPATH | PLEDGE_DEVICE, +#else + [SYS_mknodat] = PLEDGE_AND | PLEDGE_CPATH | PLEDGE_DEVICE, +#endif + [SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_CPATH | PLEDGE_NOLEARN, + /* 500: */ + [SYS_readlinkat] = PLEDGE_RPATH, + [SYS_renameat] = PLEDGE_CPATH, + [SYS_symlinkat] = PLEDGE_CPATH, + [SYS_unlinkat] = PLEDGE_CPATH, + [SYS_posix_openpt] = PLEDGE_STDIO, // TODO pledge_TTY ? + [SYS_gssd_syscall] = PLEDGE_STDIO, /* TODO */ + [SYS_jail_get] = PLEDGE_PROC, // TODO consider pledge flag for this + [SYS_jail_set] = PLEDGE_PROC, + [SYS_jail_remove] = PLEDGE_PROC, +#ifdef SYS_closefrom + [SYS_closefrom] = PLEDGE_STDIO, +#endif + /* 510: */ + [SYS___semctl] = PLEDGE_STDIO, + [SYS_msgctl] = PLEDGE_STDIO, + [SYS_shmctl] = PLEDGE_STDIO, + [SYS_lpathconf] = PLEDGE_STDIO, // TODO + [SYS___cap_rights_get] = PLEDGE_CAPSICUM, // TODO? + [SYS_cap_enter] = PLEDGE_CAPSICUM, + [SYS_cap_getmode] = PLEDGE_CAPSICUM, + [SYS_pdfork] = PLEDGE_PROC, + [SYS_pdkill] = PLEDGE_PROC, + /* 520: */ + [SYS_pdgetpid] = PLEDGE_AND | PLEDGE_STDIO | PLEDGE_PROC, + [SYS_pselect] = PLEDGE_STDIO, + [SYS_getloginclass] = PLEDGE_STDIO, + [SYS_setloginclass] = PLEDGE_STDIO, + [SYS_rctl_get_racct] = PLEDGE_STDIO, + [SYS_rctl_get_rules] = PLEDGE_STDIO, + [SYS_rctl_get_limits] = PLEDGE_STDIO, + [SYS_rctl_add_rule] = PLEDGE_STDIO, + [SYS_rctl_remove_rule] = PLEDGE_STDIO, + /* 530: */ + [SYS_posix_fallocate] = PLEDGE_STDIO, + [SYS_posix_fadvise] = PLEDGE_STDIO, + [SYS_wait6] = PLEDGE_STDIO, + [SYS_cap_rights_limit] = PLEDGE_CAPSICUM, + [SYS_cap_ioctls_limit] = PLEDGE_CAPSICUM, + [SYS_cap_ioctls_get] = PLEDGE_CAPSICUM, + [SYS_cap_fcntls_limit] = PLEDGE_CAPSICUM, + [SYS_cap_fcntls_get] = PLEDGE_CAPSICUM, + [SYS_bindat] = PLEDGE_UNIX, + [SYS_connectat] = PLEDGE_UNIX, + /* 540: */ + [SYS_chflagsat] = PLEDGE_FATTR, + [SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX, + [SYS_pipe2] = PLEDGE_STDIO, + [SYS_aio_mlock] = PLEDGE_AND | PLEDGE_AIO | PLEDGE_STDIO, + [SYS_procctl] = PLEDGE_PROC, + [SYS_ppoll] = PLEDGE_STDIO, + [SYS_futimens] = PLEDGE_FATTR, + [SYS_utimensat] = PLEDGE_FATTR, + /* 550: */ + [SYS_fdatasync] = PLEDGE_STDIO, +/* at this point twenty new syscalls were added (around 13-CURRENT).*/ +#ifdef SYS_fstat + [SYS_fstat] = PLEDGE_RPATH, /* */ +#endif +#ifdef SYS_fstatat + [SYS_fstatat] = PLEDGE_RPATH, /* */ +#endif +#ifdef SYS_fhstat + [SYS_fhstat] = PLEDGE_RPATH, /* */ +#endif +#ifdef SYS_getdirentries + [SYS_getdirentries] = PLEDGE_RPATH, +#endif +#ifdef SYS_statfs + [SYS_statfs] = PLEDGE_RPATH, /* */ +#endif +#ifdef SYS_fstatfs + [SYS_fstatfs] = PLEDGE_RPATH, /* */ +#endif +#ifdef SYS_getfsstat + [SYS_getfsstat] = PLEDGE_RPATH, /* */ +#endif +#ifdef SYS_fhstatfs + [SYS_fhstatfs] = PLEDGE_RPATH, /* */ +#endif +#ifdef SYS_mknodat + [SYS_mknodat] = PLEDGE_AND | PLEDGE_DEVICE | PLEDGE_CPATH, /* */ +#endif +/* 560: */ +#ifdef SYS_kevent + [SYS_kevent] = PLEDGE_STDIO, /* */ +#endif +#ifdef SYS_cpuset_getdomain + [SYS_cpuset_getdomain] = PLEDGE_STDIO, /* */ +#endif +#ifdef SYS_cpuset_setdomain + [SYS_cpuset_setdomain] = PLEDGE_STDIO, /* */ +#endif +#ifdef SYS_getrandom + [SYS_getrandom] = PLEDGE_NONE, /* */ +#endif +#ifdef SYS_getfhat + [SYS_getfhat] = PLEDGE_STDIO, /* */ +#endif +#ifdef SYS_fhlink + [SYS_fhlink] = PLEDGE_CPATH, /* */ +#endif +#ifdef SYS_fhlinkat + [SYS_fhlinkat] = PLEDGE_CPATH, /* */ +#endif +#ifdef SYS_fhreadlink + [SYS_fhreadlink] = PLEDGE_RPATH, /* */ +#endif +#ifdef SYS_funlinkat + [SYS_funlinkat] = PLEDGE_CPATH, /* */ +#endif +#ifdef SYS_copy_file_range + [SYS_copy_file_range] = PLEDGE_STDIO, /* */ +#endif +/* 570: */ +#ifdef SYS___sysctlbyname + [SYS___sysctlbyname] = PLEDGE_SYSCTL, /* */ +#endif +#ifdef SYS_shm_open2 + [SYS_shm_open2] = PLEDGE_STDIO, /* */ +#endif +#ifdef SYS_shm_rename + [SYS_shm_rename] = PLEDGE_STDIO, /* */ +#endif +#ifdef SYS_sigfastblock + [SYS_sigfastblock] = PLEDGE_STDIO, /* */ +#endif +/* 574: */ +#ifdef SYS___realpathat + [SYS___realpathat] = PLEDGE_RPATH, /* 574 */ +#endif +#ifdef SYS_close_range + [SYS_close_range] = PLEDGE_STDIO, /* 575 */ +#endif +#ifdef SYS_rpctls_syscall + [SYS_rpctls_syscall] = PLEDGE_STDIO, /* 576 */ +#endif +#ifdef SYS___specialfd + [SYS___specialfd] = PLEDGE_STDIO, /* 577 */ +#endif +#ifdef SYS_aio_writev + [SYS_aio_writev] = PLEDGE_AND | PLEDGE_AIO, /* 578 */ +#endif +#ifdef SYS_aio_readv + [SYS_aio_readv] = PLEDGE_AND | PLEDGE_AIO, /* 579 */ +#endif +#ifdef SYS_sched_getcpu + [SYS_sched_getcpu] = PLEDGE_STDIO, /* 581 */ +#endif +#ifdef SYS_swapoff + [SYS_swapoff] = PLEDGE_KLD, /* 582 */ +#endif +}; +_Static_assert(583 == SYS_MAXSYSCALL, "new syscalls added to sys/sys/syscall.h, hbsd_pledge.c needs to be updated. TODO would it make sense to remove this static assertion and instead display a helpful message on boot + allow the operator to declare/override the defaults via tunables to prevent situations where people can't boot after upgrading?"); +/* + * Hook used to determine whether a given syscall should be called or not. + * Main caller is sys/kern/subr_syscall.c:syscallenter + */ +int inline +pledge_syscall(struct thread * thread, const int syscall_no) +{ + if (syscall_no < 0 || SYS_MAXSYSCALL <= syscall_no) { + /* to prevent out-of-bounds access to pledge_permission_map, + * default to requiring all privileges in this case, + * (TODO and soft-failing would be good) + * (prevents breakage when enforcing is off and new + * syscalls have been added): */ + return (pledge_check_bitmap(thread, + PLEDGE_AND | PLEDGE_WILDCARD)); + } + + return (pledge_check_bitmap(thread, pledge_permission_map[syscall_no])); +} + +#ifdef HBSD_PLEDGE_MAC +// HBSD_PLEDGE_MAC is not defined, this is commented out because the MAC stuff is rean't really implemented yety +/* + * TODO here we define hooks for the mac framework, which alleviates + * the need to add hooks manually everywhere. + * see https://www.freebsd.org/doc/en_US.ISO8859-1/books/arch-handbook/mac-entry-point-reference.html#mac-access-control-checks + */ +static struct mac_policy_ops mac_pledge_ops = +{ + /* + * sys/security/mac_stub/mac_stub.c + */ + // this takes an extra argument: .mpo_syscall = pledge_syscall, + // .mpo_vnode_check_open / .mpo_check_vnode_access(struct ucred *cred, struct vnode *vp, struct label *label, int flags) + // .mpo_check_socket_connect + // .mpo_check_system_sysctl + NULL +}; + +MAC_POLICY_SET(&mac_pledge_ops, mac_pledge, "HardenedBSD MAC/pledge", + MPC_LOADTIME_FLAG_NOTLATE, NULL); +#endif /* HBSD_PLEDGE_MAC */ + +#endif /* ifdef HBSD_PLEDGE */ diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 486854b9068a..e26be55a9dc9 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,170 +1,172 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1995 Terrence R. Lambert * All rights reserved. * * Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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_ddb.h" #include "opt_kdb.h" #include "opt_init_path.h" #include "opt_pax.h" #include "opt_verbose_sysinit.h" +#include "opt_pledge.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 #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 void mi_startup(void); /* Should be elsewhere */ /* Components of the first process -- never freed. */ static struct session session0; static struct pgrp pgrp0; struct proc proc0; struct thread0_storage thread0_st __aligned(32) = { .t0st_thread = { /* * thread0.td_pflags is set with TDP_NOFAULTING to * short-cut the vm page fault handler until it is * ready. It is cleared in vm_init() after VM * initialization. */ .td_pflags = TDP_NOFAULTING, }, }; struct vmspace vmspace0; struct proc *initproc; int linux_alloc_current_noop(struct thread *td __unused, int flags __unused) { return (0); } int (*lkpi_alloc_current)(struct thread *, int) = linux_alloc_current_noop; #ifndef BOOTHOWTO #define BOOTHOWTO 0 #endif int boothowto = BOOTHOWTO; /* initialized so that it can be patched */ SYSCTL_INT(_debug, OID_AUTO, boothowto, CTLFLAG_RD, &boothowto, 0, "Boot control flags, passed from loader"); #ifndef BOOTVERBOSE #define BOOTVERBOSE 0 #endif int bootverbose = BOOTVERBOSE; SYSCTL_INT(_debug, OID_AUTO, bootverbose, CTLFLAG_RW, &bootverbose, 0, "Control the output of verbose kernel messages"); #ifdef VERBOSE_SYSINIT /* * We'll use the defined value of VERBOSE_SYSINIT from the kernel config to * dictate the default VERBOSE_SYSINIT behavior. Significant values for this * option and associated tunable are: * - 0, 'compiled in but silent by default' * - 1, 'compiled in but verbose by default' (default) */ int verbose_sysinit = VERBOSE_SYSINIT; #endif #ifdef INVARIANTS FEATURE(invariants, "Kernel compiled with INVARIANTS, may affect performance"); #endif /* * The sysinit linker set compiled into the kernel. These are placed onto the * sysinit list by mi_startup; sysinit_add can add (e.g., from klds) additional * sysinits to the linked list but the linker set here does not change. */ SET_DECLARE(sysinit_set, struct sysinit); /* * The sysinit lists. Items are moved to sysinit_done_list when done. */ static STAILQ_HEAD(sysinitlist, sysinit) sysinit_list; static struct sysinitlist sysinit_done_list = @@ -439,200 +441,203 @@ struct sysentvec null_sysvec = { .sv_psstrings = PS_STRINGS, .sv_psstringssz = sizeof(struct ps_strings), .sv_stackprot = VM_PROT_ALL, .sv_copyout_strings = NULL, .sv_setregs = NULL, .sv_fixlimit = NULL, .sv_maxssiz = NULL, .sv_flags = 0, .sv_set_syscall_retval = null_set_syscall_retval, .sv_fetch_syscall_args = null_fetch_syscall_args, .sv_syscallnames = NULL, .sv_schedtail = NULL, .sv_thread_detach = NULL, .sv_trap = NULL, .sv_pax_aslr_init = NULL, .sv_set_fork_retval = null_set_fork_retval, .sv_regset_begin = NULL, .sv_regset_end = NULL, }; /* * The two following SYSINIT's are proc0 specific glue code. I am not * convinced that they can not be safely combined, but their order of * operation has been maintained as the same as the original init_main.c * for right now. */ /* ARGSUSED*/ static void proc0_init(void *dummy __unused) { struct proc *p; struct thread *td; struct ucred *newcred; struct uidinfo tmpuinfo; struct loginclass tmplc = { .lc_name = "", }; vm_paddr_t pageablemem; int i; GIANT_REQUIRED; p = &proc0; td = &thread0; /* * Initialize magic number and osrel. */ p->p_magic = P_MAGIC; p->p_osrel = osreldate; /* * Initialize thread and process structures. */ procinit(); /* set up proc zone */ threadinit(); /* set up UMA zones */ /* * Initialise scheduler resources. * Add scheduler specific parts to proc, thread as needed. */ schedinit(); /* scheduler gets its house in order */ /* * Create process 0. */ LIST_INSERT_HEAD(&allproc, p, p_list); LIST_INSERT_HEAD(PIDHASH(0), p, p_hash); mtx_init(&pgrp0.pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK); sx_init(&pgrp0.pg_killsx, "killpg racer"); p->p_pgrp = &pgrp0; LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); LIST_INIT(&pgrp0.pg_members); LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); pgrp0.pg_session = &session0; mtx_init(&session0.s_mtx, "session", NULL, MTX_DEF); refcount_init(&session0.s_count, 1); session0.s_leader = p; p->p_sysent = &null_sysvec; p->p_flag = P_SYSTEM | P_INMEM | P_KPROC; p->p_flag2 = 0; p->p_state = PRS_NORMAL; #ifdef PAX p->p_pax = PAX_NOTE_ALL_DISABLED; #endif p->p_usrstack = USRSTACK; p->p_psstrings = PS_STRINGS; p->p_klist = knlist_alloc(&p->p_mtx); STAILQ_INIT(&p->p_ktr); p->p_nice = NZERO; td->td_tid = THREAD0_TID; tidhash_add(td); TD_SET_STATE(td, TDS_RUNNING); td->td_pri_class = PRI_TIMESHARE; td->td_user_pri = PUSER; td->td_base_user_pri = PUSER; td->td_lend_user_pri = PRI_MAX; td->td_priority = PVM; td->td_base_pri = PVM; +#ifdef HBSD_PLEDGE + td->td_pledge = PLEDGE_WILDCARD; +#endif td->td_oncpu = curcpu; td->td_flags = TDF_INMEM; td->td_pflags = TDP_KTHREAD; td->td_cpuset = cpuset_thread0(); #ifdef PAX td->td_pax = PAX_NOTE_ALL_DISABLED; #endif td->td_domain.dr_policy = td->td_cpuset->cs_domain; prison0_init(); p->p_peers = 0; p->p_leader = p; p->p_reaper = p; p->p_treeflag |= P_TREE_REAPER; LIST_INIT(&p->p_reaplist); strncpy(p->p_comm, "kernel", sizeof (p->p_comm)); strncpy(td->td_name, "kernel", sizeof (td->td_name)); callout_init_mtx(&p->p_itcallout, &p->p_mtx, 0); callout_init_mtx(&p->p_limco, &p->p_mtx, 0); callout_init(&td->td_slpcallout, 1); TAILQ_INIT(&p->p_kqtim_stop); /* Create credentials. */ newcred = crget(); newcred->cr_ngroups = 1; /* group 0 */ /* A hack to prevent uifind from tripping over NULL pointers. */ curthread->td_ucred = newcred; tmpuinfo.ui_uid = 1; newcred->cr_uidinfo = newcred->cr_ruidinfo = &tmpuinfo; newcred->cr_uidinfo = uifind(0); newcred->cr_ruidinfo = uifind(0); newcred->cr_loginclass = &tmplc; newcred->cr_loginclass = loginclass_find("default"); /* End hack. creds get properly set later with thread_cow_get_proc */ curthread->td_ucred = NULL; newcred->cr_prison = &prison0; newcred->cr_users++; /* avoid assertion failure */ p->p_ucred = crcowget(newcred); newcred->cr_users--; crfree(newcred); #ifdef AUDIT audit_cred_kproc0(newcred); #endif #ifdef MAC mac_cred_create_kproc0(newcred); #endif /* Create sigacts. */ p->p_sigacts = sigacts_alloc(); /* Initialize signal state for process 0. */ siginit(&proc0); /* Create the file descriptor table. */ p->p_pd = pdinit(NULL, false); p->p_fd = fdinit(); p->p_fdtol = NULL; /* Create the limits structures. */ p->p_limit = lim_alloc(); for (i = 0; i < RLIM_NLIMITS; i++) p->p_limit->pl_rlimit[i].rlim_cur = p->p_limit->pl_rlimit[i].rlim_max = RLIM_INFINITY; p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_cur = p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_max = maxfiles; p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_cur = p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_max = maxproc; p->p_limit->pl_rlimit[RLIMIT_DATA].rlim_cur = dfldsiz; p->p_limit->pl_rlimit[RLIMIT_DATA].rlim_max = maxdsiz; p->p_limit->pl_rlimit[RLIMIT_STACK].rlim_cur = dflssiz; p->p_limit->pl_rlimit[RLIMIT_STACK].rlim_max = maxssiz; /* Cast to avoid overflow on i386/PAE. */ pageablemem = ptoa((vm_paddr_t)vm_free_count()); p->p_limit->pl_rlimit[RLIMIT_RSS].rlim_cur = p->p_limit->pl_rlimit[RLIMIT_RSS].rlim_max = pageablemem; p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = pageablemem / 3; p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_max = pageablemem; p->p_cpulimit = RLIM_INFINITY; PROC_LOCK(p); thread_cow_get_proc(td, p); PROC_UNLOCK(p); /* Initialize resource accounting structures. */ racct_create(&p->p_racct); p->p_stats = pstats_alloc(); /* Allocate a prototype map so we have something to fork. */ p->p_vmspace = &vmspace0; refcount_init(&vmspace0.vm_refcnt, 1); pmap_pinit0(vmspace_pmap(&vmspace0)); /* * proc0 is not expected to enter usermode, so there is no special * handling for sv_minuser here, like is done for exec_new_vmspace(). */ vm_map_init(&vmspace0.vm_map, vmspace_pmap(&vmspace0), p->p_sysent->sv_minuser, p->p_sysent->sv_maxuser); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 9bb977961690..d42e4b86603c 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,248 +1,253 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 1993, David Greenman * 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 "opt_capsicum.h" #include "opt_hwpmc_hooks.h" #include "opt_hwt_hooks.h" #include "opt_ktrace.h" #include "opt_pax.h" +#include "opt_pledge.h" #include "opt_vm.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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTRACE #include #endif #include #include #include #include #include #include #include #include #include #ifdef HWPMC_HOOKS #include #endif +#ifdef HBSD_PLEDGE +#include +#endif + #ifdef HWT_HOOKS #include #endif #include #include #ifdef KDTRACE_HOOKS #include dtrace_execexit_func_t dtrace_fasttrap_exec; #endif SDT_PROVIDER_DECLARE(proc); SDT_PROBE_DEFINE1(proc, , , exec, "char *"); SDT_PROBE_DEFINE1(proc, , , exec__failure, "int"); SDT_PROBE_DEFINE1(proc, , , exec__success, "char *"); MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); int coredump_pack_fileinfo = 1; SYSCTL_INT(_kern, OID_AUTO, coredump_pack_fileinfo, CTLFLAG_RWTUN, &coredump_pack_fileinfo, 0, "Enable file path packing in 'procstat -f' coredump notes"); int coredump_pack_vmmapinfo = 1; SYSCTL_INT(_kern, OID_AUTO, coredump_pack_vmmapinfo, CTLFLAG_RWTUN, &coredump_pack_vmmapinfo, 0, "Enable file path packing in 'procstat -v' coredump notes"); static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS); static int sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS); static int sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS); static int do_execve(struct thread *td, struct image_args *args, struct mac *mac_p, struct vmspace *oldvmspace); /* XXX This should be vm_size_t. */ SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD| CTLFLAG_CAPRD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_ps_strings, "LU", "Location of process' ps_strings structure"); /* XXX This should be vm_size_t. */ SYSCTL_PROC(_kern, KERN_USRSTACK, usrstack, CTLTYPE_ULONG|CTLFLAG_RD| CTLFLAG_CAPRD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_usrstack, "LU", "Top of process stack"); SYSCTL_PROC(_kern, OID_AUTO, stackprot, CTLTYPE_INT|CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_stackprot, "I", "Stack memory permissions"); u_long ps_arg_cache_limit = PAGE_SIZE / 16; -SYSCTL_ULONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, +SYSCTL_ULONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, &ps_arg_cache_limit, 0, "Process' command line characters cache limit"); static int disallow_high_osrel; SYSCTL_INT(_kern, OID_AUTO, disallow_high_osrel, CTLFLAG_RW, &disallow_high_osrel, 0, "Disallow execution of binaries built for higher version of the world"); static int core_dump_can_intr = 1; SYSCTL_INT(_kern, OID_AUTO, core_dump_can_intr, CTLFLAG_RWTUN, &core_dump_can_intr, 0, "Core dumping interruptible with SIGKILL"); static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS) { struct proc *p; vm_offset_t ps_strings; p = curproc; #ifdef SCTL_MASK32 if (req->flags & SCTL_MASK32) { unsigned int val; val = (unsigned int)PROC_PS_STRINGS(p); return (SYSCTL_OUT(req, &val, sizeof(val))); } #endif ps_strings = PROC_PS_STRINGS(p); return (SYSCTL_OUT(req, &ps_strings, sizeof(ps_strings))); } static int sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS) { struct proc *p; int error; p = curproc; #ifdef SCTL_MASK32 if (req->flags & SCTL_MASK32) { unsigned int val; val = (unsigned int)p->p_usrstack; error = SYSCTL_OUT(req, &val, sizeof(val)); } else #endif error = SYSCTL_OUT(req, &p->p_usrstack, sizeof(p->p_usrstack)); return (error); } static int sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS) { struct proc *p; p = curproc; return (SYSCTL_OUT(req, &p->p_sysent->sv_stackprot, sizeof(p->p_sysent->sv_stackprot))); } /* * Each of the items is a pointer to a `const struct execsw', hence the * double pointer here. */ static const struct execsw **execsw; #ifndef _SYS_SYSPROTO_H_ struct execve_args { char *fname; char **argv; char **envv; }; #endif int sys_execve(struct thread *td, struct execve_args *uap) { struct image_args args; struct vmspace *oldvmspace; int error; error = pre_execve(td, &oldvmspace); if (error != 0) return (error); error = exec_copyin_args(&args, uap->fname, uap->argv, uap->envv); if (error == 0) error = kern_execve(td, &args, NULL, oldvmspace); post_execve(td, error, oldvmspace); AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td); return (error); } #ifndef _SYS_SYSPROTO_H_ struct fexecve_args { int fd; char **argv; char **envv; }; #endif @@ -467,200 +472,206 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p, #endif SDT_PROBE1(proc, , , exec, args->fname); interpret: if (args->fname != NULL) { #ifdef CAPABILITY_MODE if (CAP_TRACING(td)) ktrcapfail(CAPFAIL_NAMEI, args->fname); /* * While capability mode can't reach this point via direct * path arguments to execve(), we also don't allow * interpreters to be used in capability mode (for now). * Catch indirect lookups and return a permissions error. */ if (IN_CAPABILITY_MODE(td)) { error = ECAPMODE; goto exec_fail; } #endif /* * Translate the file name. namei() returns a vnode * pointer in ni_vp among other things. */ NDINIT(&nd, LOOKUP, ISOPEN | LOCKLEAF | LOCKSHARED | FOLLOW | AUDITVNODE1 | WANTPARENT, UIO_SYSSPACE, args->fname); error = namei(&nd); if (error) goto exec_fail; newtextvp = nd.ni_vp; newtextdvp = nd.ni_dvp; nd.ni_dvp = NULL; newbinname = malloc(nd.ni_cnd.cn_namelen + 1, M_PARGS, M_WAITOK); memcpy(newbinname, nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen); newbinname[nd.ni_cnd.cn_namelen] = '\0'; imgp->vp = newtextvp; /* * Do the best to calculate the full path to the image file. */ if (args->fname[0] == '/') { imgp->execpath = args->fname; } else { VOP_UNLOCK(imgp->vp); freepath_size = MAXPATHLEN; if (vn_fullpath_hardlink(newtextvp, newtextdvp, newbinname, nd.ni_cnd.cn_namelen, &imgp->execpath, &imgp->freepath, &freepath_size) != 0) imgp->execpath = args->fname; vn_lock(imgp->vp, LK_SHARED | LK_RETRY); } } else if (imgp->interpreter_vp) { /* * An image activator has already provided an open vnode */ newtextvp = imgp->interpreter_vp; imgp->interpreter_vp = NULL; if (vn_fullpath(newtextvp, &imgp->execpath, &imgp->freepath) != 0) imgp->execpath = args->fname; vn_lock(newtextvp, LK_SHARED | LK_RETRY); AUDIT_ARG_VNODE1(newtextvp); imgp->vp = newtextvp; } else { AUDIT_ARG_FD(args->fd); /* * If the descriptors was not opened with O_PATH, then * we require that it was opened with O_EXEC or * O_RDONLY. In either case, exec_check_permissions() * below checks _current_ file access mode regardless * of the permissions additionally checked at the * open(2). */ error = fgetvp_exec(td, args->fd, &cap_fexecve_rights, &newtextvp); if (error != 0) goto exec_fail; if (vn_fullpath(newtextvp, &imgp->execpath, &imgp->freepath) != 0) imgp->execpath = args->fname; vn_lock(newtextvp, LK_SHARED | LK_RETRY); AUDIT_ARG_VNODE1(newtextvp); imgp->vp = newtextvp; } /* * Check file permissions. Also 'opens' file and sets its vnode to * text mode. */ error = exec_check_permissions(imgp); if (error) goto exec_fail_dealloc; +#ifdef HBSD_PLEDGE + error = pledge_apply_extattr(td, imgp->vp); + if (error) + goto exec_fail_dealloc; +#endif + #ifdef PAX_CONTROL_EXTATTR error = pax_control_extattr_parse_flags(td, imgp); if (error) goto exec_fail_dealloc; #endif #ifdef PAX error = pax_elf(td, imgp); if (error) { goto exec_fail_dealloc; } #endif #ifdef PAX_HARDENING error = pax_enforce_tpe(td, imgp->vp, imgp->execpath); if (error) { pax_log_internal(td->td_proc, PAX_LOG_P_COMM | PAX_LOG_NO_P_PAX, "jid=%d,uid=%u,gid=%u: TPE violation", td->td_ucred->cr_prison->pr_id, td->td_ucred->cr_uid, td->td_ucred->cr_gid); goto exec_fail_dealloc; } #endif imgp->object = imgp->vp->v_object; if (imgp->object != NULL) vm_object_reference(imgp->object); error = exec_map_first_page(imgp); if (error) goto exec_fail_dealloc; imgp->proc->p_osrel = 0; imgp->proc->p_fctl0 = 0; imgp->proc->p_elf_brandinfo = NULL; /* * Implement image setuid/setgid. * * Determine new credentials before attempting image activators * so that it can be used by process_exec handlers to determine * credential/setid changes. * * Don't honor setuid/setgid if the filesystem prohibits it or if * the process is being traced. * * We disable setuid/setgid/etc in capability mode on the basis * that most setugid applications are not written with that * environment in mind, and will therefore almost certainly operate * incorrectly. In principle there's no reason that setugid * applications might not be useful in capability mode, so we may want * to reconsider this conservative design choice in the future. * * XXXMAC: For the time being, use NOSUID to also prohibit * transitions on the file system. */ credential_changing = false; credential_changing |= (attr.va_mode & S_ISUID) && oldcred->cr_uid != attr.va_uid; credential_changing |= (attr.va_mode & S_ISGID) && oldcred->cr_gid != attr.va_gid; #ifdef MAC will_transition = mac_vnode_execve_will_transition(oldcred, imgp->vp, interpvplabel, imgp) != 0; credential_changing |= will_transition; #endif /* Don't inherit PROC_PDEATHSIG_CTL value if setuid/setgid. */ if (credential_changing) imgp->proc->p_pdeathsig = 0; if (credential_changing && #ifdef CAPABILITY_MODE ((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) && #endif (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 && (p->p_flag & P_TRACED) == 0) { imgp->credential_setid = true; VOP_UNLOCK(imgp->vp); imgp->newcred = crdup(oldcred); if (attr.va_mode & S_ISUID) { euip = uifind(attr.va_uid); change_euid(imgp->newcred, euip); } vn_lock(imgp->vp, LK_SHARED | LK_RETRY); if (attr.va_mode & S_ISGID) change_egid(imgp->newcred, attr.va_gid); /* * Implement correct POSIX saved-id behavior. * * XXXMAC: Note that the current logic will save the * uid and gid if a MAC domain transition occurs, even * though maybe it shouldn't. */ change_svuid(imgp->newcred, imgp->newcred->cr_uid); change_svgid(imgp->newcred, imgp->newcred->cr_gid); } else { /* * Implement correct POSIX saved-id behavior. diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index 5d324a95dfac..6f146736f2f4 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -1,235 +1,246 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (C) 1994, David Greenman * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * Copyright (C) 2010 Konstantin Belousov * * This code is derived from software contributed to Berkeley by * the University of Utah, and William Jolitz. * * 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 the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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_capsicum.h" #include "opt_ktrace.h" +#include "opt_pledge.h" #include "opt_pax.h" #include #include #include #ifdef KTRACE #include #include #endif #include +#include #include static inline void syscallenter(struct thread *td) { struct proc *p; struct syscall_args *sa; struct sysent *se; int error; bool sy_thr_static, traced; VM_CNT_INC(v_syscall); p = td->td_proc; sa = &td->td_sa; td->td_pticks = 0; if (__predict_false(td->td_cowgen != atomic_load_int(&p->p_cowgen))) thread_cow_update(td); traced = (p->p_flag & P_TRACED) != 0; if (__predict_false(traced || td->td_dbgflags & TDB_USERWR)) { PROC_LOCK(p); MPASS((td->td_dbgflags & TDB_BOUNDARY) == 0); td->td_dbgflags &= ~TDB_USERWR; if (traced) td->td_dbgflags |= TDB_SCE; PROC_UNLOCK(p); } if ((td->td_pflags2 & TDP2_UEXTERR) != 0) td->td_pflags2 &= ~TDP2_EXTERR; error = (p->p_sysent->sv_fetch_syscall_args)(td); se = sa->callp; #ifdef KTRACE if (KTRPOINT(td, KTR_SYSCALL)) ktrsyscall(sa->code, se->sy_narg, sa->args); #endif KTR_START4(KTR_SYSC, "syscall", syscallname(p, sa->code), (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "arg0:%p", sa->args[0], "arg1:%p", sa->args[1], "arg2:%p", sa->args[2]); if (__predict_false(error != 0)) { td->td_errno = error; goto retval; } if (__predict_false(traced)) { PROC_LOCK(p); if (p->p_ptevents & PTRACE_SCE) ptracestop((td), SIGTRAP, NULL); PROC_UNLOCK(p); if ((td->td_dbgflags & TDB_USERWR) != 0) { /* * Reread syscall number and arguments if debugger * modified registers or memory. */ error = (p->p_sysent->sv_fetch_syscall_args)(td); se = sa->callp; #ifdef KTRACE if (KTRPOINT(td, KTR_SYSCALL)) ktrsyscall(sa->code, se->sy_narg, sa->args); #endif if (error != 0) { td->td_errno = error; goto retval; } } } #ifdef CAPABILITY_MODE /* * In capability mode, we only allow access to system calls * flagged with SYF_CAPENABLED. */ if ((se->sy_flags & SYF_CAPENABLED) == 0) { if (CAP_TRACING(td)) ktrcapfail(CAPFAIL_SYSCALL, NULL); if (IN_CAPABILITY_MODE(td)) { td->td_errno = error = ECAPMODE; goto retval; } } #endif +#ifdef HBSD_PLEDGE + /* when pledge is active*/ + error = pledge_syscall(td, sa->code); + if (error != 0) { + td->td_errno = error; // TODO should we override the error value here? + goto retval; + } +#endif + /* * Fetch fast sigblock value at the time of syscall entry to * handle sleepqueue primitives which might call cursig(). */ if (__predict_false(sigfastblock_fetch_always)) (void)sigfastblock_fetch(td); /* Let system calls set td_errno directly. */ KASSERT((td->td_pflags & TDP_NERRNO) == 0, ("%s: TDP_NERRNO set", __func__)); sy_thr_static = (se->sy_thrcnt & SY_THR_STATIC) != 0; if (__predict_false(AUDIT_SYSCALL_ENABLED() || SYSTRACE_ENABLED() || !sy_thr_static)) { if (!sy_thr_static) { error = syscall_thread_enter(td, &se); sy_thr_static = (se->sy_thrcnt & SY_THR_STATIC) != 0; if (error != 0) { td->td_errno = error; goto retval; } } #ifdef KDTRACE_HOOKS /* Give the syscall:::entry DTrace probe a chance to fire. */ if (__predict_false(se->sy_entry != 0)) (*systrace_probe_func)(sa, SYSTRACE_ENTRY, 0); #endif AUDIT_SYSCALL_ENTER(sa->code, td); error = (se->sy_call)(td, sa->args); /* Save the latest error return value. */ if (__predict_false((td->td_pflags & TDP_NERRNO) != 0)) td->td_pflags &= ~TDP_NERRNO; else td->td_errno = error; /* * Note that some syscall implementations (e.g., sys_execve) * will commit the audit record just before their final return. * These were done under the assumption that nothing of interest * would happen between their return and here, where we would * normally commit the audit record. These assumptions will * need to be revisited should any substantial logic be added * above. */ AUDIT_SYSCALL_EXIT(error, td); #ifdef KDTRACE_HOOKS /* Give the syscall:::return DTrace probe a chance to fire. */ if (__predict_false(se->sy_return != 0)) (*systrace_probe_func)(sa, SYSTRACE_RETURN, error ? -1 : td->td_retval[0]); #endif if (!sy_thr_static) syscall_thread_exit(td, se); } else { error = (se->sy_call)(td, sa->args); /* Save the latest error return value. */ if (__predict_false((td->td_pflags & TDP_NERRNO) != 0)) td->td_pflags &= ~TDP_NERRNO; else td->td_errno = error; } retval: KTR_STOP4(KTR_SYSC, "syscall", syscallname(p, sa->code), (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "error:%d", error, "retval0:%#lx", td->td_retval[0], "retval1:%#lx", td->td_retval[1]); if (__predict_false(traced)) { PROC_LOCK(p); td->td_dbgflags &= ~(TDB_SCE | TDB_BOUNDARY); PROC_UNLOCK(p); } (p->p_sysent->sv_set_syscall_retval)(td, error); if (error != 0 && (td->td_pflags2 & TDP2_UEXTERR) != 0) exterr_copyout(td); } static inline void syscallret(struct thread *td) { struct proc *p; struct syscall_args *sa; ksiginfo_t ksi; bool traced; KASSERT(td->td_errno != ERELOOKUP, ("ERELOOKUP not consumed syscall %d", td->td_sa.code)); p = td->td_proc; sa = &td->td_sa; if (__predict_false(td->td_errno == ENOTCAPABLE || td->td_errno == ECAPMODE)) { if ((trap_enotcap || (p->p_flag2 & P2_TRAPCAP) != 0) && IN_CAPABILITY_MODE(td)) { diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index c9780d9d6036..e347d9efac54 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,156 +1,160 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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_capsicum.h" #include "opt_ktrace.h" #include "opt_pax.h" +#include "opt_pledge.h" #define EXTERR_CATEGORY EXTERR_CAT_VFSSYSCALL #include #ifdef COMPAT_FREEBSD11 #include #endif #include #include #include #include #include #include #include #include #include #include #include +#include +#include +#include #include #ifdef KTRACE #include #endif #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 MALLOC_DEFINE(M_FADVISE, "fadvise", "posix_fadvise(2) information"); static int kern_chflagsat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, u_long flags, int atflag); static int setfflags(struct thread *td, struct vnode *, u_long); static int getutimes(const struct timeval *, enum uio_seg, struct timespec *); static int getutimens(const struct timespec *, enum uio_seg, struct timespec *, int *); static int setutimes(struct thread *td, struct vnode *, const struct timespec *, int, int); static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred, struct thread *td); static int kern_fhlinkat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, fhandle_t *fhp); static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, size_t count, struct thread *td); static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path, enum uio_seg segflag); uint64_t at2cnpflags(u_int at_flags, u_int mask) { uint64_t res; MPASS((at_flags & (AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)) != (AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)); res = 0; at_flags &= mask; if ((at_flags & AT_RESOLVE_BENEATH) != 0) res |= RBENEATH; if ((at_flags & AT_SYMLINK_FOLLOW) != 0) res |= FOLLOW; /* NOFOLLOW is pseudo flag */ if ((mask & AT_SYMLINK_NOFOLLOW) != 0) { res |= (at_flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : FOLLOW; } if ((mask & AT_EMPTY_PATH) != 0 && (at_flags & AT_EMPTY_PATH) != 0) res |= EMPTYPATH; return (res); } int kern_sync(struct thread *td) { struct mount *mp, *nmp; int save; mtx_lock(&mountlist_mtx); for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } 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); } mtx_lock(&mountlist_mtx); nmp = TAILQ_NEXT(mp, mnt_list); @@ -1146,200 +1150,206 @@ sys_open(struct thread *td, struct open_args *uap) #ifndef _SYS_SYSPROTO_H_ struct openat_args { int fd; char *path; int flag; int mode; }; #endif int sys_openat(struct thread *td, struct openat_args *uap) { AUDIT_ARG_FD(uap->fd); return (kern_openat(td, uap->fd, uap->path, UIO_USERSPACE, uap->flag, uap->mode)); } /* * Validate open(2) flags and convert access mode flags (O_RDONLY etc.) to their * in-kernel representations (FREAD etc.). */ static int openflags(int *flagsp) { int flags; flags = *flagsp; if ((flags & ~FUSERALLOWED) != 0) return (EINVAL); /* * Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags * may be specified. On the other hand, for O_PATH any mode * except O_EXEC is ignored. */ if ((flags & O_PATH) != 0) { flags &= ~O_ACCMODE; } else if ((flags & O_EXEC) != 0) { if ((flags & O_ACCMODE) != 0) return (EINVAL); } else if ((flags & O_ACCMODE) == O_ACCMODE) { return (EINVAL); } else { flags = FFLAGS(flags); } *flagsp = flags; return (0); } static void finit_open(struct file *fp, struct vnode *vp, int flags) { /* * Store the vnode, for any f_type. Typically, the vnode use count is * decremented by a direct call to vnops.fo_close() for files that * switched type. */ fp->f_vnode = vp; /* * If the file wasn't claimed by devfs or fifofs, bind it to the normal * vnode operations here. */ if (fp->f_ops == &badfileops) { KASSERT(vp->v_type != VFIFO || (flags & O_PATH) != 0, ("Unexpected fifo fp %p vp %p", fp, vp)); if ((flags & O_PATH) != 0) { finit(fp, (flags & FMASK) | (fp->f_flag & FKQALLOWED), DTYPE_VNODE, NULL, &path_fileops); } else { finit_vnode(fp, flags, NULL, &vnops); } } } /* * If fpp != NULL, opened file is not installed into the file * descriptor table, instead it is returned in *fpp. This is * incompatible with fdopen(), in which case we return EINVAL. */ static int openatfp(struct thread *td, int dirfd, const char *path, enum uio_seg pathseg, int flags, int mode, struct file **fpp) { struct proc *p; struct filedesc *fdp; struct pwddesc *pdp; struct file *fp; struct vnode *vp; struct filecaps *fcaps; struct nameidata nd; cap_rights_t rights; int cmode, error, indx; indx = -1; p = td->td_proc; fdp = p->p_fd; pdp = p->p_pd; +#ifdef HBSD_PLEDGE + error = pledge_openat(td, fd, path, flags, mode); + if (error != 0) + return (error); +#endif + AUDIT_ARG_FFLAGS(flags); AUDIT_ARG_MODE(mode); cap_rights_init_one(&rights, CAP_LOOKUP); flags_to_rights(flags, &rights); error = openflags(&flags); if (error != 0) return (error); /* * Allocate a file structure. The descriptor to reference it * is allocated and used by finstall_refed() below. */ error = falloc_noinstall(td, &fp); if (error != 0) return (error); /* Set the flags early so the finit in devfs can pick them up. */ fp->f_flag = flags & FMASK; cmode = ((mode & ~pdp->pd_cmask) & ALLPERMS) & ~S_ISTXT; NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | WANTIOCTLCAPS, pathseg, path, dirfd, &rights); td->td_dupfd = -1; /* XXX check for fdopen */ error = vn_open_cred(&nd, &flags, cmode, VN_OPEN_WANTIOCTLCAPS, td->td_ucred, fp); if (error != 0) { /* * If the vn_open replaced the method vector, something * wonderous happened deep below and we just pass it up * pretending we know what we do. */ if (error == ENXIO && fp->f_ops != &badfileops) { MPASS((flags & O_PATH) == 0); goto success; } /* * Handle special fdopen() case. bleh. * * Don't do this for relative (capability) lookups; we don't * understand exactly what would happen, and we don't think * that it ever should. */ if ((nd.ni_resflags & NIRES_STRICTREL) == 0 && (error == ENODEV || error == ENXIO) && td->td_dupfd >= 0) { MPASS(fpp == NULL); error = dupfdopen(td, fdp, td->td_dupfd, flags, error, &indx); if (error == 0) goto success; } goto bad; } td->td_dupfd = 0; NDFREE_PNBUF(&nd); vp = nd.ni_vp; finit_open(fp, vp, flags); VOP_UNLOCK(vp); if (flags & O_TRUNC) { error = fo_truncate(fp, 0, td->td_ucred, td); if (error != 0) goto bad; } success: if (fpp != NULL) { MPASS(error == 0); NDFREE_IOCTLCAPS(&nd); *fpp = fp; return (0); } /* * If we haven't already installed the FD (for dupfdopen), do so now. */ if (indx == -1) { #ifdef CAPABILITIES if ((nd.ni_resflags & NIRES_STRICTREL) != 0) fcaps = &nd.ni_filecaps; else #endif fcaps = NULL; if ((nd.ni_resflags & NIRES_BENEATH) != 0) flags |= O_RESOLVE_BENEATH; else flags &= ~O_RESOLVE_BENEATH; error = finstall_refed(td, fp, &indx, flags, fcaps); /* On success finstall_refed() consumes fcaps. */ if (error != 0) { goto bad; } } else { NDFREE_IOCTLCAPS(&nd); falloc_abort(td, fp); } td->td_retval[0] = indx; return (0); bad: @@ -3081,200 +3091,210 @@ kern_fchmodat(struct thread *td, int fd, const char *path, /* * Change mode of a file given a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fchmod_args { int fd; int mode; }; #endif int sys_fchmod(struct thread *td, struct fchmod_args *uap) { struct file *fp; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_MODE(uap->mode); error = fget(td, uap->fd, &cap_fchmod_rights, &fp); if (error != 0) return (error); error = fo_chmod(fp, uap->mode, td->td_ucred, td); fdrop(fp, td); return (error); } /* * Common implementation for chown(), lchown(), and fchown() */ int setfown(struct thread *td, struct ucred *cred, struct vnode *vp, uid_t uid, gid_t gid) { struct mount *mp; struct vattr vattr; int error; if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) return (error); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); VATTR_NULL(&vattr); vattr.va_uid = uid; vattr.va_gid = gid; #ifdef MAC error = mac_vnode_check_setowner(cred, vp, vattr.va_uid, vattr.va_gid); if (error == 0) #endif error = VOP_SETATTR(vp, &vattr, cred); VOP_UNLOCK(vp); vn_finished_write(mp); return (error); } /* * Set ownership given a path name. */ #ifndef _SYS_SYSPROTO_H_ struct chown_args { char *path; int uid; int gid; }; #endif int sys_chown(struct thread *td, struct chown_args *uap) { return (kern_fchownat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->uid, uap->gid, 0)); } #ifndef _SYS_SYSPROTO_H_ struct fchownat_args { int fd; const char * path; uid_t uid; gid_t gid; int flag; }; #endif int sys_fchownat(struct thread *td, struct fchownat_args *uap) { return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid, uap->gid, uap->flag)); } int kern_fchownat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, int uid, int gid, int flag) { struct nameidata nd; int error; if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH)) != 0) return (EINVAL); +#ifdef HBSD_PLEDGE + /* consult pledge syscall filtering mechanism. + * While the normal chown syscalls are handled by pledge_syscall(), + * validates access from other ABIs too:*/ + error = pledge_check_bitmap(td, PLEDGE_CHOWN); + if (error) { + return (error); + } +#endif + AUDIT_ARG_OWNER(uid, gid); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchown_rights); if ((error = namei(&nd)) != 0) return (error); NDFREE_PNBUF(&nd); error = setfown(td, td->td_ucred, nd.ni_vp, uid, gid); vrele(nd.ni_vp); return (error); } /* * Set ownership given a path name, do not cross symlinks. */ #ifndef _SYS_SYSPROTO_H_ struct lchown_args { char *path; int uid; int gid; }; #endif int sys_lchown(struct thread *td, struct lchown_args *uap) { return (kern_fchownat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->uid, uap->gid, AT_SYMLINK_NOFOLLOW)); } /* * Set ownership given a file descriptor. */ #ifndef _SYS_SYSPROTO_H_ struct fchown_args { int fd; int uid; int gid; }; #endif int sys_fchown(struct thread *td, struct fchown_args *uap) { struct file *fp; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_OWNER(uap->uid, uap->gid); error = fget(td, uap->fd, &cap_fchown_rights, &fp); if (error != 0) return (error); error = fo_chown(fp, uap->uid, uap->gid, td->td_ucred, td); fdrop(fp, td); return (error); } /* * Common implementation code for utimes(), lutimes(), and futimes(). */ static int getutimes(const struct timeval *usrtvp, enum uio_seg tvpseg, struct timespec *tsp) { struct timeval tv[2]; const struct timeval *tvp; int error; if (usrtvp == NULL) { vfs_timestamp(&tsp[0]); tsp[1] = tsp[0]; } else { if (tvpseg == UIO_SYSSPACE) { tvp = usrtvp; } else { if ((error = copyin(usrtvp, tv, sizeof(tv))) != 0) return (error); tvp = tv; } if (tvp[0].tv_usec < 0 || tvp[0].tv_usec >= 1000000 || tvp[1].tv_usec < 0 || tvp[1].tv_usec >= 1000000) return (EINVAL); TIMEVAL_TO_TIMESPEC(&tvp[0], &tsp[0]); TIMEVAL_TO_TIMESPEC(&tvp[1], &tsp[1]); } return (0); } /* * Common implementation code for futimens(), utimensat(). */ #define UTIMENS_NULL 0x1 #define UTIMENS_EXIT 0x2 static int getutimens(const struct timespec *usrtsp, enum uio_seg tspseg, struct timespec *tsp, int *retflags) { struct timespec tsnow; int error; diff --git a/sys/sys/pledge.h b/sys/sys/pledge.h new file mode 100644 index 000000000000..a16ebccb31ab --- /dev/null +++ b/sys/sys/pledge.h @@ -0,0 +1,245 @@ +#ifndef _SYS_PLEDGE_H +#define _SYS_PLEDGE_H + +#include +#include +#include + +/* + * Structure used to return recorded learning data via the sysctl + * security.pledge.learning_data + * when the learning mode is in effect, ie when sysctl + * security.pledge.learning = 1 + * Exposed to both kernel and userland. + */ +typedef struct pledge_learning_entry_t { + /* Tracks whether or not this entry is populated: */ + u_int is_populated; + /* pledge flags both possessed and actively utilized: */ + uint64_t used_flags; + /* pledge flags not possessed, but required for successful operation: */ + uint64_t violated_flags; + /* pledge flags possessed */ + uint64_t possessed; + ino_t inode; /* inode of executable that triggered this */ + dev_t fsid; /* fsid of executable that triggered this */ +} pledge_learning_entry_t; + +/* + * RB tree definitions used internally in the kernel and in /usr/sbin/pledgectl. + * The kernel walks such a tree structure and returns an + * array in response to the security.pledge.learning_data sysctl to avoid having + * to fix up kernelspace pointers, but this structure can also be used in user + * programs that need to do frequent access by inode, which is why it is + * exposed here. + * See: man 3 tree + */ + +/* + * Tree element definition + */ +typedef struct pledge_splay_t { + RB_ENTRY(pledge_splay_t) tree_link; + /* key: */ + ino_t inode; + dev_t fs_id; + /* values: */ + uint64_t used; + uint64_t violated; + uint64_t possessed; +} pledge_splay_t; + +/* + * Macros for defining the comparison function used for the RB tree + */ +#define PLEDGE_LEARNING_COMPARE_PROTOTYPE int learning_tree_compare(const pledge_splay_t *_a, const pledge_splay_t *_b); +#define PLEDGE_LEARNING_COMPARE_IMPL \ + int learning_tree_compare( \ + const struct pledge_splay_t *a, \ + const struct pledge_splay_t *b) \ + { \ + int res = 0; \ + res = (a->inode > b->inode); \ + res -= (a->inode < b->inode); \ + if (res) return res; \ + res += (a->fs_id > b->fs_id); \ + res -= (a->fs_id < b->fs_id); \ + return res; \ + } + +/* kernel functions: */ +#ifdef _KERNEL + +#include "opt_pledge.h" +#include +#include +#include +#include +#include +#include + +typedef struct pledge_jail_data { + bool is_enforcing; /* false when violations should be ignored */ + counter_u64_t violations; + struct sysctl_ctx_list sysctl_ctx; +} pledge_jail_data; + +/* TODO document that most of these may crash the thread if + * PLEDGE_SOFTFAIL is not set */ + +/* check if a thread has a given set of flags TODO document properly */ +int pledge_check_bitmap(struct thread *thread, const uint64_t flags); + +/* kernel-land function to restrict pledge permission mask for thread: */ +int kern_pledge(struct thread *thread, const uint64_t mask); + +/* + * free all entries in the learning data tree, + * returning the number of bytes the erased entries would have required to dump + * to userspace, in multiples of sizeof(pledge_learning_entry_t). + */ +size_t kern_pledge_learning_data_erase(void); + +/* syscall to restrict pledge permission mask for thread: */ +/*int sys_pledge(struct thread *thread, struct pledge_args *args); TODO */ + +/* hook for the syscall handler to determine if syscall_no may be called: */ +int pledge_syscall(struct thread *thread, const int syscall_no); + +/* hook for open() access. */ +int pledge_openat(struct thread *thread, const int fd, const char *path, + const int flags, const int mode); + +int pledge_apply_extattr(struct thread *td, struct vnode *ni_vp); + +#endif /* _KERNEL */ + + +/* pledge(2) flags */ +/* TODO would have been awful nice if C permitted uint64_t-backed enums so + * we could avoid this mess... */ + +#define PLEDGE_NONE 0ULL /* empty mask */ +#define PLEDGE_AND (1ULL << 0) /* match ALL flags */ +#define PLEDGE_SOFTFAIL (1ULL << 1) /* return EPERM instead of crashing */ + +/* These names (not the constants) are copied from OpenBSD, + * maybe we can have some interopability to easy porting: + * Note that the descriptions are most likely off. + */ + +#define PLEDGE_RPATH (1ULL << 2) /* allow open for read */ +#define PLEDGE_WPATH (1ULL << 3) /* allow open for write */ +#define PLEDGE_CPATH (1ULL << 4) /* allow creat, mkdir, unlink etc */ +#define PLEDGE_STDIO (1ULL << 5) /* operate on own pid */ +#define PLEDGE_TMPPATH (1ULL << 6) /* for mk*temp() */ +#define PLEDGE_DNS (1ULL << 7) /* DNS services */ +#define PLEDGE_INET (1ULL << 8) /* AF_INET/AF_INET6 sockets */ +#define PLEDGE_FLOCK (1ULL << 9) /* file locking */ +#define PLEDGE_UNIX (1ULL << 10) /* AF_UNIX sockets */ +#define PLEDGE_ID (1ULL << 11) /* allow setuid, setgid, etc */ +#define PLEDGE_TAPE (1ULL << 12) /* Tape ioctl */ +#define PLEDGE_GETPW (1ULL << 13) /* YP enables if ypbind.lock */ +#define PLEDGE_PROC (1ULL << 14) /* fork, waitpid, etc */ +#define PLEDGE_SETTIME (1ULL << 15) /* able to set/adj time/freq */ +#define PLEDGE_FATTR (1ULL << 16) /* allow explicit file st_* mods */ +#define PLEDGE_PROTEXEC (1ULL << 17) /* allow use of PROT_EXEC */ +#define PLEDGE_TTY (1ULL << 18) /* tty setting */ +#define PLEDGE_SENDFD (1ULL << 19) /* AF_UNIX CMSG fd sending */ +#define PLEDGE_RECVFD (1ULL << 20) /* AF_UNIX CMSG fd receiving */ +#define PLEDGE_EXEC (1ULL << 21) /* execve (etc) other programs*/ +#define PLEDGE_ROUTE (1ULL << 22) /* routing lookups */ +#define PLEDGE_MCAST (1ULL << 23) /* multicast joins */ +#define PLEDGE_VMINFO (1ULL << 24) /* vminfo listings */ +#define PLEDGE_PS (1ULL << 25) /* ps listings */ +#define PLEDGE_DISKLABEL (1ULL << 26) /* disklabels */ +#define PLEDGE_PF (1ULL << 27) /* pf ioctls */ +#define PLEDGE_AUDIO (1ULL << 28) /* audio ioctls */ +#define PLEDGE_DPATH (1ULL << 29) /* mknod & mkfifo */ +#define PLEDGE_DRM (1ULL << 30) /* drm ioctls */ +#define PLEDGE_VMM (1ULL << 31) /* vmm ioctls */ +#define PLEDGE_CHOWN (1ULL << 32) /* chown(2) family */ +#define PLEDGE_CHOWNUID (1ULL << 33) /* allow owner/group changes */ +#define PLEDGE_BPF (1ULL << 34) /* bpf ioctl */ + +/* HardenedBSD-specific constants:*/ + +/* CPATH,FATTR,CHOWN under /dev + * mount, unmount, mknod + * RPATH,WPATH under /dev when doing so requires non-world permissions + */ +#define PLEDGE_DEVICE (1ULL << 45) /* modify devices, mount, unmount */ +#define PLEDGE_KLD (1ULL << 46) /* things to do with loadable modules */ +#define PLEDGE_AIO (1ULL << 47) /* aio (asynchronous io) related */ +#define PLEDGE_SYSCTL (1ULL << 48) /* wildcard sysctl permissions */ +#define PLEDGE_IOCTL (1ULL << 49) /* wildcard ioctl permissions, potentially an overlap with cap_ioctls_limit etc? */ +#define PLEDGE_CAPSICUM (1ULL << 50) /* man 4 capsicum */ + +#define PLEDGE_NOLEARN (1ULL << 63) /* don't record this in learning mode */ +#define PLEDGE_WILDCARD ((~0ULL) ^ \ + (PLEDGE_AND | PLEDGE_SOFTFAIL \ + | PLEDGE_NOLEARN)) /* match any flag */ + + +/* + * TODO: This should not be defined like this, + * since now each user in the kernel has a static + * copy of this map (even if they don't use it?). + * Exposing it from e.g. hbsd_pledge.c would result + * in only a single copy, and that would be doubly useful + * since then DTrace scripts could do lookups here. + * For userspace we probably want to expose it from libpledge. + */ +static const +struct { + const uint64_t constant; + const char *name; +} pledge_string_map[] = { + { PLEDGE_AND, "&"}, + { PLEDGE_WILDCARD, "wildcard" }, + { PLEDGE_RPATH, "rpath" }, + { PLEDGE_WPATH, "wpath" }, + { PLEDGE_CPATH, "cpath" }, + { PLEDGE_STDIO, "stdio" }, + { PLEDGE_TMPPATH, "tmppath" }, + { PLEDGE_DNS, "dns" }, + { PLEDGE_INET, "inet" }, + { PLEDGE_FLOCK, "flock" }, + { PLEDGE_UNIX, "unix" }, + { PLEDGE_ID, "id" }, + { PLEDGE_TAPE, "tape" }, + { PLEDGE_GETPW, "getpw" }, + { PLEDGE_PROC, "proc" }, + { PLEDGE_SETTIME, "settime" }, + { PLEDGE_FATTR, "fattr" }, + { PLEDGE_PROTEXEC, "protexec" }, + { PLEDGE_TTY, "tty" }, + { PLEDGE_SENDFD, "sendfd" }, + { PLEDGE_RECVFD, "recvfd" }, + { PLEDGE_EXEC, "exec" }, + { PLEDGE_ROUTE, "route" }, + { PLEDGE_MCAST, "mcast" }, + { PLEDGE_VMINFO, "vminfo" }, + { PLEDGE_PS, "ps" }, + { PLEDGE_DISKLABEL, "disklabel" }, + { PLEDGE_PF, "pf" }, + { PLEDGE_AUDIO, "audio" }, + { PLEDGE_DPATH, "dpath" }, + { PLEDGE_DRM, "drm" }, + { PLEDGE_VMM, "vmm" }, + { PLEDGE_CHOWN, "chown" }, + { PLEDGE_CHOWNUID, "chownuid" }, + { PLEDGE_BPF, "bpf" }, + { PLEDGE_DEVICE, "device" }, + { PLEDGE_KLD, "kld" }, + { PLEDGE_AIO, "aio" }, + { PLEDGE_SOFTFAIL, "softfail" }, + { PLEDGE_NOLEARN, "nolearn" }, + { PLEDGE_SYSCTL, "sysctl" }, + { PLEDGE_IOCTL, "ioctl" }, + { PLEDGE_CAPSICUM, "capsicum" }, + { PLEDGE_NONE, "none"} +}; + + +#endif /* _SYS_PLEDGE_H */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index a97e60de6e77..302cd3297c9d 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -246,200 +246,201 @@ struct thread { struct domainset_ref td_domain; /* (a) NUMA policy */ struct seltd *td_sel; /* Select queue/channel. */ struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */ struct turnstile *td_turnstile; /* (k) Associated turnstile. */ void *td_pad1; /* Available */ struct umtx_q *td_umtxq; /* (c?) Link for when we're blocked. */ lwpid_t td_tid; /* (b) Thread ID. */ sigqueue_t td_sigqueue; /* (c) Sigs arrived, not delivered. */ #define td_siglist td_sigqueue.sq_signals u_char td_lend_user_pri; /* (t) Lend user pri. */ u_char td_allocdomain; /* (b) NUMA domain backing this struct thread. */ u_char td_base_ithread_pri; /* (t) Base ithread pri */ struct kmsan_td *td_kmsan; /* (k) KMSAN state */ /* Cleared during fork1(), thread_create(), or kthread_add(). */ #define td_startzero td_flags int td_flags; /* (t) TDF_* flags. */ int td_ast; /* (t) TDA_* indicators */ int td_inhibitors; /* (t) Why can not run. */ int td_pflags; /* (k) Private thread (TDP_*) flags. */ int td_pflags2; /* (k) Private thread (TDP2_*) flags. */ int td_dupfd; /* (k) Ret value from fdopen. XXX */ int td_sqqueue; /* (t) Sleepqueue queue blocked on. */ const void *td_wchan; /* (t) Sleep address. */ const char *td_wmesg; /* (t) Reason for sleep. */ volatile u_char td_owepreempt; /* (k*) Preempt on last critical_exit */ u_char td_tsqueue; /* (t) Turnstile queue blocked on. */ u_char _td_pad0[2]; /* Available. */ int td_locks; /* (k) Debug: count of non-spin locks */ int td_rw_rlocks; /* (k) Count of rwlock read locks. */ int td_sx_slocks; /* (k) Count of sx shared locks. */ int td_lk_slocks; /* (k) Count of lockmgr shared locks. */ struct lock_object *td_wantedlock; /* (k) Lock we are contending on */ struct turnstile *td_blocked; /* (t) Lock thread is blocked on. */ const char *td_lockname; /* (t) Name of lock blocked on. */ LIST_HEAD(, turnstile) td_contested; /* (q) Contested locks. */ struct lock_list_entry *td_sleeplocks; /* (k) Held sleep locks. */ int td_intr_nesting_level; /* (k) Interrupt recursion. */ int td_pinned; /* (k) Temporary cpu pin count. */ struct ucred *td_realucred; /* (k) Reference to credentials. */ struct ucred *td_ucred; /* (k) Used credentials, temporarily switchable. */ struct plimit *td_limit; /* (k) Resource limits. */ int td_slptick; /* (t) Time at sleep. */ int td_blktick; /* (t) Time spent blocked. */ int td_swvoltick; /* (t) Time at last SW_VOL switch. */ int td_swinvoltick; /* (t) Time at last SW_INVOL switch. */ u_int td_cow; /* (*) Number of copy-on-write faults */ struct rusage td_ru; /* (t) rusage information. */ struct rusage_ext td_rux; /* (t) Internal rusage information. */ uint64_t td_incruntime; /* (t) Cpu ticks to transfer to proc. */ uint64_t td_runtime; /* (t) How many cpu ticks we've run. */ u_int td_pticks; /* (t) Statclock hits for profiling */ u_int td_sticks; /* (t) Statclock hits in system mode. */ u_int td_iticks; /* (t) Statclock hits in intr mode. */ u_int td_uticks; /* (t) Statclock hits in user mode. */ int td_intrval; /* (t) Return value for sleepq. */ sigset_t td_oldsigmask; /* (k) Saved mask from pre sigpause. */ volatile u_int td_generation; /* (k) For detection of preemption */ stack_t td_sigstk; /* (k) Stack ptr and on-stack flag. */ int td_xsig; /* (c) Signal for ptrace */ u_long td_profil_addr; /* (k) Temporary addr until AST. */ u_int td_profil_ticks; /* (k) Temporary ticks until AST. */ char td_name[MAXCOMLEN + 1]; /* (*) Thread name. */ struct file *td_fpop; /* (k) file referencing cdev under op */ int td_dbgflags; /* (c) Userland debugger flags */ siginfo_t td_si; /* (c) For debugger or core file */ int td_ng_outbound; /* (k) Thread entered ng from above. */ struct osd td_osd; /* (k) Object specific data. */ struct vm_map_entry *td_map_def_user; /* (k) Deferred entries. */ pid_t td_dbg_forked; /* (c) Child pid for debugger. */ u_int td_no_sleeping; /* (k) Sleeping disabled count. */ struct vnode *td_vp_reserved;/* (k) Preallocated vnode. */ void *td_su; /* (k) FFS SU private */ sbintime_t td_sleeptimo; /* (t) Sleep timeout. */ int td_rtcgen; /* (s) rtc_generation of abs. sleep */ int td_errno; /* (k) Error from last syscall. */ size_t td_vslock_sz; /* (k) amount of vslock-ed space */ struct kcov_info *td_kcov_info; /* (*) Kernel code coverage data */ long td_ucredref; /* (k) references on td_realucred */ struct kexterr td_kexterr; #define td_endzero td_sigmask /* Copied during fork1(), thread_create(), or kthread_add(). */ #define td_startcopy td_endzero sigset_t td_sigmask; /* (c) Current signal mask. */ u_char td_rqindex; /* (t) Run queue index. */ u_char td_base_pri; /* (t) Thread base kernel priority. */ u_char td_priority; /* (t) Thread active priority. */ u_char td_pri_class; /* (t) Scheduling class. */ u_char td_user_pri; /* (t) User pri from estcpu and nice. */ u_char td_base_user_pri; /* (t) Base user pri */ uint32_t td_pax; /* (b) Cached PaX settings from process. */ uintptr_t td_rb_list; /* (k) Robust list head. */ uintptr_t td_rbp_list; /* (k) Robust priv list head. */ uintptr_t td_rb_inact; /* (k) Current in-action mutex loc. */ struct syscall_args td_sa; /* (kx) Syscall parameters. Copied on fork for child tracing. */ void *td_sigblock_ptr; /* (k) uptr for fast sigblock. */ uint32_t td_sigblock_val; /* (k) fast sigblock value read at td_sigblock_ptr on kern entry */ + uint64_t td_pledge; /* (k*) pledge(2) syscall whitelist bitmap.*/ void *td_exterr_ptr; #define td_endcopy td_pcb /* * Fields that must be manually set in fork1(), thread_create(), kthread_add(), * or already have been set in the allocator, constructor, etc. */ struct pcb *td_pcb; /* (k) Kernel VA of pcb and kstack. */ enum td_states { TDS_INACTIVE = 0x0, TDS_INHIBITED, TDS_CAN_RUN, TDS_RUNQ, TDS_RUNNING } td_state; /* (t) thread state */ /* Note: td_state must be accessed using TD_{GET,SET}_STATE(). */ union { syscallarg_t tdu_retval[2]; off_t tdu_off; } td_uretoff; /* (k) Syscall aux returns. */ #define td_retval td_uretoff.tdu_retval u_int td_cowgen; /* (k) Generation of COW pointers. */ /* LP64 hole */ struct callout td_slpcallout; /* (h) Callout for sleep. */ struct trapframe *td_frame; /* (k) */ char *td_kstack; /* (a) Pointer to kstack. */ u_short td_kstack_pages; /* (a) Size of the kstack. */ u_short td_kstack_domain; /* (a) Domain backing kstack KVA. */ volatile u_int td_critnest; /* (k*) Critical section nest level. */ struct mdthread td_md; /* (k) Any machine-dependent fields. */ struct kaudit_record *td_ar; /* (k) Active audit record, if any. */ struct lpohead td_lprof[2]; /* (a) lock profiling objects. */ struct kdtrace_thread *td_dtrace; /* (*) DTrace-specific data. */ struct vnet *td_vnet; /* (k) Effective vnet. */ const char *td_vnet_lpush; /* (k) Debugging vnet push / pop. */ struct trapframe *td_intr_frame;/* (k) Frame of the current irq */ struct proc *td_rfppwait_p; /* (k) The vforked child */ struct vm_page **td_ma; /* (k) uio pages held */ int td_ma_cnt; /* (k) size of *td_ma */ /* LP64 hole */ void *td_emuldata; /* Emulator state data */ int td_lastcpu; /* (t) Last cpu we were on. */ int td_oncpu; /* (t) Which cpu we are on. */ void *td_lkpi_task; /* LinuxKPI task struct pointer */ int td_pmcpend; void *td_remotereq; /* (c) dbg remote request. */ off_t td_ktr_io_lim; /* (k) limit for ktrace file size */ #ifdef EPOCH_TRACE SLIST_HEAD(, epoch_tracker) td_epochs; #endif }; struct thread0_storage { struct thread t0st_thread; uint64_t t0st_sched[10]; }; struct mtx *thread_lock_block(struct thread *); void thread_lock_block_wait(struct thread *); void thread_lock_set(struct thread *, struct mtx *); void thread_lock_unblock(struct thread *, struct mtx *); #define THREAD_LOCK_ASSERT(td, type) \ mtx_assert((td)->td_lock, (type)) #define THREAD_LOCK_BLOCKED_ASSERT(td, type) \ do { \ struct mtx *__m = (td)->td_lock; \ if (__m != &blocked_lock) \ mtx_assert(__m, (type)); \ } while (0) #ifdef INVARIANTS #define THREAD_LOCKPTR_ASSERT(td, lock) \ do { \ struct mtx *__m; \ __m = (td)->td_lock; \ KASSERT(__m == (lock), \ ("Thread %p lock %p does not match %p", td, __m, (lock))); \ } while (0) #define THREAD_LOCKPTR_BLOCKED_ASSERT(td, lock) \ do { \ struct mtx *__m; \ __m = (td)->td_lock; \ KASSERT(__m == (lock) || __m == &blocked_lock, \ ("Thread %p lock %p does not match %p", td, __m, (lock))); \ } while (0) #define TD_LOCKS_INC(td) ((td)->td_locks++) #define TD_LOCKS_DEC(td) do { \ KASSERT(SCHEDULER_STOPPED() || (td)->td_locks > 0, \ ("Thread %p owns no locks", (td))); \ (td)->td_locks--; \ } while (0) #else #define THREAD_LOCKPTR_ASSERT(td, lock) #define THREAD_LOCKPTR_BLOCKED_ASSERT(td, lock) #define TD_LOCKS_INC(td) #define TD_LOCKS_DEC(td) diff --git a/usr.bin/ncal/ncal.c b/usr.bin/ncal/ncal.c index dc50dd60bf0b..db95f99bdd91 100644 --- a/usr.bin/ncal/ncal.c +++ b/usr.bin/ncal/ncal.c @@ -1,292 +1,294 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 1997 Wolfgang Helbig * 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 #undef lines /* term.h defines this */ /* Width of one month with backward compatibility and in regular mode*/ #define MONTH_WIDTH_B_J 27 #define MONTH_WIDTH_B 20 #define MONTH_WIDTH_R_J 24 #define MONTH_WIDTH_R 18 #define MAX_WIDTH 64 typedef struct date date; struct monthlines { wchar_t name[MAX_WIDTH + 1]; char lines[7][MAX_WIDTH + 1]; char weeks[MAX_WIDTH + 1]; unsigned int extralen[7]; }; struct weekdays { wchar_t names[7][4]; }; /* The switches from Julian to Gregorian in some countries */ static struct djswitch { const char *cc; /* Country code according to ISO 3166 */ const char *nm; /* Name of country */ date dt; /* Last day of Julian calendar */ } switches[] = { {"AL", "Albania", {1912, 11, 30}}, {"AT", "Austria", {1583, 10, 5}}, {"AU", "Australia", {1752, 9, 2}}, {"BE", "Belgium", {1582, 12, 14}}, {"BG", "Bulgaria", {1916, 3, 31}}, {"CA", "Canada", {1752, 9, 2}}, {"CH", "Switzerland", {1655, 2, 28}}, {"CN", "China", {1911, 12, 18}}, {"CZ", "Czech Republic",{1584, 1, 6}}, {"DE", "Germany", {1700, 2, 18}}, {"DK", "Denmark", {1700, 2, 18}}, {"ES", "Spain", {1582, 10, 4}}, {"FI", "Finland", {1753, 2, 17}}, {"FR", "France", {1582, 12, 9}}, {"GB", "United Kingdom",{1752, 9, 2}}, {"GR", "Greece", {1924, 3, 9}}, {"HU", "Hungary", {1587, 10, 21}}, {"IS", "Iceland", {1700, 11, 16}}, {"IT", "Italy", {1582, 10, 4}}, {"JP", "Japan", {1918, 12, 18}}, {"LT", "Lithuania", {1918, 2, 1}}, {"LU", "Luxembourg", {1582, 12, 14}}, {"LV", "Latvia", {1918, 2, 1}}, {"NL", "Netherlands", {1582, 12, 14}}, {"NO", "Norway", {1700, 2, 18}}, {"PL", "Poland", {1582, 10, 4}}, {"PT", "Portugal", {1582, 10, 4}}, {"RO", "Romania", {1919, 3, 31}}, {"RU", "Russia", {1918, 1, 31}}, {"SI", "Slovenia", {1919, 3, 4}}, {"SE", "Sweden", {1753, 2, 17}}, {"TR", "Turkey", {1926, 12, 18}}, {"US", "United States", {1752, 9, 2}}, {"YU", "Yugoslavia", {1919, 3, 4}} }; static struct djswitch *dftswitch = switches + sizeof(switches) / sizeof(struct djswitch) - 2; /* default switch (should be "US") */ /* Table used to print day of month and week numbers */ static char daystr[] = " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15" " 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31" " 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47" " 48 49 50 51 52 53"; /* Table used to print day of year and week numbers */ static char jdaystr[] = " 1 2 3 4 5 6 7 8 9" " 10 11 12 13 14 15 16 17 18 19" " 20 21 22 23 24 25 26 27 28 29" " 30 31 32 33 34 35 36 37 38 39" " 40 41 42 43 44 45 46 47 48 49" " 50 51 52 53 54 55 56 57 58 59" " 60 61 62 63 64 65 66 67 68 69" " 70 71 72 73 74 75 76 77 78 79" " 80 81 82 83 84 85 86 87 88 89" " 90 91 92 93 94 95 96 97 98 99" " 100 101 102 103 104 105 106 107 108 109" " 110 111 112 113 114 115 116 117 118 119" " 120 121 122 123 124 125 126 127 128 129" " 130 131 132 133 134 135 136 137 138 139" " 140 141 142 143 144 145 146 147 148 149" " 150 151 152 153 154 155 156 157 158 159" " 160 161 162 163 164 165 166 167 168 169" " 170 171 172 173 174 175 176 177 178 179" " 180 181 182 183 184 185 186 187 188 189" " 190 191 192 193 194 195 196 197 198 199" " 200 201 202 203 204 205 206 207 208 209" " 210 211 212 213 214 215 216 217 218 219" " 220 221 222 223 224 225 226 227 228 229" " 230 231 232 233 234 235 236 237 238 239" " 240 241 242 243 244 245 246 247 248 249" " 250 251 252 253 254 255 256 257 258 259" " 260 261 262 263 264 265 266 267 268 269" " 270 271 272 273 274 275 276 277 278 279" " 280 281 282 283 284 285 286 287 288 289" " 290 291 292 293 294 295 296 297 298 299" " 300 301 302 303 304 305 306 307 308 309" " 310 311 312 313 314 315 316 317 318 319" " 320 321 322 323 324 325 326 327 328 329" " 330 331 332 333 334 335 336 337 338 339" " 340 341 342 343 344 345 346 347 348 349" " 350 351 352 353 354 355 356 357 358 359" " 360 361 362 363 364 365 366"; static int flag_highlight; /* highlighted today */ static int flag_weeks; /* user wants number of week */ static int nswitch; /* user defined switch date */ static int nswitchb; /* switch date for backward compatibility */ static int highlightdate; static bool flag_monday; /* user wants week starts on Monday */ static char *center(char *s, char *t, int w); static wchar_t *wcenter(wchar_t *s, wchar_t *t, int w); static int firstday(int y, int m); static void highlight(char *dst, char *src, int len, int *extraletters); static void mkmonthr(int year, int month, int jd_flag, struct monthlines * monthl); static void mkmonthb(int year, int month, int jd_flag, struct monthlines * monthl); static void mkweekdays(struct weekdays * wds); static void monthranger(int year, int m, int jd_flag, int before, int after); static void monthrangeb(int year, int m, int jd_flag, int before, int after); static int parsemonth(const char *s, int *m, int *y); static void printcc(void); static void printeaster(int year, int julian, int orthodox); static date *sdater(int ndays, struct date * d); static date *sdateb(int ndays, struct date * d); static int sndaysr(struct date * d); static int sndaysb(struct date * d); static void usage(void); int main(int argc, char *argv[]) { + struct djswitch *p, *q; /* to search user defined switch date */ date never = {10000, 1, 1}; /* outside valid range of dates */ date ukswitch = {1752, 9, 2};/* switch date for Great Britain */ date dt; int ch; /* holds the option character */ int m = 0; /* month */ int y = 0; /* year */ int flag_backward = 0; /* user called cal--backward compat. */ int flag_wholeyear = 0; /* user wants the whole year */ int flag_julian_cal = 0; /* user wants Julian Calendar */ int flag_julian_day = 0; /* user wants the Julian day numbers */ int flag_orthodox = 0; /* user wants Orthodox easter */ int flag_easter = 0; /* user wants easter date */ int flag_3months = 0; /* user wants 3 month display (-3) */ int flag_after = 0; /* user wants to see months after */ int flag_before = 0; /* user wants to see months before */ int flag_specifiedmonth = 0;/* user wants to see this month (-m) */ int flag_givenmonth = 0; /* user has specified month [n] */ int flag_givenyear = 0; /* user has specified year [n] */ char *cp; /* character pointer */ char *flag_today = NULL; /* debug: use date as being today */ char *flag_month = NULL; /* requested month as string */ char *flag_highlightdate = NULL; /* debug: date to highlight */ int before, after; const char *locale; /* locale to get country code */ flag_highlight = isatty(STDOUT_FILENO); flag_weeks = 0; flag_monday = false; /* * Use locale to determine the country code, * and use the country code to determine the default * switchdate and date format from the switches table. */ if (setlocale(LC_ALL, "") == NULL) warn("setlocale"); locale = setlocale(LC_TIME, NULL); if (locale == NULL || strcmp(locale, "C") == 0 || strcmp(locale, "POSIX") == 0 || strcmp(locale, "ASCII") == 0 || strcmp(locale, "US-ASCII") == 0) locale = "_US"; q = switches + sizeof(switches) / sizeof(struct djswitch); for (p = switches; p != q; p++) if ((cp = strstr(locale, p->cc)) != NULL && *(cp - 1) == '_') break; if (p == q) { nswitch = ndaysj(&dftswitch->dt); } else { nswitch = ndaysj(&p->dt); dftswitch = p; } /* * Get the filename portion of argv[0] and set flag_backward if * this program is called "cal". */ if (strncmp(basename(argv[0]), "cal", strlen("cal")) == 0) flag_backward = 1; /* Set the switch date to United Kingdom if backwards compatible */ if (flag_backward) nswitchb = ndaysj(&ukswitch); before = after = -1; while ((ch = getopt(argc, argv, "3A:B:Cd:eH:hjJm:Nops:wyM")) != -1) switch (ch) { case '3': flag_3months = 1; break; case 'A': if (flag_after > 0) errx(EX_USAGE, "Double -A specified"); flag_after = strtol(optarg, NULL, 10); if (flag_after <= 0) errx(EX_USAGE, "Argument to -A must be positive"); break; case 'B': if (flag_before > 0) errx(EX_USAGE, "Double -B specified"); flag_before = strtol(optarg, NULL, 10); if (flag_before <= 0) errx(EX_USAGE, "Argument to -B must be positive"); break; case 'J': if (flag_backward) usage(); nswitch = ndaysj(&never); flag_julian_cal = 1; break; case 'C': flag_backward = 1; break; case 'N': diff --git a/usr.bin/wc/wc.c b/usr.bin/wc/wc.c index d00a1a64da29..d88aee423129 100644 --- a/usr.bin/wc/wc.c +++ b/usr.bin/wc/wc.c @@ -1,189 +1,198 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 1987, 1991, 1993 * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 #define WC_XO_VERSION "1" static const char *stdin_filename = "stdin"; static fileargs_t *fa; static uintmax_t tlinect, twordct, tcharct, tlongline; static bool doline, doword, dochar, domulti, dolongline; static volatile sig_atomic_t siginfo; static xo_handle_t *stderr_handle; static void show_cnt(const char *file, uintmax_t linect, uintmax_t wordct, uintmax_t charct, uintmax_t llct); static int cnt(const char *); static void usage(void); static void siginfo_handler(int sig __unused) { siginfo = 1; } static void reset_siginfo(void) { signal(SIGINFO, SIG_DFL); siginfo = 0; } int main(int argc, char *argv[]) { int ch, errors, total; cap_rights_t rights; + + //if (0 != pledge(PLEDGE_RPATH /* need to read files */ + // | PLEDGE_STDIO /* need signal() */ + // | PLEDGE_WILDCARD /* TODO */ + // , NULL)) { + // return (1); + //} TODO + (void) setlocale(LC_CTYPE, ""); argc = xo_parse_args(argc, argv); if (argc < 0) exit(EXIT_FAILURE); while ((ch = getopt(argc, argv, "clmwL")) != -1) switch((char)ch) { case 'l': doline = true; break; case 'w': doword = true; break; case 'c': dochar = true; domulti = false; break; case 'L': dolongline = true; break; case 'm': domulti = true; dochar = false; break; case '?': default: usage(); } argv += optind; argc -= optind; fa = fileargs_init(argc, argv, O_RDONLY, 0, cap_rights_init(&rights, CAP_READ, CAP_FSTAT), FA_OPEN); if (fa == NULL) xo_err(EXIT_FAILURE, "Unable to initialize casper"); caph_cache_catpages(); if (caph_limit_stdio() < 0) xo_err(EXIT_FAILURE, "Unable to limit stdio"); if (caph_enter_casper() < 0) xo_err(EXIT_FAILURE, "Unable to enter capability mode"); /* Wc's flags are on by default. */ if (!(doline || doword || dochar || domulti || dolongline)) doline = doword = dochar = true; stderr_handle = xo_create_to_file(stderr, XO_STYLE_TEXT, 0); xo_set_version(WC_XO_VERSION); xo_open_container("wc"); xo_open_list("file"); (void)signal(SIGINFO, siginfo_handler); errors = 0; total = 0; if (argc == 0) { xo_open_instance("file"); if (cnt(NULL) != 0) ++errors; xo_close_instance("file"); } else { while (argc--) { xo_open_instance("file"); if (cnt(*argv++) != 0) ++errors; xo_close_instance("file"); ++total; } } xo_close_list("file"); if (total > 1) { xo_open_container("total"); show_cnt("total", tlinect, twordct, tcharct, tlongline); xo_close_container("total"); } fileargs_free(fa); xo_close_container("wc"); if (xo_finish() < 0) xo_err(EXIT_FAILURE, "stdout"); exit(errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } static void show_cnt(const char *file, uintmax_t linect, uintmax_t wordct, uintmax_t charct, uintmax_t llct) { xo_handle_t *xop; if (!siginfo) xop = NULL; else { xop = stderr_handle; siginfo = 0; } if (doline) xo_emit_h(xop, " {:lines/%7ju/%ju}", linect); diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 4ebb615f87c1..ed76a11d535f 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,159 +1,160 @@ .include SUBDIR= adduser \ arp \ binmiscctl \ boottrace \ bsdconfig \ camdd \ cdcontrol \ chkgrp \ chown \ chroot \ ckdist \ clear_locks \ crashinfo \ cron \ ctld \ ctladm \ daemon \ dconschat \ devctl \ devinfo \ diskinfo \ dumpcis \ etcupdate \ extattr \ extattrctl \ fifolog \ fstyp \ fwcontrol \ fwget \ getfmac \ getpmac \ gstat \ i2c \ ifmcstat \ iostat \ iovctl \ kldxref \ mailwrapper \ makefs \ memcontrol \ mfiutil \ mlxcontrol \ mountd \ mount_smbfs \ mpsutil \ mptutil \ mtest \ newsyslog \ nfscbd \ nfsd \ nfsdumpstate \ nfsrevoke \ nfsuserd \ nmtree \ nologin \ pciconf \ periodic \ + pledgectl \ pnfsdscopymr \ pnfsdsfile \ pnfsdskill \ powerd \ prometheus_sysctl_exporter \ pstat \ pw \ pwd_mkdb \ pwm \ quot \ rarpd \ rmt \ rpcbind \ rpc.lockd \ rpc.statd \ rpc.umntall \ rtprio \ rwhod \ service \ services_mkdb \ sesutil \ setfib \ setfmac \ setpmac \ smart \ smbmsg \ snapinfo \ spi \ spray \ syslogd \ sysrc \ tcpdrop \ tcpdump \ tcpsso \ traceroute \ trim \ tzsetup \ ugidfw \ valectl \ vigr \ vipw \ wake \ watch \ watchdogd \ zdump \ zic \ zonectl # NB: keep these sorted by MK_* knobs SUBDIR.${MK_ACCT}+= accton SUBDIR.${MK_ACCT}+= sa SUBDIR.${MK_AUDIT}+= audit SUBDIR.${MK_AUDIT}+= auditd .if ${MK_OPENSSL} != "no" SUBDIR.${MK_AUDIT}+= auditdistd .endif SUBDIR.${MK_AUDIT}+= auditreduce SUBDIR.${MK_AUDIT}+= praudit SUBDIR.${MK_AUDIT}+= setaudit SUBDIR.${MK_AUTHPF}+= authpf SUBDIR.${MK_AUTOFS}+= autofs SUBDIR.${MK_BLACKLIST}+= blacklistctl SUBDIR.${MK_BLACKLIST}+= blacklistd SUBDIR.${MK_BLOCKLIST}+= blocklistctl SUBDIR.${MK_BLOCKLIST}+= blocklistd SUBDIR.${MK_BLUETOOTH}+= bluetooth SUBDIR.${MK_BOOTPARAMD}+= bootparamd SUBDIR.${MK_BSDINSTALL}+= bsdinstall SUBDIR.${MK_BSNMP}+= bsnmpd .if ${MK_CAROOT} != "no" SUBDIR.${MK_OPENSSL}+= certctl .endif SUBDIR.${MK_CXGBETOOL}+= cxgbetool SUBDIR.${MK_EFI}+= efivar efidp efibootmgr efitable efiwake .if ${MK_OPENSSL} != "no" SUBDIR.${MK_EFI}+= uefisign .endif SUBDIR.${MK_FDT}+= ofwdump SUBDIR.${MK_FLOPPY}+= fdcontrol SUBDIR.${MK_FLOPPY}+= fdformat SUBDIR.${MK_FLOPPY}+= fdread SUBDIR.${MK_FLOPPY}+= fdwrite SUBDIR.${MK_FREEBSD_UPDATE}+= freebsd-update SUBDIR.${MK_KERBEROS_SUPPORT}+= gssd SUBDIR.${MK_GPIO}+= gpioctl SUBDIR.${MK_HBSD_UPDATE}+= hbsd-update SUBDIR.${MK_HBSDCONTROL}+= hbsdcontrol SUBDIR.${MK_HYPERV}+= hyperv SUBDIR.${MK_INET6}+= ip6addrctl SUBDIR.${MK_INET6}+= mld6query SUBDIR.${MK_INET6}+= ndp SUBDIR.${MK_INET6}+= rip6query SUBDIR.${MK_INET6}+= route6d SUBDIR.${MK_INET6}+= rrenumd SUBDIR.${MK_INET6}+= rtadvctl SUBDIR.${MK_INET6}+= rtadvd SUBDIR.${MK_INET6}+= rtsold SUBDIR.${MK_INET6}+= traceroute6 SUBDIR.${MK_INETD}+= inetd diff --git a/usr.sbin/hbsd-update/hbsd-update.conf b/usr.sbin/hbsd-update/hbsd-update.conf index 1199f0ce6eb6..5d7625c8c9d0 100644 --- a/usr.sbin/hbsd-update/hbsd-update.conf +++ b/usr.sbin/hbsd-update/hbsd-update.conf @@ -1,45 +1,45 @@ # hbsd-update.conf # Configuration settings for hbsd-update. # This file is read in through a /bin/sh shell and uses that syntax. # dnsrec: # DNS TXT record to use when looking up the version info for the # latest update. # # This record name seems redundant, but it provides the following # information: # 1) architecture -# 2) branch (hardened/current/master) in reverse form +# 2) branch (hardened/current/pledge) in reverse form # 3) repo (hardenedbsd) -dnsrec="$(uname -m).master.current.hardened.hardenedbsd.updates.hardenedbsd.org" +dnsrec="$(uname -m).$(uname -p).pledge.current.hardened.hardenedbsd.updates.hardenedbsd.org" # kernel: # Which kernel to install. # By default, this is intelligently detected by parsing `uname -v` # output. #kernel="HARDENEDBSD" # capath: # Location of the trusted root certificate store. capath="/usr/share/keys/hbsd-update/trusted" # branch: # Which branch/tag we are pointing to. This option is only used in # this file for the baseurl option below. -branch="hardened/current/master" +branch="hardened/current/pledge" # baseurl: # Where to get the update from. baseurl="https://updates.hardenedbsd.org/pub/HardenedBSD/updates/${branch}/$(uname -m)" # dnssec: # Use DNSSEC for validating the DNS TXT record. Default: yes #dnssec="yes" # force_ipv4: # Force hbsd-update to only use IPv4. #force_ipv4="no" # force_ipv6: # Force hbsd-update to only use IPv6. #force_ipv6="no" diff --git a/usr.sbin/hbsd-update/xxx b/usr.sbin/hbsd-update/xxx new file mode 100644 index 000000000000..aaba51bfaa3c --- /dev/null +++ b/usr.sbin/hbsd-update/xxx @@ -0,0 +1,9 @@ +caopt="-CApath" +# TODO quoting capath here changes semantics; before it was unset +# the -f would return 0, so we would call: +# openssl verify -CAfile ${tmpdir}/pubkey.pem +# with this change we call (when capath is empty): +# openssl verify -CApath ${tmpdir}/pubkey.pem +if [ -f "${capath}" ]; then + caopt="-CAfile" +fi diff --git a/usr.sbin/pledgectl/Makefile b/usr.sbin/pledgectl/Makefile new file mode 100644 index 000000000000..76f35adb9162 --- /dev/null +++ b/usr.sbin/pledgectl/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +#.include + +PROG= pledgectl +SRCS= pledgectl.c + +LIBADD= pledge xo + +MAN= pledgectl.8 + +#LINKS= ${BINDIR}/pledgectl /usr/sbin/pledgectl + +.include diff --git a/usr.sbin/pledgectl/pledgectl.8 b/usr.sbin/pledgectl/pledgectl.8 new file mode 100644 index 000000000000..1314df9303eb --- /dev/null +++ b/usr.sbin/pledgectl/pledgectl.8 @@ -0,0 +1,111 @@ +.Dd January 24, 2015 +.Dt PLEDGECTL 8 +.Os +.Sh NAME +.Nm pledgectl +.Nd administration of the pledge security mechanism +.\" +.Sh SYNOPSIS +.Nm +.Op Fl libxo=\fR\fIxoargs\fR +.Op Fl v +.Op Fl c | Fl L | Fl h +.Nm +.Op Fl libxo=\fR\fIxoargs\fR +.Op Fl v +.Fl s Ar mask Ar file ... +.Nm +.Op Fl libxo=\fR\fIxoargs\fR +.Op Fl v +.Fl l Ar file ... +.\" +.Sh DESCRIPTION +The +.Nm +utility interacts with the pledge(4) security mechanism and can +among other things be used to examine the "learning data" recorded by the +pledge subsystem when the +.Ar security.pledge.learning +sysctl is enabled. +The +.Nm libxo +library is used to produce structured output, see +.Xr libxo 3 +for accepted values of +.Ar "xoargs". +.\" +.Sh OPTIONS +.Bl -tag -width indent +.It Fl v +Increase output verbosity. When used once it will output information about the +interpretation of the specified task. Used twice ( +.Fl "vv") +it will print additional information about each processed item. +.It Fl E +Erase recorded learning data from the kernel. Used after modifying a binary +in order to invalidate the recorded results when they are no longer relevant. +.It Fl L +List learning data recorded by the kernel. +.It Fl l Ar file ... +List pledge extattr associated with given +.Ar "file(s)" . +Expands the binary representation (retrievable using +.Cm getextattr Fl "x system pledge" Ar "file ...") +to human-readable strings. +.It Fl m Ar mask Fl s Ar file ... +Set pledge extattr associated with given +.Ar "file(s)" . +The +.Ar mask +parameter may be either an integer value or a string accepted by +.Fn "pledge_string_to_bitmask" "mask" . +.It Fl h +Display usage / help. +.\" +.Sh EXIT STATUS +.Ex -std +.\" +.\" +.Sh EXAMPLES +.Ss Displaying hex/string representation of pledge mask: +Using the +.Ar -s +flag (with verbosity) to set an extattr mask without specifying a file will +simply print the result of the mask parsing: +.Bd -literal -offset indent +# pledgectl -v -s 'rpath stdio' +New pledge mask: 0x24: rpath stdio + +.Ed +.\" +.Ss Sandboxing a binary using extattr (no source code modifications): +.Bd -literal -offset indent +# sysctl security.pledge.learning=1 +# ncal > /dev/null +# pledgectl -L | grep ncal +/usr/bin/ncal Used:0x3c:( rpath wpath cpath stdio) Violated:0:( none) Possessed:0xfffffffffffffffc:( wildcard) +.Ed +.\" +.Bd -literal -offset indent +# pledgectl -s 'rpath wpath cpath stdio' /usr/bin/ncal +# pledgectl -l /usr/bin/ncal +/usr/bin/ncal: 0x3c: rpath wpath cpath stdio +.Ed +.\" +.Ss TODO Using DTrace +nope +.\" +.\" +.Sh SEE ALSO +.Xr pledge 4 , +.Xr pledge 3 , +.Xr libxo 3 , +.\" +.Sh HISTORY +.Nm TODO +.\" +.Sh BUGS +TODO plenty +.\" +.Sh AUTHORS +.An xxx Aq Mt example@TODO.com diff --git a/usr.sbin/pledgectl/pledgectl.c b/usr.sbin/pledgectl/pledgectl.c new file mode 100644 index 000000000000..412b3293d899 --- /dev/null +++ b/usr.sbin/pledgectl/pledgectl.c @@ -0,0 +1,669 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 1984-2025 John Q. Public + * + * Long, boring license goes here, but trimmed for brevity TODO + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int verbose = 0; + +static const char *const PLEDGECTL_XO_LEARNING_LIST = "learning"; +static const char *const CONTAINER_PLEDGECTL = "pledgectl"; +static const char *const CONTAINER_PLEDGECTL_VERSION = "1"; +/* + * These are constants for use with xo_open_instance() from libxo. + * When xo_emit() formats are change, this version number should be bumped. + */ + + +/* Forward function declarations for utility functions within this file: */ +static void usage(void); +static inline int print_learning_entry(const pledge_splay_t *const, + const char *const, const char *const); +static int pledgectl_erase_learning(void); +static int pledgectl_list_extattr(const char *); +static int pledgectl_set_extattr(const char *, uint64_t); +static const pledge_splay_t *tree_lookup_learning_entry(const dev_t, + const ino_t); +static void tree_free(void); +static int tree_build(const size_t, const pledge_learning_entry_t *const); +static int pledgectl_dump_all(void); + +static void +usage(void) +{ + xo_warnx("usage: erase: pledgectl [--libxo] [-v] -E\n" + " list-all: pledgectl [--libxo] [-v] -L\n" + " list-attr: pledgectl [--libxo] [-v] -l FILE ...\n" + " set-attr: pledgectl [--libxo] [-v] -s MASK [FILE ...]\n" + " show usage: pledgectl [--libxo] [-v] -h\n" + "TODO 'local learning mode'/'trace'/'profile' for a given execution\n" + "TODO remove extattr from file(s)\n" + "TODO -l default to stuff in PATH\n" + ); + + if (verbose) { + /* + * List flags that this version of libpledge was + * compiled with: + */ + for (unsigned int i = 0; i < sizeof(pledge_string_map) + / sizeof(pledge_string_map[0]); i++) { + xo_emit("{:constant/%18#lx}{P:\t}{:flags}\n", + pledge_string_map[i].constant, + pledge_string_map[i].name); + } + } +} + + +static int +pledgectl_erase_learning(void) +{ + size_t freed_bytes = 0 ; + pledge_learning_entry_t unused_entry = {}; + int err = sysctlbyname("security.pledge.learning_data", + NULL, &freed_bytes, &unused_entry, 0); + + if (err) { + xo_warnx("Unable to erase learning data."); + return (18); + } + + xo_emit("{Lwc:Erased entries}{:erased-entries/%zu}\n", + freed_bytes / sizeof(pledge_learning_entry_t)); + + return (0); +} + +static int +pledgectl_list_extattr(const char *filename) +{ + /* + * This is where we read the extattr for argv entry, + * stringify it, and print it to stdout. + */ + uint64_t pledge_mask = (~0ULL); + + if (!filename) { + return (2); + } + + /* TODO: list EXTATTR_NAMESPACE_USER too */ + if (sizeof(pledge_mask) == extattr_get_file(filename, + EXTATTR_NAMESPACE_SYSTEM, "pledge", + &pledge_mask, sizeof(pledge_mask))) { + + pledge_mask = le64toh(pledge_mask); + + char *mask_str = pledge_bitmask_to_string(pledge_mask); + if (!mask_str) { + xo_warnx("Unable to convert pledge flags to string."); + return (3); + } + + xo_open_instance("file"); + xo_emit_f(XOEF_RETAIN, + "{wc:filename}{wc:pledge-mask/%#lx}{:pledge-str}\n", + filename, pledge_mask, mask_str); + xo_close_instance("file"); + + free(mask_str); + return (0); /* success */ + } else { + xo_warnx("%s: error: Unable to read 'pledge' extattr " + "for file.", filename); + return (4); + } +} + +static int +pledgectl_set_extattr(const char *filename, uint64_t new_extattr_mask) +{ + /* TODO support setting the userspace */ + new_extattr_mask = htole64(new_extattr_mask); + if (sizeof(new_extattr_mask) == extattr_set_file(filename, + EXTATTR_NAMESPACE_SYSTEM, "pledge", + &new_extattr_mask, sizeof(new_extattr_mask))) { + + if (verbose > 1) { + xo_open_instance("file"); + xo_emit_f(XOEF_RETAIN, + "{wc:new-mask/%18#lx}{:filename}\n", + new_extattr_mask, filename); + xo_close_instance("file"); + } + + return (0); + } else { + xo_warnx("Setting 'pledge' extattr for %s failed.", + filename); + return (5); + } +} + + +static PLEDGE_LEARNING_COMPARE_PROTOTYPE +static PLEDGE_LEARNING_COMPARE_IMPL + +typedef RB_HEAD(learning_tree, pledge_splay_t) learning_tree_t; +static learning_tree_t learning_tree; + +RB_PROTOTYPE_STATIC(learning_tree, pledge_splay_t, + tree_link, learning_tree_compare); +RB_GENERATE_STATIC(learning_tree, + pledge_splay_t, tree_link, learning_tree_compare); + +/* + * Returns NULL when the entry does not exist in the data retrieved from + * the kernel. + */ +static const pledge_splay_t * +tree_lookup_learning_entry(const dev_t target_fsid, const ino_t target_inode) +{ + pledge_splay_t stack_el = { + .inode = target_inode, + .fs_id = target_fsid, + }; + return (learning_tree_RB_FIND(&learning_tree, &stack_el)); +} + +/* + * Free the elements of the RB tree. + */ +static void +tree_free(void) +{ + pledge_splay_t *np = NULL; + pledge_splay_t *tmp_next = NULL; + RB_FOREACH_SAFE(np, learning_tree, &learning_tree, tmp_next) { + free(learning_tree_RB_REMOVE(&learning_tree, np)); + } + /* (learning_tree) itself is statically allocated, no free() needed. */ +} + +/* + * Build an RB tree from the array of learning data retrieved from the kernel + * to enable efficient lookups of fsid,inode using tree_lookup_learning_entry(). + * If successful, the tree must subsequently be freed using tree_free(). + */ +static int +tree_build(const size_t entry_count, + const pledge_learning_entry_t *const entries) +{ + size_t cardinality = 0; + size_t unpopulated = 0; + size_t merged = 0; + for (size_t idx = 0; idx < entry_count; idx++) { + const pledge_learning_entry_t *const entry = entries + idx; + if (!entry->is_populated) { + ++unpopulated; + continue; + } + pledge_splay_t *new_el = calloc(1, sizeof(pledge_splay_t)); + if (!new_el) { + xo_warnx("error: not enough memory to " + "build tree of learning entries\n"); + return (1); + } + new_el->fs_id = entry->fsid; + new_el->inode = entry->inode; + pledge_splay_t *el = learning_tree_RB_INSERT(&learning_tree, new_el); + if (el) { + /* + * Element already existed from other CPU, + * we deduplicate and merge into a single entry: + */ + ++merged; + free(new_el); + assert(el->fs_id == entry->fsid); + assert(el->inode == entry->inode); + } else { + ++cardinality; + el = new_el; + } + el->used |= entry->used_flags; + el->violated |= entry->violated_flags; + el->possessed |= entry->possessed; + } + if (verbose) + xo_warnx("Merged learning entries from kernel: %zd " + "unpopulated: %zd merged: %zd", cardinality, unpopulated, merged); + if (verbose > 2) { + xo_open_instance("learning_tree"); + struct pledge_splay_t *tel=NULL; + RB_FOREACH(tel, learning_tree, &learning_tree) { + xo_emit_f(XOEF_RETAIN, + "{[:}{c:fs_id/%18#lx}/{c:ide/%18#lx}{]:}{P:\n}", + tel->fs_id, tel->inode + ); + } + xo_close_instance("learning_tree"); + } + return (0); +} + +/* + * Returns 1 if the entry is exempt from printing due to lack of useful + * information (no used/violated, possessed was "wildcard"), + * and non-zero on other errors. + */ +static inline int +print_learning_entry(const pledge_splay_t *const entry, + const char *const path, const char *const entname) +{ + /* Don't print if there's no useful information: */ + if ((PLEDGE_WILDCARD == entry->used || 0 == entry->used) + && 0 == entry->violated + && PLEDGE_WILDCARD == entry->possessed + ) return (1); + + char *used_str = pledge_bitmask_to_string(entry->used); + char *violated_str = pledge_bitmask_to_string(entry->violated); + char *possessed_str = pledge_bitmask_to_string(entry->possessed); + + if (!used_str || !violated_str || !possessed_str) { + uint64_t failed = 0; + if (used_str) free(used_str); + else failed = entry->used; + if (violated_str) free(violated_str); + else failed = entry->violated; + if (possessed_str) free(possessed_str); + else failed = entry->possessed; + xo_warnx("Unable to convert pledge flags %lx to string.", + failed); + return (13); + } + + // git fetch cfcs hardened/current/pledge && git checkout cfcs/hardened/current/pledge && rm -f /usr/obj/usr/src/amd64.amd64/usr.sbin/pledgectl/pledgectl.full && make && /usr/obj/usr/src/amd64.amd64/usr.sbin/pledgectl/pledgectl.full -v -L ; /usr/obj/usr/src/amd64.amd64/usr.sbin/pledgectl/pledgectl.full -v -l /usr/bin/ncal + + xo_open_instance("entry"); + + xo_emit_f(XOEF_RETAIN, + "{[:}{:directory}/{:executable}{]:}{P:\t}" + "{[:}{Lc:Used}{c:used-flags/%18#lx}{:used}{]:}{P:\t}" + "{[:}{C:/%s}{Lc:Violated}{c:violated-flags/%18#lx}{:violated}" + "{C:}{]:}{P:\t}" + "{[:}{Lc:Possessed}{c:possessed-flags/%18#lx}{:possessed}{]:}\n", + path, entname, + entry->used, used_str, + (entry->violated ? "fg-red" : ""), + entry->violated, violated_str, + entry->possessed, possessed_str); + + xo_close_instance("entry"); + + free(used_str); + free(violated_str); + free(possessed_str); + + return (0); +} + +static int +pledgectl_dump_all(void) +{ + /* Learn how many learning data entries the kernel has for us: */ + size_t requested_bytes = 0 ; + int err = sysctlbyname("security.pledge.learning_data", + NULL, &requested_bytes, NULL, 0); + if (err) { + xo_warnx("Unable to obtain count of live learning entries."); + return (7); + } + + /* + * Since the kernel estimate is a conservative estimate due to lack of + * synchronization between the CPU fetching the counter value and the + * other CPUs, we ask for a few extra entries. This lets us pick up data + * for executables that have not been scheduled on the CPU handling our + * sysctl, and which hasn't synchronized its counter recently. + * Asking for too many entries is not a problem, it will just render us + * with some entry learning data slots (and a bit more memory used): + */ + requested_bytes += 256 * sizeof(pledge_learning_entry_t); + + const size_t requested_entry_count = requested_bytes + / sizeof(pledge_learning_entry_t); + + if (verbose && requested_entry_count) { + xo_warnx("Kernel reports having %zd learning entries.", + requested_entry_count - 256); + } + + /* Allocate memory for the array of entries to receive from kernel: */ + pledge_learning_entry_t *entries = calloc(requested_entry_count, + sizeof(pledge_learning_entry_t)); + + if (!entries) { + xo_warnx("Unable to allocate %zd bytes for %zd entries.", + requested_bytes, requested_entry_count); + return (8); + } + + size_t actual_bytes = requested_bytes; + err = sysctlbyname("security.pledge.learning_data", + entries, &actual_bytes, NULL, 0); + if (err) { + free(entries); + xo_warn("Unable to obtain learning entries" + " from kernel (%d).", err); + return (9); + } + + assert(actual_bytes <= requested_bytes); + assert(0 == actual_bytes % sizeof(pledge_learning_entry_t)); + + size_t actual_count = actual_bytes / sizeof(pledge_learning_entry_t); + + assert (actual_count <= requested_entry_count); + + if (!actual_count) { + // if (verbose) + xo_warnx("No learning data recorded." + " Check that sysctl security.pledge.learning=1"); + free(entries); + return (0); + } + + RB_INIT(&learning_tree); + err = tree_build(actual_count, entries); + free(entries); + if (err) { + xo_warnx("error: Failed to build tree."); + return (err); + } + + struct statfs *statfs_array = NULL; + size_t filesystem_count = getmntinfo(&statfs_array, MNT_WAIT); + /* statfs.f_fsid */ + + if (!filesystem_count) { + xo_warn("Unable to obtain information about " + "mounted filesystems."); + return (15); + } + + /* + * We loop over each dir in $PATH, look up inode+fsid for each in our + * tree of learning data. When we have data about an executable, we + * examine it and print it if it contains any useful information. + */ + char *paths = strdup(getenv("PATH")); + if (!paths) { + xo_warnx("no $PATH given."); + /* statsfs_array is static, can't free */ + return (17); + } + + xo_open_list(PLEDGECTL_XO_LEARNING_LIST); + + unsigned int ignored = 0; + + char *dir_path = NULL; + while (NULL != (dir_path = strsep(&paths, ":"))) { + DIR *fd_dir = opendir(dir_path); + if (!fd_dir) { + continue; + } + /* Loop over each regular file in dir_path: */ + const struct dirent *dirent = NULL; + while (NULL != (dirent = readdir(fd_dir))) { + struct stat file_stat = {0}; + if (DT_REG != dirent->d_type) { + continue; /* Next entry in fd_dir */ + } + if (fstatat(dirfd(fd_dir), dirent->d_name, + &file_stat, 0)) { + xo_warn("couldn't stat %s/%s", + dir_path, dirent->d_name); + continue; + } + if (!S_ISREG(file_stat.st_mode)){ + continue; /* Next entry in fd_dir */ + } + const pledge_splay_t *const entry = + tree_lookup_learning_entry(file_stat.st_dev, + file_stat.st_ino); + _Static_assert(sizeof(entry->fs_id) == sizeof(file_stat.st_ino), "fsid/devt not compatible"); + if (NULL == entry) { + if (verbose >= 2) { + xo_warnx("%s/%s: no learning data for %lx:%lx", + dir_path, dirent->d_name, file_stat.st_dev, file_stat.st_ino); + } + } + else switch (print_learning_entry(entry, dir_path, + dirent->d_name)) { + case 0: + break; + case 1: + ++ignored; + break; + default: + xo_warnx("error printing for %s/%s", + dir_path, dirent->d_name); + } + } + if (closedir(fd_dir)) { + xo_warn("%s: error: ", dir_path); + } + } + + free(paths); + tree_free(); + + xo_close_list(PLEDGECTL_XO_LEARNING_LIST); + if (ignored && verbose) { + xo_emit("{Lwc:Ignored entries}{:ignored-entries/%u}\n", + ignored); + } + + return (0); +} + +int main(int argc, char *argv[]) +{ + int err = 0; + /* + * Drop unneeded privileges: + */ + err = pledge(PLEDGE_STDIO | PLEDGE_RPATH | PLEDGE_FATTR + | PLEDGE_DEVICE | PLEDGE_SYSCTL + | PLEDGE_CAPSICUM /* We don't actually use capsicum, + * need to investigate that.*/ + ); + + xo_set_flags(NULL, XOF_WARN | XOF_COLUMNS); + argc = xo_parse_args(argc, argv); + xo_set_version(CONTAINER_PLEDGECTL_VERSION); + xo_open_container(CONTAINER_PLEDGECTL); + + if (err) + xo_errx(1, "pledgectl: Setting pledge mask failed. " + "Is kernel compiled with config 'option HBSD_PLEDGE' ?\n");; + + if (argc < 1) { + xo_warnx("error: not enough arguments"); + } + + /* + * Parse command-line options: + */ + + enum { UNSET, ERASE_LEARNING, DUMP_ALL, LIST_EXTATTR, + SET_EXTATTR } action = UNSET; + + int ch = (-1); /* getopt variable */ + + /* pledge privs to assign to extattr: */ + uint64_t new_extattr_mask = PLEDGE_NONE; + + while (argc && (ch = getopt(argc, argv, "EhLls:v")) != -1) { + + /* + * Only permit ONE action: + */ + switch (ch) { + case 'E': + case 'L': + case 'l': + case 's': + if (UNSET != action) { + xo_warnx("conflicting option -%c", ch); + action = UNSET; + argc = 0; + } + break; + case '?': + xo_warnx("error: unrecognized option -%c", optopt); + break; + } + + switch (ch) { + case 'E': + action = ERASE_LEARNING; break; + case 'L': + action = DUMP_ALL; break; + case 'l': + action = LIST_EXTATTR; break; + case 's': + if (PLEDGE_NONE != new_extattr_mask) { + xo_warnx("error: -s given more than once"); + action = UNSET; + break; + } + + intptr_t res = + pledge_string_to_bitmask(optarg, &new_extattr_mask); + if ( res < 0 || + (res > 0 && (unsigned long)res >= strlen(optarg))) { + xo_errx(14, + "error: Unable to parse -s argument '%s'.", + optarg); + } else if (res > 0) { + /* Underline offending char: */ + // TODO PRIuPTR ? + xo_errx(15, + "error: Unable to parse -s argument '" + "%.*s\033[4m%c\033[0m%s'" + " error at offset %d.", + (int)res, optarg, + *(optarg + res), optarg + res + 1, + (int)res); + } + + if (verbose) { + char *str = pledge_bitmask_to_string( + new_extattr_mask); + if (str) { + xo_emit("{Lwc:New pledge mask}" + "{wc:new-mask/%18#lx}" + "{:new-strmask}\n", + new_extattr_mask, str); + free(str); + } + } + action = SET_EXTATTR; + break; + case 'v': + verbose++; + break; + default: + /* -h and unrecognized flags will end here: */ + action = UNSET; + argc = 0; + } + } + argc -= optind; + argv += optind; + + /* pledge privs required for requested action */ + uint64_t action_mask = PLEDGE_STDIO; + switch (action) { + case LIST_EXTATTR: + action_mask |= PLEDGE_RPATH; break; + case DUMP_ALL: + action_mask |= PLEDGE_RPATH | PLEDGE_SYSCTL; break; + case SET_EXTATTR: + action_mask |= PLEDGE_FATTR; break; + case ERASE_LEARNING: + action_mask |= PLEDGE_SYSCTL; break; + default: break; + } + + if (pledge(action_mask)) { + xo_warnx("error: Unable to drop privileges for the " + "requested action."); + goto finish; + } + + /* + * Perform requested actions: + */ + switch (action) { + case ERASE_LEARNING: /* Erase learning data in kernel with sysctl */ + err = pledgectl_erase_learning(); + break; + + case DUMP_ALL: /* Dump from kernel with sysctl */ + err = pledgectl_dump_all(); + break; + + case LIST_EXTATTR: /* Retrieve extattr pledge mask */ + xo_open_list("list-extattr"); + while (argc) { + err |= pledgectl_list_extattr( argv[--argc] ); + } + xo_close_list("list-extattr"); + break; + + case SET_EXTATTR: /* Set extattr pledge mask for executable */ + xo_open_list("set-extattr"); + while (argc) { + err |= pledgectl_set_extattr( argv[--argc], + new_extattr_mask ); + } + xo_open_list("set-extattr"); + break; + + case UNSET: + default: + usage(); + } + +finish: + xo_close_container(CONTAINER_PLEDGECTL); + xo_flush(); // TODO is flush needed here?? + xo_finish(); + + return (err); +}