Skip to content

Commit 8a73b54

Browse files
committed
GPT: verify the header CRC32 checksum stored in the header
F/229
1 parent dc96c47 commit 8a73b54

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

src/gpt.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,23 @@
3434

3535
#include "gpt.h"
3636

37+
static uint32_t gpt_crc32(const uint8_t *data, uint32_t len)
38+
{
39+
uint32_t crc = 0xFFFFFFFFU;
40+
uint32_t i;
41+
uint32_t j;
42+
43+
for (i = 0; i < len; i++) {
44+
crc ^= data[i];
45+
for (j = 0; j < 8; j++) {
46+
uint32_t mask = -(crc & 1U);
47+
crc = (crc >> 1) ^ (0xEDB88320U & mask);
48+
}
49+
}
50+
51+
return ~crc;
52+
}
53+
3754
/**
3855
* @brief Check MBR for protective GPT partition entry.
3956
*
@@ -98,6 +115,7 @@ int gpt_check_mbr_protective(const uint8_t *mbr_sector, uint32_t *gpt_lba)
98115
int gpt_parse_header(const uint8_t *sector, struct guid_ptable *hdr)
99116
{
100117
const struct guid_ptable *src;
118+
struct guid_ptable tmp;
101119

102120
if (sector == NULL || hdr == NULL) {
103121
return -1;
@@ -110,6 +128,16 @@ int gpt_parse_header(const uint8_t *sector, struct guid_ptable *hdr)
110128
return -1;
111129
}
112130

131+
if (src->hdr_size < 0x5C || src->hdr_size > GPT_SECTOR_SIZE) {
132+
return -1;
133+
}
134+
135+
memcpy(&tmp, src, sizeof(tmp));
136+
tmp.hdr_crc32 = 0;
137+
if (gpt_crc32((const uint8_t *)&tmp, src->hdr_size) != src->hdr_crc32) {
138+
return -1;
139+
}
140+
113141
/* Copy header to output */
114142
memcpy(hdr, src, sizeof(struct guid_ptable));
115143

tools/unit-tests/unit-disk.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,29 @@ static const int PART0_END = 100;
6565
static const int PART1_OFF = 101;
6666
static const int PART1_END = 200;
6767

68+
static uint32_t test_crc32(const uint8_t *data, uint32_t len)
69+
{
70+
uint32_t crc = 0xFFFFFFFFU;
71+
uint32_t i;
72+
uint32_t j;
73+
74+
for (i = 0; i < len; i++) {
75+
crc ^= data[i];
76+
for (j = 0; j < 8; j++) {
77+
uint32_t mask = -(crc & 1U);
78+
crc = (crc >> 1) ^ (0xEDB88320U & mask);
79+
}
80+
}
81+
82+
return ~crc;
83+
}
84+
85+
static void finalize_gpt_header_crc(struct guid_ptable *hdr)
86+
{
87+
hdr->hdr_crc32 = 0;
88+
hdr->hdr_crc32 = test_crc32((const uint8_t *)hdr, hdr->hdr_size);
89+
}
90+
6891
/* --- Helpers to build fake disk layouts --- */
6992

7093
/* Write a UTF-16LE string into a buffer (no BOM).
@@ -133,6 +156,8 @@ static void build_gpt_disk(void)
133156
(PART0_END - PART0_OFF + 1) * GPT_SECTOR_SIZE);
134157
memset(fake_disk + PART1_OFF * GPT_SECTOR_SIZE, 0xBB,
135158
(PART1_END - PART1_OFF + 1) * GPT_SECTOR_SIZE);
159+
160+
finalize_gpt_header_crc(gpt_hdr);
136161
}
137162

138163
/* Populate fake_disk with MBR-only layout (no GPT protective entry).
@@ -200,6 +225,17 @@ START_TEST(test_gpt_parse_header)
200225
ck_assert_uint_eq(hdr.start_array, 2);
201226
ck_assert_uint_eq(hdr.array_sz, 128);
202227

228+
/* Corrupt a header field without updating CRC */
229+
{
230+
struct guid_ptable *gpt_hdr =
231+
(struct guid_ptable *)(fake_disk + GPT_SECTOR_SIZE);
232+
gpt_hdr->n_part = 3;
233+
ck_assert_int_eq(
234+
gpt_parse_header(fake_disk + GPT_SECTOR_SIZE, &hdr), -1);
235+
gpt_hdr->n_part = 2;
236+
finalize_gpt_header_crc(gpt_hdr);
237+
}
238+
203239
/* Corrupt signature in the real header */
204240
{
205241
struct guid_ptable *gpt_hdr =
@@ -208,6 +244,7 @@ START_TEST(test_gpt_parse_header)
208244
ck_assert_int_eq(
209245
gpt_parse_header(fake_disk + GPT_SECTOR_SIZE, &hdr), -1);
210246
gpt_hdr->signature = GPT_SIGNATURE;
247+
finalize_gpt_header_crc(gpt_hdr);
211248
}
212249

213250
/* NULL inputs */
@@ -537,6 +574,7 @@ START_TEST(test_disk_open_gpt_excess_partitions)
537574

538575
gpt_hdr = (struct guid_ptable *)(fake_disk + GPT_SECTOR_SIZE);
539576
gpt_hdr->n_part = MAX_PARTITIONS + 10;
577+
finalize_gpt_header_crc(gpt_hdr);
540578

541579
/* Only 2 actual entries on disk so loop will break after parsing them,
542580
* but the capping branch is exercised. */
@@ -555,6 +593,7 @@ START_TEST(test_disk_open_gpt_large_array_sz)
555593

556594
gpt_hdr = (struct guid_ptable *)(fake_disk + GPT_SECTOR_SIZE);
557595
gpt_hdr->array_sz = GPT_PART_ENTRY_SIZE + 1; /* 257 > 256 */
596+
finalize_gpt_header_crc(gpt_hdr);
558597

559598
ck_assert_int_eq(disk_open(0), 0); /* 0 partitions found */
560599
}
@@ -571,6 +610,7 @@ START_TEST(test_disk_open_gpt_empty_entry_mid_table)
571610

572611
gpt_hdr = (struct guid_ptable *)(fake_disk + GPT_SECTOR_SIZE);
573612
gpt_hdr->n_part = 3;
613+
finalize_gpt_header_crc(gpt_hdr);
574614

575615
/* Zero out entry 1's type GUID */
576616
pe = (struct gpt_part_entry *)(fake_disk + 2 * GPT_SECTOR_SIZE + 128);

0 commit comments

Comments
 (0)