
NetBSD disklabels studied byte by byte in a hex editor
A hands-on walkthrough of the BSD disklabel on NetBSD 11: where the label is stored on disk, what each header field means, how the XOR checksum works and how to invent a partition by hand.
A post on the movq.de blog dissects the BSD disklabel on NetBSD 11 for x86_64. Its author, coming from DOS and Linux, had mostly ignored disklabels on his own OpenBSD systems and set out to learn what the individual bytes mean, where the format is documented and how much can be edited by hand.
Where the disklabel lives
Documentation starts with man disklabel, whose SEE ALSO section points to disklabel(5). Most of the post, though, works from /usr/include/sys/disklabel.h. To avoid conflicts with MBR systems, disklabels sit away from the conventional MBR area: a small C program linked against libutil returns 1 for getlabelsector() and 0 for getlabeloffset(), which places the label in the second sector, at byte offset 512.
Reading the header field by field
The label opens with disk metadata and ends with the partition array. Read as little-endian words, it starts with two magic numbers (d_magic and d_magic2), a drive type of 0x0f, meaning logical disk, and the driver name ld1, followed by geometry: 512 bytes per sector, 63 sectors per track, 16 tracks per cylinder, 260 cylinders and 262144 sectors in total, or 128 MiB. Older hardware parameters such as 3600 rpm and seek timings are mostly zero on modern x86_64, and MBR, with its CHS leftovers, is not much better; the values read from the hex dump match the output of disklabel ld1.
The partition table and its checksum
The header declares d_npartitions, and entries of 16 bytes each follow for partitions a to d. Only three fields really matter: start, size and filesystem type. Partition a has 262144 sectors at offset 0 and type 0x07, 4.2BSD (FFS). Partition d is always present on x86_64 and describes the entire disk, per a 2018 NetBSD mailing-list post by developer Martin Husemann; c stays hidden because its size, offset and type are zero.
d_checksum is defined as the xor of the data including partitions. XOR-ing every 16-bit chunk of the label yields zero, confirming the stored value is consistent, since the checksum is one of those chunks; excluding it gives 1dc6, matching the c61d seen in the dump. NetBSD's own code for this is probably dkcksum.c in sys/lib/libkern.
A partition created in a hex editor
To test what he had learned, he worked in reverse: partition i, 1234 sectors long, at sector 5678, type ZFS. The ninth entry begins at byte 788, computed as 512 + 0x94 + (9-1) * 16. He wrote p_size, p_offset and p_fstype 0x21, raised d_npartitions to 9 and recomputed the checksum as 160f.
After booting, disklabel ld1 listed the new partition as intended and warned that a and i overlap, which is expected, since a covers the whole disk. The author notes that this extra layer over MBR and GPT is easy to overlook and that only hands-on work made the format feel familiar.
SiTech — AI-powered web development
We build fast, modern websites and bring AI into real business workflows. Have a project or a question? We'd love to help.