]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: apfs: validate checksums
authorThomas Weißschuh <thomas@t-8ch.de>
Tue, 6 Aug 2024 17:07:48 +0000 (19:07 +0200)
committerThomas Weißschuh <thomas@t-8ch.de>
Fri, 23 Aug 2024 17:15:05 +0000 (19:15 +0200)
The apfs superblock contains a checksum based on Fletcher-64.
Validate the checksum to make the probing more robust.

Signed-off-by: Thomas Weißschuh <thomas@t-8ch.de>
libblkid/src/superblocks/apfs.c

index b7f09f334e310457d3031212f83ffb223f7e926b..4557abcbf115c99992e3adc50cecbfd97c980912 100644 (file)
@@ -35,7 +35,38 @@ struct apfs_super_block {
        uint64_t read_only_features;
        uint64_t incompatible_features;
        uint8_t uuid[16];
-};
+
+       uint8_t padding[4008]; // Pad to 4096 bytes for checksum
+} __attribute__((packed));
+
+static uint64_t apfs_fletcher64(const uint8_t *buf, size_t size)
+{
+       uint64_t lo32 = 0, hi32 = 0, csum_hi;
+       uint32_t csum_low;
+       size_t i;
+
+       for (i = 0; i < size / 4; i++) {
+               lo32 += le32_to_cpu(((uint32_t *)buf)[i]);
+               hi32 += lo32;
+       }
+
+       csum_low = ~((lo32 + hi32) % UINT32_MAX);
+       csum_hi = ~((lo32 + csum_low) % UINT32_MAX);
+
+       return csum_hi << 32 | csum_low;
+}
+
+static int apfs_verify_checksum(blkid_probe pr,
+                               const struct apfs_super_block *sb)
+{
+       const size_t csummed_start_offset = offsetof(__typeof__(*sb), oid);
+       uint64_t csum;
+
+       csum = apfs_fletcher64(((const uint8_t *)sb) + csummed_start_offset,
+                              sizeof(*sb) - csummed_start_offset);
+
+       return blkid_probe_verify_csum(pr, csum, le64_to_cpu(sb->checksum));
+}
 
 static int probe_apfs(blkid_probe pr, const struct blkid_idmag *mag)
 {
@@ -45,6 +76,9 @@ static int probe_apfs(blkid_probe pr, const struct blkid_idmag *mag)
        if (!sb)
                return errno ? -errno : BLKID_PROBE_NONE;
 
+       if (!apfs_verify_checksum(pr, sb))
+               return BLKID_PROBE_NONE;
+
        if (le16_to_cpu(sb->type) != APFS_CONTAINER_SUPERBLOCK_TYPE)
                return BLKID_PROBE_NONE;