[PATCH v2 01/14] tools/sbom: integrate tool in make process

Luis Augenstein
2026-01-20T11:55:36Z

Add CONFIG_SBOM option and integrate SBOM tool into the kernel build
process.

Co-developed-by: Maximilian Huber <maximilian.huber@tngtech.com>
Signed-off-by: Maximilian Huber <maximilian.huber@tngtech.com>
Signed-off-by: Luis Augenstein <luis.augenstein@tngtech.com>
---
.gitignore | 1 +
MAINTAINERS | 6 ++
Makefile | 15 +++-
lib/Kconfig.debug | 9 ++
tools/Makefile | 3 +-
tools/sbom/Makefile | 35 ++++++++
tools/sbom/README | 208 ++++++++++++++++++++++++++++++++++++++++++++
tools/sbom/sbom.py | 16 ++++
8 files changed, 291 insertions(+), 2 deletions(-)
create mode 100644 tools/sbom/Makefile
create mode 100644 tools/sbom/README
create mode 100644 tools/sbom/sbom.py

diff --git a/.gitignore b/.gitignore
index 3a7241c941f5..f3372f15eb1b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,7 @@
*.s
*.so
*.so.dbg
+*.spdx.json
*.su
*.symtypes
*.tab.[ch]
diff --git a/MAINTAINERS b/MAINTAINERS
index f1b020588597..03d7d93d8e63 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23365,6 +23365,12 @@ R: Marc Murphy <marc.murphy@sancloud.com>
S: Supported
F: arch/arm/boot/dts/ti/omap/am335x-sancloud*

+SBOM
+M: Luis Augenstein <luis.augenstein@tngtech.com>
+M: Maximilian Huber <maximilian.huber@tngtech.com>
+S: Maintained
+F: tools/sbom/
+
SC1200 WDT DRIVER
M: Zwane Mwaikambo <zwanem@gmail.com>
S: Maintained
diff --git a/Makefile b/Makefile
index 9d38125263fb..a1c0cbd110e5 100644
--- a/Makefile
+++ b/Makefile
@@ -1457,6 +1457,19 @@ prepare: tools/bpf/resolve_btfids
endif
endif

+ifdef CONFIG_SBOM
+all: tools/sbom
+tools/sbom: $(notdir $(KBUILD_IMAGE)) modules
+ $(Q)mkdir -p $(objtree)/tools
+ $(Q)$(MAKE) \
+ O=$(abspath $(objtree)) \
+ subdir=tools \
+ -C $(srctree)/tools/ \
+ sbom \
+ srctree=$(abspath $(srctree)) \
+ CONFIG_MODULES=$(CONFIG_MODULES)
+endif
+
# The tools build system is not a part of Kbuild and tends to introduce
# its own unique issues. If you need to integrate a new tool into Kbuild,
# please consider locating that tool outside the tools/ tree and using the
@@ -1612,7 +1625,7 @@ CLEAN_FILES += vmlinux.symvers modules-only.symvers \
modules.builtin.ranges vmlinux.o.map vmlinux.unstripped \
compile_commands.json rust/test \
rust-project.json .vmlinux.objs .vmlinux.export.c \
- .builtin-dtbs-list .builtin-dtb.S
+ .builtin-dtbs-list .builtin-dtb.S sbom-*.spdx.json

# Directories & files removed with 'make mrproper'
MRPROPER_FILES += include/config include/generated \
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ba36939fda79..9d03ef854f61 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -563,6 +563,15 @@ config OBJTOOL_WERROR

If unsure, say Y.

