Skip to content
Merged
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
11 changes: 10 additions & 1 deletion src/boot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,16 @@ std::vector<Finding> scan_boot(const std::string& path, std::span<const uint8_t>
{
static const uint8_t kFvh[4] = {'_', 'F', 'V', 'H'};
std::span<const uint8_t> head = data.subspan(0, std::min<size_t>(data.size(), 64u << 20));
if (find_bytes(head, kFvh, 4, 0) != std::string::npos) {
// A full BIOS image carries the FV header signature "_FVH" somewhere. A
// variable store extracted on its own (the usual chipsec/UEFITool artifact)
// has no FV wrapper: an EDK2 authenticated/variable store begins with its
// store GUID, an AMI store begins with an "NVAR" entry. Trigger on either
// so an extracted store is analyzed too; analyze_uefi self-filters (emits
// nothing without a real recovered variable), so the loose trigger is safe.
bool is_varstore = guid_at(data, 0, kAuthVarStore) || guid_at(data, 0, kVarStore) ||
(data.size() >= 4 && data[0] == 'N' && data[1] == 'V' &&
data[2] == 'A' && data[3] == 'R');
if (is_varstore || find_bytes(head, kFvh, 4, 0) != std::string::npos) {
analyze_uefi(data, out);
if (!out.empty()) return out;
}
Expand Down
18 changes: 18 additions & 0 deletions tests/test_boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,24 @@ def check(cond, msg):
check("uefi-platform-key" in types(ph) and "uefi-secureboot-on" in types(ph),
"nvar: FV at a nonzero offset (full-flash dump) still analyzed")

# A variable store extracted on its own (a chipsec/UEFITool artifact) has no FV
# wrapper, so no "_FVH" signature. It must still be analyzed -- the raw AMI store
# begins with an "NVAR" entry. A large defaults-container entry ("StdDefaults")
# sits up front, as on a real BIOS; the top-level PK/dbx after it are still
# recovered. Regression: without the store-start trigger this was silently
# skipped, so an extracted NVAR store reported nothing.
raw = b"".join(_nvar_entry(n, d) for (n, d) in
[("StdDefaults", b"\x00" * 200), ("PK", b"PKCERT" * 40),
("KEK", b"KEK" * 30), ("db", b"DB" * 300), ("dbx", sha256_siglist(5)),
("SecureBoot", b"\x01")])
check(raw[:4] == b"NVAR", "nvar: standalone store begins with an NVAR entry (no FV)")
rh = run("varstore.bin", raw)
check("uefi-platform-key" in types(rh) and "uefi-secureboot-on" in types(rh),
"nvar: standalone extracted store (no FV wrapper) is analyzed")
rdbx = [x for x in rh if x["type"] == "uefi-dbx"]
check(bool(rdbx) and "5 revocation" in rdbx[0]["label"],
"nvar: standalone store dbx enumerated past a leading container entry")

# PKFAIL through the NVAR store: PK is the AMI "DO NOT TRUST" test key.
nvpk = nvar_store([("PK", efi_sig_list(ami_cert)), ("SecureBoot", b"\x01")])
check("uefi-test-platform-key" in types(run("bios.bin", nvpk)),
Expand Down
Loading