Hi Geert, On Tue, May 19, 2026 at 2:55 PM Geert Uytterhoeven <[email protected]> wrote: > > Hi Prabhakar, > > On Tue, 19 May 2026 at 15:44, Lad, Prabhakar <[email protected]> > wrote: > > On Tue, May 19, 2026 at 2:34 PM Geert Uytterhoeven <[email protected]> > > wrote: > > > On Tue, 19 May 2026 at 15:30, Prabhakar <[email protected]> > > > wrote: > > > > From: Lad Prabhakar <[email protected]> > > > > > > > > Fix an counter tracking in mmc_test_alloc_mem() that causes a kernel > > > > panic > > > > during error unwinding. > > > > > > > > The `struct mmc_test_mem` uses the `__counted_by(cnt)` annotation on its > > > > flexible array member `arr`. While kzalloc_flex() initially sets the > > > > counter field (`cnt`) to `max_segs`, the allocation loop needs to track > > > > how many elements have actually been populated. > > > > > > > > Previously, leaving `mem->cnt` at `max_segs` meant that if the loop > > > > failed > > > > midway (e.g., "Failed to map sg list"), the error unwinding path in > > > > mmc_test_free_mem() would attempt to clean up uninitialized trailing > > > > array slots. This resulted in passing NULL pointers to __free_pages(), > > > > triggering a kernel panic: > > > > > > > > [ 66.172845] mmc0: Failed to map sg list > > > > [ 66.176722] Unable to handle kernel NULL pointer dereference at > > > > virtual address 0000000000000000 > > > > ... > > > > [ 66.432747] Call trace: > > > > [ 66.435191] ___free_pages+0x1c/0xc4 (P) > > > > [ 66.439119] __free_pages+0x14/0x20 > > > > [ 66.442608] mmc_test_area_cleanup+0x58/0x84 [mmc_test] > > > > > > > > Fix this by explicitly resetting `mem->cnt` to 0 immediately after > > > > allocation. Then, move the existing `mem->cnt` increment so that it > > > > occurs > > > > prior to populating each array slot, using `mem->cnt - 1` for the actual > > > > assignment index. This guarantees that the counter accurately tracks > > > > initialized entries for safe error cleanup, while dynamically expanding > > > > the `__counted_by` validation boundary ahead of each flexible array > > > > write. > > > > > > > > Additionally, rewrite the cleanup loop in mmc_test_free_mem() to use a > > > > standard forward for-loop. This addresses the unsafe post-decrement > > > > logic > > > > in the original `while (mem->cnt--)` loop which evaluated and > > > > decremented > > > > the counter field before indexing the array, and avoids a potential > > > > integer > > > > underflow/wrap-around of the counter field if the cleanup path is > > > > invoked > > > > when `mem->cnt` is 0. > > > > > > > > Fixes: c3126dccfd7b ("mmc: mmc_test: use kzalloc_flex") > > > > Signed-off-by: Lad Prabhakar <[email protected]> > > > > --- > > > > v1->v2: > > > > - Started with cnt = 0 and incremented before assignment to ensure > > > > accurate tracking of initialized entries in mmc_test_alloc_mem(). > > > > - In mmc_test_free_mem(), replaced the while loop with a forward > > > > for-loop to > > > > safely iterate over initialized entries without risking underflow. > > > > - Updated commit message to clarify the issue and the fix. > > > > > > Thanks for your patch! > > > > > > > --- a/drivers/mmc/core/mmc_test.c > > > > +++ b/drivers/mmc/core/mmc_test.c > > > > @@ -318,9 +318,8 @@ static void mmc_test_free_mem(struct mmc_test_mem > > > > *mem) > > > > { > > > > if (!mem) > > > > return; > > > > - while (mem->cnt--) > > > > - __free_pages(mem->arr[mem->cnt].page, > > > > - mem->arr[mem->cnt].order); > > > > + for (unsigned int i = 0; i < mem->cnt; i++) > > > > + __free_pages(mem->arr[i].page, mem->arr[i].order); > > > > kfree(mem); > > > > } > > > > > > > > @@ -356,6 +355,7 @@ static struct mmc_test_mem > > > > *mmc_test_alloc_mem(unsigned long min_sz, > > > > mem = kzalloc_flex(*mem, arr, max_segs); > > > > if (!mem) > > > > return NULL; > > > > + mem->cnt = 0; > > > > > > This is not needed, as it is set to zero by kzalloc_flex(). > > > > > Actually, kzalloc_flex() automatically sets mem->cnt to max_segs > > because cnt is annotated with __counted_by. Because of that implicit > > initialization, we need this explicit reset to get it back to zero. > > Only when your compiler supports it[1]. > > OMG... > > When I commented on the LWN.net article[2], I considered only the case > where the compiler is too old, and the counter stays at zero when the > user forgets to initialize it explicitly. Now we have the opposite > case, where we need the counter to stay at zero :-( > Yeah, it definitely introduces some tricky, asymmetrical behavior depending on the toolchain.
Cheers, Prabhakar > [1] > https://elixir.bootlin.com/linux/v7.0.9/source/include/linux/compiler_types.h#L549 > [2] https://lwn.net/Articles/1063295/ > > Gr{oetje,eeting}s, > > Geert > > -- > Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- > [email protected] > > In personal conversations with technical people, I call myself a hacker. But > when I'm talking to journalists I just say "programmer" or something like > that. > -- Linus Torvalds

