1. Correct ntfs_test test failures around attempting to validate attribute list entries as attributes. The NTFS code uses common logic in some places to parse both attributes and attribute_lists which complicates validation. 2. Correct ntfs_test test failures around attempting to validate attribute run list values. The calculation was incorrect for the 'curr' variable.
Fixes: 067b6d225d482280abad03944f04e30abcbdafa1 Signed-off-by: Andrew Hamilton <adham...@gmail.com> --- grub-core/fs/ntfs.c | 52 +++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c index b3117bf92..0d087acd8 100644 --- a/grub-core/fs/ntfs.c +++ b/grub-core/fs/ntfs.c @@ -83,6 +83,7 @@ validate_attribute (grub_uint8_t *attr, void *end) { grub_size_t attr_size = 0; grub_size_t min_size = 0; + grub_size_t run_size = 0; grub_size_t spare = (grub_uint8_t *) end - attr; /* * Just used as a temporary variable to try and deal with cases where someone @@ -174,8 +175,10 @@ validate_attribute (grub_uint8_t *attr, void *end) * These directly follow the header byte, so we use them to update * the minimum size. */ - min_size += (attr[curr] & 0x7) + ((attr[curr] >> 4) & 0x7); - curr += min_size; + run_size = (attr[curr] & 0x7) + ((attr[curr] >> 4) & 0x7); + curr += run_size; + curr++; + min_size += run_size; min_size++; if (min_size > attr_size) goto fail; @@ -216,7 +219,7 @@ validate_attribute (grub_uint8_t *attr, void *end) /* Return the next attribute if it exists, otherwise return NULL. */ static grub_uint8_t * -next_attribute (grub_uint8_t *curr_attribute, void *end) +next_attribute (grub_uint8_t *curr_attribute, void *end, bool validate) { grub_uint8_t *next = curr_attribute; @@ -228,7 +231,7 @@ next_attribute (grub_uint8_t *curr_attribute, void *end) return NULL; next += u16at (curr_attribute, 4); - if (validate_attribute (next, end) == false) + if (validate && validate_attribute (next, end) == false) return NULL; return next; @@ -313,13 +316,16 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) { grub_uint8_t *mft_end; + /* GRUB_NTFS_AF_ALST indicates the attribute list type */ if (at->flags & GRUB_NTFS_AF_ALST) { retry: while (at->attr_nxt) { at->attr_cur = at->attr_nxt; - at->attr_nxt = next_attribute (at->attr_cur, at->attr_end); + /* Go to the next attribute in the list but do not validate */ + /* because this is the attribute list type. */ + at->attr_nxt = next_attribute (at->attr_cur, at->attr_end, false); if ((*at->attr_cur == attr) || (attr == 0)) { grub_uint8_t *new_pos, *end; @@ -375,7 +381,9 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) { return new_pos; } - new_pos = next_attribute (new_pos, end); + /* Go to the next attribute in the list but do not validate */ + /* because this is the attribute list type. */ + new_pos = next_attribute (new_pos, end, false); } grub_error (GRUB_ERR_BAD_FS, "can\'t find 0x%X in attribute list", @@ -389,7 +397,19 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) mft_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); while (at->attr_cur >= at->mft->buf && at->attr_cur < mft_end && *at->attr_cur != 0xFF) { - at->attr_nxt = next_attribute (at->attr_cur, at->end); + /* We can't use validate_attribute here because this logic + * seems to be used for both parsing through attributes + * and attribute lists. */ + grub_uint16_t nsize = u16at (at->attr_cur, 4); + if (at->attr_cur + nsize >= at->end || + at->attr_cur + GRUB_NTFS_ATTRIBUTE_HEADER_SIZE >= at->end) + { + at->attr_nxt = at->attr_cur; + break; + } + else + at->attr_nxt = at->attr_cur + nsize; + if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST) at->attr_end = at->attr_cur; if ((*at->attr_cur == attr) || (attr == 0)) @@ -436,14 +456,18 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) /* From this point on pa_end is the end of the buffer */ at->end = pa_end; - if (validate_attribute (at->attr_nxt, pa_end) == false) - return NULL; + if (at->attr_end >= pa_end || at->attr_nxt >= pa_end) + return NULL; while (at->attr_nxt) { if ((*at->attr_nxt == attr) || (attr == 0)) break; - at->attr_nxt = next_attribute (at->attr_nxt, pa_end); + + grub_uint16_t nxt_offset = u16at (at->attr_nxt, 4); + at->attr_nxt += nxt_offset; + if (nxt_offset == 0 || at->attr_nxt >= (pa_end - 4)) + at->attr_nxt = NULL; } if (at->attr_nxt >= at->attr_end || at->attr_nxt == NULL) @@ -468,7 +492,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + 1)); pa = at->attr_nxt + u16at (pa, 4); - if (validate_attribute (pa, pa_end) == true) + if (pa >= pa_end) pa = NULL; while (pa) @@ -487,7 +511,9 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), at->mft->data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0)) return NULL; - pa = next_attribute (pa, pa_end); + pa += u16at(pa, 4); + if (pa >= pa_end) + pa = NULL; } at->attr_nxt = at->attr_cur; at->flags &= ~GRUB_NTFS_AF_GPOS; @@ -734,7 +760,7 @@ read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs, if (u32at (pa, 8) > vcn) break; at->attr_nxt = pa; - pa = next_attribute (pa, at->attr_end); + pa = next_attribute (pa, at->attr_end, true); } } pp = find_attr (at, attr); -- 2.39.5 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel