Re: [PATCH] fs: aio: reject partial mremap to avoid Null-pointer-dereference error

Jan Kara <[email protected]> Sat, 18 Apr 2026 13:36:28 +0200
Newsgroups gmane.linux.kernel.aio.general,gmane.linux.file-systems,gmane.linux.kernel
Message-ID <5cjnsfdi4ztbocdpmsb57tswekn6g72op2khwvdl24nq6uaovt@zfsvt5mouetq>
On Sat 18-04-26 14:06:34, Zizhi Wo wrote:
> From: Zizhi Wo <[email protected]>
> 
> [BUG]
> Recently, our internal syzkaller testing uncovered a null pointer
> dereference issue:
> BUG: kernel NULL pointer dereference, address: 0000000000000000
> ...
> [   51.111664]  filemap_read_folio+0x25/0xe0
> [   51.112410]  filemap_fault+0xad7/0x1250
> [   51.113112]  __do_fault+0x4b/0x460
> [   51.113699]  do_pte_missing+0x5bc/0x1db0
> [   51.114250]  ? __pte_offset_map+0x23/0x170
> [   51.114822]  __handle_mm_fault+0x9f8/0x1680
> ...
> Crash analysis showed the file involved was an AIO ring file. The
> phenomenon triggered is the same as the issue described in [1].
> 
> [CAUSE]
> Consider the following scenario: userspace sets up an AIO context via
> io_setup(), which creates a VMA covering the entire ring buffer. Then
> userspace calls mremap() with the AIO ring address as the source, a smaller
> old_len (less than the full ring size), MREMAP_MAYMOVE set, and without
> MREMAP_DONTUNMAP. The kernel will relocate the requested portion to a new
> destination address.
> 
> During this move, __split_vma() splits the original AIO ring VMA. The
> requested portion is unmapped from the source and re-established at the
> destination, while the remainder stays at the original source address as
> an orphan VMA. The aio_ring_mremap() callback fires on the new destination
> VMA, updating ctx->mmap_base to the destination address. But the callback
> is unaware that only a partial region was moved and that an orphan VMA
> still exists at the source:
> 
>   source(AIO):
>   +-------------------+---------------------+
>   |  moved to dest    |  orphan VMA (AIO)   |
>   +-------------------+---------------------+
>   A                 A+partial_len        A+ctx->mmap_size
> 
>   dest:
>   +-------------------+
>   |  moved VMA (AIO)  |
>   +-------------------+
>   B                 B+partial_len
> 
> Later, io_destroy() calls vm_munmap(ctx->mmap_base, ctx->mmap_size), which
> unmaps the destination. This not only fails to unmap the orphan VMA at the
> source, but also overshoots the destination VMA and may unmap unrelated
> mappings adjacent to it! After put_aio_ring_file() calls truncate_setsize()
> to remove all pages from the pagecache, any subsequent access to the orphan
> VMA triggers filemap_fault(), which calls a_ops->read_folio(). Since aio
> does not implement read_folio, this results in a NULL pointer dereference.
> 
> [FIX]
> Note that expanding mremap (new_len > old_len) is already rejected because
> AIO ring VMAs are created with VM_DONTEXPAND. The only problematic case is
> a partial move where "old_len == new_len" but both are smaller than the
> full ring size.
> 
> Fix this by checking in aio_ring_mremap() that the new VMA covers the
> entire ring. This ensures the AIO ring is always moved as a whole,
> preventing orphan VMAs and the subsequent crash.
> 
> [1]: https://lore.kernel.org/all/[email protected]/
> 
> Signed-off-by: Zizhi Wo <[email protected]>

Looks good! Thanks! Feel free to add:

Reviewed-by: Jan Kara <[email protected]>

								Honza

> ---
>  fs/aio.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/aio.c b/fs/aio.c
> index a07bdd1aaaa6..48d049ff5267 100644
> --- a/fs/aio.c
> +++ b/fs/aio.c
> @@ -369,7 +369,8 @@ static int aio_ring_mremap(struct vm_area_struct *vma)
>  
>  		ctx = rcu_dereference(table->table[i]);
>  		if (ctx && ctx->aio_ring_file == file) {
> -			if (!atomic_read(&ctx->dead)) {
> +			if (!atomic_read(&ctx->dead) &&
> +			    (ctx->mmap_size == (vma->vm_end - vma->vm_start))) {
>  				ctx->user_id = ctx->mmap_base = vma->vm_start;
>  				res = 0;
>  			}
> -- 
> 2.39.2
> 
-- 
Jan Kara <[email protected]>
SUSE Labs, CR

--
To unsubscribe, send a message with 'unsubscribe linux-aio' in
the body to [email protected].  For more info on Linux AIO,
see: http://www.kvack.org/aio/
Don't email: <a href=mailto:"[email protected]">[email protected]</a>