Skip to content

Commit

Permalink
fs/ntfs3: Mark inode as bad as soon as error detected in mi_enum_attr()
Browse files Browse the repository at this point in the history
Extended the `mi_enum_attr()` function interface with an additional
parameter, `struct ntfs_inode *ni`, to allow marking the inode
as bad as soon as an error is detected.

Reported-by: syzbot+73d8fc29ec7cba8286fa@syzkaller.appspotmail.com
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
  • Loading branch information
Konstantin Komarov committed Dec 30, 2024
1 parent 1f2bf70 commit 2afd4d2
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 80 deletions.
11 changes: 6 additions & 5 deletions fs/ntfs3/attrib.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
if (err)
goto out;

attr = mi_find_attr(mi, NULL, type, name, name_len, &le->id);
attr = mi_find_attr(ni, mi, NULL, type, name, name_len,
&le->id);
if (!attr) {
err = -EINVAL;
goto bad_inode;
Expand Down Expand Up @@ -1181,7 +1182,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
goto out;
}

attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0, &le->id);
attr = mi_find_attr(ni, mi, NULL, ATTR_DATA, NULL, 0, &le->id);
if (!attr) {
err = -EINVAL;
goto out;
Expand Down Expand Up @@ -1796,7 +1797,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
goto out;
}

attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0,
attr = mi_find_attr(ni, mi, NULL, ATTR_DATA, NULL, 0,
&le->id);
if (!attr) {
err = -EINVAL;
Expand Down Expand Up @@ -2041,8 +2042,8 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
}

/* Look for required attribute. */
attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL,
0, &le->id);
attr = mi_find_attr(ni, mi, NULL, ATTR_DATA,
NULL, 0, &le->id);
if (!attr) {
err = -EINVAL;
goto out;
Expand Down
59 changes: 31 additions & 28 deletions fs/ntfs3/frecord.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni)
{
const struct ATTRIB *attr;

attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL);
attr = mi_find_attr(ni, &ni->mi, NULL, ATTR_STD, NULL, 0, NULL);
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO)) :
NULL;
}
Expand All @@ -89,7 +89,7 @@ struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni)
{
const struct ATTRIB *attr;

attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL);
attr = mi_find_attr(ni, &ni->mi, NULL, ATTR_STD, NULL, 0, NULL);

return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5)) :
NULL;
Expand Down Expand Up @@ -201,7 +201,8 @@ struct ATTRIB *ni_find_attr(struct ntfs_inode *ni, struct ATTRIB *attr,
*mi = &ni->mi;

/* Look for required attribute in primary record. */
return mi_find_attr(&ni->mi, attr, type, name, name_len, NULL);
return mi_find_attr(ni, &ni->mi, attr, type, name, name_len,
NULL);
}

