diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2022-01-02 17:26:15 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2022-01-02 17:26:15 +0000 |
commit | dbf6d9768c501b528effaa0c8a571db86a2e90c7 (patch) | |
tree | 0b548bc4803426611c035be15ac226cc84a28f0e /sbin | |
parent | a01bb9a684011339f76c5940a2a86d03a0280ee1 (diff) |
Stop writing big-endian checksums into the little-endian GPT
header fields gh_csum and gh_part_csum.
Constrain kernel to accepting only correct little-endian
checksums.
Temporarily allow fdisk(8) to read either endian GPTs so that
big-endian GPTs can be made correct by a simple 'fdisk -e' &&
'w'.
Fixes inter-architecture, inter-OS GPT portability and GPT
fdisk(8) on big-endian architectures. Broken since initial GPT
implementation.
Suggestions and ok kettenis@
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/fdisk/gpt.c | 42 |
1 files changed, 24 insertions, 18 deletions
diff --git a/sbin/fdisk/gpt.c b/sbin/fdisk/gpt.c index eb23259bde9..d8354810310 100644 --- a/sbin/fdisk/gpt.c +++ b/sbin/fdisk/gpt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gpt.c,v 1.55 2021/12/29 00:04:45 krw Exp $ */ +/* $OpenBSD: gpt.c,v 1.56 2022/01/02 17:26:14 krw Exp $ */ /* * Copyright (c) 2015 Markus Muller <mmu@grummel.net> * Copyright (c) 2015 Kenneth R Westerback <krw@openbsd.org> @@ -116,7 +116,7 @@ get_header(const uint64_t sector) char *secbuf; uint64_t partlastlba, partslen, lba_end; int partspersec; - uint32_t orig_gh_csum, new_gh_csum; + uint32_t gh_csum; secbuf = DISK_readsectors(sector, 1); if (secbuf == NULL) @@ -161,14 +161,15 @@ get_header(const uint64_t sector) return -1; } - orig_gh_csum = gh.gh_csum; + gh_csum = gh.gh_csum; gh.gh_csum = 0; - new_gh_csum = crc32((unsigned char *)&gh, letoh32(gh.gh_size)); - gh.gh_csum = orig_gh_csum; - if (new_gh_csum != letoh32(gh.gh_csum)) { + gh.gh_csum = htole32(crc32((unsigned char *)&gh, letoh32(gh.gh_size))); + if (gh_csum != gh.gh_csum) { DPRINTF("gpt header checksum: expected 0x%x, got 0x%x\n", - new_gh_csum, letoh32(gh.gh_csum)); - return -1; + letoh32(gh.gh_csum), letoh32(gh_csum)); + /* Accept wrong-endian checksum. */ + if (swap32(gh_csum) != gh.gh_csum) + return -1; } /* XXX Assume part_num * part_size is multiple of secsize. */ @@ -220,7 +221,7 @@ get_partition_table(void) { char *secbuf; uint64_t gpbytes, gpsectors; - uint32_t checksum, partspersec; + uint32_t gh_part_csum, partspersec; DPRINTF("gpt partition table being read from LBA %llu\n", letoh64(gh.gh_part_lba)); @@ -242,11 +243,15 @@ get_partition_table(void) memcpy(&gp, secbuf, gpbytes); free(secbuf); - checksum = crc32((unsigned char *)&gp, gpbytes); - if (checksum != letoh32(gh.gh_part_csum)) { + gh_part_csum = gh.gh_part_csum; + gh.gh_part_csum = htole32(crc32((unsigned char *)&gp, gpbytes)); + if (gh_part_csum != gh.gh_part_csum) { DPRINTF("gpt partition table checksum: expected 0x%x, " - "got 0x%x\n", checksum, letoh32(gh.gh_part_csum)); - return -1; + "got 0x%x\n", letoh32(gh.gh_part_csum), + letoh32(gh_part_csum)); + /* Accept wrong-endian checksum. */ + if (swap32(gh_part_csum) != gh.gh_part_csum) + return -1; } return 0; @@ -455,8 +460,9 @@ add_partition(const uint8_t *beuuid, const char *name, uint64_t sectors) goto done; uuid_enc_le(&gp[pn].gp_guid, &uuid); - gh.gh_part_csum = crc32((unsigned char *)&gp, sizeof(gp)); - gh.gh_csum = crc32((unsigned char *)&gh, sizeof(gh)); + gh.gh_part_csum = htole32(crc32((unsigned char *)&gp, sizeof(gp))); + gh.gh_csum = 0; + gh.gh_csum = htole32(crc32((unsigned char *)&gh, sizeof(gh))); return 0; @@ -620,9 +626,9 @@ GPT_write(void) gh.gh_lba_self = htole64(prigh); gh.gh_lba_alt = htole64(altgh); gh.gh_part_lba = htole64(prigp); - gh.gh_part_csum = crc32((unsigned char *)&gp, gpbytes); + gh.gh_part_csum = htole32(crc32((unsigned char *)&gp, gpbytes)); gh.gh_csum = 0; - gh.gh_csum = crc32((unsigned char *)&gh, letoh32(gh.gh_size)); + gh.gh_csum = htole32(crc32((unsigned char *)&gh, letoh32(gh.gh_size))); secbuf = DISK_readsectors(prigh, 1); if (secbuf == NULL) @@ -638,7 +644,7 @@ GPT_write(void) gh.gh_lba_alt = htole64(prigh); gh.gh_part_lba = htole64(altgp); gh.gh_csum = 0; - gh.gh_csum = crc32((unsigned char *)&gh, letoh32(gh.gh_size)); + gh.gh_csum = htole32(crc32((unsigned char *)&gh, letoh32(gh.gh_size))); secbuf = DISK_readsectors(altgh, 1); if (secbuf == NULL) |