public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: syzbot <syzbot+6986a30df88382d1f7bf@syzkaller.appspotmail.com>
To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com
Subject: Forwarded: [PATCH] ext4: add validation and bounds checking in ext4_read_inline_data()
Date: Mon, 12 Jan 2026 22:43:12 -0800	[thread overview]
Message-ID: <6965e980.050a0220.3be5c5.000f.GAE@google.com> (raw)
In-Reply-To: <6965a06e.050a0220.38aacd.0005.GAE@google.com>

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ext4: add validation and bounds checking in ext4_read_inline_data()
Author: kartikey406@gmail.com

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master

Add comprehensive validation and bounds checking to prevent use-after-free
and out-of-bounds read vulnerabilities in ext4_read_inline_data().

The function previously trusted that:
1. The iloc buffer_head remained valid throughout execution
2. The xattr entry's e_value_offs pointed within valid inode bounds

This led to two critical vulnerabilities:

1. Use-after-free: The iloc->bh buffer could be freed by another thread
   between ext4_get_inode_loc() and ext4_read_inline_data(), causing
   reads from freed memory.

2. Out-of-bounds read: A corrupted or malicious filesystem image could
   set e_value_offs to point outside the inode's xattr area, causing
   reads beyond valid memory bounds.

This patch adds validation to:
- Check iloc and iloc->bh are non-NULL
- Verify buffer is still uptodate
- Validate xattr entry pointer is within inode bounds
- Bounds-check e_value_offs against xattr area size
- Ensure the final memcpy source and length stay within valid memory

Additionally, comprehensive debug logging has been added to aid in
diagnosing similar issues in the future.

The fix prevents both memory safety issues by catching invalid states
before the vulnerable memcpy operation at line 228.

