Skip to content

Commit aa6fdb8

Browse files
committed
x86 FSP: add TPM-NV anti-rollback with a persistent version floor and boot audit counters
1 parent 2cb873b commit aa6fdb8

21 files changed

Lines changed: 1102 additions & 30 deletions

‎.github/workflows/test-build-kontron-vx3060-s2.yml‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ jobs:
4646
export DEBIAN_FRONTEND=noninteractive
4747
sudo apt-get update -o Acquire::Retries=3
4848
sudo apt-get install --no-install-recommends -y -q -o Acquire::Retries=3 nasm gcc-multilib
49-
- name: setup git
50-
run: |
51-
git config --global user.email "you@example.com"
52-
git config --global user.name "Your Name"
5349
- name: run test
5450
run: |
5551
cp config/examples/kontron_vx3060_s2.config .config

‎.github/workflows/test-x86-fsp-qemu.yml‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ jobs:
4646
export DEBIAN_FRONTEND=noninteractive
4747
sudo apt-get update -o Acquire::Retries=3
4848
sudo apt-get install --no-install-recommends -y -q -o Acquire::Retries=3 nasm gcc-multilib qemu-system-x86 swtpm uuid-dev
49-
- name: setup git
50-
run: |
51-
git config --global user.email "you@example.com"
52-
git config --global user.name "Your Name"
5349
- name: run test
5450
run: |
5551
./tools/scripts/x86_fsp/qemu/test_qemu.sh
@@ -70,10 +66,25 @@ jobs:
7066
export DEBIAN_FRONTEND=noninteractive
7167
sudo apt-get update -o Acquire::Retries=3
7268
sudo apt-get install --no-install-recommends -y -q -o Acquire::Retries=3 nasm gcc-multilib qemu-system-x86 uuid-dev dosfstools mtools e2fsprogs
73-
- name: setup git
74-
run: |
75-
git config --global user.email "you@example.com"
76-
git config --global user.name "Your Name"
7769
- name: run test
7870
run: |
7971
./tools/scripts/x86_fsp/qemu/test_qemu.sh -f
72+
73+
# TPM-NV anti-rollback: the floor anchors on a fresh swtpm, survives a TPM
74+
# restart, and a validly signed downgrade boots and is counted.
75+
fsp_qemu_antirollback_test:
76+
runs-on: ubuntu-latest
77+
timeout-minutes: 15
78+
79+
steps:
80+
- uses: actions/checkout@v4
81+
with:
82+
submodules: true
83+
- name: install req
84+
run: |
85+
export DEBIAN_FRONTEND=noninteractive
86+
sudo apt-get update -o Acquire::Retries=3
87+
sudo apt-get install --no-install-recommends -y -q -o Acquire::Retries=3 nasm gcc-multilib qemu-system-x86 swtpm uuid-dev
88+
- name: run test
89+
run: |
90+
./tools/scripts/x86_fsp/qemu/test_qemu.sh -r

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ tools/unit-tests/unit-update-flash-enc
181181
tools/unit-tests/unit-update-flash-db
182182
tools/unit-tests/unit-update-flash-enc-full
183183
tools/unit-tests/unit-update-ram
184+
tools/unit-tests/unit-boot-state
185+
tools/unit-tests/unit-boot-state-halt
184186
tools/unit-tests/unit-boot-x86-fsp
185187
tools/unit-tests/unit-image-rsa
186188
tools/unit-tests/unit-multiboot

