fix(kernel): a GPT disk with a bad header, or an unreadable first block, is not used
The increment 2 final review's minors 1-4 (Captain Bob, 2026-10-27: "fix 1-4"): 1. A protective MBR with no "EFI PART" header is GPT_BAD, not GPT_NONE: the MBR says it is a GPT disk, and a GPT disk is never attached whole. 2. A disk whose block 0 cannot be read is GPT_EIO: "GPT: a USB drive could not be read -- not used", nothing attached (it was read raw, attached whole, and a raw Zuse drive behind it logged her in). 3. The entry array's LBA is checked against the disk's size directly. 4. gpt_bad_entries: the entry array changed, the header valid -- refused. Harness modes gpt_no_header, gpt_read_error (blkdebug EIO on sector 0), gpt_bad_entries. The plan carries the amendment. Red (amd64): gpt_no_header 070335, gpt_read_error 070717 FAIL; gpt_bad_entries 070048 PASS (existing check, now pinned). Green: every GPT mode on amd64 071113-072933; gpt_zuse, gpt_read_error, gpt_no_header on aarch64 073222-074047 and riscv64 074526-075535; the identity gate's and increment 1's sessions 080036-082345, emergency 083130 (082635 was run without EMERGENCY_CONSOLE_ENABLED=1 -- a harness invocation error). Accepted: suite EXIT 0; 093121, 093352, 093750, POST 538/538, dict_hash 0xfec8c47cfc6f437f; test-32, 0 failures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f612bb37a9
commit
2e71f7aa0d
+37
-10
@@ -39,6 +39,10 @@ the stick's, plan 2026-10-26-stick-1-screen-and-keyboard.md):
|
||||
gpt_hotplug ... pulled: session ended; added again: prompt
|
||||
gpt_foreign a GPT drive with only a Linux partition: no identity, not attached (info level)
|
||||
gpt_bad_crc the gpt_zuse image with its header CRC broken: not used, said so, not attached
|
||||
gpt_bad_entries ... its entry array changed (the header intact): the same
|
||||
gpt_no_header ... its "EFI PART" signature gone, the protective MBR kept: the same
|
||||
gpt_read_error the raw Zuse drive with reads of its sector 0 failing (blkdebug): not used,
|
||||
said so, not attached
|
||||
virtio_kbd aarch64/riscv64: QEMU's virtio keyboard types 7 ok
|
||||
|
||||
Needs only Python 3. One QEMU at a time (.claude/CLAUDE.md).
|
||||
@@ -57,7 +61,8 @@ ap.add_argument("--make", default="")
|
||||
ap.add_argument("--no-zuse", action="store_true")
|
||||
a = ap.parse_args()
|
||||
|
||||
NO_ZUSE_MODES = {"gpt_zuse", "gpt_hotplug", "gpt_foreign", "gpt_bad_crc", "headless", "hotplug", "midpull", "waitpull", "typeahead", "emergency",
|
||||
NO_ZUSE_MODES = {"gpt_zuse", "gpt_hotplug", "gpt_foreign", "gpt_bad_crc", "gpt_bad_entries", "gpt_no_header",
|
||||
"gpt_read_error", "headless", "hotplug", "midpull", "waitpull", "typeahead", "emergency",
|
||||
"alttab_after_logout", "alttab_before_pull", "emergency_pull",
|
||||
"screen_dark_until_login", "screen_console_after_login", "screen_dark_after_logout",
|
||||
"kbd_typeahead"}
|
||||
@@ -191,9 +196,11 @@ GPT_IDENTITY = "23BEBFE1-4817-4CF3-A537-9069BF159788"
|
||||
GPT_LINUX = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
|
||||
|
||||
|
||||
def make_gpt_image(path, ptype, payload, mib=72, break_crc=False):
|
||||
def make_gpt_image(path, ptype, payload, mib=72, break_crc=False, break_entries=False, break_sig=False):
|
||||
"""A GPT disk image: one partition at LBA 2048, 131072 sectors (64 MiB), of type
|
||||
`ptype`, holding `payload` from its start; optionally the primary header's CRC broken."""
|
||||
`ptype`, holding `payload` from its start; optionally the primary header's CRC broken,
|
||||
a byte of the entry array changed (the header left valid), or the header's "EFI PART"
|
||||
signature zeroed (the protective MBR left in place)."""
|
||||
subprocess.run(["truncate", "-s", f"{mib}M", path], check=True)
|
||||
sf = shutil.which("sfdisk") or "/usr/sbin/sfdisk"
|
||||
subprocess.run([sf, "--quiet", path], input=f"label: gpt\nstart=2048, size=131072, type={ptype}\n",
|
||||
@@ -206,6 +213,16 @@ def make_gpt_image(path, ptype, payload, mib=72, break_crc=False):
|
||||
b = f.read(1)
|
||||
f.seek(512 + 16)
|
||||
f.write(bytes([b[0] ^ 0xFF]))
|
||||
if break_entries:
|
||||
with open(path, "r+b") as f:
|
||||
f.seek(1024 + 56) # entry 0's name, inside the CRC'd entry array
|
||||
b = f.read(1)
|
||||
f.seek(1024 + 56)
|
||||
f.write(bytes([b[0] ^ 0xFF]))
|
||||
if break_sig:
|
||||
with open(path, "r+b") as f:
|
||||
f.seek(512) # the primary header's Signature
|
||||
f.write(bytes(8))
|
||||
|
||||
|
||||
def blk_lines():
|
||||
@@ -239,9 +256,12 @@ def screen():
|
||||
return w, h, lit, px
|
||||
|
||||
|
||||
def add_zuse(n, img=None):
|
||||
qcmd("blockdev-add", driver="raw", **{"node-name": f"zuse{n}"},
|
||||
file={"driver": "file", "filename": img or zimg})
|
||||
def add_zuse(n, img=None, fail_sector0=False):
|
||||
f = {"driver": "file", "filename": img or zimg}
|
||||
if fail_sector0: # every read touching sector 0 fails, EIO
|
||||
f = {"driver": "blkdebug", "image": f,
|
||||
"inject-error": [{"event": "none", "iotype": "read", "sector": 0, "errno": 5}]}
|
||||
qcmd("blockdev-add", driver="raw", **{"node-name": f"zuse{n}"}, file=f)
|
||||
qcmd("device_add", driver="usb-storage", bus="xhci0.0", port="1",
|
||||
drive=f"zuse{n}", id=f"zusedev{n}")
|
||||
|
||||
@@ -437,13 +457,18 @@ elif m == "emergency_pull":
|
||||
_, _, _, px2 = screen()
|
||||
check("the screen changed with what was typed", px2 != px1)
|
||||
|
||||
elif m in ("gpt_zuse", "gpt_hotplug", "gpt_foreign", "gpt_bad_crc"):
|
||||
elif m in ("gpt_zuse", "gpt_hotplug", "gpt_foreign", "gpt_bad_crc", "gpt_bad_entries", "gpt_no_header",
|
||||
"gpt_read_error"):
|
||||
gimg = os.path.join(work, "gpt.img")
|
||||
make_gpt_image(gimg, GPT_LINUX if m == "gpt_foreign" else GPT_IDENTITY, zimg,
|
||||
break_crc=(m == "gpt_bad_crc"))
|
||||
break_crc=(m == "gpt_bad_crc"), break_entries=(m == "gpt_bad_entries"),
|
||||
break_sig=(m == "gpt_no_header"))
|
||||
check("no ok> for 10 s with no drive", not wait_for(ANYPROMPT, 10))
|
||||
b0 = blk_lines()
|
||||
add_zuse(1, gimg)
|
||||
if m == "gpt_read_error":
|
||||
add_zuse(1, zimg, fail_sector0=True) # the raw Zuse drive: no GPT, but block 0 unreadable
|
||||
else:
|
||||
add_zuse(1, gimg)
|
||||
if m in ("gpt_zuse", "gpt_hotplug"):
|
||||
check("Zuse: identity confirmed", wait_for(r"Zuse: identity confirmed from attached thumbdrive", 120))
|
||||
check("[zuse@Hera] ok>", wait_for(PROMPT, 60))
|
||||
@@ -463,8 +488,10 @@ elif m in ("gpt_zuse", "gpt_hotplug", "gpt_foreign", "gpt_bad_crc"):
|
||||
add_zuse(2, gimg)
|
||||
check("[zuse@Hera] ok> again", wait_for(PROMPT, 120, p))
|
||||
else:
|
||||
if m == "gpt_bad_crc":
|
||||
if m in ("gpt_bad_crc", "gpt_bad_entries", "gpt_no_header"):
|
||||
check("the damaged table is said so", wait_for(r"GPT: a USB drive has a damaged partition table -- not used", 60))
|
||||
if m == "gpt_read_error":
|
||||
check("the unreadable drive is said so", wait_for(r"GPT: a USB drive could not be read -- not used", 60))
|
||||
check("no ok> for 30 s", not wait_for(ANYPROMPT, 30))
|
||||
check("no identity", count(r"Zuse: identity confirmed") == 0)
|
||||
check(f"not attached (blk: lines {b0} -> {blk_lines()})", blk_lines() == b0)
|
||||
|
||||
Reference in New Issue
Block a user