ntfs: fix off-by-one in mapping pairs decoding bounds checks

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>
This commit is contained in:
Ron de Bruijn 2026-05-30 09:19:18 +09:00 committed by Namjae Jeon
parent 0aad215701
commit 18760a74ef

View 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];