]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ntfs: fix off-by-one in mapping pairs decoding bounds checks
authorRon de Bruijn <rmbruijn@gmail.com>
Sat, 30 May 2026 00:19:18 +0000 (09:19 +0900)
committerNamjae Jeon <linkinjeon@kernel.org>
Fri, 5 Jun 2026 15:20:17 +0000 (00:20 +0900)
In ntfs_mapping_pairs_decompress(), attr_end points one byte past the
end of the attribute record:

    attr_end = (u8 *)attr + le32_to_cpu(attr->length);

The two bounds checks validating that mapping pair data bytes fit within
the attribute use strict greater-than (>), which allows a one-byte
out-of-bounds read when the data extends exactly to attr_end:

  b = *buf & 0xf;
  if (b) {
      if (unlikely(buf + b > attr_end))   // off-by-one
          goto io_error;
      for (deltaxcn = (s8)buf[b--]; b; b--)
          deltaxcn = (deltaxcn << 8) + buf[b];
  }

When buf + b == attr_end, the check evaluates to false and buf[b] reads
one byte past the valid attribute boundary. The same pattern appears in
the LCN delta bytes check.

Fix both checks to use >= so that buf[b] at exactly attr_end is
correctly rejected as out of bounds.

Cc: stable@vger.kernel.org # v7.1
Signed-off-by: Ron de Bruijn <rmbruijn@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/ntfs/runlist.c

index f27d78013856ed14971ebe6bbdd266f98dacd540..d8e8aa7b5bc0e98711d8505d156f8be260c7f5cd 100644 (file)
@@ -763,7 +763,7 @@ struct runlist_element *ntfs_mapping_pairs_decompress(const struct ntfs_volume *
        buf = (u8 *)attr +
                le16_to_cpu(attr->data.non_resident.mapping_pairs_offset);
        attr_end = (u8 *)attr + le32_to_cpu(attr->length);
-       if (unlikely(buf < (u8 *)attr || buf > attr_end)) {
+       if (unlikely(buf < (u8 *)attr || buf >= attr_end)) {
                ntfs_error(vol->sb, "Corrupt attribute.");
                return ERR_PTR(-EIO);
        }
@@ -811,7 +811,7 @@ struct runlist_element *ntfs_mapping_pairs_decompress(const struct ntfs_volume *
                 */
                b = *buf & 0xf;
                if (b) {
-                       if (unlikely(buf + b > attr_end))
+                       if (unlikely(buf + b >= attr_end))
                                goto io_error;
                        for (deltaxcn = (s8)buf[b--]; b; b--)
                                deltaxcn = (deltaxcn << 8) + buf[b];
@@ -855,7 +855,7 @@ struct runlist_element *ntfs_mapping_pairs_decompress(const struct ntfs_volume *
                        u8 b2 = *buf & 0xf;
 
                        b = b2 + ((*buf >> 4) & 0xf);
-                       if (buf + b > attr_end)
+                       if (buf + b >= attr_end)
                                goto io_error;
                        for (deltaxcn = (s8)buf[b--]; b > b2; b--)
                                deltaxcn = (deltaxcn << 8) + buf[b];