fix: gpt_read checks every entry, and says when there are more than max (#180)

gpt_read() stopped at max used entries (16 for the identity code, 4 in the
mint): a disk whose StarshipOS partitions came after the first max read as
having none, and the entries after max were never range-checked.

Now every entry is checked and every used one counted; a good table with more
used entries than max is GPT_MANY (the first max in parts), and the identity
code says "GPT: a USB drive has more than 16 partitions -- not used". Other
callers treat anything but GPT_OK as before.

Tested first, seen to fail: qemu_session.py gpt_many -- a data stick with its
two partitions as entries 17 and 18 after 16 others, and the same with an entry
19 past the usable range: both "not this system's stick" before (silently cut,
entry 19 never checked; logs/20261112-162236). After: "more than 16
partitions" and "a damaged partition table" (logs/20261112-162921).
Regressions: gpt_bad_entries, gpt_foreign PASS. gpt_zuse FAILS, on a stale
expectation unrelated to this change -- an identity-only GPT drive with no
system stick has been held silently as a possible real Zuse since #92 Task 4;
its log is kept here. The gpt_many images are made before the boot: a first
version made them after, failed in sgdisk and left its QEMU running, stopped
by hand (logs/20261112-162003).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
Claude
2026-11-12 16:41:00 +00:00
parent ab63789e5b
commit 9700a7b404
16 changed files with 83 additions and 7 deletions
+6 -2
View File
@@ -26,10 +26,14 @@ typedef struct {
#define GPT_BAD 2 /* a protective MBR, but its header or entry array does not check out: not used */
#define GPT_EIO 3 /* its first block could not be read: not used; gpt_write_one: nothing was written */
#define GPT_PART 4 /* gpt_write_one only: a write failed after others were made -- the disk is changed (#168) */
#define GPT_MANY 5 /* gpt_read: a valid GPT with more used entries than max -- every entry checked, none cut (#180) */
/* Read `disk`'s protective MBR, primary GPT header and partition-entry array,
* checking both CRC-32s, the revision, the sizes and the geometry. On GPT_OK,
* `*count` partitions with a non-zero type (at most `max`) are in `parts`.
* checking both CRC-32s, the revision, the sizes and the geometry, and every
* entry's range. On GPT_OK, `*count` partitions with a non-zero type (at most
* `max`) are in `parts`. GPT_MANY when the table is good but has more used
* entries than `max`: the first `max` are in `parts`, `*count` is `max`, and the
* caller says so rather than taking the disk as having only those (#180).
* Reads only. */
int gpt_read(blkio_dev_t *disk, gpt_part_t *parts, unsigned max, unsigned *count);
+8 -4
View File
@@ -124,17 +124,21 @@ int gpt_read(blkio_dev_t *disk, gpt_part_t *parts, unsigned max, unsigned *count
}
if (gpt_crc32(g_gpt_entries, ebytes) != ecrc) return GPT_BAD;
for (i = 0; i < nent && n < max; i++) {
/* every entry is checked, and every used one counted -- not only the first `max` (#180) */
for (i = 0; i < nent; i++) {
const uint8_t *e = g_gpt_entries + (size_t)i * esize;
static const uint8_t zero[16];
uint64_t first = le64(e + 32), last = le64(e + 40);
if (memcmp(e, zero, 16) == 0) continue; /* an unused entry */
if (first < first_usable || last > last_usable || first > last) return GPT_BAD;
memcpy(parts[n].type, e, 16);
parts[n].first_lba = first;
parts[n].last_lba = last;
if (n < max) {
memcpy(parts[n].type, e, 16);
parts[n].first_lba = first;
parts[n].last_lba = last;
}
n++;
}
if (n > max) { *count = max; return GPT_MANY; } /* more than the caller can hold: said, not cut */
*count = n;
memcpy(g_gpt_disk_guid, h + 56, 16);
g_gpt_alternate_lba = le64(h + 32);
+4
View File
@@ -335,6 +335,10 @@ static int sk_v4_drive_arrived(sk_v4_drive_t *d)
g_offered = d;
return 1;
}
if (gpt_rc == GPT_MANY) { /* SK_V4_GPT_PARTS: 16 (#180) */
console_println("GPT: a USB drive has more than 16 partitions -- not used");
return 1;
}
if (gpt_rc == GPT_BAD) {
console_println("GPT: a USB drive has a damaged partition table -- not used");
return 1;