sbom: generate the keystore before checking the source list

src/keystore.c holds the public keys that authorise a firmware update.  The
build generates it from the signing key, so a fresh checkout does not hold it,
and the missing-source guard read that absence as an absent submodule.  Every
Make-path SBOM job failed on it.

Depend on it, so it exists before the guard runs, and name it in the source
list unconditionally: sbom.mk expands SBOM_SRCS through $(call) while reading
the makefile, so a file that appears later can never reach the document.
Without that second half the guard passed while the document was still one
source short, which is the silent under-report the guard exists to prevent.

Build the list with $(shell) rather than $(wildcard).  GNU make 3.81 caches
directory contents, so it never sees a source generated during the same run.

Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
pull/824/head
Sameeh Jubran 2026-08-13 15:54:44 +03:00 committed by Daniele Lacamera
parent 919de4395a
commit da1d2cfc27
2 changed files with 34 additions and 15 deletions

View File

@ -900,13 +900,26 @@ WOLFBOOT_VERSION:=$(shell sed -n \
include/wolfboot/version.h) include/wolfboot/version.h)
SBOM_ROOT:=$(WOLFBOOT_ROOT) SBOM_ROOT:=$(WOLFBOOT_ROOT)
SBOM_NAME:=wolfboot SBOM_NAME:=wolfboot
SBOM_SRCS=$(wildcard $(patsubst %.o,%.c,$(OBJS))) $(wildcard $(patsubst %.o,%.S,$(OBJS))) # src/keystore.c carries the public keys that authorise a firmware update. The
# $(wildcard) above drops every object whose source is absent, and it does so # build generates it from the signing key, so a fresh tree does not hold it yet.
# before the driver can report it: --skip-missing then has nothing left to warn # It is still a compiled source, and a bootloader SBOM that omits its own trust
# about. An absent submodule therefore shrinks the document silently. A # anchor describes the wrong image, so name it and depend on it below.
# sim-tpm build without lib/wolfTPM checked out loses all eight tpm2*.c sources, SBOM_GENERATED_SRCS=$(filter ./src/keystore.c src/keystore.c,\
# emits no diagnostic, and still validates. An object that maps to no source is $(patsubst %.o,%.c,$(OBJS)))
# the signal, so compare the two lists and stop. # $(wildcard) cannot build this list. GNU make 3.81 caches directory contents,
# so a source generated during the same run stays invisible for the rest of it;
# $(shell) re-reads the filesystem instead. The generated sources go in
# unconditionally because sbom.mk expands this list through $(call) while
# reading the makefile, which is before any recipe can create them. The driver
# opens the file afterwards, by which time the guard has made it exist.
SBOM_SRCS=$(sort $(SBOM_GENERATED_SRCS) $(shell for o in $(OBJS); do \
for e in c S; do s="$${o%.o}.$$e"; [ -f "$$s" ] && printf '%s ' "$$s"; done; \
done))
# A source that is absent must not be dropped quietly. Filtering the list to
# what happens to be on disk shrinks the document with no diagnostic anywhere:
# a sim-tpm build without lib/wolfTPM checked out loses all eight tpm2*.c
# sources, emits nothing, and still validates. An object that maps to no
# source is the signal, so compare the two lists and stop.
SBOM_SRCS_MISSING=$(filter-out $(basename $(SBOM_SRCS)),$(basename $(OBJS))) SBOM_SRCS_MISSING=$(filter-out $(basename $(SBOM_SRCS)),$(basename $(OBJS)))
SBOM_CFLAGS=$(CFLAGS) SBOM_CFLAGS=$(CFLAGS)
# wolfBoot's wolfCrypt configuration is derived, not literal: include/user_settings.h # wolfBoot's wolfCrypt configuration is derived, not literal: include/user_settings.h
@ -947,7 +960,7 @@ SBOM_GEN?=
# Guards both SBOM targets: see SBOM_SRCS_MISSING above. SBOM_ALLOW_MISSING=1 # Guards both SBOM targets: see SBOM_SRCS_MISSING above. SBOM_ALLOW_MISSING=1
# accepts the partial document, and still lists what is absent. # accepts the partial document, and still lists what is absent.
sbom-check-sources: sbom-check-sources: $(SBOM_GENERATED_SRCS)
$(Q)if [ -n "$(strip $(SBOM_SRCS_MISSING))" ]; then \ $(Q)if [ -n "$(strip $(SBOM_SRCS_MISSING))" ]; then \
echo "sbom: $(words $(SBOM_SRCS_MISSING)) object(s) map to no source on disk:" >&2; \ echo "sbom: $(words $(SBOM_SRCS_MISSING)) object(s) map to no source on disk:" >&2; \
for o in $(SBOM_SRCS_MISSING); do echo " $$o.c (or .S)" >&2; done; \ for o in $(SBOM_SRCS_MISSING); do echo " $$o.c (or .S)" >&2; done; \
@ -955,9 +968,10 @@ sbom-check-sources:
echo "sbom: SBOM_ALLOW_MISSING=1 set; the SBOM will describe fewer" >&2; \ echo "sbom: SBOM_ALLOW_MISSING=1 set; the SBOM will describe fewer" >&2; \
echo "sbom: sources than the image really holds." >&2; \ echo "sbom: sources than the image really holds." >&2; \
else \ else \
echo "sbom: a submodule or a vendor SDK is absent, so the SBOM would" >&2; \ echo "sbom: the SBOM would under-report the image. A submodule is" >&2; \
echo "sbom: under-report the image. Check the tree out (git submodule" >&2; \ echo "sbom: absent (git submodule update --init), a vendor SDK lives" >&2; \
echo "sbom: update --init), or set SBOM_ALLOW_MISSING=1 to accept it." >&2; \ echo "sbom: outside the tree, or the build generates that source and" >&2; \
echo "sbom: has not run yet. Set SBOM_ALLOW_MISSING=1 to accept it." >&2; \
exit 1; \ exit 1; \
fi; \ fi; \
fi fi

View File

@ -81,10 +81,15 @@ Obey these limitations when you make an SBOM.
### Missing sources ### Missing sources
Each object that the build compiles must map to a source file on disk. If one Each object that the build compiles must map to a source file on disk. If one
does not, a submodule or a vendor SDK is absent, and the SBOM would record does not, the SBOM would record fewer sources than the image really holds. The
fewer sources than the image really holds. The `sbom` and `sbom-hal` targets `sbom` and `sbom-hal` targets stop and list the objects. Run `git submodule
stop and list the objects. Run `git submodule update --init`, or set update --init`, or set `SBOM_ALLOW_MISSING=1` to accept a partial document.
`SBOM_ALLOW_MISSING=1` to accept a partial document.
`src/keystore.c` is the exception. wolfBoot generates it from the signing key,
so a fresh tree does not hold it yet. It carries the public keys that authorise
a firmware update, so the SBOM must describe it. Both targets generate it first,
exactly as a build does, which means `make sbom` on a fresh tree also creates a
signing key if none exists.
## Coverage: the 11 build methods ## Coverage: the 11 build methods