From aded01644f758f939a463800db60a6d566f7b607 Mon Sep 17 00:00:00 2001 From: Travis Downs Date: Wed, 15 Apr 2026 15:35:15 -0400 Subject: [PATCH 1/2] bazel/hwloc: make foreign_cc build reproducible The hwloc configure_make build embeds sandbox-absolute paths into compiled objects, making the output non-deterministic across builds with different --output_base directories. Two sources of path leakage: 1. Inlined assert() macros in hwloc headers (helper.h, plugins.h) expand __FILE__ to the sandbox-absolute include path, which ends up in .rodata of 7 object files and propagates into libhwloc.a. Fix: add -ffile-prefix-map=$EXT_BUILD_ROOT=. to CFLAGS/CXXFLAGS via the env dict, remapping the sandbox root to "." in all __FILE__ expansions. 2. Autoconf derives runstatedir from --prefix, which points into the sandbox install directory. This path gets compiled into topology-linux.o as a string literal. Fix: pass --runstatedir=/var/run/hwloc to configure, overriding the prefix-derived default with a fixed path. With both fixes, libhwloc.a and all object files are bit-for-bit identical across independent builds. --- bazel/thirdparty/hwloc.BUILD | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bazel/thirdparty/hwloc.BUILD b/bazel/thirdparty/hwloc.BUILD index fb696c6854ae2..8ee65c65da2e5 100644 --- a/bazel/thirdparty/hwloc.BUILD +++ b/bazel/thirdparty/hwloc.BUILD @@ -33,9 +33,17 @@ configure_make( # Build a static library "--disable-shared", "--enable-static", + + # Use a fixed runstatedir so the autoconf-derived path doesn't embed + # the sandbox directory into compiled objects. + "--runstatedir=/var/run/hwloc", ], env = { "HWLOC_BUILD_JOBS": "$(BUILD_JOBS)", + # Remap the sandbox root in __FILE__ expansions so that inlined + # headers (helper.h, plugins.h) produce deterministic assert strings. + "CFLAGS": "-ffile-prefix-map=$$EXT_BUILD_ROOT=.", + "CXXFLAGS": "-ffile-prefix-map=$$EXT_BUILD_ROOT=.", }, lib_source = ":srcs", out_binaries = [ From 5f19753a485ac6976fb02f44c7ab51a60c880aa1 Mon Sep 17 00:00:00 2001 From: Travis Downs Date: Wed, 15 Apr 2026 15:37:48 -0400 Subject: [PATCH 2/2] bazel/openssl: make foreign_cc build reproducible Two sources of non-determinism in the openssl configure_make build: 1. util/mkbuildinf.pl captures the full CC and CFLAGS strings and embeds them into crypto/buildinf.h as a compiled-in constant (the compiler_flags[] array). Since CC and CFLAGS contain $EXT_BUILD_ROOT-relative paths (compiler wrapper, --sysroot), the sandbox-absolute path leaks into libcrypto. This string is only used by the informational OpenSSL_version(OPENSSL_CFLAGS) API (i.e., `openssl version -f`). Fix: patch mkbuildinf.pl to strip $EXT_BUILD_ROOT prefixes from the compiler string before embedding it, using the EXT_BUILD_ROOT environment variable already exported by rules_foreign_cc. 2. mkbuildinf.pl also embeds a DATE macro using the current wall-clock time via time(), causing the binary to differ between runs even with identical inputs. OpenSSL already supports the SOURCE_DATE_EPOCH convention for reproducible builds. Fix: set SOURCE_DATE_EPOCH=0 in the env dict, pinning the embedded timestamp to the Unix epoch. With both fixes, libcrypto.so.3, libssl.so.3, libcrypto.a, and the openssl binary are all bit-for-bit identical across independent builds. The only remaining diff is Configure.log (a text build log). Refs: https://reproducible-builds.org/docs/source-date-epoch/ https://wiki.openssl.org/index.php/Compilation_and_Installation --- MODULE.bazel.lock | 8 ++++++- bazel/repositories.bzl | 2 ++ .../openssl-reproducible-buildinf.patch | 21 +++++++++++++++++++ bazel/thirdparty/openssl.BUILD | 4 ++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 bazel/thirdparty/openssl-reproducible-buildinf.patch diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index d80cf3214074a..424a09d7bb380 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -307,7 +307,7 @@ "moduleExtensions": { "//bazel:extensions.bzl%non_module_dependencies": { "general": { - "bzlTransitiveDigest": "ZtSnFu4+NXfuxuGvvbUJp7UjeyCebjpwwaLk/CVuao8=", + "bzlTransitiveDigest": "SDTLfnB2Pm4MoythhHEjKLwqGadLnImYvdjBbsTPxPw=", "usagesDigest": "FEiDyZe9eAU6yEqnarZf0XMEUk+prUyYClvq1RU1J98=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -443,6 +443,12 @@ "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "build_file": "@@//bazel/thirdparty:openssl.BUILD", + "patches": [ + "@@//bazel/thirdparty:openssl-reproducible-buildinf.patch" + ], + "patch_args": [ + "-p1" + ], "sha256": "deae7c80cba99c4b4f940ecadb3c3338b13cb77418409238e57d7f31f2a3b736", "strip_prefix": "openssl-3.5.6", "url": "https://vectorized-public.s3.amazonaws.com/dependencies/openssl-3.5.6.tar.gz" diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index cfa85f2eee669..32d4d0fac805b 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -133,6 +133,8 @@ def data_dependency(): http_archive( name = "openssl", build_file = "//bazel/thirdparty:openssl.BUILD", + patches = ["//bazel/thirdparty:openssl-reproducible-buildinf.patch"], + patch_args = ["-p1"], sha256 = "deae7c80cba99c4b4f940ecadb3c3338b13cb77418409238e57d7f31f2a3b736", strip_prefix = "openssl-3.5.6", url = "https://vectorized-public.s3.amazonaws.com/dependencies/openssl-3.5.6.tar.gz", diff --git a/bazel/thirdparty/openssl-reproducible-buildinf.patch b/bazel/thirdparty/openssl-reproducible-buildinf.patch new file mode 100644 index 0000000000000..555daacef5911 --- /dev/null +++ b/bazel/thirdparty/openssl-reproducible-buildinf.patch @@ -0,0 +1,21 @@ +diff --git a/util/mkbuildinf.pl b/util/mkbuildinf.pl +index abcdef1..1234567 100644 +--- a/util/mkbuildinf.pl ++++ b/util/mkbuildinf.pl +@@ -11,6 +11,16 @@ use warnings; + my $platform = pop @ARGV; + my $cflags = join(' ', @ARGV); + $cflags =~ s(\\)(\\\\)g; ++ ++# Strip sandbox/build-root absolute paths so the output is reproducible ++# across different Bazel output bases and sandbox instances. Note: the ++# cflags modified here are only embedded as a diagnostic string (shown by ++# `openssl version -a`), not used for actual compilation. ++my $ebr = $ENV{'EXT_BUILD_ROOT'} // ''; ++if ($ebr ne '') { ++ $cflags =~ s/\Q$ebr\E\/?/./g; ++} ++ + $cflags = "compiler: $cflags"; + + # Use the value of the envvar SOURCE_DATE_EPOCH, even if it's diff --git a/bazel/thirdparty/openssl.BUILD b/bazel/thirdparty/openssl.BUILD index caa287d893dd3..f020a473565fa 100644 --- a/bazel/thirdparty/openssl.BUILD +++ b/bazel/thirdparty/openssl.BUILD @@ -67,6 +67,10 @@ configure_make( }), env = { "OPENSSL_BUILD_JOBS": "$(BUILD_JOBS)", + # Pin the build timestamp to epoch 0 for reproducible builds. + # Without this, mkbuildinf.pl embeds the current time into + # crypto/buildinf.h. + "SOURCE_DATE_EPOCH": "0", }, lib_source = ":srcs", out_binaries = [