code wiki / _hdl_build / nx_fw_safeflash_gate.nx

nx_fw_safeflash_gate.nx source

↩ module page · 116 lines · 5969 B

1// nx_fw_safeflash_gate.nx -- THE REFEREE for the never-brick firmware flash. 2// 3// Proves fw_safe_flash upholds the NEVER-BRICK invariant (active is BOOTABLE after every flash) 4// against deliberate failures, AND that each guard actually fires (no-fabricated-green): 5// 6// T1 good-flash : valid new image, clean write -> FW_OK + active bootable 7// N1 reject-bad : the SOURCE image is corrupt -> FW_REJECTED_PRE + active bootable (untouched) 8// N2 mid-corrupt : write injected with corruption -> FW_RECOVERED + active bootable (from golden) 9// N3 no-anchor : golden (recovery copy) is corrupt -> FW_REFUSED_NO_ANCHOR + active bootable (untouched) 10// N4 host-path : active path is NOT under /tmp/ -> FW_SANDBOX_VIOLATION (cannot touch host) 11// INV never-brick : active is BOOTABLE after T1,N1,N2,N3 (the headline guarantee) 12// 13// GREEN only if all six hold. Evidence -> knowledge/status/fw_safeflash_gate.log. 14// Sovereign: imports the organ + nx_framed_append + nx_syscalls (no gcc). license_tier: ORIGINAL 15import "nx_fw_safeflash.nx" 16import "nx_framed_append.nx" 17import "nx_syscalls.nx" 18 19const FWSF_LOG: *u8 = "knowledge/status/fw_safeflash_gate.log" 20const FWSF_GOOD: *u8 = "GOLDEN-ANCHOR-firmware-v1-immutable-recovery-copy" 21const FWSF_NEW: *u8 = "NEW-firmware-v2-candidate-image-being-flashed-in" 22 23func et_len(s: *u8) -> i64 { var i: i64 = 0; while s[i] != 0 as u8 { i = i + 1 } return i } 24 25func et_row(name: *u8, pass: i64) -> i64 { 26 let buf: *u8 = sys_mmap(528) 27 var o: i64 = 0 28 o = fw_cat(buf, o, "FWSF row=\x00" as *u8) 29 o = fw_cat(buf, o, name) 30 if pass == 1 { o = fw_cat(buf, o, " verdict=PASS\x00" as *u8) } else { o = fw_cat(buf, o, " verdict=FAIL\x00" as *u8) } 31 buf[o] = 0 as u8 32 fa_appendz(FWSF_LOG, buf, 512) 33 fw_puts(" "); fw_puts(name) 34 if pass == 1 { fw_puts(" PASS\n") } else { fw_puts(" FAIL\n") } 35 return 0 36} 37 38func main() -> i64 { 39 let epoch: i64 = sys_now_realtime_sec() 40 let pid: i64 = __syscall(39, 0, 0, 0, 0, 0, 0) 41 let gl: i64 = et_len(FWSF_GOOD) 42 let nl: i64 = et_len(FWSF_NEW) 43 44 let g: *u8 = sys_mmap(256); let a: *u8 = sys_mmap(256); let nw: *u8 = sys_mmap(256) 45 46 // ---- T1 good-flash ---- 47 fw_path(g, "/tmp/fwsf_t1g." as *u8, epoch, pid); fw_path(a, "/tmp/fwsf_t1a." as *u8, epoch, pid); fw_path(nw, "/tmp/fwsf_t1n." as *u8, epoch, pid) 48 fw_make(g, FWSF_GOOD, gl); fw_make(a, FWSF_GOOD, gl); fw_make(nw, FWSF_NEW, nl) 49 let s1: i64 = fw_safe_flash(a, g, nw, 0) 50 let b1: i64 = fw_bootable(a) 51 var t1: i64 = 0; if s1 == FW_OK { if b1 == 1 { t1 = 1 } } 52 53 // ---- N1 reject-bad-source ---- 54 fw_path(g, "/tmp/fwsf_n1g." as *u8, epoch, pid); fw_path(a, "/tmp/fwsf_n1a." as *u8, epoch, pid); fw_path(nw, "/tmp/fwsf_n1n." as *u8, epoch, pid) 55 fw_make(g, FWSF_GOOD, gl); fw_make(a, FWSF_GOOD, gl); fw_make(nw, FWSF_NEW, nl) 56 fw_corrupt_byte(nw) // the image we are asked to flash is bad 57 let s2: i64 = fw_safe_flash(a, g, nw, 0) 58 let b2: i64 = fw_bootable(a) 59 var n1: i64 = 0; if s2 == FW_REJECTED_PRE { if b2 == 1 { n1 = 1 } } 60 61 // ---- N2 mid-flash-corruption-recovered ---- 62 fw_path(g, "/tmp/fwsf_n2g." as *u8, epoch, pid); fw_path(a, "/tmp/fwsf_n2a." as *u8, epoch, pid); fw_path(nw, "/tmp/fwsf_n2n." as *u8, epoch, pid) 63 fw_make(g, FWSF_GOOD, gl); fw_make(a, FWSF_GOOD, gl); fw_make(nw, FWSF_NEW, nl) 64 let s3: i64 = fw_safe_flash(a, g, nw, 1) // inject corruption during the write 65 let b3: i64 = fw_bootable(a) 66 var n2: i64 = 0; if s3 == FW_RECOVERED { if b3 == 1 { n2 = 1 } } 67 68 // ---- N3 no-recovery-anchor (golden corrupt) ---- 69 fw_path(g, "/tmp/fwsf_n3g." as *u8, epoch, pid); fw_path(a, "/tmp/fwsf_n3a." as *u8, epoch, pid); fw_path(nw, "/tmp/fwsf_n3n." as *u8, epoch, pid) 70 fw_make(g, FWSF_GOOD, gl); fw_make(a, FWSF_GOOD, gl); fw_make(nw, FWSF_NEW, nl) 71 fw_corrupt_byte(g) // the recovery anchor is gone 72 let s4: i64 = fw_safe_flash(a, g, nw, 0) 73 let b4: i64 = fw_bootable(a) 74 var n3: i64 = 0; if s4 == FW_REFUSED_NO_ANCHOR { if b4 == 1 { n3 = 1 } } 75 76 // ---- N4 host-path refused (sandbox guard) ---- 77 let ahost: *u8 = sys_mmap(256); fw_path(ahost, "knowledge/fwsf_n4_HOST." as *u8, epoch, pid) 78 fw_path(g, "/tmp/fwsf_n4g." as *u8, epoch, pid); fw_path(nw, "/tmp/fwsf_n4n." as *u8, epoch, pid) 79 fw_make(g, FWSF_GOOD, gl); fw_make(nw, FWSF_NEW, nl) 80 let s5: i64 = fw_safe_flash(ahost, g, nw, 0) 81 var n4: i64 = 0; if s5 == FW_SANDBOX_VIOLATION { n4 = 1 } 82 83 // ---- INVARIANT: active bootable after every (sandboxed) scenario ---- 84 var inv: i64 = 0 85 if b1 == 1 { if b2 == 1 { if b3 == 1 { if b4 == 1 { inv = 1 } } } } 86 87 var passes: i64 = 0 88 if t1 == 1 { passes = passes + 1 } 89 if n1 == 1 { passes = passes + 1 } 90 if n2 == 1 { passes = passes + 1 } 91 if n3 == 1 { passes = passes + 1 } 92 if n4 == 1 { passes = passes + 1 } 93 if inv == 1 { passes = passes + 1 } 94 var green: i64 = 0 95 if passes == 6 { green = 1 } 96 97 fw_puts("fw-safeflash gate (never-brick invariant + 5 adversarial flashes)\n") 98 et_row("T1-good-flash-ok \x00" as *u8, t1) 99 et_row("N1-bad-source-rejected \x00" as *u8, n1) 100 et_row("N2-midflash-recovered \x00" as *u8, n2) 101 et_row("N3-no-anchor-refused \x00" as *u8, n3) 102 et_row("N4-host-path-refused \x00" as *u8, n4) 103 et_row("INV-active-never-bricked\x00" as *u8, inv) 104 105 let vb: *u8 = sys_mmap(528) 106 var o: i64 = 0 107 o = fw_cat(vb, o, "FW-SAFEFLASH verdict=\x00" as *u8) 108 if green == 1 { o = fw_cat(vb, o, "GREEN\x00" as *u8) } else { o = fw_cat(vb, o, "RED\x00" as *u8) } 109 o = fw_cat(vb, o, " passes=\x00" as *u8); o = fw_catn(vb, o, passes); o = fw_cat(vb, o, "/6 END\x00" as *u8) 110 vb[o] = 0 as u8 111 fa_appendz(FWSF_LOG, vb, 512) 112 fw_puts(vb as *u8); fw_puts("\n") 113 114 if green == 1 { return 0 } 115 return 1 116}