From: yangerkun yangerkun@huawei.com
hulk inclusion category: bugfix bugzilla: 176007 CVE: NA ---------------------------
jbd2_journal_put_journal_head protect jh with jbd_lock_bh_journal_head. jbd2_journal_forget protect jh with jbd_lock_bh_state. This two function can happen parallel, and this can lead the follow bug:
[ 1140.658593] kasan: GPF could be caused by NULL-ptr deref or user memory access ... [ 1140.660011] general protection fault: 0000 [#1] SMP KASAN ... [ 1140.664723] RIP: 0010:__jbd2_journal_remove_checkpoint+0x7b/0x6a0 [ 1140.683008] Call Trace: [ 1140.683570] jbd2_journal_forget+0x564/0x840 [ 1140.684348] jbd2_journal_revoke+0x248/0x5b0 [ 1140.685101] __ext4_forget+0x341/0x5d0 [ 1140.685802] ext4_free_blocks+0x1233/0x1970 [ 1140.692235] ext4_ext_remove_space+0x1aaf/0x34b0 [ 1140.694614] ext4_ext_truncate+0x192/0x1e0 [ 1140.695320] ext4_truncate+0xad0/0x1020 [ 1140.698187] ext4_evict_inode+0xac6/0x15c0 [ 1140.700377] evict+0x2f6/0x650 [ 1140.701586] iput+0x3aa/0x740 [ 1140.702084] dentry_unlink_inode+0x2ff/0x3b0 [ 1140.702799] d_delete+0x1dd/0x240 [ 1140.703366] vfs_rmdir+0x2d5/0x430 [ 1140.703933] do_rmdir+0x2e1/0x380 [ 1140.705848] do_syscall_64+0xbd/0x3d0 [ 1140.707384] entry_SYSCALL_64_after_hwframe+0x44/0xa9
Fix it by grab jh in jbd2_journal_forget, and put it at the end of jbd2_journal_forget.
It is a part for 464170647b56 ("jbd2: Make state lock a spinlock").
Signed-off-by: yangerkun yangerkun@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/jbd2/transaction.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 3ac205eff7fb5..f56be34564e74 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1580,11 +1580,13 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
BUFFER_TRACE(bh, "entry");
- jbd_lock_bh_state(bh); + jh = jbd2_journal_grab_journal_head(bh); + if (!jh) { + __bforget(bh); + return 0; + }
- if (!buffer_jbd(bh)) - goto not_jbd; - jh = bh2jh(bh); + jbd_lock_bh_state(bh);
/* Critical error: attempting to delete a bitmap buffer, maybe? * Don't do any jbd operations, and return an error. */ @@ -1704,18 +1706,14 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) spin_unlock(&journal->j_list_lock); } drop: - jbd_unlock_bh_state(bh); __brelse(bh); + jbd_unlock_bh_state(bh); + jbd2_journal_put_journal_head(jh); if (drop_reserve) { /* no need to reserve log space for this block -bzzz */ handle->h_total_credits++; } return err; - -not_jbd: - jbd_unlock_bh_state(bh); - __bforget(bh); - goto drop; }
/**