Skip to content

Commit 9a48837

Browse files
Alex J Lennoncursoragent
andcommitted
python3-improv: report secure_boot from U-Boot sec_boot flag (imx93-jaguar-eink)
sec.secure_boot previously always returned "unknown". This kernel exposes no userspace ELE lifecycle path (no /dev/ele_mu, no lifecycle nvmem cell; the ELE "get info" lifecycle sits behind OP-TEE/secure world), so the authoritative OEM_OPEN/OEM_CLOSED value still needs a dedicated OP-TEE TA (tracked follow-up, roadmap P0-1/P2-1). As the best available userspace signal, read U-Boot's `sec_boot` env flag (via fw_printenv), which the NXP boot script uses to gate authenticated boot (auth_os): yes => "closed", no => "open", else "unknown". This reflects the bootloader configuration, not an ELE-attested lifecycle, and remains self-reported/untrusted until attestation (P2-1). A fuse/OCOTP byte heuristic is deliberately avoided (the ELE-OCOTP shadow has non-zero UID/config words). Verified on eink-0167: fw_printenv -n sec_boot => "no" => secure_boot "open". Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent e6202ac commit 9a48837

1 file changed

Lines changed: 39 additions & 11 deletions

File tree

recipes-devtools/python/python3-improv/imx93-jaguar-eink/onboarding-server.py

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -384,18 +384,46 @@ def compute_time_status():
384384

385385

386386
def _read_secure_boot():
387-
"""i.MX93 secure-boot / lifecycle state.
388-
389-
Returns 'open' | 'closed' | 'unknown'. Correctly determining this requires
390-
the ELE "get info" lifecycle field (OEM_OPEN vs OEM_CLOSED / FIELD_RETURN)
391-
or interpreting specific SRK-hash / SEC_CONFIG fuses via the validated
392-
i.MX93 OCOTP map — the raw ELE-OCOTP0 shadow cannot be interpreted safely
393-
(every SoC has non-zero fuses: UID, boot config, ...), so a byte-level
394-
heuristic would misreport a fused board. Until that ELE query lands
395-
(tracked follow-up; see roadmap P0-1/P2-1 and BLE-BOARD-PROFILE.md §10) we
396-
report 'unknown' rather than a value that could be wrong. This field is
397-
self-reported and untrusted until backed by ELE attestation (P2-1).
387+
"""i.MX93 secure-boot posture. Returns 'open' | 'closed' | 'unknown'.
388+
389+
The authoritative source is the EdgeLock Enclave (ELE) "get info"
390+
lifecycle field (OEM_OPEN vs OEM_CLOSED / FIELD_RETURN). This kernel,
391+
however, exposes no ELE MU char device (`/dev/ele_mu` absent) and no
392+
lifecycle nvmem cell — the lifecycle lives behind OP-TEE/secure world —
393+
so it cannot be read from Linux userspace without a dedicated OP-TEE TA.
394+
That ELE-attested query remains a tracked follow-up (roadmap P0-1/P2-1,
395+
BLE-BOARD-PROFILE.md §10) and needs secure-world plumbing.
396+
397+
As the best available userspace signal we read U-Boot's `sec_boot`
398+
environment flag, which the NXP boot script uses to gate authenticated
399+
boot (`auth_os`): 'yes' => authenticated boot enforced ('closed'),
400+
'no' => not enforced ('open'). This reflects the *bootloader
401+
configuration* rather than an ELE-attested hardware lifecycle, and —
402+
like the whole `sec` block — is self-reported and untrusted until backed
403+
by attestation (P2-1). A fuse/OCOTP byte heuristic is deliberately
404+
avoided: the ELE-OCOTP0 shadow has non-zero UID/config words, so
405+
byte-level guessing would misreport a fused board.
398406
"""
407+
val = ""
408+
try:
409+
# `-n` prints just the value; falls back to parsing `k=v` for older
410+
# u-boot-fw-utils that lack `-n`.
411+
out = subprocess.run(["fw_printenv", "-n", "sec_boot"],
412+
capture_output=True, timeout=4, text=True)
413+
if out.returncode == 0:
414+
val = out.stdout.strip().lower()
415+
else:
416+
out = subprocess.run(["fw_printenv", "sec_boot"],
417+
capture_output=True, timeout=4, text=True)
418+
if out.returncode == 0 and "=" in out.stdout:
419+
val = out.stdout.strip().split("=", 1)[1].strip().lower()
420+
except Exception as e:
421+
logger.debug(f"secure_boot read failed: {e}")
422+
return "unknown"
423+
if val in ("yes", "1", "true"):
424+
return "closed"
425+
if val in ("no", "0", "false"):
426+
return "open"
399427
return "unknown"
400428

401429

0 commit comments

Comments
 (0)