diff --git a/gnu/llvm/llvm/lib/Target/X86/X86RetClean.cpp b/gnu/llvm/llvm/lib/Target/X86/X86RetClean.cpp index 623bfede5..671f4a491 100644 --- a/gnu/llvm/llvm/lib/Target/X86/X86RetClean.cpp +++ b/gnu/llvm/llvm/lib/Target/X86/X86RetClean.cpp @@ -96,6 +96,10 @@ bool RetCleanPass::runOnMachineFunction(MachineFunction &MF) { bool modified = false; + // If a setjmp-like function is called by this function, we should not clean + if (MF.exposesReturnsTwice()) + return false; + for (auto &MBB : MF) { std::vector fixups; bool foundcall = false; diff --git a/lib/libcrypto/man/X509_STORE_CTX_set_verify.3 b/lib/libcrypto/man/X509_STORE_CTX_set_verify.3 index 2c0bd692a..8c27deea5 100644 --- a/lib/libcrypto/man/X509_STORE_CTX_set_verify.3 +++ b/lib/libcrypto/man/X509_STORE_CTX_set_verify.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: X509_STORE_CTX_set_verify.3,v 1.7 2023/08/10 16:15:42 schwarze Exp $ +.\" $OpenBSD: X509_STORE_CTX_set_verify.3,v 1.8 2024/06/07 05:51:39 tb Exp $ .\" .\" Copyright (c) 2021, 2022 Ingo Schwarze .\" Copyright (c) 2023 Job Snijders @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 10 2023 $ +.Dd $Mdocdate: June 7 2024 $ .Dt X509_STORE_CTX_SET_VERIFY 3 .Os .Sh NAME @@ -142,6 +142,28 @@ function provided by the user should check whether a given certificate was issued using the CA certificate .Fa issuer , and must return 0 on failure and 1 on success. +The default implementation ignores the +.Fa ctx +argument and returns success if and only if +.Xr X509_check_issued 3 +returns +.Dv X509_V_OK . +It is important to pay close attention to the order of the +.Fa issuer +and +.Fa subject +arguments. +In +.Xr X509_check_issued 3 +the +.Fa issuer +precedes the +.Fa subject +while in +.Fn check_issued +the +.Fa subject +comes first. .Sh RETURN VALUES .Fn X509_STORE_CTX_verify_fn is supposed to return 1 to indicate that the chain is valid @@ -221,3 +243,14 @@ and .Fn X509_STORE_CTX_get_check_issued first appeared in OpenSSL 1.1.0 and have been available since .Ox 7.3 . +.Sh BUGS +The reversal of order of +.Fa subject +and +.Fa issuer +between +.Fn check_issued +and +.Xr X509_check_issued 3 +is very confusing. +It has led to bugs and will cause many more. diff --git a/lib/libcrypto/man/X509_cmp.3 b/lib/libcrypto/man/X509_cmp.3 index f90bc0e6d..b1cdec177 100644 --- a/lib/libcrypto/man/X509_cmp.3 +++ b/lib/libcrypto/man/X509_cmp.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: X509_cmp.3,v 1.3 2021/07/02 10:50:39 schwarze Exp $ +.\" $OpenBSD: X509_cmp.3,v 1.4 2024/06/07 14:00:09 job Exp $ .\" full merge up to: OpenSSL ea5d4b89 Jun 6 11:42:02 2019 +0800 .\" .\" This file is a derived work. @@ -65,7 +65,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED .\" OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: July 2 2021 $ +.Dd $Mdocdate: June 7 2024 $ .Dt X509_CMP 3 .Os .Sh NAME @@ -123,8 +123,10 @@ .Fn X509_cmp compares two X.509 certificates using .Xr memcmp 3 -on the SHA1 hashes of their canonical (DER) representations as generated with +on the hashes of their canonical (DER) representations as generated with .Xr X509_digest 3 . +The digest function is implementation-specific: LibreSSL uses SHA-512, other +implementations use SHA-1. .Pp .Fn X509_NAME_cmp compares two X.501 @@ -172,8 +174,10 @@ structures using .Fn X509_CRL_match compares two certificate revocation lists using .Xr memcmp 3 -on the SHA1 hashes of their canonical (DER) representations as generated with +on the hashes of their canonical (DER) representations as generated with .Xr X509_CRL_digest 3 . +The digest function is implementation-specific: LibreSSL uses SHA-512, other +implementations use SHA-1. .Sh RETURN VALUES All these functions return 0 to indicate a match or a non-zero value to indicate a mismatch. diff --git a/lib/libcrypto/x509/x509_verify.c b/lib/libcrypto/x509/x509_verify.c index c7b2219fa..d3534879b 100644 --- a/lib/libcrypto/x509/x509_verify.c +++ b/lib/libcrypto/x509/x509_verify.c @@ -1,4 +1,4 @@ -/* $OpenBSD: x509_verify.c,v 1.69 2024/04/08 23:46:21 beck Exp $ */ +/* $OpenBSD: x509_verify.c,v 1.70 2024/06/07 06:21:40 tb Exp $ */ /* * Copyright (c) 2020-2021 Bob Beck * @@ -528,7 +528,7 @@ x509_verify_potential_parent(struct x509_verify_ctx *ctx, X509 *parent, return (ctx->xsc->check_issued(ctx->xsc, child, parent)); /* XXX key usage */ - return X509_check_issued(child, parent) != X509_V_OK; + return X509_check_issued(parent, child) == X509_V_OK; } static int diff --git a/regress/sys/net/pf_divert/LICENSE b/regress/sys/net/pf_divert/LICENSE index 52b251631..7c7565696 100644 --- a/regress/sys/net/pf_divert/LICENSE +++ b/regress/sys/net/pf_divert/LICENSE @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2017 Alexander Bluhm +# Copyright (c) 2010-2024 Alexander Bluhm # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/regress/sys/net/pf_divert/remote.pl b/regress/sys/net/pf_divert/remote.pl index a32330f53..7d0794315 100644 --- a/regress/sys/net/pf_divert/remote.pl +++ b/regress/sys/net/pf_divert/remote.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl -# $OpenBSD: remote.pl,v 1.9 2017/12/18 17:01:27 bluhm Exp $ +# $OpenBSD: remote.pl,v 1.10 2024/06/08 22:50:40 bluhm Exp $ -# Copyright (c) 2010-2015 Alexander Bluhm +# Copyright (c) 2010-2024 Alexander Bluhm # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -272,4 +272,5 @@ sub copy_prefix { chomp; print $dst "$prefix: $_\n" if length; } + $src->clearerr(); } diff --git a/regress/usr.bin/ssh/Makefile b/regress/usr.bin/ssh/Makefile index 09870cd1a..27737c38a 100644 --- a/regress/usr.bin/ssh/Makefile +++ b/regress/usr.bin/ssh/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.133 2024/01/11 04:50:28 djm Exp $ +# $OpenBSD: Makefile,v 1.134 2024/06/06 19:49:25 djm Exp $ OPENSSL?= yes @@ -102,7 +102,8 @@ LTESTS= connect \ connection-timeout \ match-subsystem \ agent-pkcs11-restrict \ - agent-pkcs11-cert + agent-pkcs11-cert \ + penalty INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers INTEROP_TESTS+= dropbear-ciphers dropbear-kex diff --git a/regress/usr.bin/ssh/penalty.sh b/regress/usr.bin/ssh/penalty.sh new file mode 100644 index 000000000..5ac7ef67e --- /dev/null +++ b/regress/usr.bin/ssh/penalty.sh @@ -0,0 +1,51 @@ +# $OpenBSD +# Placed in the Public Domain. + +tid="penalties" + +grep -vi PerSourcePenalties $OBJ/sshd_config > $OBJ/sshd_config.bak +cp $OBJ/authorized_keys_${USER} $OBJ/authorized_keys_${USER}.bak + +conf() { + test -z "$PIDFILE" || stop_sshd + (cat $OBJ/sshd_config.bak ; + echo "PerSourcePenalties $@") > $OBJ/sshd_config + cp $OBJ/authorized_keys_${USER}.bak $OBJ/authorized_keys_${USER} + start_sshd +} + +conf "noauth:10s authfail:6s grace-exceeded:10s min:8s max:20s" + +verbose "test connect" +${SSH} -F $OBJ/ssh_config somehost true || fatal "basic connect failed" + +verbose "penalty for authentication failure" + +# Fail authentication once +cat /dev/null > $OBJ/authorized_keys_${USER} +${SSH} -F $OBJ/ssh_config somehost true && fatal "noauth connect succeeded" +cp $OBJ/authorized_keys_${USER}.bak $OBJ/authorized_keys_${USER} + +# Should be below penalty threshold +${SSH} -F $OBJ/ssh_config somehost true || fatal "authfail not expired" + +# Fail authentication again; penalty should activate +cat /dev/null > $OBJ/authorized_keys_${USER} +${SSH} -F $OBJ/ssh_config somehost true && fatal "noauth connect succeeded" +cp $OBJ/authorized_keys_${USER}.bak $OBJ/authorized_keys_${USER} + +# These should be refused by the active penalty +${SSH} -F $OBJ/ssh_config somehost true && fail "authfail not rejected" +sleep 5 +${SSH} -F $OBJ/ssh_config somehost true && fail "repeat authfail not rejected" + +# Penalty should have expired, this should succeed. +sleep 8 +${SSH} -F $OBJ/ssh_config somehost true || fail "authfail not expired" + +verbose "penalty for no authentication" +${SSHKEYSCAN} -p $PORT 127.0.0.1 >/dev/null 2>&1 || fatal "keyscan failed" + +# Repeat attempt should be penalised +${SSHKEYSCAN} -p $PORT 127.0.0.1 >/dev/null 2>&1 && fail "keyscan not rejected" + diff --git a/regress/usr.bin/ssh/test-exec.sh b/regress/usr.bin/ssh/test-exec.sh index fc9b2402b..fcf916414 100644 --- a/regress/usr.bin/ssh/test-exec.sh +++ b/regress/usr.bin/ssh/test-exec.sh @@ -1,4 +1,4 @@ -# $OpenBSD: test-exec.sh,v 1.111 2024/05/17 01:45:22 djm Exp $ +# $OpenBSD: test-exec.sh,v 1.114 2024/06/06 19:48:40 djm Exp $ # Placed in the Public Domain. #SUDO=sudo @@ -265,33 +265,31 @@ export SSH_PKCS11_HELPER SSH_SK_HELPER stop_sshd () { - if [ -f $PIDFILE ]; then - pid=`$SUDO cat $PIDFILE` - if [ "X$pid" = "X" ]; then - echo no sshd running - else - if [ $pid -lt 2 ]; then - echo bad pid for sshd: $pid - else - $SUDO kill $pid - trace "wait for sshd to exit" - i=0; - while [ -f $PIDFILE -a $i -lt 5 ]; do - i=`expr $i + 1` - sleep $i - done - if test -f $PIDFILE; then - if $SUDO kill -0 $pid; then - echo "sshd didn't exit " \ - "port $PORT pid $pid" - else - echo "sshd died without cleanup" - fi - exit 1 - fi - fi - fi + [ -f $PIDFILE ] || return + pid=`$SUDO cat $PIDFILE` + if [ "X$pid" = "X" ]; then + echo "no sshd running" 1>&2 + return + elif [ $pid -lt 2 ]; then + echo "bad pid for sshd: $pid" 1>&2 + return fi + $SUDO kill $pid + trace "wait for sshd to exit" + i=0; + while [ -f $PIDFILE -a $i -lt 5 ]; do + i=`expr $i + 1` + sleep $i + done + if test -f $PIDFILE; then + if $SUDO kill -0 $pid; then + echo "sshd didn't exit port $PORT pid $pid" 1>&2 + else + echo "sshd died without cleanup" 1>&2 + fi + exit 1 + fi + PIDFILE="" } # helper @@ -427,6 +425,7 @@ cat << EOF > $OBJ/sshd_config AcceptEnv _XXX_TEST Subsystem sftp $SFTPSERVER SshdSessionPath $SSHD_SESSION + PerSourcePenalties no EOF # This may be necessary if /usr/src and/or /usr/obj are group-writable, @@ -689,6 +688,7 @@ start_sshd () i=`expr $i + 1` sleep $i done + ln -f -s ${logfile} $TEST_SSHD_LOGFILE test -f $PIDFILE || fatal "no sshd running on port $PORT" } diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c index 670beb278..6672773a9 100644 --- a/sys/arch/amd64/amd64/cpu.c +++ b/sys/arch/amd64/amd64/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.189 2024/05/29 12:21:33 kettenis Exp $ */ +/* $OpenBSD: cpu.c,v 1.190 2024/06/07 16:53:35 kettenis Exp $ */ /* $NetBSD: cpu.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */ /*- @@ -1469,7 +1469,10 @@ int cpu_suspended; void cpu_suspend_cycle(void) { - cpu_idle_cycle_fcn(); + if (cpu_suspend_cycle_fcn) + cpu_suspend_cycle_fcn(); + else + cpu_idle_cycle_fcn(); } int diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c index b85d5a006..efdfbc96c 100644 --- a/sys/arch/amd64/amd64/intr.c +++ b/sys/arch/amd64/amd64/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.58 2024/05/29 12:21:33 kettenis Exp $ */ +/* $OpenBSD: intr.c,v 1.59 2024/06/07 06:26:23 jsg Exp $ */ /* $NetBSD: intr.c,v 1.3 2003/03/03 22:16:20 fvdl Exp $ */ /* @@ -559,8 +559,6 @@ intr_handler(struct intrframe *frame, struct intrhand *ih) return rc; } -#define CONCAT(x,y) __CONCAT(x,y) - /* * Fake interrupt handler structures for the benefit of symmetry with * other interrupt sources, and the benefit of intr_calculatemasks() diff --git a/sys/arch/amd64/amd64/ipifuncs.c b/sys/arch/amd64/amd64/ipifuncs.c index 5c330d7a1..482fc9eeb 100644 --- a/sys/arch/amd64/amd64/ipifuncs.c +++ b/sys/arch/amd64/amd64/ipifuncs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipifuncs.c,v 1.38 2023/10/30 12:50:59 mvs Exp $ */ +/* $OpenBSD: ipifuncs.c,v 1.39 2024/06/07 16:53:35 kettenis Exp $ */ /* $NetBSD: ipifuncs.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /*- @@ -128,7 +128,10 @@ x86_64_ipi_halt(struct cpu_info *ci) wbinvd(); for(;;) { - __asm volatile("hlt"); + if (cpu_suspend_cycle_fcn) + cpu_suspend_cycle_fcn(); + else + __asm volatile("hlt"); } } diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 343cc0f7e..35cea0b58 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.293 2024/04/29 00:29:48 jsg Exp $ */ +/* $OpenBSD: machdep.c,v 1.294 2024/06/07 16:53:35 kettenis Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -162,6 +162,7 @@ char machine[] = MACHINE; */ void cpu_idle_cycle_hlt(void); void (*cpu_idle_cycle_fcn)(void) = &cpu_idle_cycle_hlt; +void (*cpu_suspend_cycle_fcn)(void); /* the following is used externally for concurrent handlers */ int setperf_prio = 0; diff --git a/sys/arch/amd64/amd64/mpbios.c b/sys/arch/amd64/amd64/mpbios.c index 4ecb31846..07df036ed 100644 --- a/sys/arch/amd64/amd64/mpbios.c +++ b/sys/arch/amd64/amd64/mpbios.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpbios.c,v 1.31 2022/02/21 11:03:39 mpi Exp $ */ +/* $OpenBSD: mpbios.c,v 1.32 2024/06/07 23:19:18 jsg Exp $ */ /* $NetBSD: mpbios.c,v 1.7 2003/05/15 16:32:50 fvdl Exp $ */ /*- @@ -856,14 +856,6 @@ mp_print_eisa_intr(int intr) } #endif - - -#define TAB_UNIT 4 -#define TAB_ROUND(a) _TAB_ROUND(a, TAB_UNIT) - -#define _TAB_ROUND(a,u) (((a) + (u - 1)) & ~(u - 1)) -#define EXTEND_TAB(a,u) (!(_TAB_ROUND(a, u) == _TAB_ROUND((a + 1), u))) - void mpbios_bus(const u_int8_t *ent, struct device *self) { diff --git a/sys/arch/amd64/conf/Makefile.amd64 b/sys/arch/amd64/conf/Makefile.amd64 index 263e7fe8d..aefa751ee 100644 --- a/sys/arch/amd64/conf/Makefile.amd64 +++ b/sys/arch/amd64/conf/Makefile.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.amd64,v 1.136 2024/06/05 20:19:26 deraadt Exp $ +# $OpenBSD: Makefile.amd64,v 1.137 2024/06/07 05:17:34 deraadt Exp $ # For instructions on building kernels consult the config(8) and options(4) # manual pages. @@ -73,7 +73,7 @@ CMACHFLAGS+= -mno-retpoline -fcf-protection=none .endif .else CMACHFLAGS+= -mretpoline-external-thunk -fcf-protection=branch -#CMACHFLAGS+= -fret-clean +CMACHFLAGS+= -fret-clean .endif .if ${COMPILER_VERSION:Mclang} NO_INTEGR_AS= -no-integrated-as diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h index fab34e5bd..90f5dd9e9 100644 --- a/sys/arch/amd64/include/cpu.h +++ b/sys/arch/amd64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.171 2024/05/29 12:21:33 kettenis Exp $ */ +/* $OpenBSD: cpu.h,v 1.172 2024/06/07 16:53:35 kettenis Exp $ */ /* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */ /*- @@ -420,6 +420,7 @@ void cpu_proc_fork(struct proc *, struct proc *); int amd64_pa_used(paddr_t); #define cpu_idle_enter() do { /* nothing */ } while (0) extern void (*cpu_idle_cycle_fcn)(void); +extern void (*cpu_suspend_cycle_fcn)(void); #define cpu_idle_cycle() (*cpu_idle_cycle_fcn)() #define cpu_idle_leave() do { /* nothing */ } while (0) extern void (*initclock_func)(void); diff --git a/sys/arch/amd64/include/i82489var.h b/sys/arch/amd64/include/i82489var.h index 374c61474..61840dd38 100644 --- a/sys/arch/amd64/include/i82489var.h +++ b/sys/arch/amd64/include/i82489var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: i82489var.h,v 1.18 2018/10/04 05:00:40 guenther Exp $ */ +/* $OpenBSD: i82489var.h,v 1.19 2024/06/09 03:12:59 jsg Exp $ */ /* $NetBSD: i82489var.h,v 1.1 2003/02/26 21:26:10 fvdl Exp $ */ /*- @@ -87,21 +87,6 @@ extern void Xresume_lapic_ltimer(void); extern void Xrecurse_lapic_ltimer(void); #define LAPIC_TIMER_VECTOR 0xc0 -/* - * 'pin numbers' for local APIC - */ -#define LAPIC_PIN_TIMER 0 -#define LAPIC_PIN_PCINT 2 -#define LAPIC_PIN_LVINT0 3 -#define LAPIC_PIN_LVINT1 4 -#define LAPIC_PIN_LVERR 5 - -extern void Xintr_lapic0(void); -extern void Xintr_lapic2(void); -extern void Xintr_lapic3(void); -extern void Xintr_lapic4(void); -extern void Xintr_lapic5(void); - /* * Vector used for Xen HVM Event Channel Interrupts. */ diff --git a/sys/arch/i386/i386/db_trace.c b/sys/arch/i386/i386/db_trace.c index 5f73dabee..4e83d064b 100644 --- a/sys/arch/i386/i386/db_trace.c +++ b/sys/arch/i386/i386/db_trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_trace.c,v 1.44 2023/04/26 16:53:58 claudio Exp $ */ +/* $OpenBSD: db_trace.c,v 1.45 2024/06/07 10:14:29 jsg Exp $ */ /* $NetBSD: db_trace.c,v 1.18 1996/05/03 19:42:01 christos Exp $ */ /* @@ -68,12 +68,6 @@ struct db_variable *db_eregs = db_regs + nitems(db_regs); */ #define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS) -#define NONE 0 -#define TRAP 1 -#define SYSCALL 2 -#define INTERRUPT 3 -#define AST 4 - int db_i386_numargs(struct callframe *); /* diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 26e524330..abb46f435 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.671 2024/05/26 13:37:32 kettenis Exp $ */ +/* $OpenBSD: machdep.c,v 1.672 2024/06/07 16:53:35 kettenis Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -167,6 +167,7 @@ char machine[] = MACHINE; void (*cpu_idle_leave_fcn)(void) = NULL; void (*cpu_idle_cycle_fcn)(void) = NULL; void (*cpu_idle_enter_fcn)(void) = NULL; +void (*cpu_suspend_cycle_fcn)(void); struct uvm_constraint_range isa_constraint = { 0x0, 0x00ffffffUL }; diff --git a/sys/arch/i386/i386/mpbios.c b/sys/arch/i386/i386/mpbios.c index fb1b70357..1775fb8ad 100644 --- a/sys/arch/i386/i386/mpbios.c +++ b/sys/arch/i386/i386/mpbios.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpbios.c,v 1.46 2024/05/13 01:15:50 jsg Exp $ */ +/* $OpenBSD: mpbios.c,v 1.47 2024/06/07 23:19:18 jsg Exp $ */ /* $NetBSD: mpbios.c,v 1.2 2002/10/01 12:56:57 fvdl Exp $ */ /*- @@ -925,14 +925,6 @@ mp_print_eisa_intr(int intr) printf(" EISA irq %d", intr); } - - -#define TAB_UNIT 4 -#define TAB_ROUND(a) _TAB_ROUND(a, TAB_UNIT) - -#define _TAB_ROUND(a,u) (((a) + (u - 1)) & ~(u - 1)) -#define EXTEND_TAB(a,u) (!(_TAB_ROUND(a, u) == _TAB_ROUND((a + 1), u))) - void mpbios_bus(const u_int8_t *ent, struct device *self) { diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 72e7d3381..4eb710735 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.189 2024/05/21 23:16:06 jsg Exp $ */ +/* $OpenBSD: cpu.h,v 1.190 2024/06/07 16:53:35 kettenis Exp $ */ /* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */ /*- @@ -375,6 +375,7 @@ extern const struct cpu_cpuid_nameclass i386_cpuid_cpus[]; extern void (*cpu_idle_enter_fcn)(void); extern void (*cpu_idle_cycle_fcn)(void); extern void (*cpu_idle_leave_fcn)(void); +extern void (*cpu_suspend_cycle_fcn)(void); extern int cpuspeed; diff --git a/sys/arch/i386/isa/clock.c b/sys/arch/i386/isa/clock.c index 3363ba15f..b9aad35cb 100644 --- a/sys/arch/i386/isa/clock.c +++ b/sys/arch/i386/isa/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.69 2024/05/13 01:15:50 jsg Exp $ */ +/* $OpenBSD: clock.c,v 1.70 2024/06/08 00:24:00 jsg Exp $ */ /* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */ /*- @@ -138,9 +138,6 @@ static struct timecounter i8254_timecounter = { struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH); u_long rtclock_tval; -#define SECMIN ((unsigned)60) /* seconds per minute */ -#define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ - u_int mc146818_read(void *sc, u_int reg) { diff --git a/sys/dev/acpi/acpicpu.c b/sys/dev/acpi/acpicpu.c index 0a5ee1fea..6a126fadd 100644 --- a/sys/dev/acpi/acpicpu.c +++ b/sys/dev/acpi/acpicpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpicpu.c,v 1.92 2022/04/06 18:59:27 naddy Exp $ */ +/* $OpenBSD: acpicpu.c,v 1.93 2024/06/07 16:53:35 kettenis Exp $ */ /* * Copyright (c) 2005 Marco Peereboom * Copyright (c) 2015 Philip Guenther @@ -172,6 +172,7 @@ void acpicpu_add_cstate(struct acpicpu_softc *_sc, int _state, int _method, int _flags, int _latency, int _power, uint64_t _address); void acpicpu_set_pdc(struct acpicpu_softc *); void acpicpu_idle(void); +void acpicpu_suspend(void); #if 0 void acpicpu_set_throttle(struct acpicpu_softc *, int); @@ -747,6 +748,7 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux) extern uint32_t acpi_force_bm; cpu_idle_cycle_fcn = &acpicpu_idle; + cpu_suspend_cycle_fcn = &acpicpu_suspend; /* * C3 (and maybe C2?) needs BM_RLD to be set to @@ -1277,3 +1279,66 @@ acpicpu_idle(void) sc->sc_prev_sleep = (sc->sc_prev_sleep + (sc->sc_prev_sleep >> 1) + itime) >> 1; } + +void +acpicpu_suspend(void) +{ + extern int cpu_suspended; + struct cpu_info *ci = curcpu(); + struct acpicpu_softc *sc = (struct acpicpu_softc *)ci->ci_acpicpudev; + struct acpi_cstate *best, *cx; + + if (sc == NULL) { + __asm volatile("sti"); + panic("null acpicpu"); + } + + /* + * Find the lowest usable state. + */ + best = cx = SLIST_FIRST(&sc->sc_cstates); + while ((cx->flags & CST_FLAG_SKIP)) { + if ((cx = SLIST_NEXT(cx, link)) == NULL) + break; + best = cx; + } + + switch (best->method) { + default: + case CST_METH_HALT: + __asm volatile("sti; hlt"); + break; + + case CST_METH_IO_HALT: + inb((u_short)best->address); + __asm volatile("sti; hlt"); + break; + + case CST_METH_MWAIT: + { + unsigned int hints; + + hints = (unsigned)best->address; + /* intel errata AAI65: cflush before monitor */ + if (ci->ci_cflushsz != 0 && + strcmp(cpu_vendor, "GenuineIntel") == 0) { + membar_sync(); + clflush((unsigned long)&cpu_suspended); + membar_sync(); + } + + monitor(&cpu_suspended, 0, 0); + if (cpu_suspended || !CPU_IS_PRIMARY(ci)) + mwait(0, hints); + + break; + } + + case CST_METH_GAS_IO: + inb((u_short)best->address); + /* something harmless to give system time to change state */ + acpi_read_pmreg(acpi_softc, ACPIREG_PM1_STS, 0); + break; + + } +} diff --git a/sys/dev/audio.c b/sys/dev/audio.c index 0d8bf45ab..7986ba477 100644 --- a/sys/dev/audio.c +++ b/sys/dev/audio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: audio.c,v 1.206 2023/02/10 14:34:16 visa Exp $ */ +/* $OpenBSD: audio.c,v 1.207 2024/06/07 08:48:10 jsg Exp $ */ /* * Copyright (c) 2015 Alexandre Ratchov * @@ -48,8 +48,6 @@ #define DPRINTFN(n, ...) do {} while(0) #endif -#define IPL_SOFTAUDIO IPL_SOFTNET - #define DEVNAME(sc) ((sc)->dev.dv_xname) #define AUDIO_UNIT(n) (minor(n) & 0x0f) #define AUDIO_DEV(n) (minor(n) & 0xf0) diff --git a/sys/dev/ic/ufshci.c b/sys/dev/ic/ufshci.c index 8f3c5d120..1e56a3c06 100644 --- a/sys/dev/ic/ufshci.c +++ b/sys/dev/ic/ufshci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ufshci.c,v 1.34 2024/06/05 04:58:05 mglocker Exp $ */ +/* $OpenBSD: ufshci.c,v 1.35 2024/06/09 03:21:54 jsg Exp $ */ /* * Copyright (c) 2022 Marcus Glocker @@ -89,8 +89,6 @@ int ufshci_utr_cmd_sync(struct ufshci_softc *, struct ufshci_ccb *, struct scsi_xfer *, uint32_t, uint16_t); int ufshci_xfer_complete(struct ufshci_softc *); -int ufshci_powerdown(struct ufshci_softc *); -int ufshci_resume(struct ufshci_softc *); /* SCSI */ int ufshci_ccb_alloc(struct ufshci_softc *, int); diff --git a/sys/dev/pci/fms.c b/sys/dev/pci/fms.c index e8fa53bfd..eebd73e93 100644 --- a/sys/dev/pci/fms.c +++ b/sys/dev/pci/fms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fms.c,v 1.38 2024/05/24 06:02:53 jsg Exp $ */ +/* $OpenBSD: fms.c,v 1.39 2024/06/09 05:18:12 jsg Exp $ */ /* $NetBSD: fms.c,v 1.5.4.1 2000/06/30 16:27:50 simonb Exp $ */ /*- @@ -118,9 +118,6 @@ int fms_read_codec(void *, u_int8_t, u_int16_t *); int fms_write_codec(void *, u_int8_t, u_int16_t); void fms_reset_codec(void *); -int fms_allocmem(struct fms_softc *, size_t, size_t, - struct fms_dma *); - int fms_match(struct device *parent, void *match, void *aux) { diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h index 61f2dde68..623e3feab 100644 --- a/sys/dev/pci/if_em_hw.h +++ b/sys/dev/pci/if_em_hw.h @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.h,v 1.94 2024/05/13 01:15:51 jsg Exp $ */ +/* $OpenBSD: if_em_hw.h,v 1.95 2024/06/09 05:18:12 jsg Exp $ */ /* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */ /* if_em_hw.h @@ -408,8 +408,6 @@ struct em_host_mng_dhcp_cookie{ }; int32_t em_read_part_num(struct em_hw *hw, uint32_t *part_num); -int32_t em_mng_write_dhcp_info(struct em_hw *hw, uint8_t *buffer, - uint16_t length); boolean_t em_check_mng_mode(struct em_hw *hw); boolean_t em_enable_tx_pkt_filtering(struct em_hw *hw); int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); diff --git a/sys/dev/pci/if_vmx.c b/sys/dev/pci/if_vmx.c index 0c5883a1b..e70d9b50f 100644 --- a/sys/dev/pci/if_vmx.c +++ b/sys/dev/pci/if_vmx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vmx.c,v 1.86 2024/05/21 19:49:06 jan Exp $ */ +/* $OpenBSD: if_vmx.c,v 1.87 2024/06/07 08:44:25 jan Exp $ */ /* * Copyright (c) 2013 Tsubai Masanari @@ -114,6 +114,8 @@ struct vmxnet3_comp_ring { }; u_int next; u_int32_t gen; + struct mbuf *sendmp; + struct mbuf *lastmp; }; struct vmxnet3_txqueue { @@ -160,6 +162,7 @@ struct vmxnet3_softc { struct vmxnet3_queue *sc_q; struct intrmap *sc_intrmap; + u_int sc_vrrs; struct vmxnet3_driver_shared *sc_ds; u_int8_t *sc_mcast; struct vmxnet3_upt1_rss_conf *sc_rss; @@ -170,7 +173,7 @@ struct vmxnet3_softc { #endif }; -#define JUMBO_LEN (1024 * 9) +#define JUMBO_LEN ((16 * 1024) - 1) #define DMAADDR(map) ((map)->dm_segs[0].ds_addr) #define READ_BAR0(sc, reg) bus_space_read_4((sc)->sc_iot0, (sc)->sc_ioh0, reg) @@ -273,15 +276,21 @@ vmxnet3_attach(struct device *parent, struct device *self, void *aux) return; } + /* Vmxnet3 Revision Report and Selection */ ver = READ_BAR1(sc, VMXNET3_BAR1_VRRS); - if ((ver & 0x1) == 0) { + if (ISSET(ver, 0x2)) { + sc->sc_vrrs = 2; + } else if (ISSET(ver, 0x1)) { + sc->sc_vrrs = 1; + } else { printf(": unsupported hardware version 0x%x\n", ver); return; } - WRITE_BAR1(sc, VMXNET3_BAR1_VRRS, 1); + WRITE_BAR1(sc, VMXNET3_BAR1_VRRS, sc->sc_vrrs); + /* UPT Version Report and Selection */ ver = READ_BAR1(sc, VMXNET3_BAR1_UVRS); - if ((ver & 0x1) == 0) { + if (!ISSET(ver, 0x1)) { printf(": incompatible UPT version 0x%x\n", ver); return; } @@ -410,6 +419,11 @@ vmxnet3_attach(struct device *parent, struct device *self, void *aux) ifp->if_capabilities |= IFCAP_TSOv4 | IFCAP_TSOv6; + if (sc->sc_vrrs == 2) { + ifp->if_xflags |= IFXF_LRO; + ifp->if_capabilities |= IFCAP_LRO; + } + #if NVLAN > 0 if (sc->sc_ds->upt_features & UPT1_F_VLAN) ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; @@ -704,6 +718,10 @@ vmxnet3_rxfill(struct vmxnet3_rxring *ring) uint32_t rgen; uint32_t type = htole32(VMXNET3_BTYPE_HEAD << VMXNET3_RX_BTYPE_S); + /* Second ring just contains packet bodies. */ + if (ring->rid == 1) + type = htole32(VMXNET3_BTYPE_BODY << VMXNET3_RX_BTYPE_S); + MUTEX_ASSERT_LOCKED(&ring->mtx); slots = if_rxr_get(&ring->rxr, NRXDESC); @@ -781,17 +799,17 @@ vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq) VMX_DMA_LEN(&ring->dmamem)); bus_dmamap_sync(sc->sc_dmat, VMX_DMA_MAP(&ring->dmamem), 0, VMX_DMA_LEN(&ring->dmamem), BUS_DMASYNC_PREWRITE); - } - /* XXX only fill ring 0 */ - ring = &rq->cmd_ring[0]; - mtx_enter(&ring->mtx); - vmxnet3_rxfill(ring); - mtx_leave(&ring->mtx); + mtx_enter(&ring->mtx); + vmxnet3_rxfill(ring); + mtx_leave(&ring->mtx); + } comp_ring = &rq->comp_ring; comp_ring->next = 0; comp_ring->gen = VMX_RXC_GEN; + comp_ring->sendmp = NULL; + comp_ring->lastmp = NULL; memset(VMX_DMA_KVA(&comp_ring->dmamem), 0, VMX_DMA_LEN(&comp_ring->dmamem)); @@ -1074,9 +1092,9 @@ vmxnet3_rxintr(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq) struct mbuf_list ml = MBUF_LIST_INITIALIZER(); struct mbuf *m; bus_dmamap_t map; - unsigned int idx, len; + unsigned int idx; unsigned int next, rgen; - unsigned int done = 0; + unsigned int rid, done[2] = {0, 0}; next = comp_ring->next; rgen = comp_ring->gen; @@ -1096,11 +1114,14 @@ vmxnet3_rxintr(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq) idx = letoh32((rxcd->rxc_word0 >> VMXNET3_RXC_IDX_S) & VMXNET3_RXC_IDX_M); + if (letoh32((rxcd->rxc_word0 >> VMXNET3_RXC_QID_S) & VMXNET3_RXC_QID_M) < sc->sc_nqueues) - ring = &rq->cmd_ring[0]; + rid = 0; else - ring = &rq->cmd_ring[1]; + rid = 1; + + ring = &rq->cmd_ring[rid]; m = ring->m[idx]; KASSERT(m != NULL); @@ -1111,31 +1132,62 @@ vmxnet3_rxintr(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq) BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->sc_dmat, map); - done++; + done[rid]++; + + /* + * A receive descriptor of type 4 which is flaged as start of + * packet, contains the number of TCP segment of an LRO packet. + */ + if (letoh32((rxcd->rxc_word3 & VMXNET3_RXC_TYPE_M) >> + VMXNET3_RXC_TYPE_S) == 4 && + ISSET(rxcd->rxc_word0, VMXNET3_RXC_SOP)) { + m->m_pkthdr.ph_mss = letoh32(rxcd->rxc_word1 & + VMXNET3_RXC_SEG_CNT_M); + } + + m->m_len = letoh32((rxcd->rxc_word2 >> VMXNET3_RXC_LEN_S) & + VMXNET3_RXC_LEN_M); + + if (comp_ring->sendmp == NULL) { + comp_ring->sendmp = comp_ring->lastmp = m; + comp_ring->sendmp->m_pkthdr.len = 0; + } else { + CLR(m->m_flags, M_PKTHDR); + comp_ring->lastmp->m_next = m; + comp_ring->lastmp = m; + } + comp_ring->sendmp->m_pkthdr.len += m->m_len; + + if (!ISSET(rxcd->rxc_word0, VMXNET3_RXC_EOP)) + continue; + + /* + * End of Packet + */ if (letoh32(rxcd->rxc_word2 & VMXNET3_RXC_ERROR)) { ifp->if_ierrors++; - m_freem(m); + m_freem(comp_ring->sendmp); + comp_ring->sendmp = comp_ring->lastmp = NULL; continue; } - len = letoh32((rxcd->rxc_word2 >> VMXNET3_RXC_LEN_S) & - VMXNET3_RXC_LEN_M); - if (len < VMXNET3_MIN_MTU) { - m_freem(m); + if (comp_ring->sendmp->m_pkthdr.len < VMXNET3_MIN_MTU) { + m_freem(comp_ring->sendmp); + comp_ring->sendmp = comp_ring->lastmp = NULL; continue; } - m->m_pkthdr.len = m->m_len = len; - - vmxnet3_rx_offload(rxcd, m); if (((letoh32(rxcd->rxc_word0) >> VMXNET3_RXC_RSSTYPE_S) & VMXNET3_RXC_RSSTYPE_M) != VMXNET3_RXC_RSSTYPE_NONE) { - m->m_pkthdr.ph_flowid = letoh32(rxcd->rxc_word1); - SET(m->m_pkthdr.csum_flags, M_FLOWID); + comp_ring->sendmp->m_pkthdr.ph_flowid = + letoh32(rxcd->rxc_word1); + SET(comp_ring->sendmp->m_pkthdr.csum_flags, M_FLOWID); } - ml_enqueue(&ml, m); + vmxnet3_rx_offload(rxcd, comp_ring->sendmp); + ml_enqueue(&ml, comp_ring->sendmp); + comp_ring->sendmp = comp_ring->lastmp = NULL; } bus_dmamap_sync(sc->sc_dmat, VMX_DMA_MAP(&comp_ring->dmamem), @@ -1144,19 +1196,20 @@ vmxnet3_rxintr(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq) comp_ring->next = next; comp_ring->gen = rgen; - if (done == 0) - return; + for (int i = 0; i < 2; i++) { + if (done[i] == 0) + continue; - ring = &rq->cmd_ring[0]; + ring = &rq->cmd_ring[i]; - if (ifiq_input(rq->ifiq, &ml)) - if_rxr_livelocked(&ring->rxr); + if (ifiq_input(rq->ifiq, &ml)) + if_rxr_livelocked(&ring->rxr); - /* XXX Should we (try to) allocate buffers for ring 2 too? */ - mtx_enter(&ring->mtx); - if_rxr_put(&ring->rxr, done); - vmxnet3_rxfill(ring); - mtx_leave(&ring->mtx); + mtx_enter(&ring->mtx); + if_rxr_put(&ring->rxr, done[i]); + vmxnet3_rxfill(ring); + mtx_leave(&ring->mtx); + } } void @@ -1211,6 +1264,8 @@ vmxnet3_iff(struct vmxnet3_softc *sc) void vmxnet3_rx_offload(struct vmxnet3_rxcompdesc *rxcd, struct mbuf *m) { + uint32_t pkts; + /* * VLAN Offload */ @@ -1243,6 +1298,45 @@ vmxnet3_rx_offload(struct vmxnet3_rxcompdesc *rxcd, struct mbuf *m) else if (ISSET(rxcd->rxc_word3, VMXNET3_RXC_UDP)) SET(m->m_pkthdr.csum_flags, M_UDP_CSUM_IN_OK); } + + /* + * TCP Large Receive Offload + */ + + pkts = m->m_pkthdr.ph_mss; + m->m_pkthdr.ph_mss = 0; + + if (pkts > 1) { + struct ether_extracted ext; + uint32_t paylen; + + ether_extract_headers(m, &ext); + + paylen = ext.iplen; + if (ext.ip4 || ext.ip6) + paylen -= ext.iphlen; + + if (ext.tcp) { + paylen -= ext.tcphlen; + tcpstat_inc(tcps_inhwlro); + tcpstat_add(tcps_inpktlro, pkts); + } else { + tcpstat_inc(tcps_inbadlro); + } + + /* + * If we gonna forward this packet, we have to mark it as TSO, + * set a correct mss, and recalculate the TCP checksum. + */ + if (ext.tcp && paylen >= pkts) { + SET(m->m_pkthdr.csum_flags, M_TCP_TSO); + m->m_pkthdr.ph_mss = paylen / pkts; + } + if (ext.tcp && + ISSET(m->m_pkthdr.csum_flags, M_TCP_CSUM_IN_OK)) { + SET(m->m_pkthdr.csum_flags, M_TCP_CSUM_OUT); + } + } } void @@ -1309,6 +1403,13 @@ vmxnet3_init(struct vmxnet3_softc *sc) return EIO; } + /* TCP Large Receive Offload */ + if (ISSET(ifp->if_xflags, IFXF_LRO)) + SET(sc->sc_ds->upt_features, UPT1_F_LRO); + else + CLR(sc->sc_ds->upt_features, UPT1_F_LRO); + WRITE_CMD(sc, VMXNET3_CMD_SET_FEATURE); + /* Program promiscuous mode and multicast filters. */ vmxnet3_iff(sc); diff --git a/sys/dev/pci/if_vmxreg.h b/sys/dev/pci/if_vmxreg.h index c5338b720..55a5114c2 100644 --- a/sys/dev/pci/if_vmxreg.h +++ b/sys/dev/pci/if_vmxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vmxreg.h,v 1.9 2020/07/07 01:36:49 dlg Exp $ */ +/* $OpenBSD: if_vmxreg.h,v 1.10 2024/06/07 08:44:25 jan Exp $ */ /* * Copyright (c) 2013 Tsubai Masanari @@ -76,6 +76,7 @@ enum UPT1_RxStats { #define VMXNET3_CMD_RESET 0xcafe0002 /* reset device */ #define VMXNET3_CMD_SET_RXMODE 0xcafe0003 /* set interface flags */ #define VMXNET3_CMD_SET_FILTER 0xcafe0004 /* set address filter */ +#define VMXNET3_CMD_SET_FEATURE 0xcafe0009 /* set features */ #define VMXNET3_CMD_GET_STATUS 0xf00d0000 /* get queue errors */ #define VMXNET3_CMD_GET_STATS 0xf00d0001 #define VMXNET3_CMD_GET_LINK 0xf00d0002 /* get link status */ @@ -189,6 +190,7 @@ struct vmxnet3_rxcompdesc { u_int32_t rxc_word1; #define VMXNET3_RXC_RSSHASH_M 0xffffffff /* RSS hash value */ #define VMXNET3_RXC_RSSHASH_S 0 +#define VMXNET3_RXC_SEG_CNT_M 0x000000ff /* No. of seg. in LRO pkt */ u_int32_t rxc_word2; #define VMXNET3_RXC_LEN_M 0x00003fff @@ -210,6 +212,7 @@ struct vmxnet3_rxcompdesc { #define VMXNET3_RXC_FRAGMENT 0x00400000 /* IP fragment */ #define VMXNET3_RXC_FCS 0x00800000 /* frame CRC correct */ #define VMXNET3_RXC_TYPE_M 0x7f000000 +#define VMXNET3_RXC_TYPE_S 24 #define VMXNET3_RXC_GEN_M 0x00000001U #define VMXNET3_RXC_GEN_S 31 } __packed; diff --git a/sys/dev/pci/igc_api.h b/sys/dev/pci/igc_api.h index dee8557c7..ea56c5265 100644 --- a/sys/dev/pci/igc_api.h +++ b/sys/dev/pci/igc_api.h @@ -1,4 +1,4 @@ -/* $OpenBSD: igc_api.h,v 1.2 2022/05/11 06:14:15 kevlo Exp $ */ +/* $OpenBSD: igc_api.h,v 1.3 2024/06/09 05:18:12 jsg Exp $ */ /*- * Copyright 2021 Intel Corp * Copyright 2021 Rubicon Communications, LLC (Netgate) @@ -20,35 +20,17 @@ int igc_setup_init_funcs(struct igc_hw *, bool); int igc_init_mac_params(struct igc_hw *); int igc_init_nvm_params(struct igc_hw *); int igc_init_phy_params(struct igc_hw *); -int igc_get_bus_info(struct igc_hw *); -void igc_clear_vfta(struct igc_hw *); -void igc_write_vfta(struct igc_hw *, uint32_t, uint32_t); -int igc_force_mac_fc(struct igc_hw *); int igc_check_for_link(struct igc_hw *); int igc_reset_hw(struct igc_hw *); int igc_init_hw(struct igc_hw *); -int igc_setup_link(struct igc_hw *); int igc_get_speed_and_duplex(struct igc_hw *, uint16_t *, uint16_t *); -int igc_disable_pcie_master(struct igc_hw *); -void igc_config_collision_dist(struct igc_hw *); int igc_rar_set(struct igc_hw *, uint8_t *, uint32_t); -uint32_t igc_hash_mc_addr(struct igc_hw *, uint8_t *); void igc_update_mc_addr_list(struct igc_hw *, uint8_t *, uint32_t); int igc_check_reset_block(struct igc_hw *); -int igc_get_cable_length(struct igc_hw *); -int igc_validate_mdi_setting(struct igc_hw *); int igc_get_phy_info(struct igc_hw *); int igc_phy_hw_reset(struct igc_hw *); -void igc_power_up_phy(struct igc_hw *); -void igc_power_down_phy(struct igc_hw *); int igc_read_mac_addr(struct igc_hw *); -int igc_read_pba_string(struct igc_hw *, uint8_t *, uint32_t); -void igc_reload_nvm(struct igc_hw *); int igc_validate_nvm_checksum(struct igc_hw *); -int igc_read_nvm(struct igc_hw *, uint16_t, uint16_t, uint16_t *); -int igc_write_nvm(struct igc_hw *, uint16_t, uint16_t, uint16_t *); -int igc_set_d3_lplu_state(struct igc_hw *, bool); -int igc_set_d0_lplu_state(struct igc_hw *, bool); #endif /* _IGC_API_H_ */ diff --git a/sys/dev/pci/igc_mac.h b/sys/dev/pci/igc_mac.h index 0b800e9a1..524cd4caa 100644 --- a/sys/dev/pci/igc_mac.h +++ b/sys/dev/pci/igc_mac.h @@ -1,4 +1,4 @@ -/* $OpenBSD: igc_mac.h,v 1.1 2021/10/31 14:52:57 patrick Exp $ */ +/* $OpenBSD: igc_mac.h,v 1.2 2024/06/09 05:18:12 jsg Exp $ */ /*- * Copyright 2021 Intel Corp * Copyright 2021 Rubicon Communications, LLC (Netgate) @@ -12,34 +12,23 @@ void igc_init_mac_ops_generic(struct igc_hw *); int igc_null_ops_generic(struct igc_hw *); -int igc_null_link_info(struct igc_hw *, uint16_t *, uint16_t *); -bool igc_null_mng_mode(struct igc_hw *); -void igc_null_update_mc(struct igc_hw *, uint8_t *h, uint32_t); -void igc_null_write_vfta(struct igc_hw *, uint32_t a, uint32_t); -int igc_check_for_copper_link_generic(struct igc_hw *); int igc_config_fc_after_link_up_generic(struct igc_hw *); int igc_disable_pcie_master_generic(struct igc_hw *); int igc_force_mac_fc_generic(struct igc_hw *); int igc_get_auto_rd_done_generic(struct igc_hw *); -int igc_get_bus_info_pcie_generic(struct igc_hw *); -void igc_set_lan_id_single_port(struct igc_hw *); int igc_get_speed_and_duplex_copper_generic(struct igc_hw *, uint16_t *, uint16_t *); void igc_update_mc_addr_list_generic(struct igc_hw *, uint8_t *, uint32_t); int igc_rar_set_generic(struct igc_hw *, uint8_t *, uint32_t); int igc_set_fc_watermarks_generic(struct igc_hw *); int igc_setup_link_generic(struct igc_hw *); -int igc_validate_mdi_setting_crossover_generic(struct igc_hw *); int igc_hash_mc_addr_generic(struct igc_hw *, uint8_t *); void igc_clear_hw_cntrs_base_generic(struct igc_hw *); -void igc_clear_vfta_generic(struct igc_hw *); void igc_init_rx_addrs_generic(struct igc_hw *, uint16_t); -void igc_pcix_mmrbc_workaround_generic(struct igc_hw *); void igc_put_hw_semaphore_generic(struct igc_hw *); int igc_check_alt_mac_addr_generic(struct igc_hw *); -void igc_set_pcie_no_snoop_generic(struct igc_hw *, uint32_t); void igc_write_vfta_generic(struct igc_hw *, uint32_t, uint32_t); void igc_config_collision_dist_generic(struct igc_hw *); diff --git a/sys/dev/pci/igc_nvm.h b/sys/dev/pci/igc_nvm.h index 39404cee0..cc1ec3d8e 100644 --- a/sys/dev/pci/igc_nvm.h +++ b/sys/dev/pci/igc_nvm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: igc_nvm.h,v 1.1 2021/10/31 14:52:57 patrick Exp $ */ +/* $OpenBSD: igc_nvm.h,v 1.2 2024/06/09 05:18:12 jsg Exp $ */ /*- * Copyright 2021 Intel Corp * Copyright 2021 Rubicon Communications, LLC (Netgate) @@ -13,17 +13,11 @@ void igc_init_nvm_ops_generic(struct igc_hw *); int igc_null_read_nvm(struct igc_hw *, uint16_t, uint16_t, uint16_t *); void igc_null_nvm_generic(struct igc_hw *); -int igc_null_led_default(struct igc_hw *, uint16_t *); int igc_null_write_nvm(struct igc_hw *, uint16_t, uint16_t, uint16_t *); int igc_poll_eerd_eewr_done(struct igc_hw *, int); int igc_read_mac_addr_generic(struct igc_hw *); -int igc_read_pba_string_generic(struct igc_hw *, uint8_t *, uint32_t); int igc_read_nvm_eerd(struct igc_hw *, uint16_t, uint16_t, uint16_t *); -int igc_valid_led_default_generic(struct igc_hw *, uint16_t *); int igc_validate_nvm_checksum_generic(struct igc_hw *); -int igc_write_nvm_spi(struct igc_hw *, uint16_t, uint16_t, uint16_t *); -int igc_update_nvm_checksum_generic(struct igc_hw *); -void igc_release_nvm_generic(struct igc_hw *); void igc_reload_nvm_generic(struct igc_hw *); #endif /* _IGC_NVM_H_ */ diff --git a/sys/dev/pci/igc_phy.h b/sys/dev/pci/igc_phy.h index 9dafd927f..db9e41124 100644 --- a/sys/dev/pci/igc_phy.h +++ b/sys/dev/pci/igc_phy.h @@ -1,4 +1,4 @@ -/* $OpenBSD: igc_phy.h,v 1.2 2022/05/11 06:14:15 kevlo Exp $ */ +/* $OpenBSD: igc_phy.h,v 1.3 2024/06/09 05:18:12 jsg Exp $ */ /*- * Copyright 2021 Intel Corp * Copyright 2021 Rubicon Communications, LLC (Netgate) @@ -20,13 +20,8 @@ int igc_check_downshift_generic(struct igc_hw *); int igc_check_reset_block_generic(struct igc_hw *); int igc_get_phy_id(struct igc_hw *); int igc_phy_hw_reset_generic(struct igc_hw *); -int igc_phy_reset_dsp_generic(struct igc_hw *); -int igc_set_d3_lplu_state_generic(struct igc_hw *, bool); int igc_setup_copper_link_generic(struct igc_hw *); int igc_phy_has_link_generic(struct igc_hw *, uint32_t, uint32_t, bool *); -int igc_determine_phy_address(struct igc_hw *); -int igc_enable_phy_wakeup_reg_access_bm(struct igc_hw *, uint16_t *); -int igc_disable_phy_wakeup_reg_access_bm(struct igc_hw *, uint16_t *); void igc_power_up_phy_copper(struct igc_hw *); void igc_power_down_phy_copper(struct igc_hw *); int igc_read_phy_reg_mdic(struct igc_hw *, uint32_t offset, uint16_t *); diff --git a/sys/dev/pci/ixgbe.h b/sys/dev/pci/ixgbe.h index 2851b2858..e0a03bd26 100644 --- a/sys/dev/pci/ixgbe.h +++ b/sys/dev/pci/ixgbe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ixgbe.h,v 1.35 2024/04/12 19:27:43 jan Exp $ */ +/* $OpenBSD: ixgbe.h,v 1.36 2024/06/09 05:18:12 jsg Exp $ */ /****************************************************************************** @@ -268,10 +268,6 @@ int32_t ixgbe_init_hw(struct ixgbe_hw *hw); enum ixgbe_media_type ixgbe_get_media_type(struct ixgbe_hw *hw); int32_t ixgbe_identify_phy(struct ixgbe_hw *hw); void ixgbe_flap_tx_laser(struct ixgbe_hw *hw); -int32_t ixgbe_setup_link(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg_wait_to_complete); -int32_t ixgbe_setup_mac_link(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg_wait_to_complete); int32_t ixgbe_check_link(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool link_up_wait_to_complete); diff --git a/sys/net/pf.c b/sys/net/pf.c index 8591b044e..ecc6bfef4 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.1196 2024/05/14 08:26:13 jsg Exp $ */ +/* $OpenBSD: pf.c,v 1.1197 2024/06/07 18:24:16 bluhm Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -7958,12 +7958,17 @@ done: switch (pd.naf) { case AF_INET: if (pd.dir == PF_IN) { - if (ipforwarding == 0) { + int flags; + + if (ip_forwarding == 0) { ipstat_inc(ips_cantforward); action = PF_DROP; break; } - ip_forward(pd.m, ifp, NULL, 1); + flags = IP_FORWARDING | IP_REDIRECT; + if (ip_directedbcast) + SET(flags, IP_ALLOWBROADCAST); + ip_forward(pd.m, ifp, NULL, flags); } else ip_output(pd.m, NULL, NULL, 0, NULL, NULL, 0); break; diff --git a/sys/net/pipex.c b/sys/net/pipex.c index c2901741e..4aefbdfac 100644 --- a/sys/net/pipex.c +++ b/sys/net/pipex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pipex.c,v 1.153 2024/01/23 17:57:21 mvs Exp $ */ +/* $OpenBSD: pipex.c,v 1.154 2024/06/07 13:43:21 jsg Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -104,9 +104,6 @@ int pipex_prune = 1; /* [I] walk list every seconds */ struct mbuf_queue pipexoutq = MBUF_QUEUE_INITIALIZER( IFQ_MAXLEN, IPL_SOFTNET); -/* borrow an mbuf pkthdr field */ -#define ph_ppp_proto ether_vtag - #ifdef PIPEX_DEBUG int pipex_debug = 0; /* [A] systcl net.inet.ip.pipex_debug */ #endif diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c index ac4d6292b..a951063b8 100644 --- a/sys/netinet/ip_esp.c +++ b/sys/netinet/ip_esp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_esp.c,v 1.195 2022/05/03 09:18:11 claudio Exp $ */ +/* $OpenBSD: ip_esp.c,v 1.196 2024/06/07 13:15:25 jsg Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -334,8 +334,6 @@ esp_zeroize(struct tdb *tdbp) return error; } -#define MAXBUFSIZ (AH_ALEN_MAX > ESP_MAX_IVS ? AH_ALEN_MAX : ESP_MAX_IVS) - /* * ESP input processing, called (eventually) through the protocol switch. */ diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index 30bec63a5..2d42796dc 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_icmp.c,v 1.192 2023/09/16 09:33:27 mpi Exp $ */ +/* $OpenBSD: ip_icmp.c,v 1.193 2024/06/07 18:24:16 bluhm Exp $ */ /* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */ /* @@ -589,7 +589,7 @@ reflect: struct sockaddr_in ssrc; struct rtentry *newrt = NULL; - if (icmp_rediraccept == 0 || ipforwarding == 1) + if (icmp_rediraccept == 0 || ip_forwarding == 1) goto freeit; if (code > 3) goto badcode; diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index ad0455b50..38057fceb 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_input.c,v 1.394 2024/05/08 13:01:30 bluhm Exp $ */ +/* $OpenBSD: ip_input.c,v 1.395 2024/06/07 18:24:16 bluhm Exp $ */ /* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */ /* @@ -84,10 +84,10 @@ #endif /* values controllable via sysctl */ -int ipforwarding = 0; +int ip_forwarding = 0; int ipmforwarding = 0; int ipmultipath = 0; -int ipsendredirects = 1; +int ip_sendredirects = 1; int ip_dosourceroute = 0; int ip_defttl = IPDEFTTL; int ip_mtudisc = 1; @@ -108,8 +108,8 @@ const struct sysctl_bounded_args ipctl_vars[] = { #ifdef MROUTING { IPCTL_MRTPROTO, &ip_mrtproto, SYSCTL_INT_READONLY }, #endif - { IPCTL_FORWARDING, &ipforwarding, 0, 2 }, - { IPCTL_SENDREDIRECTS, &ipsendredirects, 0, 1 }, + { IPCTL_FORWARDING, &ip_forwarding, 0, 2 }, + { IPCTL_SENDREDIRECTS, &ip_sendredirects, 0, 1 }, { IPCTL_DEFTTL, &ip_defttl, 0, 255 }, { IPCTL_DIRECTEDBCAST, &ip_directedbcast, 0, 1 }, { IPCTL_IPPORT_FIRSTAUTO, &ipport_firstauto, 0, 65535 }, @@ -137,8 +137,8 @@ static struct mbuf_queue ipsendraw_mq; extern struct niqueue arpinq; int ip_ours(struct mbuf **, int *, int, int); -int ip_dooptions(struct mbuf *, struct ifnet *); -int in_ouraddr(struct mbuf *, struct ifnet *, struct route *); +int ip_dooptions(struct mbuf *, struct ifnet *, int); +int in_ouraddr(struct mbuf *, struct ifnet *, struct route *, int); int ip_fragcheck(struct mbuf **, int *); struct mbuf * ip_reass(struct ipqent *, struct ipq *); @@ -431,7 +431,7 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) #if NPF > 0 struct in_addr odst; #endif - int pfrdr = 0; + int flags = 0; KASSERT(*offp == 0); @@ -461,9 +461,15 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) goto bad; ip = mtod(m, struct ip *); - pfrdr = odst.s_addr != ip->ip_dst.s_addr; + if (odst.s_addr != ip->ip_dst.s_addr) + SET(flags, IP_REDIRECT); #endif + if (ip_forwarding != 0) + SET(flags, IP_FORWARDING); + if (ip_directedbcast) + SET(flags, IP_ALLOWBROADCAST); + hlen = ip->ip_hl << 2; /* @@ -472,7 +478,7 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ - if (hlen > sizeof (struct ip) && ip_dooptions(m, ifp)) { + if (hlen > sizeof (struct ip) && ip_dooptions(m, ifp, flags)) { m = *mp = NULL; goto bad; } @@ -483,7 +489,7 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) goto out; } - switch(in_ouraddr(m, ifp, &ro)) { + switch(in_ouraddr(m, ifp, &ro, flags)) { case 2: goto bad; case 1: @@ -565,7 +571,7 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) /* * Not for us; forward if possible and desirable. */ - if (ipforwarding == 0) { + if (!ISSET(flags, IP_FORWARDING)) { ipstat_inc(ips_cantforward); goto bad; } @@ -585,7 +591,7 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) } #endif /* IPSEC */ - ip_forward(m, ifp, &ro, pfrdr); + ip_forward(m, ifp, &ro, flags); *mp = NULL; rtfree(ro.ro_rt); return IPPROTO_DONE; @@ -807,7 +813,7 @@ ip_deliver(struct mbuf **mp, int *offp, int nxt, int af, int shared) #undef IPSTAT_INC int -in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct route *ro) +in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct route *ro, int flags) { struct rtentry *rt; struct ip *ip; @@ -837,7 +843,8 @@ in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct route *ro) * if it is received on the interface with that address. */ if (ISSET(rt->rt_flags, RTF_BROADCAST) && - (!ip_directedbcast || rt->rt_ifidx == ifp->if_index)) { + (!ISSET(flags, IP_ALLOWBROADCAST) || + rt->rt_ifidx == ifp->if_index)) { match = 1; /* Make sure M_BCAST is set */ @@ -876,7 +883,8 @@ in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct route *ro) break; } } - } else if (ipforwarding == 0 && rt->rt_ifidx != ifp->if_index && + } else if (!ISSET(flags, IP_FORWARDING) && + rt->rt_ifidx != ifp->if_index && !((ifp->if_flags & IFF_LOOPBACK) || (ifp->if_type == IFT_ENC) || (m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST))) { /* received on wrong interface. */ @@ -1150,7 +1158,7 @@ ip_flush(void) * 0 if the packet should be processed further. */ int -ip_dooptions(struct mbuf *m, struct ifnet *ifp) +ip_dooptions(struct mbuf *m, struct ifnet *ifp, int flags) { struct ip *ip = mtod(m, struct ip *); unsigned int rtableid = m->m_pkthdr.ph_rtableid; @@ -1371,8 +1379,8 @@ ip_dooptions(struct mbuf *m, struct ifnet *ifp) } } KERNEL_UNLOCK(); - if (forward && ipforwarding > 0) { - ip_forward(m, ifp, NULL, 1); + if (forward && ISSET(flags, IP_FORWARDING)) { + ip_forward(m, ifp, NULL, flags | IP_REDIRECT); return (1); } return (0); @@ -1514,7 +1522,7 @@ const u_char inetctlerrmap[PRC_NCMDS] = { * of codes and types. * * If not forwarding, just drop the packet. This could be confusing - * if ipforwarding was zero but some routing protocol was advancing + * if ip_forwarding was zero but some routing protocol was advancing * us as a gateway to somewhere. However, we must let the routing * protocol deal with that. * @@ -1522,7 +1530,7 @@ const u_char inetctlerrmap[PRC_NCMDS] = { * via a source route. */ void -ip_forward(struct mbuf *m, struct ifnet *ifp, struct route *ro, int srcrt) +ip_forward(struct mbuf *m, struct ifnet *ifp, struct route *ro, int flags) { struct mbuf mfake, *mcopy; struct ip *ip = mtod(m, struct ip *); @@ -1588,7 +1596,7 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct route *ro, int srcrt) if ((rt->rt_ifidx == ifp->if_index) && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && satosin(rt_key(rt))->sin_addr.s_addr != 0 && - ipsendredirects && !srcrt && + ip_sendredirects && !ISSET(flags, IP_REDIRECT) && !arpproxy(satosin(rt_key(rt))->sin_addr, m->m_pkthdr.ph_rtableid)) { if ((ip->ip_src.s_addr & ifatoia(rt->rt_ifa)->ia_netmask) == ifatoia(rt->rt_ifa)->ia_net) { @@ -1602,9 +1610,7 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct route *ro, int srcrt) } } - error = ip_output(m, NULL, ro, - (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), - NULL, NULL, 0); + error = ip_output(m, NULL, ro, flags | IP_FORWARDING, NULL, NULL, 0); rt = ro->ro_rt; if (error) ipstat_inc(ips_cantforward); diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index c0aeb7693..b21683a11 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.399 2024/05/16 13:01:04 bluhm Exp $ */ +/* $OpenBSD: ip_output.c,v 1.400 2024/06/07 18:24:16 bluhm Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -428,7 +428,7 @@ sendit: #endif #ifdef IPSEC - if ((flags & IP_FORWARDING) && ipforwarding == 2 && + if ((flags & IP_FORWARDING) && ip_forwarding == 2 && (!ipsec_in_use || m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) == NULL)) { error = EHOSTUNREACH; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index a963798db..d4e216344 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_var.h,v 1.117 2024/04/17 20:48:51 bluhm Exp $ */ +/* $OpenBSD: ip_var.h,v 1.118 2024/06/07 18:24:16 bluhm Exp $ */ /* $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $ */ /* @@ -204,10 +204,11 @@ struct ipoffnxt { }; /* flags passed to ip_output */ -#define IP_FORWARDING 0x1 /* most of ip header exists */ -#define IP_RAWOUTPUT 0x2 /* raw ip header exists */ -#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ -#define IP_MTUDISC 0x0800 /* pmtu discovery, set DF */ +#define IP_FORWARDING 0x0001 /* most of ip header exists */ +#define IP_RAWOUTPUT 0x0002 /* raw ip header exists */ +#define IP_REDIRECT 0x0004 /* redirected by pf or source route */ +#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ +#define IP_MTUDISC 0x0800 /* pmtu discovery, set DF */ extern struct ipstat ipstat; extern int ip_defttl; /* default IP ttl */ @@ -221,11 +222,12 @@ extern int ipport_firstauto; /* min port for port allocation */ extern int ipport_lastauto; /* max port for port allocation */ extern int ipport_hifirstauto; /* min dynamic/private port number */ extern int ipport_hilastauto; /* max dynamic/private port number */ -extern int ipforwarding; /* enable IP forwarding */ +extern int ip_forwarding; /* enable IP forwarding */ #ifdef MROUTING extern int ipmforwarding; /* enable multicast forwarding */ #endif extern int ipmultipath; /* enable multipath routing */ +extern int ip_directedbcast; /* accept all broadcast packets */ extern unsigned int la_hold_total; extern const struct pr_usrreqs rip_usrreqs; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 328521d6f..9ba66ae6d 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.405 2024/04/17 20:48:51 bluhm Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.406 2024/06/07 08:02:17 jsg Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -106,11 +106,6 @@ int tcp_flush_queue(struct tcpcb *); #ifdef INET6 #include #include - -/* for the packet header length in the mbuf */ -#define M_PH_LEN(m) (((struct mbuf *)(m))->m_pkthdr.len) -#define M_V6_LEN(m) (M_PH_LEN(m) - sizeof(struct ip6_hdr)) -#define M_V4_LEN(m) (M_PH_LEN(m) - sizeof(struct ip)) #endif /* INET6 */ int tcprexmtthresh = 3; diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index d5e8e2c25..9202ddacb 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6.c,v 1.266 2024/05/21 15:12:25 florian Exp $ */ +/* $OpenBSD: in6.c,v 1.267 2024/06/07 09:48:19 florian Exp $ */ /* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */ /* @@ -549,7 +549,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, struct in6_ifaddr *ia6) { int error = 0, hostIsNew = 0, plen = -1; - struct sockaddr_in6 dst6; + struct sockaddr_in6 dst6, gw6; struct in6_addrlifetime *lt; struct in6_multi_mship *imm; struct rtentry *rt; @@ -604,7 +604,13 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL); } - dst6 = ifra->ifra_dstaddr; + if (ifra->ifra_flags & IN6_IFF_AUTOCONF) { + gw6 = ifra->ifra_dstaddr; + memset(&dst6, 0, sizeof(dst6)); + } else { + dst6 = ifra->ifra_dstaddr; + memset(&gw6, 0, sizeof(gw6)); + } if (dst6.sin6_family == AF_INET6) { error = in6_check_embed_scope(&dst6, ifp->if_index); if (error) @@ -614,6 +620,11 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, (ifp->if_flags & IFF_LOOPBACK)) && plen != 128) return (EINVAL); } + if (gw6.sin6_family == AF_INET6) { + error = in6_check_embed_scope(&gw6, ifp->if_index); + if (error) + return error; + } /* lifetime consistency check */ lt = &ifra->ifra_lifetime; if (lt->ia6t_pltime > lt->ia6t_vltime) @@ -702,10 +713,10 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, } if ((ifra->ifra_flags & IN6_IFF_AUTOCONF) && - dst6.sin6_family == AF_INET6 && + gw6.sin6_family == AF_INET6 && !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia6->ia_gwaddr.sin6_addr)) { /* Set or update announcing router */ - ia6->ia_gwaddr = dst6; + ia6->ia_gwaddr = gw6; } /* diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 913fb6430..13e603754 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_forward.c,v 1.117 2024/04/16 12:56:39 bluhm Exp $ */ +/* $OpenBSD: ip6_forward.c,v 1.118 2024/06/07 18:24:16 bluhm Exp $ */ /* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */ /* @@ -75,7 +75,7 @@ * of codes and types. * * If not forwarding, just drop the packet. This could be confusing - * if ipforwarding was zero but some routing protocol was advancing + * if ip6_forwarding was zero but some routing protocol was advancing * us as a gateway to somewhere. However, we must let the routing * protocol deal with that. * diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index bf700ec32..f2ab244ff 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_mroute.c,v 1.141 2024/04/06 14:23:27 bluhm Exp $ */ +/* $OpenBSD: ip6_mroute.c,v 1.142 2024/06/07 08:37:59 jsg Exp $ */ /* $NetBSD: ip6_mroute.c,v 1.59 2003/12/10 09:28:38 itojun Exp $ */ /* $KAME: ip6_mroute.c,v 1.45 2001/03/25 08:38:51 itojun Exp $ */ @@ -135,34 +135,6 @@ int ip6_mrouter_ver = 0; int ip6_mrtproto; /* for netstat only */ struct mrt6stat mrt6stat; -#define NO_RTE_FOUND 0x1 -#define RTE_FOUND 0x2 - -/* - * Macros to compute elapsed time efficiently - * Borrowed from Van Jacobson's scheduling code - */ -#define TV_DELTA(a, b, delta) do { \ - int xxs; \ - \ - delta = (a).tv_usec - (b).tv_usec; \ - if ((xxs = (a).tv_sec - (b).tv_sec)) { \ - switch (xxs) { \ - case 2: \ - delta += 1000000; \ - /* FALLTHROUGH */ \ - case 1: \ - delta += 1000000; \ - break; \ - default: \ - delta += (1000000 * xxs); \ - } \ - } \ -} while (0) - -#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \ - (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) - int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int); int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int); int ip6_mrouter_init(struct socket *, int, int); diff --git a/sys/ufs/ext2fs/ext2fs_vfsops.c b/sys/ufs/ext2fs/ext2fs_vfsops.c index f74a722a2..ce929251c 100644 --- a/sys/ufs/ext2fs/ext2fs_vfsops.c +++ b/sys/ufs/ext2fs/ext2fs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_vfsops.c,v 1.119 2024/05/12 09:19:54 jsg Exp $ */ +/* $OpenBSD: ext2fs_vfsops.c,v 1.120 2024/06/07 09:26:37 jsg Exp $ */ /* $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */ /* @@ -101,10 +101,7 @@ ext2fs_init(struct vfsconf *vfsp) /* * Called by main() when ext2fs is going to be mounted as root. - * - * Name is updated by mount(8) after booting. */ -#define ROOTNAME "root_device" int ext2fs_mountroot(void) diff --git a/sys/uvm/uvm_addr.c b/sys/uvm/uvm_addr.c index 69aff636a..904218034 100644 --- a/sys/uvm/uvm_addr.c +++ b/sys/uvm/uvm_addr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_addr.c,v 1.34 2024/05/13 01:15:53 jsg Exp $ */ +/* $OpenBSD: uvm_addr.c,v 1.35 2024/06/07 06:04:43 jsg Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt @@ -24,8 +24,6 @@ #include #include -/* Max gap between hint allocations. */ -#define UADDR_HINT_MAXGAP (4 * PAGE_SIZE) /* Number of pivots in pivot allocator. */ #define NUM_PIVOTS 16 /* diff --git a/usr.bin/ssh/misc.c b/usr.bin/ssh/misc.c index 38f987549..33327ad5c 100644 --- a/usr.bin/ssh/misc.c +++ b/usr.bin/ssh/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.195 2024/05/17 06:11:17 deraadt Exp $ */ +/* $OpenBSD: misc.c,v 1.196 2024/06/06 17:15:25 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. @@ -2947,3 +2947,19 @@ lib_contains_symbol(const char *path, const char *s) free(nl[0].n_name); return ret; } + +int +signal_is_crash(int sig) +{ + switch (sig) { + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + case SIGSYS: + case SIGFPE: + case SIGILL: + case SIGABRT: + return 1; + } + return 0; +} diff --git a/usr.bin/ssh/misc.h b/usr.bin/ssh/misc.h index 00b8bc5d0..7589d28e8 100644 --- a/usr.bin/ssh/misc.h +++ b/usr.bin/ssh/misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.h,v 1.108 2024/05/17 00:30:24 djm Exp $ */ +/* $OpenBSD: misc.h,v 1.109 2024/06/06 17:15:25 djm Exp $ */ /* * Author: Tatu Ylonen @@ -250,6 +250,7 @@ void notify_complete(struct notifier_ctx *, const char *, ...) typedef void (*sshsig_t)(int); sshsig_t ssh_signal(int, sshsig_t); +int signal_is_crash(int); /* On OpenBSD time_t is int64_t which is long long. */ #define SSH_TIME_T_MAX LLONG_MAX diff --git a/usr.bin/ssh/monitor.c b/usr.bin/ssh/monitor.c index b5bbdf305..0ada9a5b9 100644 --- a/usr.bin/ssh/monitor.c +++ b/usr.bin/ssh/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.239 2024/05/17 06:42:04 jsg Exp $ */ +/* $OpenBSD: monitor.c,v 1.240 2024/06/06 17:15:25 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -132,6 +132,7 @@ static char *auth_submethod = NULL; static u_int session_id2_len = 0; static u_char *session_id2 = NULL; static pid_t monitor_child_pid; +int auth_attempted = 0; struct mon_table { enum monitor_reqtype type; @@ -248,6 +249,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) authenticated = (monitor_read(ssh, pmonitor, mon_dispatch, &ent) == 1); + /* Record that auth was attempted to set exit status later */ + if ((ent->flags & MON_AUTH) != 0) + auth_attempted = 1; + /* Special handling for multiple required authentications */ if (options.num_auth_methods != 0) { if (authenticated && @@ -290,6 +295,7 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) fatal_f("authentication method name unknown"); debug_f("user %s authenticated by privileged process", authctxt->user); + auth_attempted = 0; ssh->authctxt = NULL; ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); diff --git a/usr.bin/ssh/monitor_wrap.c b/usr.bin/ssh/monitor_wrap.c index 6287a8c71..ae254bc26 100644 --- a/usr.bin/ssh/monitor_wrap.c +++ b/usr.bin/ssh/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.130 2024/05/17 00:30:24 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.131 2024/06/06 17:15:25 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -69,6 +70,7 @@ #include "session.h" #include "servconf.h" #include "monitor_wrap.h" +#include "srclimit.h" #include "ssherr.h" @@ -133,6 +135,36 @@ mm_request_send(int sock, enum monitor_reqtype type, struct sshbuf *m) fatal_f("write: %s", strerror(errno)); } +static void +mm_reap(void) +{ + int status = -1; + + if (!mm_is_monitor()) + return; + while (waitpid(pmonitor->m_pid, &status, 0) == -1) { + if (errno == EINTR) + continue; + pmonitor->m_pid = -1; + fatal_f("waitpid: %s", strerror(errno)); + } + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) { + debug_f("preauth child exited with status %d", + WEXITSTATUS(status)); + cleanup_exit(255); + } + } else if (WIFSIGNALED(status)) { + error_f("preauth child terminated by signal %d", + WTERMSIG(status)); + cleanup_exit(signal_is_crash(WTERMSIG(status)) ? + EXIT_CHILD_CRASH : 255); + } else { + error_f("preauth child terminated abnormally"); + cleanup_exit(EXIT_CHILD_CRASH); + } +} + void mm_request_receive(int sock, struct sshbuf *m) { @@ -145,6 +177,7 @@ mm_request_receive(int sock, struct sshbuf *m) if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) { if (errno == EPIPE) { debug3_f("monitor fd closed"); + mm_reap(); cleanup_exit(255); } fatal_f("read: %s", strerror(errno)); diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index 02ec30553..89909819c 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.407 2024/05/17 01:17:40 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.409 2024/06/06 20:25:48 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -145,6 +145,16 @@ initialize_server_options(ServerOptions *options) options->per_source_max_startups = -1; options->per_source_masklen_ipv4 = -1; options->per_source_masklen_ipv6 = -1; + options->per_source_penalty_exempt = NULL; + options->per_source_penalty.enabled = -1; + options->per_source_penalty.max_sources = -1; + options->per_source_penalty.overflow_mode = -1; + options->per_source_penalty.penalty_crash = -1; + options->per_source_penalty.penalty_authfail = -1; + options->per_source_penalty.penalty_noauth = -1; + options->per_source_penalty.penalty_grace = -1; + options->per_source_penalty.penalty_max = -1; + options->per_source_penalty.penalty_min = -1; options->max_authtries = -1; options->max_sessions = -1; options->banner = NULL; @@ -377,6 +387,24 @@ fill_default_server_options(ServerOptions *options) options->per_source_masklen_ipv4 = 32; if (options->per_source_masklen_ipv6 == -1) options->per_source_masklen_ipv6 = 128; + if (options->per_source_penalty.enabled == -1) + options->per_source_penalty.enabled = 1; + if (options->per_source_penalty.max_sources == -1) + options->per_source_penalty.max_sources = 65536; + if (options->per_source_penalty.overflow_mode == -1) + options->per_source_penalty.overflow_mode = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE; + if (options->per_source_penalty.penalty_crash == -1) + options->per_source_penalty.penalty_crash = 90; + if (options->per_source_penalty.penalty_grace == -1) + options->per_source_penalty.penalty_grace = 20; + if (options->per_source_penalty.penalty_authfail == -1) + options->per_source_penalty.penalty_authfail = 5; + if (options->per_source_penalty.penalty_noauth == -1) + options->per_source_penalty.penalty_noauth = 1; + if (options->per_source_penalty.penalty_min == -1) + options->per_source_penalty.penalty_min = 15; + if (options->per_source_penalty.penalty_max == -1) + options->per_source_penalty.penalty_max = 600; if (options->max_authtries == -1) options->max_authtries = DEFAULT_AUTH_FAIL_MAX; if (options->max_sessions == -1) @@ -454,6 +482,7 @@ fill_default_server_options(ServerOptions *options) CLEAR_ON_NONE(options->chroot_directory); CLEAR_ON_NONE(options->routing_domain); CLEAR_ON_NONE(options->host_key_agent); + CLEAR_ON_NONE(options->per_source_penalty_exempt); for (i = 0; i < options->num_host_key_files; i++) CLEAR_ON_NONE(options->host_key_files[i]); @@ -485,6 +514,7 @@ typedef enum { sBanner, sUseDNS, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, + sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, sAcceptEnv, sSetEnv, sPermitTunnel, @@ -601,6 +631,8 @@ static struct { { "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, { "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL }, { "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL }, + { "persourcepenalties", sPerSourcePenalties, SSHCFG_GLOBAL }, + { "persourcepenaltyexemptlist", sPerSourcePenaltyExemptList, SSHCFG_GLOBAL }, { "maxauthtries", sMaxAuthTries, SSHCFG_ALL }, { "maxsessions", sMaxSessions, SSHCFG_ALL }, { "banner", sBanner, SSHCFG_ALL }, @@ -1888,6 +1920,89 @@ process_server_config_line_depth(ServerOptions *options, char *line, options->per_source_max_startups = value; break; + case sPerSourcePenaltyExemptList: + charptr = &options->per_source_penalty_exempt; + arg = argv_next(&ac, &av); + if (!arg || *arg == '\0') + fatal("%s line %d: missing file name.", + filename, linenum); + if (addr_match_list(NULL, arg) != 0) { + fatal("%s line %d: keyword %s " + "invalid address argument.", + filename, linenum, keyword); + } + if (*activep && *charptr == NULL) + *charptr = xstrdup(arg); + break; + + case sPerSourcePenalties: + while ((arg = argv_next(&ac, &av)) != NULL) { + found = 1; + value = -1; + value2 = 0; + p = NULL; + /* Allow no/yes only in first position */ + if (strcasecmp(arg, "no") == 0 || + (value2 = (strcasecmp(arg, "yes") == 0))) { + if (ac > 0) { + fatal("%s line %d: keyword %s \"%s\" " + "argument must appear alone.", + filename, linenum, keyword, arg); + } + if (*activep && + options->per_source_penalty.enabled == -1) + options->per_source_penalty.enabled = value2; + continue; + } else if (strncmp(arg, "crash:", 6) == 0) { + p = arg + 6; + intptr = &options->per_source_penalty.penalty_crash; + } else if (strncmp(arg, "authfail:", 9) == 0) { + p = arg + 9; + intptr = &options->per_source_penalty.penalty_authfail; + } else if (strncmp(arg, "noauth:", 7) == 0) { + p = arg + 7; + intptr = &options->per_source_penalty.penalty_noauth; + } else if (strncmp(arg, "grace-exceeded:", 15) == 0) { + p = arg + 15; + intptr = &options->per_source_penalty.penalty_grace; + } else if (strncmp(arg, "max:", 4) == 0) { + p = arg + 4; + intptr = &options->per_source_penalty.penalty_max; + } else if (strncmp(arg, "min:", 4) == 0) { + p = arg + 4; + intptr = &options->per_source_penalty.penalty_min; + } else if (strncmp(arg, "max-sources:", 12) == 0) { + intptr = &options->per_source_penalty.max_sources; + if ((errstr = atoi_err(arg+12, &value)) != NULL) + fatal("%s line %d: %s value %s.", + filename, linenum, keyword, errstr); + } else if (strcmp(arg, "overflow:deny-all") == 0) { + intptr = &options->per_source_penalty.overflow_mode; + value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL; + } else if (strcmp(arg, "overflow:permissive") == 0) { + intptr = &options->per_source_penalty.overflow_mode; + value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE; + } else { + fatal("%s line %d: unsupported %s keyword %s", + filename, linenum, keyword, arg); + } + /* If no value was parsed above, assume it's a time */ + if (value == -1 && (value = convtime(p)) == -1) { + fatal("%s line %d: invalid %s time value.", + filename, linenum, keyword); + } + if (*activep && *intptr == -1) { + *intptr = value; + /* any option implicitly enables penalties */ + options->per_source_penalty.enabled = 1; + } + } + if (!found) { + fatal("%s line %d: no %s specified", + filename, linenum, keyword); + } + break; + case sMaxAuthTries: intptr = &options->max_authtries; goto parse_int; @@ -3012,6 +3127,7 @@ dump_config(ServerOptions *o) dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos); dump_cfg_string(sRDomain, o->routing_domain); dump_cfg_string(sSshdSessionPath, o->sshd_session_path); + dump_cfg_string(sPerSourcePenaltyExemptList, o->per_source_penalty_exempt); /* string arguments requiring a lookup */ dump_cfg_string(sLogLevel, log_level_name(o->log_level)); @@ -3099,4 +3215,20 @@ dump_config(ServerOptions *o) if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED) printf(" verify-required"); printf("\n"); + + if (o->per_source_penalty.enabled) { + printf("persourcepenalties crash:%d authfail:%d noauth:%d " + "grace-exceeded:%d max:%d min:%d max-sources:%d " + "overflow:%s\n", o->per_source_penalty.penalty_crash, + o->per_source_penalty.penalty_authfail, + o->per_source_penalty.penalty_noauth, + o->per_source_penalty.penalty_grace, + o->per_source_penalty.penalty_max, + o->per_source_penalty.penalty_min, + o->per_source_penalty.max_sources, + o->per_source_penalty.overflow_mode == + PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ? + "deny-all" : "permissive"); + } else + printf("persourcepenalties no\n"); } diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 8ebdca5e2..4a4ac1cdb 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.163 2024/05/23 23:47:16 jsg Exp $ */ +/* $OpenBSD: servconf.h,v 1.164 2024/06/06 17:15:25 djm Exp $ */ /* * Author: Tatu Ylonen @@ -65,6 +65,20 @@ struct listenaddr { struct addrinfo *addrs; }; +#define PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL 1 +#define PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE 2 +struct per_source_penalty { + int enabled; + int max_sources; + int overflow_mode; + int penalty_crash; + int penalty_grace; + int penalty_authfail; + int penalty_noauth; + int penalty_max; + int penalty_min; +}; + typedef struct { u_int num_ports; u_int ports_from_cmdline; @@ -172,6 +186,8 @@ typedef struct { int per_source_max_startups; int per_source_masklen_ipv4; int per_source_masklen_ipv6; + char *per_source_penalty_exempt; + struct per_source_penalty per_source_penalty; int max_authtries; int max_sessions; char *banner; /* SSH-2 banner message */ diff --git a/usr.bin/ssh/srclimit.c b/usr.bin/ssh/srclimit.c index 853a0eef9..ffea6a397 100644 --- a/usr.bin/ssh/srclimit.c +++ b/usr.bin/ssh/srclimit.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Darren Tucker + * Copyright (c) 2024 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,11 +17,13 @@ #include #include +#include #include #include #include #include +#include #include "addr.h" #include "canohost.h" @@ -28,17 +31,71 @@ #include "misc.h" #include "srclimit.h" #include "xmalloc.h" +#include "servconf.h" +#include "match.h" static int max_children, max_persource, ipv4_masklen, ipv6_masklen; +static struct per_source_penalty penalty_cfg; +static char *penalty_exempt; /* Per connection state, used to enforce unauthenticated connection limit. */ static struct child_info { int id; struct xaddr addr; -} *child; +} *children; + +/* + * Penalised addresses, active entries here prohibit connections until expired. + * Entries become active when more than penalty_min seconds of penalty are + * outstanding. + */ +struct penalty { + struct xaddr addr; + time_t expiry; + int active; + const char *reason; + RB_ENTRY(penalty) by_addr; + RB_ENTRY(penalty) by_expiry; +}; +static int penalty_addr_cmp(struct penalty *a, struct penalty *b); +static int penalty_expiry_cmp(struct penalty *a, struct penalty *b); +RB_HEAD(penalties_by_addr, penalty) penalties_by_addr; +RB_HEAD(penalties_by_expiry, penalty) penalties_by_expiry; +RB_GENERATE_STATIC(penalties_by_addr, penalty, by_addr, penalty_addr_cmp) +RB_GENERATE_STATIC(penalties_by_expiry, penalty, by_expiry, penalty_expiry_cmp) +static size_t npenalties; + +static int +srclimit_mask_addr(const struct xaddr *addr, int bits, struct xaddr *masked) +{ + struct xaddr xmask; + + /* Mask address off address to desired size. */ + if (addr_netmask(addr->af, bits, &xmask) != 0 || + addr_and(masked, addr, &xmask) != 0) { + debug3_f("%s: invalid mask %d bits", __func__, bits); + return -1; + } + return 0; +} + +static int +srclimit_peer_addr(int sock, struct xaddr *addr) +{ + struct sockaddr_storage storage; + socklen_t addrlen = sizeof(storage); + struct sockaddr *sa = (struct sockaddr *)&storage; + + if (getpeername(sock, sa, &addrlen) != 0) + return 1; /* not remote socket? */ + if (addr_sa_to_xaddr(sa, addrlen, addr) != 0) + return 1; /* unknown address family? */ + return 0; +} void -srclimit_init(int max, int persource, int ipv4len, int ipv6len) +srclimit_init(int max, int persource, int ipv4len, int ipv6len, + struct per_source_penalty *penalty_conf, const char *penalty_exempt_conf) { int i; @@ -46,25 +103,27 @@ srclimit_init(int max, int persource, int ipv4len, int ipv6len) ipv4_masklen = ipv4len; ipv6_masklen = ipv6len; max_persource = persource; + penalty_cfg = *penalty_conf; + penalty_exempt = penalty_exempt_conf == NULL ? + NULL : xstrdup(penalty_exempt_conf); if (max_persource == INT_MAX) /* no limit */ return; debug("%s: max connections %d, per source %d, masks %d,%d", __func__, max, persource, ipv4len, ipv6len); if (max <= 0) fatal("%s: invalid number of sockets: %d", __func__, max); - child = xcalloc(max_children, sizeof(*child)); + children = xcalloc(max_children, sizeof(*children)); for (i = 0; i < max_children; i++) - child[i].id = -1; + children[i].id = -1; + RB_INIT(&penalties_by_addr); + RB_INIT(&penalties_by_expiry); } /* returns 1 if connection allowed, 0 if not allowed. */ int srclimit_check_allow(int sock, int id) { - struct xaddr xa, xb, xmask; - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - struct sockaddr *sa = (struct sockaddr *)&addr; + struct xaddr xa, xb; int i, bits, first_unused, count = 0; char xas[NI_MAXHOST]; @@ -72,26 +131,19 @@ srclimit_check_allow(int sock, int id) return 1; debug("%s: sock %d id %d limit %d", __func__, sock, id, max_persource); - if (getpeername(sock, sa, &addrlen) != 0) - return 1; /* not remote socket? */ - if (addr_sa_to_xaddr(sa, addrlen, &xa) != 0) - return 1; /* unknown address family? */ - - /* Mask address off address to desired size. */ - bits = xa.af == AF_INET ? ipv4_masklen : ipv6_masklen; - if (addr_netmask(xa.af, bits, &xmask) != 0 || - addr_and(&xb, &xa, &xmask) != 0) { - debug3("%s: invalid mask %d bits", __func__, bits); + if (srclimit_peer_addr(sock, &xa) != 0) + return 1; + bits = xa.af == AF_INET ? ipv4_masklen : ipv6_masklen; + if (srclimit_mask_addr(&xa, bits, &xb) != 0) return 1; - } first_unused = max_children; /* Count matching entries and find first unused one. */ for (i = 0; i < max_children; i++) { - if (child[i].id == -1) { + if (children[i].id == -1) { if (i < first_unused) first_unused = i; - } else if (addr_cmp(&child[i].addr, &xb) == 0) { + } else if (addr_cmp(&children[i].addr, &xb) == 0) { count++; } } @@ -114,8 +166,8 @@ srclimit_check_allow(int sock, int id) return 0; /* Connection allowed, store masked address. */ - child[first_unused].id = id; - memcpy(&child[first_unused].addr, &xb, sizeof(xb)); + children[first_unused].id = id; + memcpy(&children[first_unused].addr, &xb, sizeof(xb)); return 1; } @@ -130,9 +182,249 @@ srclimit_done(int id) debug("%s: id %d", __func__, id); /* Clear corresponding state entry. */ for (i = 0; i < max_children; i++) { - if (child[i].id == id) { - child[i].id = -1; + if (children[i].id == id) { + children[i].id = -1; return; } } } + +static int +penalty_addr_cmp(struct penalty *a, struct penalty *b) +{ + return addr_cmp(&a->addr, &b->addr); + /* Addresses must be unique in by_addr, so no need to tiebreak */ +} + +static int +penalty_expiry_cmp(struct penalty *a, struct penalty *b) +{ + if (a->expiry != b->expiry) + return a->expiry < b->expiry ? -1 : 1; + /* Tiebreak on addresses */ + return addr_cmp(&a->addr, &b->addr); +} + +static void +expire_penalties(time_t now) +{ + struct penalty *penalty, *tmp; + + /* XXX avoid full scan of tree, e.g. min-heap */ + RB_FOREACH_SAFE(penalty, penalties_by_expiry, + &penalties_by_expiry, tmp) { + if (penalty->expiry >= now) + break; + if (RB_REMOVE(penalties_by_expiry, &penalties_by_expiry, + penalty) != penalty || + RB_REMOVE(penalties_by_addr, &penalties_by_addr, + penalty) != penalty) + fatal_f("internal error: penalty tables corrupt"); + free(penalty); + if (npenalties-- == 0) + fatal_f("internal error: npenalties underflow"); + } +} + +static void +addr_masklen_ntop(struct xaddr *addr, int masklen, char *s, size_t slen) +{ + size_t o; + + if (addr_ntop(addr, s, slen) != 0) { + strlcpy(s, "UNKNOWN", slen); + return; + } + if ((o = strlen(s)) < slen) + snprintf(s + o, slen - o, "/%d", masklen); +} + +int +srclimit_penalty_check_allow(int sock, const char **reason) +{ + struct xaddr addr; + struct penalty find, *penalty; + time_t now; + int bits; + char addr_s[NI_MAXHOST]; + + if (!penalty_cfg.enabled) + return 1; + if (srclimit_peer_addr(sock, &addr) != 0) + return 1; + if (penalty_exempt != NULL) { + if (addr_ntop(&addr, addr_s, sizeof(addr_s)) != 0) + return 1; /* shouldn't happen */ + if (addr_match_list(addr_s, penalty_exempt) == 1) { + return 1; + } + } + if (npenalties > (size_t)penalty_cfg.max_sources && + penalty_cfg.overflow_mode == PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL) { + *reason = "too many penalised addresses"; + return 0; + } + bits = addr.af == AF_INET ? ipv4_masklen : ipv6_masklen; + memset(&find, 0, sizeof(find)); + if (srclimit_mask_addr(&addr, bits, &find.addr) != 0) + return 1; + now = monotime(); + if ((penalty = RB_FIND(penalties_by_addr, + &penalties_by_addr, &find)) == NULL) + return 1; /* no penalty */ + if (penalty->expiry < now) { + expire_penalties(now); + return 1; /* expired penalty */ + } + if (!penalty->active) + return 1; /* Penalty hasn't hit activation threshold yet */ + *reason = penalty->reason; + return 0; +} + +static void +srclimit_remove_expired_penalties(void) +{ + struct penalty *p = NULL; + int bits; + char s[NI_MAXHOST + 4]; + + /* Delete the soonest-to-expire penalties. */ + while (npenalties > (size_t)penalty_cfg.max_sources) { + if ((p = RB_MIN(penalties_by_expiry, + &penalties_by_expiry)) == NULL) + break; /* shouldn't happen */ + bits = p->addr.af == AF_INET ? ipv4_masklen : ipv6_masklen; + addr_masklen_ntop(&p->addr, bits, s, sizeof(s)); + debug3_f("overflow, remove %s", s); + if (RB_REMOVE(penalties_by_expiry, + &penalties_by_expiry, p) != p || + RB_REMOVE(penalties_by_addr, &penalties_by_addr, p) != p) + fatal_f("internal error: penalty tables corrupt"); + free(p); + npenalties--; + } +} + +void +srclimit_penalise(struct xaddr *addr, int penalty_type) +{ + struct xaddr masked; + struct penalty *penalty, *existing; + time_t now; + int bits, penalty_secs; + char addrnetmask[NI_MAXHOST + 4]; + const char *reason = NULL; + + if (!penalty_cfg.enabled) + return; + if (penalty_exempt != NULL) { + if (addr_ntop(addr, addrnetmask, sizeof(addrnetmask)) != 0) + return; /* shouldn't happen */ + if (addr_match_list(addrnetmask, penalty_exempt) == 1) { + debug3_f("address %s is exempt", addrnetmask); + return; + } + } + + switch (penalty_type) { + case SRCLIMIT_PENALTY_NONE: + return; + case SRCLIMIT_PENALTY_CRASH: + penalty_secs = penalty_cfg.penalty_crash; + reason = "penalty: caused crash"; + break; + case SRCLIMIT_PENALTY_AUTHFAIL: + penalty_secs = penalty_cfg.penalty_authfail; + reason = "penalty: failed authentication"; + break; + case SRCLIMIT_PENALTY_NOAUTH: + penalty_secs = penalty_cfg.penalty_noauth; + reason = "penalty: connections without attempting authentication"; + break; + case SRCLIMIT_PENALTY_GRACE_EXCEEDED: + penalty_secs = penalty_cfg.penalty_crash; + reason = "penalty: exceeded LoginGraceTime"; + break; + default: + fatal_f("internal error: unknown penalty %d", penalty_type); + } + bits = addr->af == AF_INET ? ipv4_masklen : ipv6_masklen; + if (srclimit_mask_addr(addr, bits, &masked) != 0) + return; + addr_masklen_ntop(addr, bits, addrnetmask, sizeof(addrnetmask)); + + now = monotime(); + expire_penalties(now); + if (npenalties > (size_t)penalty_cfg.max_sources && + penalty_cfg.overflow_mode == PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL) { + verbose_f("penalty table full, cannot penalise %s for %s", + addrnetmask, reason); + return; + } + + penalty = xcalloc(1, sizeof(*penalty)); + penalty->addr = masked; + penalty->expiry = now + penalty_secs; + penalty->reason = reason; + if ((existing = RB_INSERT(penalties_by_addr, &penalties_by_addr, + penalty)) == NULL) { + /* penalty didn't previously exist */ + if (penalty_secs > penalty_cfg.penalty_min) + penalty->active = 1; + if (RB_INSERT(penalties_by_expiry, &penalties_by_expiry, + penalty) != NULL) + fatal_f("internal error: penalty tables corrupt"); + verbose_f("%s: new %s penalty of %d seconds for %s", + addrnetmask, penalty->active ? "active" : "deferred", + penalty_secs, reason); + if (++npenalties > (size_t)penalty_cfg.max_sources) + srclimit_remove_expired_penalties(); /* permissive */ + return; + } + debug_f("%s penalty for %s already exists, %lld seconds remaining", + existing->active ? "active" : "inactive", + addrnetmask, (long long)(existing->expiry - now)); + /* Expiry information is about to change, remove from tree */ + if (RB_REMOVE(penalties_by_expiry, &penalties_by_expiry, + existing) != existing) + fatal_f("internal error: penalty tables corrupt (remove)"); + /* An entry already existed. Accumulate penalty up to maximum */ + existing->expiry += penalty_secs; + if (existing->expiry - now > penalty_cfg.penalty_max) + existing->expiry = now + penalty_cfg.penalty_max; + if (existing->expiry - now > penalty_cfg.penalty_min && + !existing->active) { + verbose_f("%s: activating penalty of %lld seconds for %s", + addrnetmask, (long long)(existing->expiry - now), reason); + existing->active = 1; + } + existing->reason = penalty->reason; + free(penalty); + /* Re-insert into expiry tree */ + if (RB_INSERT(penalties_by_expiry, &penalties_by_expiry, + existing) != NULL) + fatal_f("internal error: penalty tables corrupt (insert)"); +} + +void +srclimit_penalty_info(void) +{ + struct penalty *p = NULL; + int bits; + char s[NI_MAXHOST + 4]; + time_t now; + + now = monotime(); + logit("%zu active penalties", npenalties); + RB_FOREACH(p, penalties_by_expiry, &penalties_by_expiry) { + bits = p->addr.af == AF_INET ? ipv4_masklen : ipv6_masklen; + addr_masklen_ntop(&p->addr, bits, s, sizeof(s)); + if (p->expiry < now) + logit("client %s %s (expired)", s, p->reason); + else { + logit("client %s %s (%llu secs left)", s, p->reason, + (long long)(p->expiry - now)); + } + } +} diff --git a/usr.bin/ssh/srclimit.h b/usr.bin/ssh/srclimit.h index 6e04f32b3..74a6f2b83 100644 --- a/usr.bin/ssh/srclimit.h +++ b/usr.bin/ssh/srclimit.h @@ -13,6 +13,26 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -void srclimit_init(int, int, int, int); +struct xaddr; + +struct per_source_penalty; + +void srclimit_init(int, int, int, int, + struct per_source_penalty *, const char *); int srclimit_check_allow(int, int); void srclimit_done(int); + +#define SRCLIMIT_PENALTY_NONE 0 +#define SRCLIMIT_PENALTY_CRASH 1 +#define SRCLIMIT_PENALTY_AUTHFAIL 2 +#define SRCLIMIT_PENALTY_GRACE_EXCEEDED 3 +#define SRCLIMIT_PENALTY_NOAUTH 4 + +/* meaningful exit values, used by sshd listener for penalties */ +#define EXIT_LOGIN_GRACE 3 /* login grace period exceeded */ +#define EXIT_CHILD_CRASH 4 /* preauth child crashed */ +#define EXIT_AUTH_ATTEMPTED 5 /* at least one auth attempt made */ + +void srclimit_penalise(struct xaddr *, int); +int srclimit_penalty_check_allow(int, const char **); +void srclimit_penalty_info(void); diff --git a/usr.bin/ssh/sshd-session.c b/usr.bin/ssh/sshd-session.c index b800f2b5a..e75b4f80b 100644 --- a/usr.bin/ssh/sshd-session.c +++ b/usr.bin/ssh/sshd-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-session.c,v 1.2 2024/05/17 02:39:11 jsg Exp $ */ +/* $OpenBSD: sshd-session.c,v 1.3 2024/06/06 17:15:25 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -188,11 +188,7 @@ grace_alarm_handler(int sig) ssh_signal(SIGTERM, SIG_IGN); kill(0, SIGTERM); } - - /* Log error and exit. */ - sigdie("Timeout before authentication for %s port %d", - ssh_remote_ipaddr(the_active_state), - ssh_remote_port(the_active_state)); + _exit(EXIT_LOGIN_GRACE); } /* Destroy the host and server keys. They will no longer be needed. */ @@ -1220,6 +1216,8 @@ main(int ac, char **av) ssh_signal(SIGALRM, SIG_DFL); authctxt->authenticated = 1; if (startup_pipe != -1) { + /* signal listener that authentication completed successfully */ + (void)atomicio(vwrite, startup_pipe, "\001", 1); close(startup_pipe); startup_pipe = -1; } @@ -1338,6 +1336,8 @@ do_ssh2_kex(struct ssh *ssh) void cleanup_exit(int i) { + extern int auth_attempted; /* monitor.c */ + if (the_active_state != NULL && the_authctxt != NULL) { do_cleanup(the_active_state, the_authctxt); if (privsep_is_preauth && @@ -1350,5 +1350,8 @@ cleanup_exit(int i) } } } + /* Override default fatal exit value when auth was attempted */ + if (i == 255 && auth_attempted) + _exit(EXIT_AUTH_ATTEMPTED); _exit(i); } diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index d310779be..adc71cefe 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.605 2024/06/01 07:03:37 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.607 2024/06/06 19:50:01 djm Exp $ */ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. @@ -72,6 +72,7 @@ #include "version.h" #include "ssherr.h" #include "sk-api.h" +#include "addr.h" #include "srclimit.h" /* Re-exec fds */ @@ -120,6 +121,8 @@ struct { } sensitive_data; /* This is set to true when a signal is received. */ +static volatile sig_atomic_t received_siginfo = 0; +static volatile sig_atomic_t received_sigchld = 0; static volatile sig_atomic_t received_sighup = 0; static volatile sig_atomic_t received_sigterm = 0; @@ -127,8 +130,9 @@ static volatile sig_atomic_t received_sigterm = 0; u_int utmp_len = HOST_NAME_MAX+1; /* - * startup_pipes/flags are used for tracking children of the listening sshd - * process early in their lifespans. This tracking is needed for three things: + * The early_child/children array below is used for tracking children of the + * listening sshd process early in their lifespans, before they have + * completed authentication. This tracking is needed for four things: * * 1) Implementing the MaxStartups limit of concurrent unauthenticated * connections. @@ -137,14 +141,31 @@ u_int utmp_len = HOST_NAME_MAX+1; * after it restarts. * 3) Ensuring that rexec'd sshd processes have received their initial state * from the parent listen process before handling SIGHUP. + * 4) Tracking and logging unsuccessful exits from the preauth sshd monitor, + * including and especially those for LoginGraceTime timeouts. * * Child processes signal that they have completed closure of the listen_socks * and (if applicable) received their rexec state by sending a char over their - * sock. Child processes signal that authentication has completed by closing - * the sock (or by exiting). + * sock. + * + * Child processes signal that authentication has completed by sending a + * second char over the socket before closing it, otherwise the listener will + * continue tracking the child (and using up a MaxStartups slot) until the + * preauth subprocess exits, whereupon the listener will log its exit status. + * preauth processes will exit with a status of EXIT_LOGIN_GRACE to indicate + * they did not authenticate before the LoginGraceTime alarm fired. */ -static int *startup_pipes = NULL; -static int *startup_flags = NULL; /* Indicates child closed listener */ +struct early_child { + int pipefd; + int early; /* Indicates child closed listener */ + char *id; /* human readable connection identifier */ + pid_t pid; + struct xaddr addr; + int have_addr; + int status, have_status; +}; +static struct early_child *children; +static int children_active; static int startup_pipe = -1; /* in child */ /* sshd_config buffer */ @@ -171,15 +192,257 @@ close_listen_socks(void) num_listen_socks = 0; } +/* Allocate and initialise the children array */ +static void +child_alloc(void) +{ + int i; + + children = xcalloc(options.max_startups, sizeof(*children)); + for (i = 0; i < options.max_startups; i++) { + children[i].pipefd = -1; + children[i].pid = -1; + } +} + +/* Register a new connection in the children array; child pid comes later */ +static struct early_child * +child_register(int pipefd, int sockfd) +{ + int i, lport, rport; + char *laddr = NULL, *raddr = NULL; + struct early_child *child = NULL; + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + struct sockaddr *sa = (struct sockaddr *)&addr; + + for (i = 0; i < options.max_startups; i++) { + if (children[i].pipefd != -1 || children[i].pid > 0) + continue; + child = &(children[i]); + break; + } + if (child == NULL) { + fatal_f("error: accepted connection when all %d child " + " slots full", options.max_startups); + } + child->pipefd = pipefd; + child->early = 1; + /* record peer address, if available */ + if (getpeername(sockfd, sa, &addrlen) == 0 && + addr_sa_to_xaddr(sa, addrlen, &child->addr) == 0) + child->have_addr = 1; + /* format peer address string for logs */ + if ((lport = get_local_port(sockfd)) == 0 || + (rport = get_peer_port(sockfd)) == 0) { + /* Not a TCP socket */ + raddr = get_peer_ipaddr(sockfd); + xasprintf(&child->id, "connection from %s", raddr); + } else { + laddr = get_local_ipaddr(sockfd); + raddr = get_peer_ipaddr(sockfd); + xasprintf(&child->id, "connection from %s to %s", laddr, raddr); + } + free(laddr); + free(raddr); + if (++children_active > options.max_startups) + fatal_f("internal error: more children than max_startups"); + + return child; +} + +/* + * Finally free a child entry. Don't call this directly. + */ +static void +child_finish(struct early_child *child) +{ + if (children_active == 0) + fatal_f("internal error: children_active underflow"); + if (child->pipefd != -1) + close(child->pipefd); + free(child->id); + memset(child, '\0', sizeof(*child)); + child->pipefd = -1; + child->pid = -1; + children_active--; +} + +/* + * Close a child's pipe. This will not stop tracking the child immediately + * (it will still be tracked for waitpid()) unless force_final is set, or + * child has already exited. + */ +static void +child_close(struct early_child *child, int force_final, int quiet) +{ + if (!quiet) + debug_f("enter%s", force_final ? " (forcing)" : ""); + if (child->pipefd != -1) { + close(child->pipefd); + child->pipefd = -1; + } + if (child->pid == -1 || force_final) + child_finish(child); +} + +/* Record a child exit. Safe to call from signal handlers */ +static void +child_exit(pid_t pid, int status) +{ + int i; + + if (children == NULL || pid <= 0) + return; + for (i = 0; i < options.max_startups; i++) { + if (children[i].pid == pid) { + children[i].have_status = 1; + children[i].status = status; + break; + } + } +} + +/* + * Reap a child entry that has exited, as previously flagged + * using child_exit(). + * Handles logging of exit condition and will finalise the child if its pipe + * had already been closed. + */ +static void +child_reap(struct early_child *child) +{ + LogLevel level = SYSLOG_LEVEL_DEBUG1; + int was_crash, penalty_type = SRCLIMIT_PENALTY_NONE; + + /* Log exit information */ + if (WIFSIGNALED(child->status)) { + /* + * Increase logging for signals potentially associated + * with serious conditions. + */ + if ((was_crash = signal_is_crash(WTERMSIG(child->status)))) + level = SYSLOG_LEVEL_ERROR; + do_log2(level, "session process %ld for %s killed by " + "signal %d%s", (long)child->pid, child->id, + WTERMSIG(child->status), child->early ? " (early)" : ""); + if (was_crash) + penalty_type = SRCLIMIT_PENALTY_CRASH; + } else if (!WIFEXITED(child->status)) { + penalty_type = SRCLIMIT_PENALTY_CRASH; + error("session process %ld for %s terminated abnormally, " + "status=0x%x%s", (long)child->pid, child->id, child->status, + child->early ? " (early)" : ""); + } else { + /* Normal exit. We care about the status */ + switch (WEXITSTATUS(child->status)) { + case 0: + debug3_f("preauth child %ld for %s completed " + "normally %s", (long)child->pid, child->id, + child->early ? " (early)" : ""); + break; + case EXIT_LOGIN_GRACE: + penalty_type = SRCLIMIT_PENALTY_GRACE_EXCEEDED; + logit("Timeout before authentication for %s, " + "pid = %ld%s", child->id, (long)child->pid, + child->early ? " (early)" : ""); + break; + case EXIT_CHILD_CRASH: + penalty_type = SRCLIMIT_PENALTY_CRASH; + logit("Session process %ld unpriv child crash for %s%s", + (long)child->pid, child->id, + child->early ? " (early)" : ""); + break; + case EXIT_AUTH_ATTEMPTED: + penalty_type = SRCLIMIT_PENALTY_AUTHFAIL; + debug_f("preauth child %ld for %s exited " + "after unsuccessful auth attempt %s", + (long)child->pid, child->id, + child->early ? " (early)" : ""); + break; + default: + penalty_type = SRCLIMIT_PENALTY_NOAUTH; + debug_f("preauth child %ld for %s exited " + "with status %d%s", (long)child->pid, child->id, + WEXITSTATUS(child->status), + child->early ? " (early)" : ""); + break; + } + } + /* + * XXX would be nice to have more subtlety here. + * - Different penalties + * a) authentication failures without success (e.g. brute force) + * b) login grace exceeded (penalise DoS) + * c) monitor crash (penalise exploit attempt) + * d) unpriv preauth crash (penalise exploit attempt) + * - Unpriv auth exit status/WIFSIGNALLED is not available because + * the "mm_request_receive: monitor fd closed" fatal kills the + * monitor before waitpid() can occur. It would be good to use the + * unpriv exit status to detect crashes. + * + * For now, just penalise (a), (b) and (c), since that is what we have + * readily available. The authentication failures detection cannot + * discern between failed authentication and other connection problems + * until we have the unpriv exist status plumbed through (and the unpriv + * child modified to use a different exit status when auth has been + * attempted), but it's a start. + */ + if (child->have_addr) + srclimit_penalise(&child->addr, penalty_type); + + child->pid = -1; + child->have_status = 0; + if (child->pipefd == -1) + child_finish(child); +} + +/* Reap all children that have exited; called after SIGCHLD */ +static void +child_reap_all_exited(void) +{ + int i; + + if (children == NULL) + return; + for (i = 0; i < options.max_startups; i++) { + if (!children[i].have_status) + continue; + child_reap(&(children[i])); + } +} + static void close_startup_pipes(void) { int i; - if (startup_pipes) - for (i = 0; i < options.max_startups; i++) - if (startup_pipes[i] != -1) - close(startup_pipes[i]); + if (children == NULL) + return; + for (i = 0; i < options.max_startups; i++) { + if (children[i].pipefd != -1) + child_close(&(children[i]), 1, 1); + } +} + +/* Called after SIGINFO */ +static void +show_info(void) +{ + int i; + + /* XXX print listening sockets here too */ + if (children == NULL) + return; + logit("%d active startups", children_active); + for (i = 0; i < options.max_startups; i++) { + if (children[i].pipefd == -1 && children[i].pid <= 0) + continue; + logit("child %d: fd=%d pid=%ld %s%s", i, children[i].pipefd, + (long)children[i].pid, children[i].id, + children[i].early ? " (early)" : ""); + } + srclimit_penalty_info(); } /* @@ -222,6 +485,12 @@ sigterm_handler(int sig) received_sigterm = sig; } +static void +siginfo_handler(int sig) +{ + received_siginfo = 1; +} + /* * SIGCHLD handler. This is called whenever a child dies. This will then * reap any zombies left by exited children. @@ -233,9 +502,17 @@ main_sigchld_handler(int sig) pid_t pid; int status; - while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || - (pid == -1 && errno == EINTR)) - ; + for (;;) { + if ((pid = waitpid(-1, &status, WNOHANG)) == 0) + break; + else if (pid == -1) { + if (errno == EINTR) + continue; + break; + } + child_exit(pid, status); + received_sigchld = 1; + } errno = save_errno; } @@ -268,7 +545,7 @@ should_drop_connection(int startups) } /* - * Check whether connection should be accepted by MaxStartups. + * Check whether connection should be accepted by MaxStartups or for penalty. * Returns 0 if the connection is accepted. If the connection is refused, * returns 1 and attempts to send notification to client. * Logs when the MaxStartups condition is entered or exited, and periodically @@ -278,12 +555,17 @@ static int drop_connection(int sock, int startups, int notify_pipe) { char *laddr, *raddr; - const char msg[] = "Exceeded MaxStartups\r\n"; + const char *reason = NULL, msg[] = "Not allowed at this time\r\n"; static time_t last_drop, first_drop; static u_int ndropped; LogLevel drop_level = SYSLOG_LEVEL_VERBOSE; time_t now; + if (!srclimit_penalty_check_allow(sock, &reason)) { + drop_level = SYSLOG_LEVEL_INFO; + goto handle; + } + now = monotime(); if (!should_drop_connection(startups) && srclimit_check_allow(sock, notify_pipe) == 1) { @@ -313,12 +595,16 @@ drop_connection(int sock, int startups, int notify_pipe) } last_drop = now; ndropped++; + reason = "past Maxstartups"; + handle: laddr = get_local_ipaddr(sock); raddr = get_peer_ipaddr(sock); - do_log2(drop_level, "drop connection #%d from [%s]:%d on [%s]:%d " - "past MaxStartups", startups, raddr, get_peer_port(sock), - laddr, get_local_port(sock)); + do_log2(drop_level, "drop connection #%d from [%s]:%d on [%s]:%d %s", + startups, + raddr, get_peer_port(sock), + laddr, get_local_port(sock), + reason); free(laddr); free(raddr); /* best-effort notification to client */ @@ -521,8 +807,12 @@ server_listen(void) u_int i; /* Initialise per-source limit tracking. */ - srclimit_init(options.max_startups, options.per_source_max_startups, - options.per_source_masklen_ipv4, options.per_source_masklen_ipv6); + srclimit_init(options.max_startups, + options.per_source_max_startups, + options.per_source_masklen_ipv4, + options.per_source_masklen_ipv6, + &options.per_source_penalty, + options.per_source_penalty_exempt); for (i = 0; i < options.num_listen_addrs; i++) { listen_on_addrs(&options.listen_addrs[i]); @@ -548,32 +838,30 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, int log_stderr) { struct pollfd *pfd = NULL; - int i, j, ret, npfd; - int ostartups = -1, startups = 0, listening = 0, lameduck = 0; + int i, ret, npfd; + int oactive = -1, listening = 0, lameduck = 0; int startup_p[2] = { -1 , -1 }, *startup_pollfd; char c = 0; struct sockaddr_storage from; + struct early_child *child; socklen_t fromlen; - pid_t pid; sigset_t nsigset, osigset; /* setup fd set for accept */ /* pipes connected to unauthenticated child sshd processes */ - startup_pipes = xcalloc(options.max_startups, sizeof(int)); - startup_flags = xcalloc(options.max_startups, sizeof(int)); + child_alloc(); startup_pollfd = xcalloc(options.max_startups, sizeof(int)); - for (i = 0; i < options.max_startups; i++) - startup_pipes[i] = -1; /* * Prepare signal mask that we use to block signals that might set - * received_sigterm or received_sighup, so that we are guaranteed + * received_sigterm/hup/chld/info, so that we are guaranteed * to immediately wake up the ppoll if a signal is received after * the flag is checked. */ sigemptyset(&nsigset); sigaddset(&nsigset, SIGHUP); sigaddset(&nsigset, SIGCHLD); + sigaddset(&nsigset, SIGINFO); sigaddset(&nsigset, SIGTERM); sigaddset(&nsigset, SIGQUIT); @@ -595,11 +883,19 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, unlink(options.pid_file); exit(received_sigterm == SIGTERM ? 0 : 255); } - if (ostartups != startups) { + if (received_sigchld) { + child_reap_all_exited(); + received_sigchld = 0; + } + if (received_siginfo) { + show_info(); + received_siginfo = 0; + } + if (oactive != children_active) { setproctitle("%s [listener] %d of %d-%d startups", - listener_proctitle, startups, + listener_proctitle, children_active, options.max_startups_begin, options.max_startups); - ostartups = startups; + oactive = children_active; } if (received_sighup) { if (!lameduck) { @@ -620,8 +916,8 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, npfd = num_listen_socks; for (i = 0; i < options.max_startups; i++) { startup_pollfd[i] = -1; - if (startup_pipes[i] != -1) { - pfd[npfd].fd = startup_pipes[i]; + if (children[i].pipefd != -1) { + pfd[npfd].fd = children[i].pipefd; pfd[npfd].events = POLLIN; startup_pollfd[i] = npfd++; } @@ -639,34 +935,46 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, continue; for (i = 0; i < options.max_startups; i++) { - if (startup_pipes[i] == -1 || + if (children[i].pipefd == -1 || startup_pollfd[i] == -1 || !(pfd[startup_pollfd[i]].revents & (POLLIN|POLLHUP))) continue; - switch (read(startup_pipes[i], &c, sizeof(c))) { + switch (read(children[i].pipefd, &c, sizeof(c))) { case -1: if (errno == EINTR || errno == EAGAIN) continue; if (errno != EPIPE) { error_f("startup pipe %d (fd=%d): " - "read %s", i, startup_pipes[i], + "read %s", i, children[i].pipefd, strerror(errno)); } /* FALLTHROUGH */ case 0: - /* child exited or completed auth */ - close(startup_pipes[i]); - srclimit_done(startup_pipes[i]); - startup_pipes[i] = -1; - startups--; - if (startup_flags[i]) + /* child exited preauth */ + if (children[i].early) listening--; + srclimit_done(children[i].pipefd); + child_close(&(children[i]), 0, 0); break; case 1: - /* child has finished preliminaries */ - if (startup_flags[i]) { + if (children[i].early && c == '\0') { + /* child has finished preliminaries */ listening--; - startup_flags[i] = 0; + children[i].early = 0; + debug2_f("child %lu for %s received " + "config", (long)children[i].pid, + children[i].id); + } else if (!children[i].early && c == '\001') { + /* child has completed auth */ + debug2_f("child %lu for %s auth done", + (long)children[i].pid, + children[i].id); + child_close(&(children[i]), 1, 0); + } else { + error_f("unexpected message 0x%02x " + "child %ld for %s in state %d", + (int)c, (long)children[i].pid, + children[i].id, children[i].early); } break; } @@ -695,7 +1003,8 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, close(*newsock); continue; } - if (drop_connection(*newsock, startups, startup_p[0])) { + if (drop_connection(*newsock, + children_active, startup_p[0])) { close(*newsock); close(startup_p[0]); close(startup_p[1]); @@ -712,14 +1021,6 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, continue; } - for (j = 0; j < options.max_startups; j++) - if (startup_pipes[j] == -1) { - startup_pipes[j] = startup_p[0]; - startups++; - startup_flags[j] = 1; - break; - } - /* * Got connection. Fork a child to handle it, unless * we are in debugging mode. @@ -737,7 +1038,6 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, close(startup_p[0]); close(startup_p[1]); startup_pipe = -1; - pid = getpid(); send_rexec_state(config_s[0], cfg); close(config_s[0]); free(pfd); @@ -750,7 +1050,8 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, * parent continues listening. */ listening++; - if ((pid = fork()) == 0) { + child = child_register(startup_p[0], *newsock); + if ((child->pid = fork()) == 0) { /* * Child. Close the listening and * max_startup sockets. Start using @@ -774,10 +1075,10 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, } /* Parent. Stay in the loop. */ - if (pid == -1) + if (child->pid == -1) error("fork: %.100s", strerror(errno)); else - debug("Forked child %ld.", (long)pid); + debug("Forked child %ld.", (long)child->pid); close(startup_p[1]); @@ -1340,6 +1641,7 @@ main(int ac, char **av) ssh_signal(SIGCHLD, main_sigchld_handler); ssh_signal(SIGTERM, sigterm_handler); ssh_signal(SIGQUIT, sigterm_handler); + ssh_signal(SIGINFO, siginfo_handler); /* * Write out the pid file after the sigterm handler @@ -1395,6 +1697,7 @@ main(int ac, char **av) fatal("dup2 startup_p: %s", strerror(errno)); close(startup_pipe); } + log_redirect_stderr_to(NULL); closefrom(REEXEC_MIN_FREE_FD); ssh_signal(SIGHUP, SIG_IGN); /* avoid reset to SIG_DFL */ diff --git a/usr.bin/ssh/sshd_config.5 b/usr.bin/ssh/sshd_config.5 index 93afc3eeb..92c183466 100644 --- a/usr.bin/ssh/sshd_config.5 +++ b/usr.bin/ssh/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.355 2024/02/21 06:17:29 djm Exp $ -.Dd $Mdocdate: February 21 2024 $ +.\" $OpenBSD: sshd_config.5,v 1.358 2024/06/06 21:14:49 jmc Exp $ +.Dd $Mdocdate: June 6 2024 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -1558,6 +1558,69 @@ Values for IPv4 and optionally IPv6 may be specified, separated by a colon. The default is .Cm 32:128 , which means each address is considered individually. +.It Cm PerSourcePenalties +Controls penalties for various conditions that may represent attacks on +.Xr sshd 8 . +If a penalty is enforced against a client then its source address and any +others in the +.Cm PerSourceNetBlockSize +will be refused connection for a period. +A penalty doesn't affect concurrent connections in progress, but multiple +penalties from the same source from concurrent connections will accumulate +up to a maximum. +Conversely, penalties are not applied until a minimum threshold time has been +accumulated. +Penalties are off by default but may be enabled using default settings using the +.Cm yes +keyword or by specifying one or more of the keywords below. +.Pp +Penalties are controlled using the following keywords, all of which accept +arguments, e.g.\& +.Qq crash:2m . +.Bl -tag -width Ds +.It Cm crash:duration +Specifies how long to refuse clients that cause a crash of +.Xr sshd 8 . +.It Cm authfail:duration +Specifies how long to refuse clients that disconnect after making one or more +unsuccessful authentication attempts. +.It Cm noauth:duration +Specifies how long to refuse clients that disconnect without attempting +authentication. +This timeout should be used cautiously otherwise it may penalise legitimate +scanning tools such as +.Xr ssh-keyscan 1 . +.It Cm grace-exceeded:duration +Specifies how long to refuse clients that fail to authenticate after +.Cm LoginGraceTime . +.It Cm max:duration +Specifies the maximum time a particular source address range will be refused +access for. +Repeated penalties will accumulate up to this maximum. +.It Cm min:duration +Specifies the minimum penalty that must accrue before enforcement begins. +.It Cm max-sources:number +Specifies the maximum number of penalise client address ranges to track. +.It Cm overflow:mode +Controls how the server behaves when +.Cm max-sources +is exceeded. +There are two operating modes: +.Cm deny-all , +which denies all incoming connections other than those exempted via +.Cm PerSourcePenaltyExemptList +until a penalty expires, and +.Cm permissive , +which allows new connections by removing existing penalties early. +.El +.It Cm PerSourcePenaltyExemptList +Specifies a comma-separated list of addresses to exempt from penalties. +This list may contain wildcards and CIDR address/masklen ranges. +Note that the mask length provided must be consistent with the address - +it is an error to specify a mask length that is too long for the address +or one with bits set in this host portion of the address. +For example, 192.0.2.0/33 and 192.0.2.0/8, respectively. +The default is not to exempt any addresses. .It Cm PidFile Specifies the file that contains the process ID of the SSH daemon, or diff --git a/usr.sbin/dhcp6leasectl/dhcp6leasectl.8 b/usr.sbin/dhcp6leasectl/dhcp6leasectl.8 index f5ebd9a08..bb07409bc 100644 --- a/usr.sbin/dhcp6leasectl/dhcp6leasectl.8 +++ b/usr.sbin/dhcp6leasectl/dhcp6leasectl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: dhcp6leasectl.8,v 1.1 2024/06/06 15:16:57 florian Exp $ +.\" $OpenBSD: dhcp6leasectl.8,v 1.2 2024/06/07 17:38:22 jmc Exp $ .\" .\" Copyright (c) 2021 Florian Obser .\" Copyright (c) 2016 Kenneth R Westerback @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 6 2024 $ +.Dd $Mdocdate: June 7 2024 $ .Dt DHCP6LEASECTL 8 .Os .Sh NAME @@ -52,9 +52,7 @@ to communicate with Specify the maximum number of seconds to wait for .Ar interface to be configured. -The default is to wait 10 seconds unless -.Fl l -is specified. +The default is 10 seconds. .El .Sh FILES .Bl -tag -width "/dev/dhcp6leased.sockXX" -compact diff --git a/usr.sbin/dhcpleasectl/dhcpleasectl.8 b/usr.sbin/dhcpleasectl/dhcpleasectl.8 index adf87157b..e346dd06b 100644 --- a/usr.sbin/dhcpleasectl/dhcpleasectl.8 +++ b/usr.sbin/dhcpleasectl/dhcpleasectl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: dhcpleasectl.8,v 1.5 2023/03/02 17:09:54 jmc Exp $ +.\" $OpenBSD: dhcpleasectl.8,v 1.6 2024/06/07 17:38:22 jmc Exp $ .\" .\" Copyright (c) 2021 Florian Obser .\" Copyright (c) 2016 Kenneth R Westerback @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: March 2 2023 $ +.Dd $Mdocdate: June 7 2024 $ .Dt DHCPLEASECTL 8 .Os .Sh NAME @@ -52,9 +52,7 @@ to communicate with Specify the maximum number of seconds to wait for .Ar interface to be configured. -The default is to wait 10 seconds unless -.Fl l -is specified. +The default is 10 seconds. .El .Sh FILES .Bl -tag -width "/dev/dhcpleased.sockXX" -compact diff --git a/usr.sbin/rpki-client/cert.c b/usr.sbin/rpki-client/cert.c index 0b0794412..ba29b7e48 100644 --- a/usr.sbin/rpki-client/cert.c +++ b/usr.sbin/rpki-client/cert.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cert.c,v 1.140 2024/06/06 12:38:02 tb Exp $ */ +/* $OpenBSD: cert.c,v 1.144 2024/06/08 13:33:49 tb Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2021 Job Snijders @@ -744,6 +744,15 @@ cert_parse_ee_cert(const char *fn, int talid, X509 *x) if (!cert_check_subject_and_issuer(fn, x)) goto out; + if (!x509_cache_extensions(x, fn)) + goto out; + + if ((cert->purpose = x509_get_purpose(x, fn)) != CERT_PURPOSE_EE) { + warnx("%s: expected EE cert, got %s", fn, + purpose2str(cert->purpose)); + goto out; + } + if (X509_get_key_usage(x) != KU_DIGITAL_SIGNATURE) { warnx("%s: RFC 6487 section 4.8.4: KU must be digitalSignature", fn); @@ -827,11 +836,8 @@ cert_parse_pre(const char *fn, const unsigned char *der, size_t len) goto out; } - /* Cache X509v3 extensions, see X509_check_ca(3). */ - if (X509_check_purpose(x, -1, -1) <= 0) { - warnx("%s: could not cache X509v3 extensions", fn); + if (!x509_cache_extensions(x, fn)) goto out; - } if (X509_get_version(x) != 2) { warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn); @@ -957,11 +963,12 @@ cert_parse_pre(const char *fn, const unsigned char *der, size_t len) goto out; if (!x509_get_notafter(x, fn, &cert->notafter)) goto out; - cert->purpose = x509_get_purpose(x, fn); /* Validation on required fields. */ - + cert->purpose = x509_get_purpose(x, fn); switch (cert->purpose) { + case CERT_PURPOSE_TA: + /* XXX - caller should indicate if it expects TA or CA cert */ case CERT_PURPOSE_CA: if ((pkey = X509_get0_pubkey(x)) == NULL) { warnx("%s: X509_get0_pubkey failed", fn); @@ -1015,6 +1022,9 @@ cert_parse_pre(const char *fn, const unsigned char *der, size_t len) goto out; } break; + case CERT_PURPOSE_EE: + warn("%s: unexpected EE cert", fn); + goto out; default: warnx("%s: x509_get_purpose failed in %s", fn, __func__); goto out; @@ -1117,8 +1127,9 @@ ta_parse(const char *fn, struct cert *p, const unsigned char *pkey, "trust anchor may not specify CRL resource", fn); goto badcert; } - if (p->purpose == CERT_PURPOSE_BGPSEC_ROUTER) { - warnx("%s: BGPsec cert cannot be a trust anchor", fn); + if (p->purpose != CERT_PURPOSE_TA) { + warnx("%s: expected trust anchor purpose, got %s", fn, + purpose2str(p->purpose)); goto badcert; } /* diff --git a/usr.sbin/rpki-client/cms.c b/usr.sbin/rpki-client/cms.c index 5ef647e15..0394680e5 100644 --- a/usr.sbin/rpki-client/cms.c +++ b/usr.sbin/rpki-client/cms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cms.c,v 1.45 2024/05/24 12:57:20 tb Exp $ */ +/* $OpenBSD: cms.c,v 1.46 2024/06/08 13:28:35 tb Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -324,11 +324,8 @@ cms_parse_validate_internal(X509 **xp, const char *fn, const unsigned char *der, goto out; } - /* Cache X509v3 extensions, see X509_check_ca(3). */ - if (X509_check_purpose(*xp, -1, -1) <= 0) { - warnx("%s: could not cache X509v3 extensions", fn); + if (!x509_cache_extensions(*xp, fn)) goto out; - } if (!x509_get_notafter(*xp, fn, ¬after)) goto out; diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index 601d7d289..b811b485e 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.221 2024/06/04 04:17:18 tb Exp $ */ +/* $OpenBSD: extern.h,v 1.224 2024/06/08 13:30:35 tb Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -107,8 +107,10 @@ struct cert_ip { enum cert_purpose { CERT_PURPOSE_INVALID, + CERT_PURPOSE_TA, CERT_PURPOSE_CA, - CERT_PURPOSE_BGPSEC_ROUTER + CERT_PURPOSE_EE, + CERT_PURPOSE_BGPSEC_ROUTER, }; /* @@ -901,6 +903,7 @@ struct ibuf *io_buf_recvfd(int, struct ibuf **); /* X509 helpers. */ void x509_init_oid(void); +int x509_cache_extensions(X509 *, const char *); int x509_get_aia(X509 *, const char *, char **); int x509_get_aki(X509 *, const char *, char **); int x509_get_sia(X509 *, const char *, char **); @@ -922,6 +925,7 @@ time_t x509_find_expires(time_t, struct auth *, struct crl_tree *); /* printers */ char *nid2str(int); +const char *purpose2str(enum cert_purpose); char *time2str(time_t); void x509_print(const X509 *); void tal_print(const struct tal *); diff --git a/usr.sbin/rpki-client/filemode.c b/usr.sbin/rpki-client/filemode.c index 630b633b2..689817c7c 100644 --- a/usr.sbin/rpki-client/filemode.c +++ b/usr.sbin/rpki-client/filemode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: filemode.c,v 1.43 2024/06/06 07:19:10 tb Exp $ */ +/* $OpenBSD: filemode.c,v 1.45 2024/06/08 13:34:59 tb Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -157,7 +157,8 @@ parse_load_cert(char *uri) if (cert == NULL) goto done; if (cert->purpose != CERT_PURPOSE_CA) { - warnx("AIA reference to bgpsec cert %s", uri); + warnx("AIA reference to %s in %s", + purpose2str(cert->purpose), uri); goto done; } /* try to load the CRL of this cert */ @@ -403,7 +404,7 @@ proc_parser_file(char *file, unsigned char *buf, size_t len) cert = cert_parse_pre(file, buf, len); if (cert == NULL) break; - is_ta = X509_get_extension_flags(cert->x509) & EXFLAG_SS; + is_ta = (cert->purpose == CERT_PURPOSE_TA); if (!is_ta) cert = cert_parse(file, cert); if (cert == NULL) diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c index ffd010013..342548ce3 100644 --- a/usr.sbin/rpki-client/main.c +++ b/usr.sbin/rpki-client/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.258 2024/05/20 15:51:43 claudio Exp $ */ +/* $OpenBSD: main.c,v 1.260 2024/06/08 13:31:38 tb Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -481,7 +481,7 @@ queue_add_from_tal(struct tal *tal) /* steal the pkey from the tal structure */ data = tal->pkey; tal->pkey = NULL; - entityq_add(NULL, nfile, RTYPE_CER, DIR_VALID, repo, data, + entityq_add(NULL, nfile, RTYPE_CER, DIR_UNKNOWN, repo, data, tal->pkeysz, tal->id, tal->id, NULL); } @@ -618,6 +618,7 @@ entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree, } cert = cert_read(b); switch (cert->purpose) { + case CERT_PURPOSE_TA: case CERT_PURPOSE_CA: queue_add_from_cert(cert); break; @@ -626,7 +627,7 @@ entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree, repo_stat_inc(rp, talid, type, STYPE_BGPSEC); break; default: - errx(1, "unexpected cert purpose received"); + errx(1, "unexpected %s", purpose2str(cert->purpose)); break; } cert_free(cert); diff --git a/usr.sbin/rpki-client/parser.c b/usr.sbin/rpki-client/parser.c index 98b1eac70..10f7975a9 100644 --- a/usr.sbin/rpki-client/parser.c +++ b/usr.sbin/rpki-client/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.136 2024/05/20 15:51:43 claudio Exp $ */ +/* $OpenBSD: parser.c,v 1.139 2024/06/07 13:24:35 tb Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -570,35 +570,101 @@ proc_parser_cert(char *file, const unsigned char *der, size_t len, return cert; } -/* - * Root certificates come from TALs (has a pkey and is self-signed). - * Parse the certificate, ensure that its public key matches the - * known public key from the TAL, and then validate the RPKI - * content. - * - * This returns a certificate (which must not be freed) or NULL on - * parse failure. - */ -static struct cert * -proc_parser_root_cert(char *file, const unsigned char *der, size_t len, - unsigned char *pkey, size_t pkeysz, int talid) +static int +proc_parser_ta_cmp(const struct cert *cert1, const struct cert *cert2) { - struct cert *cert; - - /* Extract certificate data. */ - - cert = cert_parse_pre(file, der, len); - cert = ta_parse(file, cert, pkey, pkeysz); - if (cert == NULL) - return NULL; - cert->talid = talid; + if (cert1 == NULL) + return -1; + if (cert2 == NULL) + return 1; /* - * Add valid roots to the RPKI auth tree. + * The standards don't specify tiebreakers. While RFC 6487 and other + * sources advise against backdating, it's explicitly allowed and some + * TAs do. Some TAs have also re-issued with new dates and old + * serialNumber. + * Our tiebreaker logic: a more recent notBefore is taken to mean a + * more recent issuance, and thus preferable. Given equal notBefore + * values, prefer the TA cert with the narrower validity window. This + * hopefully encourages TA operators to reduce egregiously long TA + * validity periods. */ - auth_insert(file, &auths, cert, NULL); - return cert; + if (cert1->notbefore < cert2->notbefore) + return -1; + if (cert1->notbefore > cert2->notbefore) + return 1; + + if (cert1->notafter > cert2->notafter) + return -1; + if (cert1->notafter < cert2->notafter) + return 1; + + /* + * Both certs are valid from our perspective. If anything changed, + * prefer the freshly-fetched one. We rely on cert_parse_pre() having + * cached the extensions and thus libcrypto has already computed the + * certs' hashes (SHA-1 for OpenSSL, SHA-512 for LibreSSL). The below + * compares them. + */ + + return X509_cmp(cert1->x509, cert2->x509) != 0; +} + +/* + * Root certificates come from TALs. Inspect and validate both options and + * compare the two. The cert in out_cert must not be freed. Returns the file + * name of the chosen TA. + */ +static char * +proc_parser_root_cert(struct entity *entp, struct cert **out_cert) +{ + struct cert *cert1 = NULL, *cert2 = NULL; + char *file1 = NULL, *file2 = NULL; + unsigned char *der = NULL, *pkey = entp->data; + size_t der_len = 0, pkeysz = entp->datasz; + int cmp; + + *out_cert = NULL; + + file2 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_VALID); + der = load_file(file2, &der_len); + cert2 = cert_parse_pre(file2, der, der_len); + free(der); + cert2 = ta_parse(file2, cert2, pkey, pkeysz); + + if (!noop) { + file1 = parse_filepath(entp->repoid, entp->path, entp->file, + DIR_TEMP); + der = load_file(file1, &der_len); + cert1 = cert_parse_pre(file1, der, der_len); + free(der); + cert1 = ta_parse(file1, cert1, pkey, pkeysz); + } + + if ((cmp = proc_parser_ta_cmp(cert1, cert2)) > 0) { + cert_free(cert2); + free(file2); + + cert1->talid = entp->talid; + auth_insert(file1, &auths, cert1, NULL); + + *out_cert = cert1; + return file1; + } else { + if (cmp < 0 && cert1 != NULL && cert2 != NULL) + warnx("%s: cached TA is newer", entp->file); + cert_free(cert1); + free(file1); + + if (cert2 != 0) { + cert2->talid = entp->talid; + auth_insert(file2, &auths, cert2, NULL); + } + + *out_cert = cert2; + return file2; + } } /* @@ -784,14 +850,13 @@ parse_entity(struct entityq *q, struct msgbuf *msgq) tal_free(tal); break; case RTYPE_CER: - file = parse_load_file(entp, &f, &flen); - io_str_buffer(b, file); - if (entp->data != NULL) - cert = proc_parser_root_cert(file, - f, flen, entp->data, entp->datasz, - entp->talid); - else + if (entp->data != NULL) { + file = proc_parser_root_cert(entp, &cert); + } else { + file = parse_load_file(entp, &f, &flen); cert = proc_parser_cert(file, f, flen, entp); + } + io_str_buffer(b, file); if (cert != NULL) mtime = cert->notbefore; io_simple_buffer(b, &mtime, sizeof(mtime)); diff --git a/usr.sbin/rpki-client/print.c b/usr.sbin/rpki-client/print.c index 3fbf35537..6738cbc7a 100644 --- a/usr.sbin/rpki-client/print.c +++ b/usr.sbin/rpki-client/print.c @@ -1,4 +1,4 @@ -/* $OpenBSD: print.c,v 1.54 2024/06/06 05:57:36 tb Exp $ */ +/* $OpenBSD: print.c,v 1.55 2024/06/08 13:30:35 tb Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -65,6 +65,25 @@ nid2str(int nid) return buf; } +const char * +purpose2str(enum cert_purpose purpose) +{ + switch (purpose) { + case CERT_PURPOSE_INVALID: + return "invalid cert"; + case CERT_PURPOSE_TA: + return "TA cert"; + case CERT_PURPOSE_CA: + return "CA cert"; + case CERT_PURPOSE_EE: + return "EE cert"; + case CERT_PURPOSE_BGPSEC_ROUTER: + return "BGPsec Router cert"; + default: + return "unknown certificate purpose"; + } +} + char * time2str(time_t t) { diff --git a/usr.sbin/rpki-client/repo.c b/usr.sbin/rpki-client/repo.c index 15ff513f0..0dd47cd0b 100644 --- a/usr.sbin/rpki-client/repo.c +++ b/usr.sbin/rpki-client/repo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: repo.c,v 1.59 2024/05/30 12:33:15 claudio Exp $ */ +/* $OpenBSD: repo.c,v 1.60 2024/06/07 08:22:53 claudio Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -78,7 +78,6 @@ struct tarepo { SLIST_ENTRY(tarepo) entry; char *descr; char *basedir; - char *temp; char **uri; size_t urisz; size_t uriidx; @@ -322,7 +321,7 @@ repo_done(const void *vp, int ok) * If temp is set add Xs for mkostemp. */ static char * -ta_filename(const struct tarepo *tr, int temp) +ta_filename(const struct tarepo *tr) { const char *file; char *nfile; @@ -331,8 +330,7 @@ ta_filename(const struct tarepo *tr, int temp) file = strrchr(tr->uri[0], '/'); assert(file); - if (asprintf(&nfile, "%s%s%s", tr->basedir, file, - temp ? ".XXXXXXXX" : "") == -1) + if (asprintf(&nfile, "%s%s", tr->basedir, file) == -1) err(1, NULL); return nfile; @@ -367,18 +365,21 @@ ta_fetch(struct tarepo *tr) */ rsync_fetch(tr->id, tr->uri[tr->uriidx], tr->basedir, NULL); } else { + char *temp; int fd; - tr->temp = ta_filename(tr, 1); - fd = mkostemp(tr->temp, O_CLOEXEC); + temp = ta_filename(tr); + fd = open(temp, + O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd == -1) { - warn("mkostemp: %s", tr->temp); + warn("open: %s", temp); + free(temp); http_finish(tr->id, HTTP_FAILED, NULL); return; } - if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) - warn("fchmod: %s", tr->temp); + free(temp); http_fetch(tr->id, tr->uri[tr->uriidx], NULL, fd); } } @@ -392,12 +393,21 @@ ta_get(struct tal *tal) if ((tr = calloc(1, sizeof(*tr))) == NULL) err(1, NULL); + tr->id = ++repoid; SLIST_INSERT_HEAD(&tarepos, tr, entry); if ((tr->descr = strdup(tal->descr)) == NULL) err(1, NULL); - tr->basedir = repo_dir(tal->descr, "ta", 0); + tr->basedir = repo_dir(tal->descr, ".ta", 0); + + /* create base directory */ + if (mkpath(tr->basedir) == -1) { + warn("mkpath %s", tr->basedir); + tr->state = REPO_FAILED; + repo_done(tr, 0); + return tr; + } /* steal URI information from TAL */ tr->urisz = tal->urisz; @@ -430,7 +440,6 @@ ta_free(void) SLIST_REMOVE_HEAD(&tarepos, entry); free(tr->descr); free(tr->basedir); - free(tr->temp); free(tr->uri); free(tr); } @@ -1070,20 +1079,12 @@ http_finish(unsigned int id, enum http_result res, const char *last_mod) /* Move downloaded TA file into place, or unlink on failure. */ if (res == HTTP_OK) { - char *file; - - file = ta_filename(tr, 0); - if (rename(tr->temp, file) == -1) - warn("rename to %s", file); - free(file); - logx("ta/%s: loaded from network", tr->descr); tr->state = REPO_DONE; stats.http_repos++; repo_done(tr, 1); } else { - if (unlink(tr->temp) == -1 && errno != ENOENT) - warn("unlink %s", tr->temp); + remove_contents(tr->basedir); tr->uriidx++; warnx("ta/%s: load from network failed", tr->descr); @@ -1632,15 +1633,19 @@ repo_move_valid(struct filepath_tree *tree) struct filepath *fp, *nfp; size_t rsyncsz = strlen(".rsync/"); size_t rrdpsz = strlen(".rrdp/"); + size_t tasz = strlen(".ta/"); char *fn, *base; RB_FOREACH_SAFE(fp, filepath_tree, tree, nfp) { if (strncmp(fp->file, ".rsync/", rsyncsz) != 0 && - strncmp(fp->file, ".rrdp/", rrdpsz) != 0) + strncmp(fp->file, ".rrdp/", rrdpsz) != 0 && + strncmp(fp->file, ".ta/", tasz) != 0) continue; /* not a temporary file path */ if (strncmp(fp->file, ".rsync/", rsyncsz) == 0) { fn = fp->file + rsyncsz; + } else if (strncmp(fp->file, ".ta/", tasz) == 0) { + fn = fp->file + 1; /* just skip the '.' */ } else { base = strchr(fp->file + rrdpsz, '/'); assert(base != NULL); @@ -1690,8 +1695,8 @@ repo_move_valid(struct filepath_tree *tree) } struct fts_state { - enum { BASE_DIR, RSYNC_DIR, RRDP_DIR } type; - struct repo *rp; + enum { BASE_DIR, RSYNC_DIR, TA_DIR, RRDP_DIR } type; + struct repo *rp; } fts_state; static const struct rrdprepo * @@ -1768,8 +1773,9 @@ repo_cleanup_entry(FTSENT *e, struct filepath_tree *tree, int cachefd) unlink: if (unlink(e->fts_accpath) == -1) { warn("unlink %s", path); - } else if (fts_state.type == RSYNC_DIR) { - /* no need to keep rsync files */ + } else if (fts_state.type == RSYNC_DIR || + fts_state.type == TA_DIR) { + /* no need to keep rsync or ta files */ if (verbose > 1) logx("deleted superfluous %s", path); if (fts_state.rp != NULL) @@ -1792,9 +1798,11 @@ repo_cleanup_entry(FTSENT *e, struct filepath_tree *tree, int cachefd) fts_state.rp = NULL; } if (e->fts_level == 1) { - /* rpki.example.org or .rrdp / .rsync */ + /* rpki.example.org or .rrdp / .rsync / .ta */ if (strcmp(".rsync", e->fts_name) == 0) fts_state.type = RSYNC_DIR; + else if (strcmp(".ta", e->fts_name) == 0) + fts_state.type = TA_DIR; else if (strcmp(".rrdp", e->fts_name) == 0) fts_state.type = RRDP_DIR; else @@ -1805,6 +1813,8 @@ repo_cleanup_entry(FTSENT *e, struct filepath_tree *tree, int cachefd) /* rpki.example.org/repository or .rrdp/hashdir */ if (fts_state.type == BASE_DIR) fts_state.rp = repo_bypath(path); + if (fts_state.type == TA_DIR) + fts_state.rp = repo_bypath(path + 1); /* * special handling for rrdp directories, * clear them if they are not used anymore but @@ -1826,7 +1836,8 @@ repo_cleanup_entry(FTSENT *e, struct filepath_tree *tree, int cachefd) /* do not remove .rsync and .rrdp */ fts_state.rp = NULL; if (fts_state.type == RRDP_DIR || - fts_state.type == RSYNC_DIR) + fts_state.type == RSYNC_DIR || + fts_state.type == TA_DIR) break; } diff --git a/usr.sbin/rpki-client/x509.c b/usr.sbin/rpki-client/x509.c index 4082242e5..c264b7327 100644 --- a/usr.sbin/rpki-client/x509.c +++ b/usr.sbin/rpki-client/x509.c @@ -1,4 +1,4 @@ -/* $OpenBSD: x509.c,v 1.93 2024/06/04 14:17:24 tb Exp $ */ +/* $OpenBSD: x509.c,v 1.97 2024/06/08 13:32:30 tb Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2021 Claudio Jeker @@ -132,6 +132,26 @@ x509_init_oid(void) } } +/* + * A number of critical OpenSSL API functions can't properly indicate failure + * and are unreliable if the extensions aren't already cached. An old trick is + * to cache the extensions using an error-checked call to X509_check_purpose() + * with a purpose of -1. This way functions such as X509_check_ca(), X509_cmp(), + * X509_get_key_usage(), X509_get_extended_key_usage() won't lie. + * + * Should be called right after deserialization and is essentially free to call + * multiple times. + */ +int +x509_cache_extensions(X509 *x509, const char *fn) +{ + if (X509_check_purpose(x509, -1, 0) <= 0) { + warnx("%s: could not cache X509v3 extensions", fn); + return 0; + } + return 1; +} + /* * Parse X509v3 authority key identifier (AKI), RFC 6487 sec. 4.8.3. * Returns the AKI or NULL if it could not be parsed. @@ -246,18 +266,34 @@ x509_get_ski(X509 *x, const char *fn, char **ski) } /* - * Check the certificate's purpose: CA or BGPsec Router. - * Return a member of enum cert_purpose. + * Check the cert's purpose: the cA bit in basic constraints distinguishes + * between TA/CA and EE/BGPsec router. TAs are self-signed, CAs not self-issued, + * EEs have no extended key usage, BGPsec router have id-kp-bgpsec-router OID. */ enum cert_purpose x509_get_purpose(X509 *x, const char *fn) { BASIC_CONSTRAINTS *bc = NULL; EXTENDED_KEY_USAGE *eku = NULL; - int crit; + int crit, ext_flags, is_ca; enum cert_purpose purpose = CERT_PURPOSE_INVALID; - if (X509_check_ca(x) == 1) { + if (!x509_cache_extensions(x, fn)) + goto out; + + ext_flags = X509_get_extension_flags(x); + + /* This weird API can return 0, 1, 2, 4, 5 but can't error... */ + if ((is_ca = X509_check_ca(x)) > 1) { + if (is_ca == 4) + warnx("%s: RFC 6487: sections 4.8.1 and 4.8.4: " + "no basic constraints, but keyCertSign set", fn); + else + warnx("%s: unexpected legacy certificate", fn); + goto out; + } + + if (is_ca) { bc = X509_get_ext_d2i(x, NID_basic_constraints, &crit, NULL); if (bc == NULL) { if (crit != -1) @@ -278,27 +314,50 @@ x509_get_purpose(X509 *x, const char *fn) "Constraint must be absent", fn); goto out; } - purpose = CERT_PURPOSE_CA; + /* + * EXFLAG_SI means that issuer and subject are identical. + * EXFLAG_SS is SI plus the AKI is absent or matches the SKI. + * Thus, exactly the trust anchors should have EXFLAG_SS set + * and we should never see EXFLAG_SI without EXFLAG_SS. + */ + if ((ext_flags & EXFLAG_SS) != 0) + purpose = CERT_PURPOSE_TA; + else if ((ext_flags & EXFLAG_SI) == 0) + purpose = CERT_PURPOSE_CA; + else + warnx("%s: RFC 6487, section 4.8.3: " + "self-issued cert with AKI-SKI mismatch", fn); goto out; } - if (X509_get_extension_flags(x) & EXFLAG_BCONS) { + if ((ext_flags & EXFLAG_BCONS) != 0) { warnx("%s: Basic Constraints ext in non-CA cert", fn); goto out; } + /* + * EKU is only defined for BGPsec Router certs and must be absent from + * EE certs. + */ eku = X509_get_ext_d2i(x, NID_ext_key_usage, &crit, NULL); if (eku == NULL) { if (crit != -1) warnx("%s: error parsing EKU", fn); else - warnx("%s: EKU: extension missing", fn); + purpose = CERT_PURPOSE_EE; /* EKU absent */ goto out; } if (crit != 0) { warnx("%s: EKU: extension must not be marked critical", fn); goto out; } + + /* + * XXX - this isn't quite correct: other EKU OIDs are allowed per + * RFC 8209, section 3.1.3.2, e.g., anyEKU could potentially help + * avoid tripping up validators that don't know about the BGPsec + * router purpose. Drop check or downgrade from error to warning? + */ if (sk_ASN1_OBJECT_num(eku) != 1) { warnx("%s: EKU: expected 1 purpose, have %d", fn, sk_ASN1_OBJECT_num(eku)); diff --git a/usr.sbin/sysupgrade/sysupgrade.sh b/usr.sbin/sysupgrade/sysupgrade.sh index 588c48693..4b9fb053c 100644 --- a/usr.sbin/sysupgrade/sysupgrade.sh +++ b/usr.sbin/sysupgrade/sysupgrade.sh @@ -1,6 +1,6 @@ #!/bin/ksh # -# $OpenBSD: sysupgrade.sh,v 1.49 2023/10/12 12:31:15 kn Exp $ +# $OpenBSD: sysupgrade.sh,v 1.50 2024/06/08 06:05:40 florian Exp $ # # Copyright (c) 1997-2015 Todd Miller, Theo de Raadt, Ken Westerback # Copyright (c) 2015 Robert Peichaer @@ -139,16 +139,21 @@ unpriv -f SHA256.sig ftp -N sysupgrade -Vmo SHA256.sig ${URL}SHA256.sig _KEY=secbsd-${_KERNV[0]%.*}${_KERNV[0]#*.}-base.pub _NEXTKEY=secbsd-${NEXT_VERSION%.*}${NEXT_VERSION#*.}-base.pub -read _LINE