Re: [PATCH] bcache: Fix a NULL or wild pointer dereference in btree_split

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> 2023年2月2日 19:05,Zheng Wang <zyytlz.wz@xxxxxxx> 写道:
> 
> In btree_split, btree_node_alloc_replacement() is assigned to
> n1 and return error code or NULL on failure. n1->c->cache is
> passed to block_bytes. So there is a dereference of it
> without checks, which may lead to wild pointer dereference or
>  NULL pointer dereference depending on n1. The initial code only
>  judge the error code but igore the NULL pointer.
> So does n2 and n3.
> 
> Fix this bug by adding IS_ERR_OR_NULL check of n1, n2 and n3.
> 
> Note that, as a bug found by static analysis, it can be a false
> positive or hard to trigger.
> 
> Fixes: cafe56359144 ("bcache: A block layer cache")
> Signed-off-by: Zheng Wang <zyytlz.wz@xxxxxxx>

Hmm, there should be something to be fixed, but not the non-exist NULL dereference.

If you look inside btree_node_alloc_replacement(), you may find __bch_btree_node_alloc() which does the real work indeed. And yes, I would suggest you to improve a bit inside __bch_btree_node_alloc().

1088 struct btree *__bch_btree_node_alloc(struct cache_set *c, struct btree_op *op,
[snipped]
1093         struct btree *b = ERR_PTR(-EAGAIN);
1094
1095         mutex_lock(&c->bucket_lock);
1096 retry:
1097         if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, wait))
1098                 goto err;
[snipped]
1102
1103         b = mca_alloc(c, op, &k.key, level);
1104         if (IS_ERR(b))
1105                 goto err_free;
1106
1107         if (!b) {
1108                 cache_bug(c,
1109                         "Tried to allocate bucket that was in btree cache");
1110                 goto retry;
1111         }
1112

>From the above code, at line 1097 if __bch_bucket_alloc_set() returns non-zero value, the code will jump to label err: and returns ERR_PTR(-EAGAIN). But if the code fails at line 1103 and b is set to NULL, at line 1110 the code will jump back to label retry: and calls __bch_bucket_alloc_set() again. If the second time __bch_bucket_alloc_set() returns non-zero value and the code jumps to label err:, a NULL pointer other than ERR_PTR(-EAGAIN) will be returned. This inconsistent return value on same location at line 1097 seems incorrect, where ERR_PTR(-EAGAIN) should be returned IMHO.

Therefore I feel that “b = ERR_PTR(-EAGAIN)” should be moved to the location after label retry:, then btree_node_alloc_replacement() will only return error code, and no NULL pointer returned.

After this change, all following IS_ERR_OR_NULL() checks to btree_node_alloc_replacement() are unnecessary and IS_ERR() just enough, because no NULL will be returned.

This is a nice catch. I’d like to have it to be fixed. I do appreciate if you want to compose two patches for the fix. Otherwise I can handle it myself.

Thanks.

Coly Li


> ---
> drivers/md/bcache/btree.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
> index 147c493a989a..d5ed382fc43c 100644
> --- a/drivers/md/bcache/btree.c
> +++ b/drivers/md/bcache/btree.c
> @@ -2206,7 +2206,7 @@ static int btree_split(struct btree *b, struct btree_op *op,
> }
> 
> n1 = btree_node_alloc_replacement(b, op);
> - if (IS_ERR(n1))
> + if (IS_ERR_OR_NULL(n1))
> goto err;
> 
> split = set_blocks(btree_bset_first(n1),
> @@ -2218,12 +2218,12 @@ static int btree_split(struct btree *b, struct btree_op *op,
> trace_bcache_btree_node_split(b, btree_bset_first(n1)->keys);
> 
> n2 = bch_btree_node_alloc(b->c, op, b->level, b->parent);
> - if (IS_ERR(n2))
> + if (IS_ERR_OR_NULL(n2))
> goto err_free1;
> 
> if (!b->parent) {
> n3 = bch_btree_node_alloc(b->c, op, b->level + 1, NULL);
> - if (IS_ERR(n3))
> + if (IS_ERR_OR_NULL(n3))
> goto err_free2;
> }
> 
> -- 
> 2.25.1
> 





[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux ARM Kernel]     [Linux Filesystem Development]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux