ocfs2: fix kernel BUG in ocfs2_find_victim_chain
Subsystems (2)
PATCH v2 1/1 ocfs2: fix kernel BUG in ocfs2_find_victim_chain
syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the cl_next_free_rec field of the allocation chain list is 0, triggring the BUG_ON(!cl->cl_next_free_rec) condition and panicking the kernel.
To fix this, cl_next_free_rec is checked inside the caller of ocfs2_find_victim_chain() i.e. ocfs2_claim_suballoc_bits() and if it is equal to 0, ocfs2_error() is called, to log the corruption and force the filesystem into read-only mode, to prevent further damage.
---v1->v2:
- Remove extra line before the if statement in patch
- Add upper limit check for cl->cl_next_free_rec in the if condition
fs/ocfs2/suballoc.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/ocfs2/suballoc.c +7 -0
@@ -1992,6 +1992,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, } cl = (struct ocfs2_chain_list *) &fe->id2.i_chain; +if (!le16_to_cpu (cl->cl_next_free_rec) || +le16_to_cpu (cl->cl_next_free_rec) >le16_to_cpu (cl->cl_count)) { + status =ocfs2_error (ac->ac_inode->i_sb, +"Chain allocator dinode %llu has 0 chains\n" , + (unsigned long long )le64_to_cpu (fe->i_blkno)); + goto bail; + } victim =ocfs2_find_victim_chain (cl); ac->ac_chain = victim;
base-commit: 939f15e640f193616691d3bcde0089760e75b0d3
Signature · 1 line
2.34.1
Joseph Qi
maintainerQuoted 27 lines · Prithvi Tambewagh
syzbot reported a kernel BUG in
ocfs2_find_victim_chain()because thecl_next_free_recfield of the allocation chain list is 0, triggring theBUG_ON(!cl->cl_next_free_rec)condition and panicking the kernel.To fix this,
cl_next_free_recis checked inside the caller ofocfs2_find_victim_chain()i.e.ocfs2_claim_suballoc_bits()and if it is equal to 0,ocfs2_error()is called, to log the corruption and force the filesystem into read-only mode, to prevent further damage.Reported-by [email protected]Tested-by [email protected]Signed-off-by Prithvi Tambewagh <[email protected]>---
v1->v2:
- Remove extra line before the if statement in patch
- Add upper limit check forcl->cl_next_free_recin the if conditionfs/ocfs2/suballoc.c | 7 +++++++ 1 file changed, 7 insertions(+)fs/ocfs2/suballoc.c +0
-0
fs/ocfs2/suballoc.c static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, · line 1998
Quoted 7 lines
fs/ocfs2/suballoc.c +4
-0@@ -1992,6 +1992,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, } cl = (struct ocfs2_chain_list *) &fe->id2.i_chain; +if (!le16_to_cpu (cl->cl_next_free_rec) || +le16_to_cpu (cl->cl_next_free_rec) >le16_to_cpu (cl->cl_count)) { + status = ocfs2_error(ac->ac_inode->i_sb, + "Chain allocator dinode %llu has 0 chains\n",
The log message also has to be updateed. How about:
if (!le16_to_cpu(cl->cl_next_free_rec) ||
le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)) {
status = ocfs2_error(ac->ac_inode->i_sb,
"Chain allocator dinode %llu has invalid next "
"free chain record %u, but only %u total\n",
(unsigned long long)le64_to_cpu(fe->i_blkno),
le16_to_cpu(cl->cl_next_free_rec),
le16_to_cpu(cl->cl_count));Joseph
Quoted 8 lines
fs/ocfs2/suballoc.c +3
-0+ (unsigned long long)le64_to_cpu(fe->i_blkno)); + goto bail; + } victim =ocfs2_find_victim_chain (cl); ac->ac_chain = victim;base-commit:
939f15e640f193616691d3bcde0089760e75b0d3
Quoted 32 lines · Joseph Qi
Quoted 29 lines · Prithvi Tambewagh
syzbot reported a kernel BUG in
ocfs2_find_victim_chain()because thecl_next_free_recfield of the allocation chain list is 0, triggring theBUG_ON(!cl->cl_next_free_rec)condition and panicking the kernel.To fix this,
cl_next_free_recis checked inside the caller ofocfs2_find_victim_chain()i.e.ocfs2_claim_suballoc_bits()and if it is equal to 0,ocfs2_error()is called, to log the corruption and force the filesystem into read-only mode, to prevent further damage.Reported-by [email protected]Tested-by [email protected]Signed-off-by Prithvi Tambewagh <[email protected]>---
v1->v2:
- Remove extra line before the if statement in patch
- Add upper limit check forcl->cl_next_free_recin the if conditionfs/ocfs2/suballoc.c | 7 +++++++ 1 file changed, 7 insertions(+)fs/ocfs2/suballoc.c +0
-0@@ -1992,6 +1992,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, }
Quoted 7 lines
fs/ocfs2/suballoc.c static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, · line 1998
Quoted 5 lines
fs/ocfs2/suballoc.c +4
-0cl = (struct ocfs2_chain_list *) &fe->id2.i_chain; +if (!le16_to_cpu (cl->cl_next_free_rec) || +le16_to_cpu (cl->cl_next_free_rec) >le16_to_cpu (cl->cl_count)) { + status = ocfs2_error(ac->ac_inode->i_sb, + "Chain allocator dinode %llu has 0 chains\n",The log message also has to be updateed. How about:
Apologies for the mistake. I will rectify it.
Quoted 9 lines
if (!le16_to_cpu(cl->cl_next_free_rec) ||
le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)) { status = ocfs2_error(ac->ac_inode->i_sb, "Chain allocator dinode %llu has invalid next " "free chain record %u, but only %u total\n", (unsigned long long)le64_to_cpu(fe->i_blkno), le16_to_cpu(cl->cl_next_free_rec), le16_to_cpu(cl->cl_count));
Thanks for the feedback! I will make v3 for the patch with these suggested changes.
Quoted 12 lines
Joseph
Quoted 8 lines
fs/ocfs2/suballoc.c +3
-0+ (unsigned long long)le64_to_cpu(fe->i_blkno)); + goto bail; + } victim =ocfs2_find_victim_chain (cl); ac->ac_chain = victim;base-commit:
939f15e640f193616691d3bcde0089760e75b0d3
Best Regards,
Prithvi