From: "Darrick J. Wong" <djwong@kernel.org>
To: Ahmet Eray Karadag <eraykrdg1@gmail.com>
Cc: tytso@mit.edu, adilger.kernel@dilger.ca,
linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org,
syzbot+0be4f339a8218d2a5bb1@syzkaller.appspotmail.com,
Albin Babu Varghese <albinbabuvarghese20@gmail.com>
Subject: Re: [PATCH v2] Fix: ext4: guard against EA inode refcount underflow in xattr update
Date: Tue, 23 Sep 2025 16:39:34 -0700 [thread overview]
Message-ID: <20250923233934.GJ8084@frogsfrogsfrogs> (raw)
In-Reply-To: <20250920021342.45575-1-eraykrdg1@gmail.com>
On Sat, Sep 20, 2025 at 05:13:43AM +0300, Ahmet Eray Karadag wrote:
> syzkaller found a path where ext4_xattr_inode_update_ref() reads an EA
> inode refcount that is already <= 0 and then applies ref_change (often
> -1). That lets the refcount underflow and we proceed with a bogus value,
> triggering errors like:
>
> EXT4-fs error: EA inode <n> ref underflow: ref_count=-1 ref_change=-1
> EXT4-fs warning: ea_inode dec ref err=-117
>
> Make the invariant explicit: if the current refcount is non-positive,
> treat this as on-disk corruption, emit ext4_error_inode(), and fail the
> operation with -EFSCORRUPTED instead of updating the refcount. Delete the
> WARN_ONCE() as negative refcounts are now impossible; keep error reporting
> in ext4_error_inode().
>
> This prevents the underflow and the follow-on orphan/cleanup churn.
>
> Reported-by: syzbot+0be4f339a8218d2a5bb1@syzkaller.appspotmail.com
> Fixes: https://syzbot.org/bug?extid=0be4f339a8218d2a5bb1
> Co-developed-by: Albin Babu Varghese <albinbabuvarghese20@gmail.com>
> Signed-off-by: Albin Babu Varghese <albinbabuvarghese20@gmail.com>
> Signed-off-by: Ahmet Eray Karadag <eraykrdg1@gmail.com>
> ---
> v2:
> - Move underflow guard before the update
> - Add overflow guard for the opposite case
> - Use u64 type instead s64, since ext4_xattr_inode_update_ref() returns u64 and ext4_xattr_inode_set_ref() expects u64.
>
> ---
> fs/ext4/xattr.c | 15 ++++++++-------
> 1 file changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
> index 5a6fe1513fd2..a510693e04ac 100644
> --- a/fs/ext4/xattr.c
> +++ b/fs/ext4/xattr.c
> @@ -1019,7 +1019,7 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
> int ref_change)
> {
> struct ext4_iloc iloc;
> - s64 ref_count;
> + u64 ref_count;
> int ret;
>
> inode_lock_nested(ea_inode, I_MUTEX_XATTR);
> @@ -1029,13 +1029,17 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
> goto out;
>
> ref_count = ext4_xattr_inode_get_ref(ea_inode);
> + if ((ref_count == 0 && ref_change < 0) || (ref_count == U64_MAX && ref_change > 0)) {
/me wonders if you could use check_add_overflow for this, but otherwise
everthing looks fine to me...
> + ext4_error_inode(ea_inode, __func__, __LINE__, 0,
> + "EA inode %lu ref wraparound: ref_count=%lld ref_change=%d",
Nit: %llu since ref_count is now unsigned.
> + ea_inode->i_ino, ref_count, ref_change);
> + ret = -EFSCORRUPTED;
> + goto out;
> + }
> ref_count += ref_change;
> ext4_xattr_inode_set_ref(ea_inode, ref_count);
>
> if (ref_change > 0) {
> - WARN_ONCE(ref_count <= 0, "EA inode %lu ref_count=%lld",
> - ea_inode->i_ino, ref_count);
> -
> if (ref_count == 1) {
> WARN_ONCE(ea_inode->i_nlink, "EA inode %lu i_nlink=%u",
> ea_inode->i_ino, ea_inode->i_nlink);
...though while you're modifying the precondition checking here, I think
these i_nlink preconditions should also be hoisted to the top and cause
an EFSCORRUPTED return on bad inputs.
--D
> @@ -1044,9 +1048,6 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
> ext4_orphan_del(handle, ea_inode);
> }
> } else {
> - WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld",
> - ea_inode->i_ino, ref_count);
> -
> if (ref_count == 0) {
> WARN_ONCE(ea_inode->i_nlink != 1,
> "EA inode %lu i_nlink=%u",
> --
> 2.34.1
>
>
next prev parent reply other threads:[~2025-09-23 23:39 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-18 17:55 [PATCH] Fix: ext4: guard against EA inode refcount underflow in xattr update Ahmet Eray Karadag
2025-09-18 18:18 ` Darrick J. Wong
2025-09-19 14:45 ` Theodore Ts'o
2025-09-20 2:13 ` [PATCH v2] " Ahmet Eray Karadag
2025-09-23 23:39 ` Darrick J. Wong [this message]
2025-09-24 22:53 ` Albin Babu Varghese
2025-09-26 21:47 ` Theodore Ts'o
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=20250923233934.GJ8084@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=adilger.kernel@dilger.ca \
--cc=albinbabuvarghese20@gmail.com \
--cc=eraykrdg1@gmail.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=syzbot+0be4f339a8218d2a5bb1@syzkaller.appspotmail.com \
--cc=tytso@mit.edu \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.