From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ot1-f71.google.com (mail-ot1-f71.google.com [209.85.210.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D1DD3DDDAA for ; Mon, 4 May 2026 23:52:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.71 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777938747; cv=none; b=PXjJ8cDmYdjFKUYy7zx2Q7iOuoyjRWDfjWck6wUZtES8dRBYf4Jx2AIBVHvgdhRZ7h8j9N1L4u09sO2ktyD1fbBZrfF1uUhDiGpUgR+b9fZRMQUt1d/XznF1VEMnEr2ze0NdsrVbGySO3QQNrvgG1JHttZ8+zDbf0isLjjuEGu0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777938747; c=relaxed/simple; bh=f3xviEpOIPiTQYD6qkLGpNDqaK46q1DpZEppWhpPzAo=; h=MIME-Version:Date:In-Reply-To:Message-ID:Subject:From:To: Content-Type; b=IZWhOJVg4TT0WvKsq3QFcy3bDEyivkHmEVQJGRPbbv8kRpLXjRoa9Cbb21rJsnNDu+O7RpvrlBuTn7gQ70tVNSO3EZfI9kImrEYG35i4LoU/A5F5OdkPu+ZcMDSJixFM2ya14tz1FUZtZh8YHxGPQr8VDMQpQ4oAriWpZVA/hQ4= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com; arc=none smtp.client-ip=209.85.210.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com Received: by mail-ot1-f71.google.com with SMTP id 46e09a7af769-7dbe0e914adso7772128a34.2 for ; Mon, 04 May 2026 16:52:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777938744; x=1778543544; h=to:from:subject:message-id:in-reply-to:date:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mRWaEOAsa06V69VgZb/5H3cJVU1SR9TcDrDktiOFxv8=; b=U+TygJZBWoQwb9/+q9I01PFjFs5mgmuHyBXPL9IEFehHYl8B9MVeucJIQySmKJxd4v 54f3b2KX3rpkwnc6bCTJ6wUNnI4B4ynCeC8en38hlda8O9/7SSREQsPy2kK5afO/PWQF tQmH14UjNKsdobAgFrPvsiAzlJXvjQT1N/lIMrtjJ057RKNKrIElDiJ7K7hKYea4+kbG xYnK4aZzAj5Wjd+AjKszJhG1S6GKIW3JZdEv0nQxK6VIhl6L0cBCT0WmUCU3e6MH0fQ0 zijptCqy7S4kBTRDh59N8k9Nfv17AeV9mwBQrpxln14e4sVITrrHyi9vKphSWzKhVLoN wd3Q== X-Gm-Message-State: AOJu0YzCXbrH78zNhRmwExGLFME9NJoEd7xj3yATurBhmACQeLVqj5tF FJ95/VJjvjIUmMn5GTSD49XJAUGQAobuPfjSL/qidpYyvA/qOylzXnwbdJK4cPjidSvOchxF85n TjTY01SckyEon4ca1NHmcDdqhqZPeIlPEuKJNiMkOgcWSexanB50Nkx9mlvg= Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Received: by 2002:a05:6820:4b85:b0:694:a362:4b86 with SMTP id 006d021491bc7-696979ec1b6mr5928190eaf.22.1777938744540; Mon, 04 May 2026 16:52:24 -0700 (PDT) Date: Mon, 04 May 2026 16:52:24 -0700 In-Reply-To: <69f91d55.170a0220.bb392.000b.GAE@google.com> X-Google-Appengine-App-Id: s~syzkaller X-Google-Appengine-App-Id-Alias: syzkaller Message-ID: <69f93138.050a0220.892e9.00de.GAE@google.com> Subject: Forwarded: [PATCH] jbd2: check for aborted handle in jbd2_journal_dirty_metadata() From: syzbot To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com Content-Type: text/plain; charset="UTF-8" For archival purposes, forwarding an incoming command email to linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com. *** Subject: [PATCH] jbd2: check for aborted handle in jbd2_journal_dirty_metadata() Author: kartikey406@gmail.com #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master jbd2_journal_dirty_metadata() unconditionally dereferences handle->h_transaction at function entry to obtain the journal pointer: transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; However, h_transaction may legitimately be NULL for an aborted handle. The is_handle_aborted() helper in include/linux/jbd2.h explicitly treats !h_transaction as one of the aborted states: if (handle->h_aborted || !handle->h_transaction) return 1; Every other entry point in fs/jbd2/transaction.c (jbd2_journal_get_{write,undo,create}_access, jbd2_journal_extend, jbd2_journal_restart, jbd2_journal_stop, etc.) guards against this with an is_handle_aborted() check before any dereference of h_transaction. jbd2_journal_dirty_metadata() was missing this guard. This is reachable from ocfs2's xattr code. ocfs2_xa_set() intentionally falls through to ocfs2_xa_journal_dirty() even after ocfs2_xa_prepare_entry() fails, on the assumption that the buffer needs to be journaled to record any partial modifications (see the comment above the out_dirty label in fs/ocfs2/xattr.c). If the failure was caused by the journal being aborted -- e.g. an underlying I/O error during a sub-operation such as __ocfs2_remove_xattr_range() -- the handle's h_transaction has been cleared by the abort path, and the unconditional deref in jbd2_journal_dirty_metadata() becomes a NULL deref. Reproduced by syzbot with a crafted ocfs2 image where I/O against the loop device backing the mount is sabotaged via LOOP_SET_STATUS64 between two setxattr() calls, causing the second setxattr (which truncates an external xattr value) to abort the journal mid-flight: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000 KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: jbd2_journal_dirty_metadata+0x4a/0xd30 fs/jbd2/transaction.c:1520 Call Trace: ocfs2_journal_dirty+0x130/0x700 fs/ocfs2/journal.c:831 ocfs2_xa_journal_dirty fs/ocfs2/xattr.c:1483 [inline] ocfs2_xa_set+0x15e3/0x2ec0 fs/ocfs2/xattr.c:2294 ocfs2_xattr_block_set+0x3e0/0x33c0 fs/ocfs2/xattr.c:3016 __ocfs2_xattr_set_handle+0x6b3/0xf50 fs/ocfs2/xattr.c:3418 ocfs2_xattr_set+0xf3f/0x13e0 fs/ocfs2/xattr.c:3681 __vfs_setxattr+0x43c/0x480 fs/xattr.c:218 ... Fix by adding the standard is_handle_aborted() guard at the top of jbd2_journal_dirty_metadata() and returning -EROFS, matching the pattern used by every other entry point in this file. ocfs2_journal_dirty() already handles a non-zero return from jbd2_journal_dirty_metadata() correctly. Reported-by: syzbot+98f651460e558a21baae@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=98f651460e558a21baae Signed-off-by: Deepanshu Kartikey --- fs/jbd2/transaction.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 4885903bbd10..aa0be9e9c876 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1516,14 +1516,19 @@ void jbd2_buffer_abort_trigger(struct journal_head *jh, */ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) { - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; + transaction_t *transaction; + journal_t *journal; struct journal_head *jh; int ret = 0; + if (is_handle_aborted(handle)) + return -EROFS; if (!buffer_jbd(bh)) return -EUCLEAN; + transaction = handle->h_transaction; + journal = transaction->t_journal; + /* * We don't grab jh reference here since the buffer must be part * of the running transaction. -- 2.43.0