Commit 8c95307a0 (fs/ntfs: Correct possible access violations) added a
check that the run list offset of a non-resident attribute stays inside
the attribute. However, end_ptr is computed as pa + len, where len is
the number of bytes the caller asked to read, not the length of the
attribute. Any read shorter than the run list offset (0x40 for an
unnamed $DATA attribute) therefore fails with "run offset out of range",
even on a valid file system.

Most readers go through bufio and request larger blocks, so they are not
affected. Unbuffered small reads are: "file --is-hibernated-hiberfil"
reads 4 bytes and so always returns false for hiberfil.sys on a real
Windows installation, where the file is non-resident.

Use the attribute length from the attribute header instead. The existing
check against at->end still keeps the run list inside the MFT record
buffer.

Fixes: 8c95307a0 (fs/ntfs: Correct possible access violations)
Signed-off-by: YuziO2 <[email protected]>
---
Tested on x86_64-efi in QEMU/OVMF with a full build of master (this patch
on top of b07cc37ca, default -Werror), against a small NTFS volume holding
non-resident files:

                                         before    after
  file --is-hibernated-hiberfil (HIBR)   false*    true
  source of a 2 KiB config file          ok        ok
  loadfont of a pf2 font                 ok        ok
  background_image of a PNG              ok        ok

  * error: ../../grub-core/fs/ntfs.c:read_data:722:run offset out of range.

The same before/after results were obtained with GRUB 2.14.

On real hardware, a 4 KiB read of the non-resident, 13 GB hiberfil.sys of
a hibernated Windows installation returns the HIBR signature.

 grub-core/fs/ntfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
index bb3cec4e6..986adc44d 100644
--- a/grub-core/fs/ntfs.c
+++ b/grub-core/fs/ntfs.c
@@ -683,7 +683,7 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, 
grub_uint8_t *dest,
           grub_disk_read_hook_t read_hook, void *read_hook_data)
 {
   struct grub_ntfs_rlst cc, *ctx;
-  grub_uint8_t *end_ptr = (pa + len);
+  grub_uint8_t *end_ptr = pa + u32at (pa, 4);
   grub_uint16_t run_offset;
 
   if (len == 0)

base-commit: b07cc37ca64fe99260884e7325abc333374e098b
-- 
2.55.0


_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to