[PATCH] btrfs: add a sanity check for btrfs root

Lizhi Xu posted 1 patch 1 month ago
fs/btrfs/ctree.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
[PATCH] btrfs: add a sanity check for btrfs root
Posted by Lizhi Xu 1 month ago
Syzbot report a null-ptr-deref in btrfs_search_slot.
It use the input logical can't find the extent root in extent_from_logical,
and triger the null-ptr-deref in btrfs_search_slot.
Add sanity check for btrfs root before using it in btrfs_search_slot.

Reported-by: syzbot+3030e17bd57a73d39bd7@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=3030e17bd57a73d39bd7
Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com>
---
 fs/btrfs/ctree.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 0cc919d15b14..9c05cab473f5 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -2010,7 +2010,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		      const struct btrfs_key *key, struct btrfs_path *p,
 		      int ins_len, int cow)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
+	struct btrfs_fs_info *fs_info;
 	struct extent_buffer *b;
 	int slot;
 	int ret;
@@ -2023,6 +2023,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 	int min_write_lock_level;
 	int prev_cmp;
 
+	if (!root)
+		return -EINVAL;
+
+	fs_info = root->fs_info;
 	might_sleep();
 
 	lowest_level = p->lowest_level;
-- 
2.43.0
Re: [PATCH] btrfs: add a sanity check for btrfs root
Posted by Qu Wenruo 1 month ago

在 2024/10/25 15:25, Lizhi Xu 写道:
> Syzbot report a null-ptr-deref in btrfs_search_slot.
> It use the input logical can't find the extent root in extent_from_logical,
> and triger the null-ptr-deref in btrfs_search_slot.
> Add sanity check for btrfs root before using it in btrfs_search_slot.

Although I'd prefer to explain a little more about why the NULL root
pointer can happen (caused by the rescue=all mount option), which can
cause NULL root pointer for non-critical tree roots, like
uuid/csum/extent or even device trees.

You don't need to bother sending an update.
I can add such info when pushing to the maintainer's tree.

>
> Reported-by: syzbot+3030e17bd57a73d39bd7@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=3030e17bd57a73d39bd7
> Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com>

Reviewed-by: Qu Wenruo <wqu@suse.com>