+config SBOM
+ bool "Generate Software Bill of Materials"
+ help
+ If enabled, the kernel build will generate SPDX SBOM documents
+ describing all source files, and build artifacts involved in the build.
+ The SBOM documents are generated in SPDX 3.0.1 format and saved to the build output
+ directory after the build completes.
+ For more information, see tools/sbom/README
+
config STACK_VALIDATION
bool "Compile-time stack metadata validation"
depends on HAVE_STACK_VALIDATION && UNWINDER_FRAME_POINTER
diff --git a/tools/Makefile b/tools/Makefile
index cb40961a740f..7b4b1c96dcd5 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -27,6 +27,7 @@ help:
@echo ' nolibc - nolibc headers testing and installation'
@echo ' objtool - an ELF object analysis tool'
@echo ' perf - Linux performance measurement and analysis tool'
+ @echo ' sbom - SBOM generation tool'
@echo ' selftests - various kernel selftests'
@echo ' sched_ext - sched_ext example schedulers'
@echo ' bootconfig - boot config tool'
@@ -70,7 +71,7 @@ acpi: FORCE
cpupower: FORCE
$(call descend,power/$@)

-counter dma firewire hv guest bootconfig spi usb virtio mm bpf iio gpio objtool leds wmi firmware debugging tracing: FORCE
+counter dma firewire hv guest bootconfig spi usb virtio mm bpf iio gpio objtool leds wmi firmware debugging tracing sbom: FORCE
$(call descend,$@)