Reported-by: syzbot+6986a30df88382d1f7bf@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6986a30df88382d1f7bf
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/ext4/inline.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 1f6bc05593df..f807598e96c9 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -188,16 +188,44 @@ static int ext4_read_inline_data(struct inode *inode, void *buffer,
 	struct ext4_xattr_ibody_header *header;
 	int cp_len = 0;
 	struct ext4_inode *raw_inode;
+	void *xattr_start, *xattr_end;
+	u32 value_offs;
+	void *source;
 
 	if (!len)
 		return 0;
 
+	printk(KERN_ERR "ext4_read_inline_data: START - inode=%lu, len=%u\n",
+	       inode->i_ino, len);
+
+	/* VALIDATION 1: Check iloc and buffer validity */
+	if (!iloc) {
+		printk(KERN_ERR "ext4_read_inline_data: ERROR - iloc is NULL\n");
+		return -EFSCORRUPTED;
+	}
+
+	if (!iloc->bh) {
+		printk(KERN_ERR "ext4_read_inline_data: ERROR - iloc->bh is NULL\n");
+		return -EFSCORRUPTED;
+	}
+
+	printk(KERN_ERR "ext4_read_inline_data: iloc->bh=%px, refcount=%d\n",
+	       iloc->bh, atomic_read(&iloc->bh->b_count));
+
+	if (!buffer_uptodate(iloc->bh)) {
+		printk(KERN_ERR "ext4_read_inline_data: ERROR - buffer not uptodate\n");
+		return -EIO;
+	}
+
 	BUG_ON(len > EXT4_I(inode)->i_inline_size);
 
 	cp_len = min_t(unsigned int, len, EXT4_MIN_INLINE_DATA_SIZE);
 
 	raw_inode = ext4_raw_inode(iloc);
+	printk(KERN_ERR "ext4_read_inline_data: raw_inode=%px\n", raw_inode);
+
 	memcpy(buffer, (void *)(raw_inode->i_block), cp_len);
+	printk(KERN_ERR "ext4_read_inline_data: copied %d bytes from i_block\n", cp_len);
 
 	len -= cp_len;
 	buffer += cp_len;
@@ -208,17 +236,77 @@ static int ext4_read_inline_data(struct inode *inode, void *buffer,
 	header = IHDR(inode, raw_inode);
 	entry = (struct ext4_xattr_entry *)((void *)raw_inode +
 					    EXT4_I(inode)->i_inline_off);
+
+	printk(KERN_ERR "ext4_read_inline_data: header=%px, entry=%px, i_inline_off=%u\n",
+	       header, entry, EXT4_I(inode)->i_inline_off);
+
+	/* VALIDATION 2: Calculate and check bounds */
+	xattr_start = (void *)IFIRST(header);
+	xattr_end = (void *)raw_inode + EXT4_INODE_SIZE(inode->i_sb);
+
+	printk(KERN_ERR "ext4_read_inline_data: BOUNDS - xattr_start=%px, xattr_end=%px, size=%ld\n",
+	       xattr_start, xattr_end, (long)(xattr_end - xattr_start));
+
+	/* VALIDATION 3: Check entry pointer is within inode */
+	if ((void *)entry < (void *)raw_inode || (void *)entry >= xattr_end) {
+		printk(KERN_ERR "ext4_read_inline_data: ERROR - entry %px outside inode bounds [%px-%px]\n",
+		       entry, raw_inode, xattr_end);
+		ext4_error_inode(inode, __func__, __LINE__, 0,
+				 "xattr entry outside inode bounds");
+		return -EFSCORRUPTED;
+	}
+
+	/* VALIDATION 4: Check e_value_offs */
+	value_offs = le16_to_cpu(entry->e_value_offs);
+	printk(KERN_ERR "ext4_read_inline_data: e_value_offs=%u, e_value_size=%u\n",
+	       value_offs, le32_to_cpu(entry->e_value_size));
+
+	if (value_offs > (xattr_end - xattr_start)) {
+		printk(KERN_ERR "ext4_read_inline_data: ERROR - value_offs %u exceeds xattr bounds %ld\n",
+		       value_offs, (long)(xattr_end - xattr_start));
+		ext4_error_inode(inode, __func__, __LINE__, 0,
+				 "corrupt xattr offset: %u", value_offs);
+		return -EFSCORRUPTED;
+	}
+
 	len = min_t(unsigned int, len,
 		    (unsigned int)le32_to_cpu(entry->e_value_size));
 
-	memcpy(buffer,
-	       (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs), len);
+	/* VALIDATION 5: Check final read bounds */
+	source = xattr_start + value_offs;
+
+	printk(KERN_ERR "ext4_read_inline_data: FINAL CHECK - source=%px, len=%u, end=%px\n",
+	       source, len, source + len);
+
+	if (source < (void *)raw_inode) {
+		printk(KERN_ERR "ext4_read_inline_data: ERROR - source %px before inode start %px\n",
+		       source, raw_inode);
+		return -EFSCORRUPTED;
+	}
+
+	if ((source + len) > xattr_end) {
+		printk(KERN_ERR "ext4_read_inline_data: ERROR - read [%px-%px] exceeds inode end %px\n",
+		       source, source + len, xattr_end);
+		ext4_error_inode(inode, __func__, __LINE__, 0,
+				 "xattr read exceeds inode bounds");
+		return -EFSCORRUPTED;
+	}
+
+	printk(KERN_ERR "ext4_read_inline_data: ABOUT TO MEMCPY - source=%px, dest=%px, len=%u\n",
+	       source, buffer, len);
+
+	memcpy(buffer, source, len);
+
+	printk(KERN_ERR "ext4_read_inline_data: memcpy SUCCESS\n");
+
 	cp_len += len;
 
 out:
+	printk(KERN_ERR "ext4_read_inline_data: DONE - copied %d bytes total\n", cp_len);
 	return cp_len;
 }
 
+
 /*
  * write the buffer to the inline inode.
  * If 'create' is set, we don't need to do the extra copy in the xattr
-- 
2.43.0


  reply	other threads:[~2026-01-13  6:43 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-13  1:31 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_read_inline_data syzbot
2026-01-13  6:43 ` syzbot [this message]
2026-01-13 13:05 ` Forwarded: [PATCH] ext4: hold buffer reference in ext4_read_inline_dir to prevent UAF syzbot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6965e980.050a0220.3be5c5.000f.GAE@google.com \
    --to=syzbot+6986a30df88382d1f7bf@syzkaller.appspotmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=syzkaller-bugs@googlegroups.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox