Re: [PATCH] ntfs: fix memmove overlap in ntfs_new_attr_flags
Hyunchul Lee <[email protected]>
| Newsgroups | org.kernel.vger.stable,dev.linux.lists.ntfs,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CANFS6bZczfbx3HKO9pN2wOm9Wy8oCX0GAA_uAoXzhu1j34Jo7w@mail.gmail.com> |
Hi Hongling, 2026년 8월 24일 (월) 오후 4:59, Hongling Zeng <[email protected]>님이 작성: > > When the record shrinks while the payload offsets increase (e.g., enabling > compression reduces padding, making arec_size < old_arec_size, but the header > grows by 8 bytes), moving the name first can overwrite the old mapping_pairs > before they are copied. Move mapping_pairs first in this case. Can this situation occur even when it is not a crafted image? > > Since mp_ofs is derived from name_ofs, they always change in the same > direction. Checking name_ofs alone is sufficient. > > Fixes: fc053f05ca28 ("ntfs: add reparse and ea operations") > Cc: [email protected] > Signed-off-by: Hongling Zeng <[email protected]> > --- > fs/ntfs/ea.c | 33 +++++++++++++++++++++++++++------ > 1 file changed, 27 insertions(+), 6 deletions(-) > > diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c > index 534f7efaf128..c836d33ab0d3 100644 > --- a/fs/ntfs/ea.c > +++ b/fs/ntfs/ea.c > @@ -729,15 +729,36 @@ static int ntfs_new_attr_flags(struct ntfs_inode *ni, __le32 fattr) > old_arec_size = le32_to_cpu(a->length); > > /* > - * Move payloads before shrinking the record. Otherwise resizing moves > + * Move payloads before shrinking the record. Otherwise resizing moves > * the following attribute over the old payload before it can be copied. > + * > + * When offsets increase, move mapping_pairs first to avoid name > + * overwriting the start of mapping_pairs. > */ > if (arec_size < old_arec_size) { > - if (a->name_length && name_ofs != old_name_ofs) > - memmove((u8 *)a + name_ofs, (u8 *)a + old_name_ofs, > - a->name_length * sizeof(__le16)); > - if (mp_ofs != old_mp_ofs) > - memmove((u8 *)a + mp_ofs, (u8 *)a + old_mp_ofs, mp_size); > + if (name_ofs > old_name_ofs) { > + /* Payload offsets increased: move mapping pairs first. */ > + if (mp_ofs != old_mp_ofs) > + memmove((u8 *)a + mp_ofs, > + (u8 *)a + old_mp_ofs, > + mp_size); > + if (a->name_length && name_ofs != old_name_ofs) > + memmove((u8 *)a + name_ofs, > + (u8 *)a + old_name_ofs, > + a->name_length * > + sizeof(__le16)); > + } else { > + /* Payload offsets decreased or unchanged: move name first. */ > + if (a->name_length && name_ofs != old_name_ofs) > + memmove((u8 *)a + name_ofs, > + (u8 *)a + old_name_ofs, > + a->name_length * > + sizeof(__le16)); > + if (mp_ofs != old_mp_ofs) > + memmove((u8 *)a + mp_ofs, > + (u8 *)a + old_mp_ofs, > + mp_size); > + } > } > > err = ntfs_attr_record_resize(ctx->mrec, a, arec_size); > -- > 2.25.1 > -- Thanks, Hyunchul