bpf/%: FORCE
diff --git a/tools/sbom/Makefile b/tools/sbom/Makefile
new file mode 100644
index 000000000000..8be7f2f3e631
--- /dev/null
+++ b/tools/sbom/Makefile
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: GPL-2.0-only OR MIT
+# Copyright (C) 2025 TNG Technology Consulting GmbH
+
+SBOM_SOURCE_FILE := $(objtree)/sbom-source.spdx.json
+SBOM_BUILD_FILE := $(objtree)/sbom-build.spdx.json
+SBOM_OUTPUT_FILE := $(objtree)/sbom-output.spdx.json
+SBOM_ROOTS_FILE := $(objtree)/sbom-roots.txt
+
+
+ifeq ($(srctree),$(objtree))
+ SBOM_TARGETS := $(SBOM_BUILD_FILE) $(SBOM_OUTPUT_FILE)
+else
+ SBOM_TARGETS := $(SBOM_SOURCE_FILE) $(SBOM_BUILD_FILE) $(SBOM_OUTPUT_FILE)
+endif
+
+SBOM_DEPS := $(objtree)/$(KBUILD_IMAGE) $(objtree)/include/generated/autoconf.h
+ifdef CONFIG_MODULES
+ SBOM_DEPS += $(objtree)/modules.order
+endif
+
+sbom: $(SBOM_TARGETS)
+
+$(SBOM_TARGETS) &: $(SBOM_DEPS)
+ @echo " GEN $(notdir $(SBOM_TARGETS))"
+
+ @printf "%s\n" "$(KBUILD_IMAGE)" > $(SBOM_ROOTS_FILE)
+ @if [ "$(CONFIG_MODULES)" = "y" ]; then \
+ sed 's/\.o$$/.ko/' $(objtree)/modules.order >> $(SBOM_ROOTS_FILE); \
+ fi
+
+ @python3 sbom.py
+
+ @rm $(SBOM_ROOTS_FILE)
+
+.PHONY: sbom
diff --git a/tools/sbom/README b/tools/sbom/README
new file mode 100644
index 000000000000..5d157a1f9af8
--- /dev/null
+++ b/tools/sbom/README
@@ -0,0 +1,208 @@
+<!--
+SPDX-License-Identifier: GPL-2.0-only OR MIT
+Copyright (C) 2025 TNG Technology Consulting GmbH
+-->
+
+KernelSbom
+==========
+
+Introduction
+------------
+
+The kernel `CONFIG_SBOM` option enables the KernelSbom tool,
+a Python script `sbom.py` that runs during the kernel build process
+after all build outputs have been generated.
+KernelSbom analyzes every file involved in the build and produces
+Software Bill of Materials (SBOM) documents in SPDX 3.0.1 format.
+The generated SBOM documents capture:
+- **Final output artifacts**, typically the kernel image and modules
+- **All source files** that contributed to the build with metadata
+ and licensing information
+- **Details of the build process**, including intermediate artifacts
+ and the build commands linking source files to the final output
+ artifacts
+
+KernelSbom is originally developed in the
+[KernelSbom repository](https://github.com/TNG/KernelSbom).
+
+Requirements
+------------
+
+Python 3.10 or later. No libraries or other dependencies are required.
+
+Basic Usage
+-----------
+
+Enable the `CONFIG_SBOM` option and start a kernel build.
+For example:
+
+ $ make defconfig O=kernel_build
+ $ scripts/config --file kernel_build/.config --enable SBOM
+ $ make O=kernel_build -j$(nproc)
+
+After all build outputs have been generated, KernelSbom produces three
+SPDX documents in the root directory of the object tree:
+
+- `sbom-source.spdx.json`
+ Describes all source files involved in the build and
+ associates each file with its corresponding license expression.
+
+- `sbom-output.spdx.json`
+ Captures all final build outputs (kernel image and `.ko` module files)
+ and includes build metadata such as environment variables and
+ a hash of the `.config` file used for the build.
+
+- `sbom-build.spdx.json`
+ Imports files from the source and output documents and describes every
+ intermediate build artifact. For each artifact, it records the exact
+ build command used and establishes the relationship between
+ input files and generated outputs.
+
+When enabling the KernelSbom tool, it is recommended to perform
+out-of-tree builds using `O=<objtree>`. KernelSbom classifies files as
+source files when they are located in the source tree and not in the
+object tree. For in-tree builds, where the source and object trees are
+the same directory, this distinction can no longer be made reliably.
+In that case, KernelSbom does not generate a dedicated source SBOM.
+Instead, source files are included in the build SBOM.
+
+Standalone Usage
+----------------
+
+KernelSbom can also be used as a standalone script to generate
+SPDX documents for specific build outputs. For example, after a
+successful x86 kernel build, KernelSbom can generate SPDX documents
+for the `bzImage` kernel image:
+
+ $ SRCARCH=x86 python3 tools/sbom/sbom.py \
+ --src-tree . \
+ --obj-tree ./kernel_build \
+ --roots arch/x86/boot/bzImage \
+ --generate-spdx \
+ --generate-used-files \
+ --prettify-json \
+ --debug
+
+Note that when KernelSbom is invoked outside of the `make` process,
+the environment variables used during compilation are not available and
+therefore cannot be included in the generated SPDX documents. It is
+recommended to set at least the `SRCARCH` environment variable to the
+architecture for which the build was performed.
+
+For a full list of command-line options, run:
+
+ $ python3 tools/sbom/sbom.py --help
+
+Output Format
+-------------
+
+KernelSbom generates documents conforming to the
+[SPDX 3.0.1 specification](https://spdx.github.io/spdx-spec/v3.0.1/)
+serialized as JSON-LD.
+
+To reduce file size, the output documents use the JSON-LD `@context`
+to define custom prefixes for `spdxId` values. While this is compliant
+with the SPDX specification, only a limited number of tools in the
+current SPDX ecosystem support custom JSON-LD contexts. To use such
+tools with the generated documents, the custom JSON-LD context must
+be expanded before providing the documents.
+See https://lists.spdx.org/g/Spdx-tech/message/6064 for more information.
+
+How it Works
+------------
+
+KernelSbom operates in two major phases:
+1. **Generate the cmd graph**, an acyclic directed dependency graph.
+2. **Generate SPDX documents** based on the cmd graph.
+
+KernelSbom begins from the root artifacts specified by the user, e.g.,
+`arch/x86/boot/bzImage`. For each root artifact, it collects all
+dependencies required to build that artifact. The dependencies come
+from multiple sources:
+
+- **`.cmd` files**: The primary source is the `.cmd` file of the
+ generated artifact, e.g., `arch/x86/boot/.bzImage.cmd`. These files
+ contain the exact command used to build the artifact and often include
+ an explicit list of input dependencies. By parsing the `.cmd` file,
+ the full list of dependencies can be obtained.
+
+- **`.incbin` statements**: The second source are include binary
+ `.incbin` statements in `.S` assembly files.
+
+- **Hardcoded dependencies**: Unfortunately, not all build dependencies
+ can be found via `.cmd` files and `.incbin` statements. Some build
+ dependencies are directly defined in Makefiles or Kbuild files.
+ Parsing these files is considered too complex for the scope of this
+ project. Instead, the remaining gaps of the graph are filled using a
+ list of manually defined dependencies, see
+ `sbom/cmd_graph/hardcoded_dependencies.py`. This list is known to be
+ incomplete. However, analysis of the cmd graph indicates a ~99%
+ completeness. For more information about the completeness analysis,
+ see [KernelSbom #95](https://github.com/TNG/KernelSbom/issues/95).
+
+Given the list of dependency files, KernelSbom recursively processes
+each file, expanding the dependency chain all the way to the version
+controlled source files. The result is a complete dependency graph
+where nodes represent files, and edges represent "file A was used to
+build file B" relationships.
+
+Using the cmd graph, KernelSbom produces three SPDX documents.
+For every file in the graph, KernelSbom:
+
+- Parses `SPDX-License-Identifier` headers,
+- Computes file hashes,
+- Estimates the file type based on extension and path,
+- Records build relationships between files.
+
+Each root output file is additionally associated with an SPDX Package
+element that captures version information, license data, and copyright.
+
+Advanced Usage
+--------------
+
+Including Kernel Modules
+------------------------
+
+The list of all `.ko` kernel modules produced during a build can be
+extracted from the `modules.order` file within the object tree.
+For example:
+
+ $ echo "arch/x86/boot/bzImage" > sbom-roots.txt
+ $ sed 's/\.o$/.ko/' ./kernel_build/modules.order >> sbom-roots.txt
+
+Then use the generated roots file:
+
+ $ SRCARCH=x86 python3 tools/sbom/sbom.py \
+ --src-tree . \
+ --obj-tree ./kernel_build \
+ --roots-file sbom-roots.txt \
+ --generate-spdx
+
+
+Equal Source and Object Trees
+------------------------------
+
+When the source tree and object tree are identical (for example, when
+building in-tree), source files can no longer be reliably distinguished
+from generated files.
+In this scenario, KernelSbom does not produce a dedicated
+`sbom-source.spdx.json` document. Instead, both source files and build
+artifacts are included together in `sbom-build.spdx.json`, and
+`sbom.used-files.txt` lists all files referenced in the build document.
+
+Unknown Build Commands
+----------------------
+
+Because the kernel supports a wide range of configurations and versions,
+KernelSbom may encounter build commands in `.cmd` files that it does
+not yet support. By default, KernelSbom will fail if an unknown build
+command is encountered.
+
+If you still wish to generate SPDX documents despite unsupported
+commands, you can use the `--do-not-fail-on-unknown-build-command`
+option. KernelSbom will continue and produce the documents, although
+the resulting SBOM will be incomplete.
+
+This option should only be used when the missing portion of the
+dependency graph is small and an incomplete SBOM is acceptable for
+your use case.
diff --git a/tools/sbom/sbom.py b/tools/sbom/sbom.py
new file mode 100644
index 000000000000..9c2e4c7f17ce
--- /dev/null
+++ b/tools/sbom/sbom.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only OR MIT
+# Copyright (C) 2025 TNG Technology Consulting GmbH
+
+"""
+Compute software bill of materials in SPDX format describing a kernel build.
+"""
+
+
+def main():
+ pass
+
+
+# Call main method
+if __name__ == "__main__":
+ main()
--
2.34.1