diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index 9ec5d058aa3c..b2277d91a9df 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -3348,10 +3348,21 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe, break; case DeleteAttribute: - asize = le32_to_cpu(attr->size); used = le32_to_cpu(rec->used); - if (!check_if_attr(rec, lrh)) + /* + * check_if_attr() accepts a record_off that points at the + * ATTR_END marker, which is how CreateAttribute appends. The + * bytes there are not an attribute and check_attr() never + * validated them, so refuse an offset that cannot hold a + * resident header before reading attr->size, and then bound it + * as mi_remove_attr() does. + */ + if (!check_if_attr(rec, lrh) || roff + SIZEOF_RESIDENT > used) + goto dirty_vol; + + asize = le32_to_cpu(attr->size); + if (asize > used - roff) goto dirty_vol; rec->used = cpu_to_le32(used - asize);