‎arch.mk‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,10 @@ ifeq ("${FSP}", "1")
23122312
OBJS += src/x86/fsp_s.o
23132313
UPDATE_OBJS := src/update_disk.o
23142314
CFLAGS+=-DWOLFBOOT_UPDATE_DISK
2315+
ifeq ($(ANTI_ROLLBACK),1)
2316+
OBJS += src/boot_state.o
2317+
OBJS += src/boot_state_tpm.o
2318+
endif
23152319
ifeq ($(64BIT),1)
23162320
LDFLAGS += -m elf_x86_64 --oformat elf64-x86-64
23172321
CFLAGS += -m64
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
ARCH=x86_64
2+
TARGET=x86_fsp_qemu
3+
WOLFBOOT_SMALL_STACK=1
4+
SIGN=ECC256
5+
HASH=SHA256
6+
DEBUG=1
7+
SPMATH=1
8+
FORCE_32BIT=1
9+
ENCRYPTION=0
10+
WOLFBOOT_NO_PARTITIONS=1
11+
12+
# TPM Keystore options
13+
#WOLFBOOT_TPM_KEYSTORE?=1
14+
#WOLFBOOT_TPM_KEYSTORE_NV_BASE?=0x01800200
15+
#WOLFBOOT_TPM_POLICY_NV_INDEX?=0x01800201
16+
17+
# 4gb - 8mb
18+
WOLFBOOT_LOAD_BASE=0x2000000
19+
WOLFBOOT_LOAD_ADDRESS=0x1000000
20+
21+
# required for keytools
22+
WOLFBOOT_SECTOR_SIZE?=0x1000
23+
WOLFBOOT_DATA_ADDRESS=0x1000000
24+
25+
FSP_M_BASE=0xffe30000
26+
FSP_S_BASE=0xffed6000
27+
FSP_T_BASE=0xfffe0000
28+
FSP_S_LOAD_BASE=0x0FED5F00
29+
WOLFBOOT_ORIGIN=0xfff80000
30+
31+
BOOTLOADER_PARTITION_SIZE=0xe0000
32+
BIOS_REGION_SIZE=0x800000
33+
MACHINE_OBJ=src/x86/qemu_fsp.o
34+
FSP_T_BIN=./src/x86/fsp_t.bin
35+
FSP_M_BIN=./src/x86/fsp_m.bin
36+
FSP_S_BIN=./src/x86/fsp_s.bin
37+
STAGE1_AUTH=1
38+
64BIT=1
39+
ELF=1
40+
MULTIBOOT2=1
41+
42+
# TPM-NV anti-rollback (version floor and audit counters), tested by
43+
# tools/scripts/x86_fsp/qemu/test_qemu.sh -r
44+
ANTI_ROLLBACK=1
45+
ANTI_ROLLBACK_HALT_ON_FAILURE=1

