Skip to content

Commit

Permalink
fs/ntfs3: Add more attributes checks in mi_enum_attr()
Browse files Browse the repository at this point in the history
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
  • Loading branch information
aalexandrovich committed Sep 28, 2023
1 parent fc471e3 commit 013ff63
Showing 1 changed file with 52 additions and 16 deletions.
68 changes: 52 additions & 16 deletions fs/ntfs3/record.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,9 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
{
const struct MFT_REC *rec = mi->mrec;
u32 used = le32_to_cpu(rec->used);
u32 t32, off, asize;
u32 t32, off, asize, prev_type;
u16 t16;
u64 data_size, alloc_size, tot_size;

if (!attr) {
u32 total = le32_to_cpu(rec->total);
Expand All @@ -213,6 +214,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
if (!is_rec_inuse(rec))
return NULL;

prev_type = 0;
attr = Add2Ptr(rec, off);
} else {
/* Check if input attr inside record. */
Expand All @@ -226,11 +228,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
return NULL;
}

if (off + asize < off) {
/* Overflow check. */
/* Overflow check. */
if (off + asize < off)
return NULL;
}

prev_type = le32_to_cpu(attr->type);
attr = Add2Ptr(attr, asize);
off += asize;
}
Expand All @@ -250,7 +252,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)

/* 0x100 is last known attribute for now. */
t32 = le32_to_cpu(attr->type);
if ((t32 & 0xf) || (t32 > 0x100))
if (!t32 || (t32 & 0xf) || (t32 > 0x100))
return NULL;

/* attributes in record must be ordered by type */
if (t32 < prev_type)
return NULL;

/* Check overflow and boundary. */
Expand All @@ -259,16 +265,15 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)

/* Check size of attribute. */
if (!attr->non_res) {
/* Check resident fields. */
if (asize < SIZEOF_RESIDENT)
return NULL;

t16 = le16_to_cpu(attr->res.data_off);

if (t16 > asize)
return NULL;

t32 = le32_to_cpu(attr->res.data_size);
if (t16 + t32 > asize)
if (t16 + le32_to_cpu(attr->res.data_size) > asize)
return NULL;

t32 = sizeof(short) * attr->name_len;
Expand All @@ -278,21 +283,52 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
return attr;
}

/* Check some nonresident fields. */
if (attr->name_len &&
le16_to_cpu(attr->name_off) + sizeof(short) * attr->name_len >
le16_to_cpu(attr->nres.run_off)) {
/* Check nonresident fields. */
if (attr->non_res != 1)
return NULL;

t16 = le16_to_cpu(attr->nres.run_off);
if (t16 > asize)
return NULL;

t32 = sizeof(short) * attr->name_len;
if (t32 && le16_to_cpu(attr->name_off) + t32 > t16)
return NULL;

/* Check start/end vcn. */
if (le64_to_cpu(attr->nres.svcn) > le64_to_cpu(attr->nres.evcn) + 1)
return NULL;

data_size = le64_to_cpu(attr->nres.data_size);
if (le64_to_cpu(attr->nres.valid_size) > data_size)
return NULL;
}

if (attr->nres.svcn || !is_attr_ext(attr)) {
alloc_size = le64_to_cpu(attr->nres.alloc_size);
if (data_size > alloc_size)
return NULL;

t32 = mi->sbi->cluster_mask;
if (alloc_size & t32)
return NULL;

if (!attr->nres.svcn && is_attr_ext(attr)) {
/* First segment of sparse/compressed attribute */
if (asize + 8 < SIZEOF_NONRESIDENT_EX)
return NULL;

tot_size = le64_to_cpu(attr->nres.total_size);
if (tot_size & t32)
return NULL;

if (tot_size > alloc_size)
return NULL;
} else {
if (asize + 8 < SIZEOF_NONRESIDENT)
return NULL;

if (attr->nres.c_unit)
return NULL;
} else if (asize + 8 < SIZEOF_NONRESIDENT_EX)
return NULL;
}

return attr;
}
Expand Down

0 comments on commit 013ff63

Please # to comment.