From 470190bae7e7fdde3947d735cc26009b8cca905b Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Mon, 31 Aug 2026 15:50:24 -0400 Subject: [PATCH 1/4] Disable module signing in server kernels This is useless because we use an ephemeral key that we immediately throw away and don't distribute. On the negative side it makes the build unreproducible. --- configs/config-securedrop-6.6 | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/configs/config-securedrop-6.6 b/configs/config-securedrop-6.6 index 7c6fa6f..0f7fa6b 100644 --- a/configs/config-securedrop-6.6 +++ b/configs/config-securedrop-6.6 @@ -818,22 +818,13 @@ CONFIG_FUNCTION_ALIGNMENT=32 CONFIG_RT_MUTEXES=y CONFIG_BASE_SMALL=0 -CONFIG_MODULE_SIG_FORMAT=y CONFIG_MODULES=y # CONFIG_MODULE_FORCE_LOAD is not set CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set # CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_MODULE_SIG=y -# CONFIG_MODULE_SIG_FORCE is not set -CONFIG_MODULE_SIG_ALL=y -# CONFIG_MODULE_SIG_SHA1 is not set -# CONFIG_MODULE_SIG_SHA224 is not set -# CONFIG_MODULE_SIG_SHA256 is not set -# CONFIG_MODULE_SIG_SHA384 is not set -CONFIG_MODULE_SIG_SHA512=y -CONFIG_MODULE_SIG_HASH="sha512" +# CONFIG_MODULE_SIG is not set CONFIG_MODULE_COMPRESS_NONE=y # CONFIG_MODULE_COMPRESS_GZIP is not set # CONFIG_MODULE_COMPRESS_XZ is not set @@ -9853,9 +9844,6 @@ CONFIG_SIGNED_PE_FILE_VERIFICATION=y # # Certificates for signature checking # -CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" -CONFIG_MODULE_SIG_KEY_TYPE_RSA=y -# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set CONFIG_SYSTEM_TRUSTED_KEYRING=y CONFIG_SYSTEM_TRUSTED_KEYS="" CONFIG_SYSTEM_EXTRA_CERTIFICATE=y From 09a9ec8fabeb63077b9d18196880db13f486b613 Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Mon, 31 Aug 2026 15:52:04 -0400 Subject: [PATCH 2/4] Enable CONFIG_SLAB_FREELIST_HARDENED in server kernels Extra hardening that the workstation has that Claude noticed the server was missing. --- configs/config-securedrop-6.6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/config-securedrop-6.6 b/configs/config-securedrop-6.6 index 0f7fa6b..17b9279 100644 --- a/configs/config-securedrop-6.6 +++ b/configs/config-securedrop-6.6 @@ -950,7 +950,7 @@ CONFIG_ZSMALLOC_CHAIN_SIZE=8 CONFIG_SLUB=y # CONFIG_SLUB_TINY is not set # CONFIG_SLAB_FREELIST_RANDOM is not set -# CONFIG_SLAB_FREELIST_HARDENED is not set +CONFIG_SLAB_FREELIST_HARDENED=y # CONFIG_SLUB_STATS is not set CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_RANDOM_KMALLOC_CACHES is not set From 7b44690e9c22e3e0652f2a2bdf68c2e657a54d8d Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Mon, 31 Aug 2026 16:04:04 -0400 Subject: [PATCH 3/4] Use a deterministic seed for reproducibility Because our kernels are public, using a random seed has minimal value for a dedicated attacker because they can figure out e.g. randomized struct layout by using the published headers or decompiling vmlinux. It could have some value in forcing attackers to make their exploits work with our layouts. But since it interferes with reproducibility, use a fixed seed so we still retain the advantage of a different layout than stock kernels but builds will not actually be random. --- build-kernel.py | 64 ++++++++++++++++++++++++++++++++++++- debian/source/local-options | 2 ++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 debian/source/local-options diff --git a/build-kernel.py b/build-kernel.py index d2f2a07..1bc0d2d 100755 --- a/build-kernel.py +++ b/build-kernel.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import hashlib import os import re import shutil @@ -17,6 +18,61 @@ def render_template(filename, context): Path(filename).write_text(rendered_content) +def derive_seed(release, purpose): + """ + Because our kernels are public, using a random seed doesn't provide any hardening + but it interferes with reproducibility. Instead we use a deterministic seed. + """ + return hashlib.sha256(f"{release}-{purpose}".encode()).hexdigest() + + +def pin_build_seeds(srcdir, release): + """ + Override various scripts that reach for randomness with values based on our + deterministic seed instead. + """ + print("Pinning build seeds for", release) + # randstruct: scripts/basic/Makefile calls this with the seed file and the + # hashed-seed header as $1 and $2. Same 64 hex chars as `od -t x8 -N 32`. + randstruct = srcdir / "scripts/gen-randstruct-seed.sh" + if not randstruct.exists(): + print(f"ERROR: {randstruct} not found, cannot pin the randstruct seed") + sys.exit(1) + randstruct.write_text( + "#!/bin/sh\n" + "# SPDX-License-Identifier: GPL-2.0\n" + "# Seed pinned by kernel-builder for reproducibility; see derive_seed().\n" + f'SEED="{derive_seed(release, "randstruct")}"\n' + 'echo "$SEED" > "$1"\n' + 'HASH=$(echo -n "$SEED" | sha256sum | cut -d" " -f1)\n' + 'echo "#define RANDSTRUCT_HASHED_SEED \\"$HASH\\"" > "$2"\n' + ) + + # type_canary (grsecurity only): writes the header to stdout. The original + # emits four ULL words from 32 bytes of urandom, then an 8-char hash of them. + type_canary = srcdir / "scripts/gcc-plugins/gen-type_canary.sh" + if type_canary.exists(): + digest = bytes.fromhex(derive_seed(release, "type_canary")) + words = ", ".join( + f"0x{int.from_bytes(digest[i : i + 8], 'big'):016x}ULL" for i in range(0, 32, 8) + ) + type_canary.write_text( + "#!/bin/sh\n" + "# SPDX-License-Identifier: GPL-2.0\n" + "# Seed pinned by kernel-builder for reproducibility; see derive_seed().\n" + f'RAND=" {words} "\n' + 'HASH=$(echo "$RAND" | sha256sum | cut -d" " -f1 | tr -d " \\n" | cut -c1-8)\n' + "cat< Date: Mon, 31 Aug 2026 16:05:03 -0400 Subject: [PATCH 4/4] Enable RANDSTRUCT and LATENT_ENTROPY in CI builds To verify our code that injects a deterministic seed works as expected and that it doesn't break reproducibility. --- configs/tinyconfig-6.18 | 5 ++++- configs/tinyconfig-6.6 | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/configs/tinyconfig-6.18 b/configs/tinyconfig-6.18 index 00bedeb..c38c5e6 100644 --- a/configs/tinyconfig-6.18 +++ b/configs/tinyconfig-6.18 @@ -534,6 +534,8 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y # end of GCOV-based kernel profiling CONFIG_HAVE_GCC_PLUGINS=y +CONFIG_GCC_PLUGINS=y +CONFIG_GCC_PLUGIN_LATENT_ENTROPY=y CONFIG_FUNCTION_ALIGNMENT_4B=y CONFIG_FUNCTION_ALIGNMENT=4 CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT=y @@ -1146,7 +1148,8 @@ CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y # CONFIG_BUG_ON_DATA_CORRUPTION is not set # end of Hardening of kernel data structures -CONFIG_RANDSTRUCT_NONE=y +# CONFIG_RANDSTRUCT_NONE is not set +CONFIG_RANDSTRUCT_FULL=y # end of Kernel hardening options # end of Security options diff --git a/configs/tinyconfig-6.6 b/configs/tinyconfig-6.6 index d8ef519..1e8277a 100644 --- a/configs/tinyconfig-6.6 +++ b/configs/tinyconfig-6.6 @@ -487,7 +487,8 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y # end of GCOV-based kernel profiling CONFIG_HAVE_GCC_PLUGINS=y -# CONFIG_GCC_PLUGINS is not set +CONFIG_GCC_PLUGINS=y +CONFIG_GCC_PLUGIN_LATENT_ENTROPY=y CONFIG_FUNCTION_ALIGNMENT_4B=y CONFIG_FUNCTION_ALIGNMENT=4 # end of General architecture-dependent options @@ -1051,7 +1052,8 @@ CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y # CONFIG_BUG_ON_DATA_CORRUPTION is not set # end of Hardening of kernel data structures -CONFIG_RANDSTRUCT_NONE=y +# CONFIG_RANDSTRUCT_NONE is not set +CONFIG_RANDSTRUCT_FULL=y # end of Kernel hardening options # end of Security options