‎include/boot_state.h‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* boot_state.h
2+
*
3+
* Persistent anti-rollback reference and boot audit counters.
4+
*
5+
* Copyright (C) 2026 wolfSSL Inc.
6+
*
7+
* This file is part of wolfBoot.
8+
*
9+
* wolfBoot is free software; you can redistribute it and/or modify
10+
* it under the terms of the GNU General Public License as published by
11+
* the Free Software Foundation; either version 2 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* wolfBoot is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program; if not, write to the Free Software
21+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
22+
*/
23+
24+
/* Anti-rollback state: anchor = highest version ever booted (trust on first
25+
* use), record = last booted. See the Anti-rollback section of Targets.md. */
26+
27+
#ifndef BOOT_STATE_H
28+
#define BOOT_STATE_H
29+
30+
#include <stdint.h>
31+
32+
#define BOOT_STATE_MAGIC 0x42535431UL /* "BST1" */
33+
#define BOOT_STATE_VERSION 1
34+
35+
/* Result of loading the persisted state. */
36+
#define BOOT_STATE_OK 0 /* loaded and trustworthy */
37+
#define BOOT_STATE_UNPROVISIONED 1 /* nothing stored yet; not an error */
38+
#define BOOT_STATE_CORRUPT (-1) /* stored but unusable -- fatal */
39+
#define BOOT_STATE_UNAVAILABLE (-2) /* backend could not be reached */
40+
41+
/* Failure codes recorded in last_fail_code. */
42+
#define BOOT_FAIL_NONE 0
43+
#define BOOT_FAIL_NO_IMAGE 1
44+
#define BOOT_FAIL_VERIFY_PRIMARY 2
45+
#define BOOT_FAIL_VERIFY_BOTH 3
46+
#define BOOT_FAIL_ROLLBACK 4
47+
48+
/* On-storage layout. Packed and explicitly sized so the representation does
49+
* not shift between the bootloader and any provisioning tool. */
50+
struct boot_state {
51+
uint32_t magic;
52+
uint32_t anchor;
53+
uint32_t record;
54+
uint32_t rollback_count;
55+
uint32_t last_rollback_from;
56+
uint32_t last_rollback_to;
57+
uint32_t boot_fail_count;
58+
uint32_t last_fail_code;
59+
uint16_t struct_version;
60+
uint16_t reserved;
61+
uint32_t crc;
62+
} __attribute__((packed));
63+
64+
/* Backend, implemented per platform. v1 uses TPM NV (src/boot_state_tpm.c). */
65+
int boot_state_backend_read(uint8_t *buf, uint32_t len);
66+
int boot_state_backend_write(const uint8_t *buf, uint32_t len);
67+
/* Write-locks the record until the next TPM reset, so the booted OS cannot
68+
* rewrite it. */
69+
int boot_state_backend_lock(void);
70+
71+
/* Load the persisted state. Returns one of the BOOT_STATE_* codes above. */
72+
int boot_state_load(struct boot_state *st);
73+
74+
/* Called once an image has verified, immediately before handing off.
75+
* Applies the rollback check, updates anchor and record, and persists. */
76+
void boot_state_on_boot(uint32_t booted_version);
77+
/* Lock the stored state against the OS without recording a boot (golden
78+
* slot). Halts on failure with ANTI_ROLLBACK_HALT_ON_FAILURE. */
79+
void boot_state_lock(void);
80+
81+
/* Called when the boot policy has decided no image may be booted. Records the
82+
* failure so the evidence survives the power cycle. */
83+
void boot_state_on_failure(uint32_t fail_code);
84+
85+
#endif /* BOOT_STATE_H */

‎include/tpm.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ extern WOLFTPM2_KEY wolftpm_srk;
4040
#ifndef WOLFBOOT_TPM_SEAL_NV_BASE
4141
#define WOLFBOOT_TPM_SEAL_NV_BASE 0x01400300
4242
#endif
43+
#ifndef WOLFBOOT_TPM_BOOT_STATE_NV_BASE
44+
#define WOLFBOOT_TPM_BOOT_STATE_NV_BASE 0x01400400
45+
#endif
4346
/* The PCR bank algorithm and its digest size must always agree. They used to
4447
* be defined together under a single #ifndef on the algorithm, which meant
4548
* overriding only WOLFBOOT_TPM_PCR_ALG left WOLFBOOT_TPM_PCR_DIG_SZ undefined

‎options.mk‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ ifeq ($(ACPI),1)
5757
CFLAGS+=-D"WOLFBOOT_ACPI"
5858
endif
5959

60+
# TPM NV version floor and boot audit counters (see docs/Targets.md).
61+
# HALT_ON_FAILURE also halts when the TPM state cannot be read or locked.
62+
ifeq ($(ANTI_ROLLBACK),1)
63+
ifeq ($(filter $(TARGET),x86_fsp_qemu kontron_vx3060_s2 nai_68int6),)
64+
$(error ANTI_ROLLBACK=1 is only wired into the x86 FSP disk boot)
65+
endif
66+
CFLAGS+=-D"WOLFBOOT_ANTI_ROLLBACK"
67+
# The backend is TPM NV (src/boot_state_tpm.c), so wolfTPM is required.
68+
WOLFTPM:=1
69+
ifeq ($(ANTI_ROLLBACK_HALT_ON_FAILURE),1)
70+
CFLAGS+=-D"WOLFBOOT_ANTI_ROLLBACK_HALT_ON_FAILURE"
71+
endif
72+
endif
73+
6074
ifeq ($(USE_CLANG),1)
6175
ifeq ($(USE_GCC),1)
6276
$(error USE_CLANG=1 is incompatible with USE_GCC=1; set USE_GCC=0)

0 commit comments

Comments
 (0)