mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH RESEND] fs/ntfs3: fix out-of-bounds read in the index root ops of do_action()
@ 2026-09-29 20:41 Stanley Shen
  0 siblings, 0 replies; only message in thread
From: Stanley Shen @ 2026-09-29 20:41 UTC (permalink / raw)
  To: Konstantin Komarov; +Cc: ntfs3, linux-kernel

The five index root redo handlers in do_action() (AddIndexEntryRoot,
DeleteIndexEntryRoot, SetIndexEntryVcnRoot, UpdateFileNameRoot and
UpdateRecordDataRoot) read the index root before anything has validated
the offset the attribute was derived from:

	root = resident_data(attr);
	hdr = &root->ihdr;
	used = le32_to_cpu(hdr->used);

	if (!check_if_index_root(rec, lrh) ||
	    !check_if_root_index(attr, hdr, lrh)) {

attr is Add2Ptr(rec, le16_to_cpu(lrh->record_off)) and rec is the
record_size-sized buffer allocated in mi_init(), while record_off comes
verbatim from the on-disk log record header. check_if_index_root() is
what bounds it, by walking the attribute chain from rec->attr_off (which
check_file_record() has already validated) and accepting record_off only
when it is the offset of an ATTR_ROOT of that chain. Until it has run,
both the attr->res.data_off read inside resident_data() and the hdr->used
read that follows can land outside the allocation; record_off and
data_off are both __le16, so a crafted log record can push the access
almost 128K past a 1K or 4K record.

Once check_if_index_root() has passed, check_attr() has already bounded
the attribute and its resident data inside the record, so run it first in
all five handlers. check_if_root_index() needs hdr and stays put.

Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Assisted-by: LLM
Signed-off-by: Stanley Shen <stanleyshen1886@gmail.com>
---
 fs/ntfs3/fslog.c | 39 +++++++++++++++++++++++++--------------
 1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c
index ed50c1d0c23..c7c2b477643 100644
--- a/fs/ntfs3/fslog.c
+++ b/fs/ntfs3/fslog.c
@@ -3471,12 +3471,19 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
 	case AddIndexEntryRoot:
 		e = (struct NTFS_DE *)data;
 		esize = le16_to_cpu(e->size);
+
+		/*
+		 * check_if_index_root() is what validates lrh->record_off, so
+		 * it has to run before attr is dereferenced.
+		 */
+		if (!check_if_index_root(rec, lrh))
+			goto dirty_vol;
+
 		root = resident_data(attr);
 		hdr = &root->ihdr;
 		used = le32_to_cpu(hdr->used);
 
-		if (!check_if_index_root(rec, lrh) ||
-		    !check_if_root_index(attr, hdr, lrh) ||
+		if (!check_if_root_index(attr, hdr, lrh) ||
 		    Add2Ptr(data, esize) > Add2Ptr(lrh, rec_len) ||
 		    esize > le32_to_cpu(rec->total) - le32_to_cpu(rec->used)) {
 			goto dirty_vol;
@@ -3498,14 +3505,15 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
 		break;
 
 	case DeleteIndexEntryRoot:
+		if (!check_if_index_root(rec, lrh))
+			goto dirty_vol;
+
 		root = resident_data(attr);
 		hdr = &root->ihdr;
 		used = le32_to_cpu(hdr->used);
 
-		if (!check_if_index_root(rec, lrh) ||
-		    !check_if_root_index(attr, hdr, lrh)) {
+		if (!check_if_root_index(attr, hdr, lrh))
 			goto dirty_vol;
-		}
 
 		e1 = Add2Ptr(attr, le16_to_cpu(lrh->attr_off));
 		esize = le16_to_cpu(e1->size);
@@ -3526,13 +3534,14 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
 		break;
 
 	case SetIndexEntryVcnRoot:
+		if (!check_if_index_root(rec, lrh))
+			goto dirty_vol;
+
 		root = resident_data(attr);
 		hdr = &root->ihdr;
 
-		if (!check_if_index_root(rec, lrh) ||
-		    !check_if_root_index(attr, hdr, lrh)) {
+		if (!check_if_root_index(attr, hdr, lrh))
 			goto dirty_vol;
-		}
 
 		e = Add2Ptr(attr, le16_to_cpu(lrh->attr_off));
 
@@ -3541,13 +3550,14 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
 		break;
 
 	case UpdateFileNameRoot:
+		if (!check_if_index_root(rec, lrh))
+			goto dirty_vol;
+
 		root = resident_data(attr);
 		hdr = &root->ihdr;
 
-		if (!check_if_index_root(rec, lrh) ||
-		    !check_if_root_index(attr, hdr, lrh)) {
+		if (!check_if_root_index(attr, hdr, lrh))
 			goto dirty_vol;
-		}
 
 		e = Add2Ptr(attr, le16_to_cpu(lrh->attr_off));
 		fname = (struct ATTR_FILE_NAME *)(e + 1);
@@ -3556,13 +3566,14 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
 		break;
 
 	case UpdateRecordDataRoot:
+		if (!check_if_index_root(rec, lrh))
+			goto dirty_vol;
+
 		root = resident_data(attr);
 		hdr = &root->ihdr;
 
-		if (!check_if_index_root(rec, lrh) ||
-		    !check_if_root_index(attr, hdr, lrh)) {
+		if (!check_if_root_index(attr, hdr, lrh))
 			goto dirty_vol;
-		}
 
 		e = Add2Ptr(attr, le16_to_cpu(lrh->attr_off));
 
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-29 20:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-29 20:41 [PATCH RESEND] fs/ntfs3: fix out-of-bounds read in the index root ops of do_action() Stanley Shen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®