Skip to content

Commit 6098790

Browse files
charsyamnamjaejeon
authored andcommitted
ntfs: validate MFT attrs_offset against bytes_in_use
ntfs_mft_record_check() verifies that attrs_offset is aligned and that the resulting pointer stays within the allocated MFT record buffer, but it does not check that the first attribute header starts within the bytes_in_use area. A malformed record with attrs_offset greater than bytes_in_use can pass this check as long as attrs_offset is still within bytes_allocated. The attribute parser then computes the remaining record space by subtracting the attribute pointer from bytes_in_use. Because that value is unsigned, the subtraction can underflow and allow bytes after bytes_in_use to be interpreted as an attribute. Reject records where attrs_offset is outside bytes_in_use or where the used area does not even contain the four-byte attribute type/AT_END terminator at attrs_offset. A small userspace model with attrs_offset=128 and bytes_in_use=64 shows the current check accepts the record and the parser space calculation underflows to 0xffffffc0. With this change the same malformed record is rejected before the attribute walker is entered. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: DaeMyung Kang <charsyam@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
1 parent d1aabc2 commit 6098790

1 file changed

Lines changed: 12 additions & 1 deletion

File tree

fs/ntfs/mft.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ int ntfs_mft_record_check(const struct ntfs_volume *vol, struct mft_record *m,
3030
{
3131
struct attr_record *a;
3232
struct super_block *sb = vol->sb;
33+
u16 attrs_offset;
34+
u32 bytes_in_use;
3335

3436
if (!ntfs_is_file_record(m->magic)) {
3537
ntfs_error(sb, "Record %llu has no FILE magic (0x%x)\n",
@@ -65,7 +67,16 @@ int ntfs_mft_record_check(const struct ntfs_volume *vol, struct mft_record *m,
6567
goto err_out;
6668
}
6769

68-
a = (struct attr_record *)((char *)m + le16_to_cpu(m->attrs_offset));
70+
attrs_offset = le16_to_cpu(m->attrs_offset);
71+
bytes_in_use = le32_to_cpu(m->bytes_in_use);
72+
73+
if (attrs_offset > bytes_in_use ||
74+
bytes_in_use - attrs_offset < sizeof_field(struct attr_record, type)) {
75+
ntfs_error(sb, "Record %llu has corrupt attribute offset\n", mft_no);
76+
goto err_out;
77+
}
78+
79+
a = (struct attr_record *)((char *)m + attrs_offset);
6980
if ((char *)a < (char *)m || (char *)a > (char *)m + vol->mft_record_size) {
7081
ntfs_error(sb, "Record %llu is corrupt\n", mft_no);
7182
goto err_out;

0 commit comments

Comments
 (0)