]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: Compute CRC with sb_crc zeroed
authorJeremy Linton <jeremy.linton@arm.com>
Fri, 14 Apr 2023 21:25:28 +0000 (16:25 -0500)
committerJeremy Linton <jeremy.linton@arm.com>
Fri, 14 Apr 2023 23:49:27 +0000 (18:49 -0500)
The Linux kernel computes the sb_crc by crcing the
superblock with the CRC field set to 0. The code is
trying to avoid doing this in three separate CRC calls
like the kernel performs by simply zeroing the field
and making a single call.

Except that the passed copy "ondisk" isn't the same
as the returned copy "csummed" so the zeroing goes into
the wrong buffer. Meaning that the CRC is computed
incorrectly. This results in blkid returning:

/dev/sda4: PARTUUID="2f162043-63c2-d145-869b-e53f9db57476"

rather than:

/dev/sda4: UUID="45b931b7-592a-46dc-9c33-d38d5901ec29" BLOCK_SIZE="4096" TYPE="xfs" PARTUUID="2f162043-63c2-d145-869b-e53f9db57476"

Which can result in lots of failures including boot
failures if XFS modules aren't placed into the initrd,
or scripts/etc cannot determine the fs UUID.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
libblkid/src/superblocks/xfs.c

index 4f80c5c9689161e6bc6b5919dd8f234cb6f1ccf6..6ab47ef1e4ccf36596d7b3b7430df42025f11b7a 100644 (file)
@@ -207,6 +207,7 @@ static int xfs_verify_sb(struct xfs_super_block *ondisk, blkid_probe pr,
        if ((sbp->sb_versionnum & 0x0f) == 5) {
                uint32_t expected, crc;
                unsigned char *csummed;
+               int crc_offset = offsetof(struct xfs_super_block, sb_crc);
 
                if (!(sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT))
                        return 0;
@@ -218,8 +219,8 @@ static int xfs_verify_sb(struct xfs_super_block *ondisk, blkid_probe pr,
                if (!csummed)
                        return 0;
 
-               ondisk->sb_crc = 0;
-               crc = crc32c(~0LL, csummed, sbp->sb_sectsize);
+               crc = ul_crc32c_exclude_offset(~0LL, csummed, sbp->sb_sectsize,
+                                              crc_offset, sizeof(sbp->sb_crc));
                crc = bswap_32(crc ^ ~0LL);
 
                if (!blkid_probe_verify_csum(pr, crc, expected))