]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: fix integer overflow in nvidia_raid size check
authorKarel Zak <kzak@redhat.com>
Wed, 25 Feb 2026 08:58:32 +0000 (09:58 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 25 Feb 2026 08:58:32 +0000 (09:58 +0100)
The size validation `le32_to_cpu(nv->size) * 4 != NVIDIA_SUPERBLOCK_SIZE`
is subject to 32-bit unsigned integer overflow. A crafted value like
0x4000001E overflows when multiplied by 4, wrapping to 120 and passing
the check. The checksum loop then iterates ~1 billion times, reading
far beyond the 120-byte buffer.

Fix by comparing against the expected count directly without
multiplication. Also add a buffer size parameter to
nvraid_verify_checksum() as defense-in-depth against oversized reads.

Signed-off-by: Karel Zak <kzak@redhat.com>
libblkid/src/superblocks/nvidia_raid.c

index 1a88dbd7c89f68ca33b071cda1059b1b8c7769ec..daee52b57db2c3af5e907a56dffc59a22aba8ba4 100644 (file)
@@ -27,10 +27,16 @@ struct nv_metadata {
 #define NVIDIA_SUPERBLOCK_SIZE         120
 
 
-static int nvraid_verify_checksum(blkid_probe pr, const struct nv_metadata *nv)
+static int nvraid_verify_checksum(blkid_probe pr, const struct nv_metadata *nv,
+                                 size_t bufsiz)
 {
        uint32_t csum = le32_to_cpu(nv->chksum);
-       for (size_t i = 0; i < le32_to_cpu(nv->size); i++)
+       uint32_t count = le32_to_cpu(nv->size);
+
+       if (count > bufsiz / sizeof(uint32_t))
+               return 0;
+
+       for (size_t i = 0; i < count; i++)
                csum += le32_to_cpu(((uint32_t *) nv)[i]);
        return blkid_probe_verify_csum(pr, csum, le32_to_cpu(nv->chksum));
 }
@@ -54,9 +60,9 @@ static int probe_nvraid(blkid_probe pr,
 
        if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
                return 1;
-       if (le32_to_cpu(nv->size) * 4 != NVIDIA_SUPERBLOCK_SIZE)
+       if (le32_to_cpu(nv->size) != NVIDIA_SUPERBLOCK_SIZE / 4)
                return 1;
-       if (!nvraid_verify_checksum(pr, nv))
+       if (!nvraid_verify_checksum(pr, nv, NVIDIA_SUPERBLOCK_SIZE))
                return 1;
        if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0)
                return 1;