Re: [PATCH v5 08/29] md/md-llbitmap: prevent create failure bitmap UAF

[email protected] Sun, 02 Aug 2026 20:39:14 +0000
Newsgroups gmane.linux.raid
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(=
s) to consider:

Pre-existing issues:
- [High] Early publication of `mddev->bitmap` in `llbitmap_create()` races =
with lockless deferred IO (unplug callbacks), leading to UAF or NULL pointe=
r dereference.
- [Medium] Improper cleanup sequence in `llbitmap_read_sb()`: `__free_page(=
)` is called before `kunmap_local()`.
--

--- Patch [8]: [PATCH v5 08/29] md/md-llbitmap: prevent create failure bitm=
ap UAF ---
commit f0da60fcfbc2742e91e414951699e4a59d581559
Author: Yu Kuai <[email protected]>

md/md-llbitmap: prevent create failure bitmap UAF

llbitmap_create() publishes mddev->bitmap before reading the bitmap
superblock. If llbitmap_read_sb() fails, the old cleanup dropped
bitmap_info.mutex and freed llbitmap before clearing mddev->bitmap. This
commit clears mddev->bitmap while still holding the mutex.

> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
> index 948bf64c5ad24..af80a630bd21a 100644
> --- a/drivers/md/md-llbitmap.c
> +++ b/drivers/md/md-llbitmap.c
> @@ -1126,10 +1126,11 @@ static int llbitmap_create(struct mddev *mddev)
>  	mutex_lock(&mddev->bitmap_info.mutex);
>  	mddev->bitmap =3D llbitmap;
>  	ret =3D llbitmap_read_sb(llbitmap);

[Severity: Medium]
This is a pre-existing issue, but is the cleanup sequence in
llbitmap_read_sb() correct when returning an error?

When llbitmap_read_sb() encounters an error, it jumps to out_put_page
and calls __free_page() before kunmap_local():

drivers/md/md-llbitmap.c:llbitmap_read_sb() {
    ...
out_put_page:
    __free_page(sb_page);
    kunmap_local(sb);
    return ret;
}

Does calling __free_page() before kunmap_local() violate the kmap_local API
contract and potentially cause memory debugging warnings?

> +	if (ret)
> +		mddev->bitmap =3D NULL;
>  	mutex_unlock(&mddev->bitmap_info.mutex);

[Severity: High]
This is a pre-existing issue, but does publishing and clearing mddev->bitmap
here still leave a race with lockless deferred IO?

If mddev->bitmap is set to NULL on failure, but mddev->bitmap_ops is still
active, a concurrent unplug callback executing locklessly might trigger a
NULL pointer dereference.

For example, if a user task unplugs and calls raid1_prepare_flush_writes(),
it can execute mddev->bitmap_ops->unplug() locklessly. llbitmap_unplug()
unconditionally reads mddev->bitmap and passes it to llbitmap_dirty():

drivers/md/md-llbitmap.c:llbitmap_unplug() {
    struct llbitmap *llbitmap =3D mddev->bitmap;
    if (!llbitmap_dirty(llbitmap))
        return;
    ...
}

Can llbitmap_unplug() crash if it observes the NULL bitmap?

Also, if llbitmap_unplug() runs during llbitmap_cache_pages(), can it
observe llbitmap->nr_pages being set before the llbitmap->pctl[i]
pointers are initialized, leading to a NULL dereference in
llbitmap_dirty() when it accesses llbitmap->pctl[i]->flags?

drivers/md/md-llbitmap.c:llbitmap_cache_pages() {
    ...
    llbitmap->nr_pages =3D nr_pages;
    for (i =3D 0; i < nr_pages; i++, pctl =3D (void *)pctl + size) {
        struct page *page =3D llbitmap_read_page(llbitmap, i);
        llbitmap->pctl[i] =3D pctl;
        ...
}

>  	if (ret) {
>  		kfree(llbitmap);
> -		mddev->bitmap =3D NULL;
>  	}
> =20
>  	return ret;

--=20
Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260802195038.1642=
[email protected]?part=3D8