/* First look for list entry of required type. */
Expand All @@ -217,7 +218,7 @@ struct ATTRIB *ni_find_attr(struct ntfs_inode *ni, struct ATTRIB *attr,
return NULL;

/* Look for required attribute. */
attr = mi_find_attr(m, NULL, type, name, name_len, &le->id);
attr = mi_find_attr(ni, m, NULL, type, name, name_len, &le->id);

if (!attr)
goto out;
Expand Down Expand Up @@ -259,7 +260,7 @@ struct ATTRIB *ni_enum_attr_ex(struct ntfs_inode *ni, struct ATTRIB *attr,
if (mi)
*mi = &ni->mi;
/* Enum attributes in primary record. */
return mi_enum_attr(&ni->mi, attr);
return mi_enum_attr(ni, &ni->mi, attr);
}

/* Get next list entry. */
Expand All @@ -275,7 +276,7 @@ struct ATTRIB *ni_enum_attr_ex(struct ntfs_inode *ni, struct ATTRIB *attr,
*mi = mi2;

/* Find attribute in loaded record. */
return rec_find_attr_le(mi2, le2);
return rec_find_attr_le(ni, mi2, le2);
}

/*
Expand All @@ -293,7 +294,8 @@ struct ATTRIB *ni_load_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
if (!ni->attr_list.size) {
if (pmi)
*pmi = &ni->mi;
return mi_find_attr(&ni->mi, NULL, type, name, name_len, NULL);
return mi_find_attr(ni, &ni->mi, NULL, type, name, name_len,
NULL);
}

le = al_find_ex(ni, NULL, type, name, name_len, NULL);
Expand All @@ -319,7 +321,7 @@ struct ATTRIB *ni_load_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
if (pmi)
*pmi = mi;

attr = mi_find_attr(mi, NULL, type, name, name_len, &le->id);
attr = mi_find_attr(ni, mi, NULL, type, name, name_len, &le->id);
if (!attr)
return NULL;

Expand Down Expand Up @@ -398,7 +400,8 @@ int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
int diff;

if (base_only || type == ATTR_LIST || !ni->attr_list.size) {
attr = mi_find_attr(&ni->mi, NULL, type, name, name_len, id);
attr = mi_find_attr(ni, &ni->mi, NULL, type, name, name_len,
id);
if (!attr)
return -ENOENT;

Expand Down Expand Up @@ -437,7 +440,7 @@ int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,

al_remove_le(ni, le);

attr = mi_find_attr(mi, NULL, type, name, name_len, id);
attr = mi_find_attr(ni, mi, NULL, type, name, name_len, id);
if (!attr)
return -ENOENT;

Expand Down Expand Up @@ -485,7 +488,7 @@ ni_ins_new_attr(struct ntfs_inode *ni, struct mft_inode *mi,
name = le->name;
}

attr = mi_insert_attr(mi, type, name, name_len, asize, name_off);
attr = mi_insert_attr(ni, mi, type, name, name_len, asize, name_off);
if (!attr) {
if (le_added)
al_remove_le(ni, le);
Expand Down Expand Up @@ -673,7 +676,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
if (err)
return err;

attr_list = mi_find_attr(&ni->mi, NULL, ATTR_LIST, NULL, 0, NULL);
attr_list = mi_find_attr(ni, &ni->mi, NULL, ATTR_LIST, NULL, 0, NULL);
if (!attr_list)
return 0;

Expand All @@ -695,7 +698,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
if (!mi)
return 0;

attr = mi_find_attr(mi, NULL, le->type, le_name(le),
attr = mi_find_attr(ni, mi, NULL, le->type, le_name(le),
le->name_len, &le->id);
if (!attr)
return 0;
Expand Down Expand Up @@ -731,7 +734,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
goto out;
}

attr = mi_find_attr(mi, NULL, le->type, le_name(le),
attr = mi_find_attr(ni, mi, NULL, le->type, le_name(le),
le->name_len, &le->id);
if (!attr) {
/* Should never happened, 'cause already checked. */
Expand All @@ -740,7 +743,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
asize = le32_to_cpu(attr->size);

/* Insert into primary record. */
attr_ins = mi_insert_attr(&ni->mi, le->type, le_name(le),
attr_ins = mi_insert_attr(ni, &ni->mi, le->type, le_name(le),
le->name_len, asize,
le16_to_cpu(attr->name_off));
if (!attr_ins) {
Expand Down Expand Up @@ -768,7 +771,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
if (!mi)
continue;

attr = mi_find_attr(mi, NULL, le->type, le_name(le),
attr = mi_find_attr(ni, mi, NULL, le->type, le_name(le),
le->name_len, &le->id);
if (!attr)
continue;
Expand Down Expand Up @@ -831,7 +834,7 @@ int ni_create_attr_list(struct ntfs_inode *ni)
free_b = 0;
attr = NULL;

for (; (attr = mi_enum_attr(&ni->mi, attr)); le = Add2Ptr(le, sz)) {
for (; (attr = mi_enum_attr(ni, &ni->mi, attr)); le = Add2Ptr(le, sz)) {
sz = le_size(attr->name_len);
le->type = attr->type;
le->size = cpu_to_le16(sz);
Expand Down Expand Up @@ -886,7 +889,7 @@ int ni_create_attr_list(struct ntfs_inode *ni)
u32 asize = le32_to_cpu(b->size);
u16 name_off = le16_to_cpu(b->name_off);

attr = mi_insert_attr(mi, b->type, Add2Ptr(b, name_off),
attr = mi_insert_attr(ni, mi, b->type, Add2Ptr(b, name_off),
b->name_len, asize, name_off);
if (!attr)
goto out;
Expand All @@ -909,7 +912,7 @@ int ni_create_attr_list(struct ntfs_inode *ni)
goto out;
}

attr = mi_insert_attr(&ni->mi, ATTR_LIST, NULL, 0,
attr = mi_insert_attr(ni, &ni->mi, ATTR_LIST, NULL, 0,
lsize + SIZEOF_RESIDENT, SIZEOF_RESIDENT);
if (!attr)
goto out;
Expand Down Expand Up @@ -993,13 +996,13 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
mi = rb_entry(node, struct mft_inode, node);

if (is_mft_data &&
(mi_enum_attr(mi, NULL) ||
(mi_enum_attr(ni, mi, NULL) ||
vbo <= ((u64)mi->rno << sbi->record_bits))) {
/* We can't accept this record 'cause MFT's bootstrapping. */
continue;
}
if (is_mft &&
mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0, NULL)) {
mi_find_attr(ni, mi, NULL, ATTR_DATA, NULL, 0, NULL)) {
/*
* This child record already has a ATTR_DATA.
* So it can't accept any other records.
Expand All @@ -1008,7 +1011,7 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
}

if ((type != ATTR_NAME || name_len) &&
mi_find_attr(mi, NULL, type, name, name_len, NULL)) {
mi_find_attr(ni, mi, NULL, type, name, name_len, NULL)) {
/* Only indexed attributes can share same record. */
continue;
}
Expand Down Expand Up @@ -1157,7 +1160,7 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
/* Estimate the result of moving all possible attributes away. */
attr = NULL;

while ((attr = mi_enum_attr(&ni->mi, attr))) {
while ((attr = mi_enum_attr(ni, &ni->mi, attr))) {
if (attr->type == ATTR_STD)
continue;
if (attr->type == ATTR_LIST)
Expand All @@ -1175,7 +1178,7 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
attr = NULL;

for (;;) {
attr = mi_enum_attr(&ni->mi, attr);
attr = mi_enum_attr(ni, &ni->mi, attr);
if (!attr) {
/* We should never be here 'cause we have already check this case. */
err = -EINVAL;
Expand Down Expand Up @@ -1259,7 +1262,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
for (node = rb_first(&ni->mi_tree); node; node = rb_next(node)) {
mi = rb_entry(node, struct mft_inode, node);

attr = mi_enum_attr(mi, NULL);
attr = mi_enum_attr(ni, mi, NULL);

if (!attr) {
mft_min = mi->rno;
Expand All @@ -1280,7 +1283,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
ni_remove_mi(ni, mi_new);
}

attr = mi_find_attr(&ni->mi, NULL, ATTR_DATA, NULL, 0, NULL);
attr = mi_find_attr(ni, &ni->mi, NULL, ATTR_DATA, NULL, 0, NULL);
if (!attr) {
err = -EINVAL;
goto out;
Expand Down Expand Up @@ -1397,7 +1400,7 @@ int ni_expand_list(struct ntfs_inode *ni)
continue;

/* Find attribute in primary record. */
attr = rec_find_attr_le(&ni->mi, le);
attr = rec_find_attr_le(ni, &ni->mi, le);
if (!attr) {
err = -EINVAL;
goto out;
Expand Down Expand Up @@ -3344,7 +3347,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
if (!mi->dirty)
continue;

is_empty = !mi_enum_attr(mi, NULL);
is_empty = !mi_enum_attr(ni, mi, NULL);

if (is_empty)
clear_rec_inuse(mi->mrec);
Expand Down
21 changes: 11 additions & 10 deletions fs/ntfs3/ntfs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,23 +745,24 @@ int mi_get(struct ntfs_sb_info *sbi, CLST rno, struct mft_inode **mi);
void mi_put(struct mft_inode *mi);
int mi_init(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno);
int mi_read(struct mft_inode *mi, bool is_mft);
struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr);
// TODO: id?
struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr,
enum ATTR_TYPE type, const __le16 *name,
u8 name_len, const __le16 *id);
static inline struct ATTRIB *rec_find_attr_le(struct mft_inode *rec,
struct ATTRIB *mi_enum_attr(struct ntfs_inode *ni, struct mft_inode *mi,
struct ATTRIB *attr);
struct ATTRIB *mi_find_attr(struct ntfs_inode *ni, struct mft_inode *mi,
struct ATTRIB *attr, enum ATTR_TYPE type,
const __le16 *name, u8 name_len, const __le16 *id);
static inline struct ATTRIB *rec_find_attr_le(struct ntfs_inode *ni,
struct mft_inode *rec,
struct ATTR_LIST_ENTRY *le)
{
return mi_find_attr(rec, NULL, le->type, le_name(le), le->name_len,
return mi_find_attr(ni, rec, NULL, le->type, le_name(le), le->name_len,
&le->id);
}
int mi_write(struct mft_inode *mi, int wait);
int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
__le16 flags, bool is_mft);
struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
const __le16 *name, u8 name_len, u32 asize,
u16 name_off);
struct ATTRIB *mi_insert_attr(struct ntfs_inode *ni, struct mft_inode *mi,
enum ATTR_TYPE type, const __le16 *name,
u8 name_len, u32 asize, u16 name_off);

bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
struct ATTRIB *attr);
Expand Down
Loading

0 comments on commit 2afd4d2

Please sign in to comment.