[PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()

Li Wang posted 1 patch 1 month, 3 weeks ago
fs/fuse/dev_uring.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
[PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()
Posted by Li Wang 1 month, 3 weeks ago
A kernel NULL pointer dereference was triggered when testing the
'fuse over io_uring' feature with passthrough_ll. The call trace
is as follows:
  BUG: kernel NULL pointer dereference, address: 0000000000000878
  RIP: 0010:fuse_uring_add_req_to_ring_ent+0x89/0xd0 [fuse]
  Call Trace:
  <TASK>
  fuse_uring_queue_fuse_req+0x82/0x100 [fuse]
  fuse_chan_send+0xe6/0x180 [fuse]
  fuse_lookup_name+0x131/0x2b0 [fuse]
  fuse_lookup+0x78/0x1a0 [fuse]
  fuse_atomic_open+0xfc/0x140 [fuse]
  atomic_open+0x4b/0xf0
  path_openat+0x746/0x1080
  do_file_open+0xc9/0x180

fuse_uring_create_queue() must initialize struct fuse_pqueue before assigning
the per-hash processing table:

- Call fuse_pqueue_init() before setting fpq.processing. fuse_pqueue_init()
  clears fpq.processing; assigning the kcalloc'd bucket array must happen
  afterwards.

- After allocating the processing bucket array with kzalloc_objs(), initialize
  each list head with INIT_LIST_HEAD(), matching fuse_pqueue_alloc() in dev.c.
  Zeroed list_head values are not valid empty lists; list_move_tail() would
  dereference NULL prev/next.

Signed-off-by: Li Wang <liwang@kylinos.cn>
---
 fs/fuse/dev_uring.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
index d6d75e024b35..b765c1ff5e2d 100644
--- a/fs/fuse/dev_uring.c
+++ b/fs/fuse/dev_uring.c
@@ -282,6 +282,8 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
 		kfree(queue);
 		return NULL;
 	}
+	for (int i = 0; i < FUSE_PQ_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&pq[i]);
 
 	queue->qid = qid;
 	queue->ring = ring;
@@ -295,8 +297,8 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
 	INIT_LIST_HEAD(&queue->fuse_req_bg_queue);
 	INIT_LIST_HEAD(&queue->ent_released);
 
-	queue->fpq.processing = pq;
 	fuse_pqueue_init(&queue->fpq);
+	queue->fpq.processing = pq;
 
 	spin_lock(&fch->lock);
 	if (ring->queues[qid]) {
-- 
2.34.1
Re: [PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()
Posted by Joanne Koong 1 month, 3 weeks ago
On Wed, Apr 22, 2026 at 3:38 AM Li Wang <liwang@kylinos.cn> wrote:
>
> A kernel NULL pointer dereference was triggered when testing the
> 'fuse over io_uring' feature with passthrough_ll. The call trace
> is as follows:
>   BUG: kernel NULL pointer dereference, address: 0000000000000878
>   RIP: 0010:fuse_uring_add_req_to_ring_ent+0x89/0xd0 [fuse]
>   Call Trace:
>   <TASK>
>   fuse_uring_queue_fuse_req+0x82/0x100 [fuse]
>   fuse_chan_send+0xe6/0x180 [fuse]
>   fuse_lookup_name+0x131/0x2b0 [fuse]
>   fuse_lookup+0x78/0x1a0 [fuse]
>   fuse_atomic_open+0xfc/0x140 [fuse]
>   atomic_open+0x4b/0xf0
>   path_openat+0x746/0x1080
>   do_file_open+0xc9/0x180
>
> fuse_uring_create_queue() must initialize struct fuse_pqueue before assigning
> the per-hash processing table:
>
> - Call fuse_pqueue_init() before setting fpq.processing. fuse_pqueue_init()
>   clears fpq.processing; assigning the kcalloc'd bucket array must happen
>   afterwards.
>
> - After allocating the processing bucket array with kzalloc_objs(), initialize
>   each list head with INIT_LIST_HEAD(), matching fuse_pqueue_alloc() in dev.c.
>   Zeroed list_head values are not valid empty lists; list_move_tail() would
>   dereference NULL prev/next.
>
> Signed-off-by: Li Wang <liwang@kylinos.cn>
> ---
>  fs/fuse/dev_uring.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
> index d6d75e024b35..b765c1ff5e2d 100644
> --- a/fs/fuse/dev_uring.c
> +++ b/fs/fuse/dev_uring.c
> @@ -282,6 +282,8 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
>                 kfree(queue);
>                 return NULL;
>         }
> +       for (int i = 0; i < FUSE_PQ_HASH_SIZE; i++)
> +               INIT_LIST_HEAD(&pq[i]);
>
>         queue->qid = qid;
>         queue->ring = ring;
> @@ -295,8 +297,8 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
>         INIT_LIST_HEAD(&queue->fuse_req_bg_queue);
>         INIT_LIST_HEAD(&queue->ent_released);
>
> -       queue->fpq.processing = pq;
>         fuse_pqueue_init(&queue->fpq);
> +       queue->fpq.processing = pq;
>
>         spin_lock(&fch->lock);
>         if (ring->queues[qid]) {
> --
> 2.34.1
>

Thanks for testing/reporting this! This lgtm but afaict, the patches
in that patchset aren't finalized yet so imo it'd be cleaner if this
gets folded into the original patch [1] instead of being its own
separate commit.

I think using fuse_pqueue_alloc() ends up being a tad bit cleaner, eg

diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
index 5abf447e9710..e467b23e6895 100644
--- a/fs/fuse/dev_uring.c
+++ b/fs/fuse/dev_uring.c
@@ -277,7 +277,7 @@ static struct fuse_ring_queue
*fuse_uring_create_queue(struct fuse_ring *ring,
        queue = kzalloc_obj(*queue, GFP_KERNEL_ACCOUNT);
        if (!queue)
                return NULL;
-       pq = kzalloc_objs(struct list_head, FUSE_PQ_HASH_SIZE);
+       pq = fuse_pqueue_alloc();
        if (!pq) {
                kfree(queue);
                return NULL;
@@ -295,8 +295,8 @@ static struct fuse_ring_queue
*fuse_uring_create_queue(struct fuse_ring *ring,
        INIT_LIST_HEAD(&queue->fuse_req_bg_queue);
        INIT_LIST_HEAD(&queue->ent_released);

-       queue->fpq.processing = pq;
        fuse_pqueue_init(&queue->fpq);
+       queue->fpq.processing = pq;

after exporting fuse_pqueue_alloc() into fuse_dev_i.h

Thanks,
Joanne

[1] https://lore.kernel.org/fuse-devel/20260416091658.462783-32-mszeredi@redhat.com/
Re: [PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()
Posted by Li Wang 1 month, 3 weeks ago
Hi Joanne,

On 23/04/2026 03:18, Joanne Koong wrote:

> 
> Thanks for testing/reporting this! This lgtm but afaict, the patches
> in that patchset aren't finalized yet so imo it'd be cleaner if this
> gets folded into the original patch [1] instead of being its own
> separate commit.
> 
> I think using fuse_pqueue_alloc() ends up being a tad bit cleaner
> 

Thanks for the feedback. I'm fine with either way (fold or split), 
and I will follow your suggestions and send out a v2.

Thanks,
Li

> diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
> index 5abf447e9710..e467b23e6895 100644
> --- a/fs/fuse/dev_uring.c
> +++ b/fs/fuse/dev_uring.c
> @@ -277,7 +277,7 @@ static struct fuse_ring_queue
> *fuse_uring_create_queue(struct fuse_ring *ring,
>         queue = kzalloc_obj(*queue, GFP_KERNEL_ACCOUNT);
>         if (!queue)
>                 return NULL;
> -       pq = kzalloc_objs(struct list_head, FUSE_PQ_HASH_SIZE);
> +       pq = fuse_pqueue_alloc();
>         if (!pq) {
>                 kfree(queue);
>                 return NULL;
> @@ -295,8 +295,8 @@ static struct fuse_ring_queue
> *fuse_uring_create_queue(struct fuse_ring *ring,
>         INIT_LIST_HEAD(&queue->fuse_req_bg_queue);
>         INIT_LIST_HEAD(&queue->ent_released);
> 
> -       queue->fpq.processing = pq;
>         fuse_pqueue_init(&queue->fpq);
> +       queue->fpq.processing = pq;
> 
> after exporting fuse_pqueue_alloc() into fuse_dev_i.h
> 
> Thanks,
> Joanne
> 
> [1] https://lore.kernel.org/fuse-devel/20260416091658.462783-32-mszeredi@redhat.com/
Re: [PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()
Posted by Miklos Szeredi 1 month, 3 weeks ago
On Thu, 23 Apr 2026 at 08:45, Li Wang <liwang@kylinos.cn> wrote:

> > diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
> > index 5abf447e9710..e467b23e6895 100644
> > --- a/fs/fuse/dev_uring.c
> > +++ b/fs/fuse/dev_uring.c
> > @@ -277,7 +277,7 @@ static struct fuse_ring_queue
> > *fuse_uring_create_queue(struct fuse_ring *ring,
> >         queue = kzalloc_obj(*queue, GFP_KERNEL_ACCOUNT);
> >         if (!queue)
> >                 return NULL;
> > -       pq = kzalloc_objs(struct list_head, FUSE_PQ_HASH_SIZE);
> > +       pq = fuse_pqueue_alloc();
> >         if (!pq) {
> >                 kfree(queue);
> >                 return NULL;
> > @@ -295,8 +295,8 @@ static struct fuse_ring_queue
> > *fuse_uring_create_queue(struct fuse_ring *ring,
> >         INIT_LIST_HEAD(&queue->fuse_req_bg_queue);
> >         INIT_LIST_HEAD(&queue->ent_released);
> >
> > -       queue->fpq.processing = pq;
> >         fuse_pqueue_init(&queue->fpq);
> > +       queue->fpq.processing = pq;
> >
> > after exporting fuse_pqueue_alloc() into fuse_dev_i.h

Folded.

Thanks,
Miklos
Re: [PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()
Posted by Bernd Schubert 1 month, 3 weeks ago

On 4/22/26 12:36, Li Wang wrote:
> A kernel NULL pointer dereference was triggered when testing the
> 'fuse over io_uring' feature with passthrough_ll. The call trace
> is as follows:
>   BUG: kernel NULL pointer dereference, address: 0000000000000878
>   RIP: 0010:fuse_uring_add_req_to_ring_ent+0x89/0xd0 [fuse]
>   Call Trace:
>   <TASK>
>   fuse_uring_queue_fuse_req+0x82/0x100 [fuse]
>   fuse_chan_send+0xe6/0x180 [fuse]

Is this linux-next?

>   fuse_lookup_name+0x131/0x2b0 [fuse]
>   fuse_lookup+0x78/0x1a0 [fuse]
>   fuse_atomic_open+0xfc/0x140 [fuse]
>   atomic_open+0x4b/0xf0
>   path_openat+0x746/0x1080
>   do_file_open+0xc9/0x180
> 
> fuse_uring_create_queue() must initialize struct fuse_pqueue before assigning
> the per-hash processing table:
> 
> - Call fuse_pqueue_init() before setting fpq.processing. fuse_pqueue_init()
>   clears fpq.processing; assigning the kcalloc'd bucket array must happen
>   afterwards.
> 
> - After allocating the processing bucket array with kzalloc_objs(), initialize
>   each list head with INIT_LIST_HEAD(), matching fuse_pqueue_alloc() in dev.c.
>   Zeroed list_head values are not valid empty lists; list_move_tail() would
>   dereference NULL prev/next.
> 
> Signed-off-by: Li Wang <liwang@kylinos.cn>
> ---
>  fs/fuse/dev_uring.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
> index d6d75e024b35..b765c1ff5e2d 100644
> --- a/fs/fuse/dev_uring.c
> +++ b/fs/fuse/dev_uring.c
> @@ -282,6 +282,8 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
>  		kfree(queue);
>  		return NULL;
>  	}
> +	for (int i = 0; i < FUSE_PQ_HASH_SIZE; i++)
> +		INIT_LIST_HEAD(&pq[i]);
>  
>  	queue->qid = qid;
>  	queue->ring = ring;
> @@ -295,8 +297,8 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring,
>  	INIT_LIST_HEAD(&queue->fuse_req_bg_queue);
>  	INIT_LIST_HEAD(&queue->ent_released);
>  
> -	queue->fpq.processing = pq;
>  	fuse_pqueue_init(&queue->fpq);
> +	queue->fpq.processing = pq;
>  
>  	spin_lock(&fch->lock);
>  	if (ring->queues[qid]) {

I don't think this patch is right. The existing order is

	queue = kzalloc_obj(*queue, GFP_KERNEL_ACCOUNT);
	pq = kzalloc_objs(struct list_head, FUSE_PQ_HASH_SIZE);
	queue->fpq.processing = pq;
	fuse_pqueue_init(&queue->fpq); =====> INIT_LIST_HEAD() of pg


I need to look at Miklos' patches, I guess it sends to fuse-io-uring,
although that is not ready yet.


Thanks,
Bernd
Re: [PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()
Posted by Li Wang 1 month, 3 weeks ago
Hi Bernd,

On 22/04/2026 19:39, Bernd Schubert wrote:
> 
> I don't think this patch is right. The existing order is
> 
> 	queue = kzalloc_obj(*queue, GFP_KERNEL_ACCOUNT);
> 	pq = kzalloc_objs(struct list_head, FUSE_PQ_HASH_SIZE);
> 	queue->fpq.processing = pq;
> 	fuse_pqueue_init(&queue->fpq); =====> INIT_LIST_HEAD() of pg
> 
> 
> I need to look at Miklos' patches, I guess it sends to fuse-io-uring,
> although that is not ready yet.
> 
> 
> Thanks,
> Bernd

The test is based on 
git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git#for-next
It seems the code ordering has been changed.

Thanks,
Li
Re: [PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()
Posted by Jingbo Xu 1 month, 3 weeks ago

On 4/22/26 6:36 PM, Li Wang wrote:
> A kernel NULL pointer dereference was triggered when testing the
> 'fuse over io_uring' feature with passthrough_ll. The call trace
> is as follows:
>   BUG: kernel NULL pointer dereference, address: 0000000000000878
>   RIP: 0010:fuse_uring_add_req_to_ring_ent+0x89/0xd0 [fuse]
>   Call Trace:
>   <TASK>
>   fuse_uring_queue_fuse_req+0x82/0x100 [fuse]
>   fuse_chan_send+0xe6/0x180 [fuse]

I don't see fuse_chan_send() in upstream kernel.  I think you are
testing kernel with this patchset[1] applied?

[1] https://lore.kernel.org/all/20260416091658.462783-1-mszeredi@redhat.com/

-- 
Thanks,
Jingbo
Re: [PATCH] fuse: fix kernel NULL pointer dereference in fuse_uring_add_to_pq()
Posted by Li Wang 1 month, 3 weeks ago
Hi Jingbo,

On 22/04/2026 19:18, Jingbo Xu wrote:
> 
> 
> On 4/22/26 6:36 PM, Li Wang wrote:
>> A kernel NULL pointer dereference was triggered when testing the
>> 'fuse over io_uring' feature with passthrough_ll. The call trace
>> is as follows:
>>   BUG: kernel NULL pointer dereference, address: 0000000000000878
>>   RIP: 0010:fuse_uring_add_req_to_ring_ent+0x89/0xd0 [fuse]
>>   Call Trace:
>>   <TASK>
>>   fuse_uring_queue_fuse_req+0x82/0x100 [fuse]
>>   fuse_chan_send+0xe6/0x180 [fuse]
> 
> I don't see fuse_chan_send() in upstream kernel.  I think you are
> testing kernel with this patchset[1] applied?
> 
> [1] https://lore.kernel.org/all/20260416091658.462783-1-mszeredi@redhat.com/
> 

The test is based on 
git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git#for-next

Thanks,
Li