Thanks,
Qu
> ---
>   fs/btrfs/ctree.c | 6 +++++-
>   1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index 0cc919d15b14..9c05cab473f5 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -2010,7 +2010,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
>   		      const struct btrfs_key *key, struct btrfs_path *p,
>   		      int ins_len, int cow)
>   {
> -	struct btrfs_fs_info *fs_info = root->fs_info;
> +	struct btrfs_fs_info *fs_info;
>   	struct extent_buffer *b;
>   	int slot;
>   	int ret;
> @@ -2023,6 +2023,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
>   	int min_write_lock_level;
>   	int prev_cmp;
>
> +	if (!root)
> +		return -EINVAL;
> +
> +	fs_info = root->fs_info;
>   	might_sleep();
>
>   	lowest_level = p->lowest_level;
Re: [PATCH] btrfs: add a sanity check for btrfs root
Posted by David Sterba 1 month ago
On Fri, Oct 25, 2024 at 08:23:07PM +1030, Qu Wenruo wrote:
> 
> 
> 在 2024/10/25 15:25, Lizhi Xu 写道:
> > Syzbot report a null-ptr-deref in btrfs_search_slot.
> > It use the input logical can't find the extent root in extent_from_logical,
> > and triger the null-ptr-deref in btrfs_search_slot.
> > Add sanity check for btrfs root before using it in btrfs_search_slot.
> 
> Although I'd prefer to explain a little more about why the NULL root
> pointer can happen (caused by the rescue=all mount option), which can
> cause NULL root pointer for non-critical tree roots, like
> uuid/csum/extent or even device trees.
> 
> You don't need to bother sending an update.
> I can add such info when pushing to the maintainer's tree.
> 
> >
> > Reported-by: syzbot+3030e17bd57a73d39bd7@syzkaller.appspotmail.com
> > Closes: https://syzkaller.appspot.com/bug?extid=3030e17bd57a73d39bd7
> > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com>
> 
> Reviewed-by: Qu Wenruo <wqu@suse.com>

> > @@ -2023,6 +2023,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
> >   	int min_write_lock_level;
> >   	int prev_cmp;
> >
> > +	if (!root)
> > +		return -EINVAL;

The function returns errors indirectly so it's not clear which could be
ultimately returned. I did a quick search over the calls starting in
btrfs_search_slot() and it seems that EINVAL is not used so we'd know if
it ends up in some error report. The ones I found: EAGAIN, EIO, EUCLEAN,
ENOMEM.
Re: [PATCH] btrfs: add a sanity check for btrfs root
Posted by Qu Wenruo 1 month ago

在 2024/10/26 04:33, David Sterba 写道:
> On Fri, Oct 25, 2024 at 08:23:07PM +1030, Qu Wenruo wrote:
>>
>>
>> 在 2024/10/25 15:25, Lizhi Xu 写道:
>>> Syzbot report a null-ptr-deref in btrfs_search_slot.
>>> It use the input logical can't find the extent root in extent_from_logical,
>>> and triger the null-ptr-deref in btrfs_search_slot.
>>> Add sanity check for btrfs root before using it in btrfs_search_slot.
>>
>> Although I'd prefer to explain a little more about why the NULL root
>> pointer can happen (caused by the rescue=all mount option), which can
>> cause NULL root pointer for non-critical tree roots, like
>> uuid/csum/extent or even device trees.
>>
>> You don't need to bother sending an update.
>> I can add such info when pushing to the maintainer's tree.
>>
>>>
>>> Reported-by: syzbot+3030e17bd57a73d39bd7@syzkaller.appspotmail.com
>>> Closes: https://syzkaller.appspot.com/bug?extid=3030e17bd57a73d39bd7
>>> Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com>
>>
>> Reviewed-by: Qu Wenruo <wqu@suse.com>
>
>>> @@ -2023,6 +2023,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
>>>    	int min_write_lock_level;
>>>    	int prev_cmp;
>>>
>>> +	if (!root)
>>> +		return -EINVAL;
>
> The function returns errors indirectly so it's not clear which could be
> ultimately returned. I did a quick search over the calls starting in
> btrfs_search_slot() and it seems that EINVAL is not used so we'd know if
> it ends up in some error report. The ones I found: EAGAIN, EIO, EUCLEAN,
> ENOMEM.
>

If you want, I can add extra (ratelimited though) error/warning message
for such cases.

Considering this is only possible for rescue=all cases, extra error
messages should be fine.

Or do you prefer some more rare return values?

Thanks,
Qu
Re: [PATCH] btrfs: add a sanity check for btrfs root
Posted by David Sterba 1 month ago
On Sat, Oct 26, 2024 at 07:33:59AM +1030, Qu Wenruo wrote:
> 
> 
> 在 2024/10/26 04:33, David Sterba 写道:
> > On Fri, Oct 25, 2024 at 08:23:07PM +1030, Qu Wenruo wrote:
> >>
> >>
> >> 在 2024/10/25 15:25, Lizhi Xu 写道:
> >>> Syzbot report a null-ptr-deref in btrfs_search_slot.
> >>> It use the input logical can't find the extent root in extent_from_logical,
> >>> and triger the null-ptr-deref in btrfs_search_slot.
> >>> Add sanity check for btrfs root before using it in btrfs_search_slot.
> >>
> >> Although I'd prefer to explain a little more about why the NULL root
> >> pointer can happen (caused by the rescue=all mount option), which can
> >> cause NULL root pointer for non-critical tree roots, like
> >> uuid/csum/extent or even device trees.
> >>
> >> You don't need to bother sending an update.
> >> I can add such info when pushing to the maintainer's tree.
> >>
> >>>
> >>> Reported-by: syzbot+3030e17bd57a73d39bd7@syzkaller.appspotmail.com
> >>> Closes: https://syzkaller.appspot.com/bug?extid=3030e17bd57a73d39bd7
> >>> Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com>
> >>
> >> Reviewed-by: Qu Wenruo <wqu@suse.com>
> >
> >>> @@ -2023,6 +2023,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
> >>>    	int min_write_lock_level;
> >>>    	int prev_cmp;
> >>>
> >>> +	if (!root)
> >>> +		return -EINVAL;
> >
> > The function returns errors indirectly so it's not clear which could be
> > ultimately returned. I did a quick search over the calls starting in
> > btrfs_search_slot() and it seems that EINVAL is not used so we'd know if
> > it ends up in some error report. The ones I found: EAGAIN, EIO, EUCLEAN,
> > ENOMEM.
> 
> If you want, I can add extra (ratelimited though) error/warning message
> for such cases.
> 
> Considering this is only possible for rescue=all cases, extra error
> messages should be fine.
> 
> Or do you prefer some more rare return values?

I haven't thought about printing a message, even with rate limiting it
could be noisy and I don't see what information would it bring to the
user, namely in combination with the rescue=all.

The error from search slot can bubble up from various functions, though
with the missing csum tree it's probably not that many. The only other
error code that's remotely relevant is ENOENT (no such entry), but this
is more suitable for entries in structures, not whole structures.

Even if we'd use some random error, the string for the error code would
be misleading. So let's keep EINVAL for now.