Eric Biggers wrote: > I found that the validation contained an off-by-one error. The > expression '(u32)(usa_ofs + (usa_count * 2)) > size' used 'usa_count' > after it had been decremented to skip the update sequence number entry. > Consequently, the code could read out of bounds, up to two bytes past the > end of the MST-protected record. > > Furthermore, as documented in the comment in layout.h for "NTFS_RECORD" > and also on MSDN for "MULTI_SECTOR_HEADER", the update sequence array > must end before the last le16 in the first sector --- not merely before > the end of the record. > > Fix the validation and move it into a helper function, as it was done > identically in the read and write paths. > > Signed-off-by: Eric Biggers <ebigge...@gmail.com> > --- > libntfs-3g/mst.c | 45 +++++++++++++++++++++++++++------------------ > 1 file changed, 27 insertions(+), 18 deletions(-) > > diff --git a/libntfs-3g/mst.c b/libntfs-3g/mst.c > index 9dff773..88b9cdb 100644 > --- a/libntfs-3g/mst.c > +++ b/libntfs-3g/mst.c > @@ -31,6 +31,21 @@ > #include "mst.h" > #include "logging.h" > > +/* > + * Basic validation of a NTFS multi-sector record. The record size must be a > + * multiple of the sector size; and the update sequence array must be > properly > + * aligned, of the expected length, and must end before the last le16 in the > + * first sector.
Can you disambiguate the word "sector" here ? This is not a physical sector, but an ntfs logical sector whose size is NTFS_BLOCK_SIZE (512 bytes). This might not have been known to the original developer, and it would be useful to have it documented somewhere. Jean-Pierre > + */ > +static BOOL > +is_valid_record(u32 size, u16 usa_ofs, u16 usa_count) > +{ > + return size % NTFS_BLOCK_SIZE == 0 && > + usa_ofs % 2 == 0 && > + usa_count == 1 + (size / NTFS_BLOCK_SIZE) && > + usa_ofs + ((u32)usa_count * 2) <= NTFS_BLOCK_SIZE - 2; > +} > + > /** > * ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data > * @b: pointer to the data to deprotect > @@ -57,12 +72,9 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const > u32 size, > > /* Setup the variables. */ > usa_ofs = le16_to_cpu(b->usa_ofs); > - /* Decrement usa_count to get number of fixups. */ > - usa_count = le16_to_cpu(b->usa_count) - 1; > - /* Size and alignment checks. */ > - if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 || > - (u32)(usa_ofs + (usa_count * 2)) > size || > - (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { > + usa_count = le16_to_cpu(b->usa_count); > + > + if (!is_valid_record(size, usa_ofs, usa_count)) { > errno = EINVAL; > if (warn) { > ntfs_log_perror("%s: magic: 0x%08lx size: %ld " > @@ -91,7 +103,7 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const > u32 size, > /* > * Check for incomplete multi sector transfer(s). > */ > - while (usa_count--) { > + while (--usa_count) { > if (*data_pos != usn) { > /* > * Incomplete multi sector transfer detected! )-: > @@ -109,10 +121,10 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const > u32 size, > data_pos += NTFS_BLOCK_SIZE/sizeof(u16); > } > /* Re-setup the variables. */ > - usa_count = le16_to_cpu(b->usa_count) - 1; > + usa_count = le16_to_cpu(b->usa_count); > data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1; > /* Fixup all sectors. */ > - while (usa_count--) { > + while (--usa_count) { > /* > * Increment position in usa and restore original data from > * the usa into the data buffer. > @@ -171,12 +183,9 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 > size) > } > /* Setup the variables. */ > usa_ofs = le16_to_cpu(b->usa_ofs); > - /* Decrement usa_count to get number of fixups. */ > - usa_count = le16_to_cpu(b->usa_count) - 1; > - /* Size and alignment checks. */ > - if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 || > - (u32)(usa_ofs + (usa_count * 2)) > size || > - (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { > + usa_count = le16_to_cpu(b->usa_count); > + > + if (!is_valid_record(size, usa_ofs, usa_count)) { > errno = EINVAL; > ntfs_log_perror("%s", __FUNCTION__); > return -1; > @@ -195,7 +204,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 > size) > /* Position in data of first le16 that needs fixing up. */ > data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(le16) - 1; > /* Fixup all sectors. */ > - while (usa_count--) { > + while (--usa_count) { > /* > * Increment the position in the usa and save the > * original data from the data buffer into the usa. > @@ -223,7 +232,7 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b) > u16 *usa_pos, *data_pos; > > u16 usa_ofs = le16_to_cpu(b->usa_ofs); > - u16 usa_count = le16_to_cpu(b->usa_count) - 1; > + u16 usa_count = le16_to_cpu(b->usa_count); > > ntfs_log_trace("Entering\n"); > > @@ -234,7 +243,7 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b) > data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1; > > /* Fixup all sectors. */ > - while (usa_count--) { > + while (--usa_count) { > /* > * Increment position in usa and restore original data from > * the usa into the data buffer. > ------------------------------------------------------------------------------ What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic patterns at an interface-level. Reveals which users, apps, and protocols are consuming the most bandwidth. Provides multi-vendor support for NetFlow, J-Flow, sFlow and other flows. Make informed decisions using capacity planning reports.http://sdm.link/zohodev2dev _______________________________________________ ntfs-3g-devel mailing list ntfs-3g-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ntfs-3g-devel