From 29b94c09d49ea65c64b8061e80016e45828cca52 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Tue, 10 Feb 2026 14:14:07 -0600 Subject: [PATCH] Fix segfault from Alpine version mismatch, add crash handler The builder (rust:1.93-alpine) uses Alpine 3.23 but the runtime used Alpine 3.19. The net-snmp-dev headers from 3.23 don't match net-snmp-libs from 3.19, causing a segfault on the first SNMP call. Also adds a SIGSEGV/SIGBUS/SIGABRT signal handler that prints a diagnostic message instead of silently exiting with code 139. --- Dockerfile | 5 +++-- src/main.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9a3e070..6aca1c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,8 +52,9 @@ RUN --mount=type=cache,id=cargo-registry-${TARGETARCH},target=/usr/local/cargo/r BUILD_VERSION="$VERSION" cargo build --release --target "$RUST_TARGET" && \ cp "target/$RUST_TARGET/release/towerops-agent" /tmp/towerops-agent -# Runtime stage -FROM alpine:3.19 +# Runtime stage - must match builder's Alpine version for ABI compatibility +# (rust:1.93-alpine uses Alpine 3.23) +FROM alpine:3.23 # Install runtime dependencies # iputils provides ping with setuid root (doesn't require CAP_NET_RAW) diff --git a/src/main.rs b/src/main.rs index 71097b3..ab4741f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -116,7 +116,40 @@ struct Args { snmpv3_priv_pass: String, } +fn install_crash_handler() { + unsafe { + // Install a signal handler for SIGSEGV/SIGBUS/SIGABRT so we get + // diagnostic output instead of a silent exit code 139. + extern "C" fn crash_handler(sig: libc::c_int) { + let name = match sig { + libc::SIGSEGV => "SIGSEGV (segmentation fault)", + libc::SIGBUS => "SIGBUS (bus error)", + libc::SIGABRT => "SIGABRT (abort)", + _ => "unknown signal", + }; + let msg = format!( + "\n*** FATAL: {} (signal {})\n\ + *** This is likely a bug in C FFI code (libnetsnmp).\n\ + *** Set RUST_BACKTRACE=1 for more info.\n", + name, sig + ); + unsafe { + libc::write(libc::STDERR_FILENO, msg.as_ptr() as _, msg.len()); + // Re-raise with default handler to get the correct exit code + libc::signal(sig, libc::SIG_DFL); + libc::raise(sig); + } + } + + libc::signal(libc::SIGSEGV, crash_handler as libc::sighandler_t); + libc::signal(libc::SIGBUS, crash_handler as libc::sighandler_t); + libc::signal(libc::SIGABRT, crash_handler as libc::sighandler_t); + } +} + fn main() { + install_crash_handler(); + // Install ring as the default TLS crypto provider. Required because both // ring and aws-lc-rs features are enabled transitively, so rustls can't // auto-detect which one to use.