Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion build-kernel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
import hashlib
import os
import re
import shutil
Expand All @@ -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<<EOF\n"
"/*\n"
" * Automatically generated file, do not edit!\n"
" */\n"
"\n"
"#define TYPE_CANARY_SEED_INIT\t{ $RAND }\n"
'#define TYPE_CANARY_SEED_HASH\t"$HASH"\n'
"EOF\n"
)


def main(): # noqa: PLR0915
# Whether to use grsecurity patches
grsecurity = os.environ.get("GRSECURITY") == "1"
Expand Down Expand Up @@ -114,7 +170,9 @@ def main(): # noqa: PLR0915
# otherwise we can re-use the upstream one
linux_build_version = f"{linux_version}-{build_version}"
version_suffix = ("grsec-" if grsecurity else "") + local_version
orig_tarball = f"linux-upstream_{linux_build_version}-{version_suffix}.orig.tar.xz"
release = f"{linux_build_version}-{version_suffix}"
orig_tarball = f"linux-upstream_{release}.orig.tar.xz"
pin_build_seeds(Path(f"linux-{linux_version}"), release)
if grsecurity:
print("Generating orig tarball")
subprocess.check_call(
Expand Down Expand Up @@ -156,8 +214,12 @@ def main(): # noqa: PLR0915

# Building Linux kernel source
print("Building Linux kernel source", linux_version)
env = os.environ.copy()
# inject our deterministic seed for latent_entropy plugin
env["KCFLAGS"] = f"-frandom-seed={derive_seed(release, 'latent_entropy')}"
subprocess.check_call(
["/usr/bin/dpkg-buildpackage", "-uc", "-us"],
env=env,
)

os.chdir("..")
Expand Down
16 changes: 2 additions & 14 deletions configs/config-securedrop-6.6
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -959,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
Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion configs/tinyconfig-6.18
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
6 changes: 4 additions & 2 deletions configs/tinyconfig-6.6
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions debian/source/local-options
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# we modify these files to inject our deterministic seed
extend-diff-ignore = "^scripts/(gen-randstruct-seed\.sh|gcc-plugins/gen-type_canary\.sh)$"