Re: [PATCH] mm/slub: initialize allocated object's freepointer before debug check
From: hu.shengming
Date: Thu Apr 30 2026 - 05:32:00 EST
Harry wrote:
> On Thu, Apr 30, 2026 at 04:35:04PM +0800, hu.shengming@xxxxxxxxxx wrote:
> > From: Shengming Hu <hu.shengming@xxxxxxxxxx>
> >
> > The deferred-freelist path allocates the first object from a fresh slab
> > before building the freelist for the remaining objects. Unlike the old
> > path, the selected object is no longer the head of a pre-built freelist,
> > so its freepointer remains uninitialized.
> >
> > alloc_debug_processing() still checks its freepointer. As a result,
> > boot can report:
> >
> > BUG kmem_cache (Tainted: G B W T ): Freepointer corrupt
> >
> > Restore the old invariant by storing a valid freepointer in the selected
> > object before alloc_debug_processing() runs. The pointer is the head of
> > the leftover freelist, matching what the old pre-built freelist path
> > would have left in the allocated object.
> >
> > Fixes: 895272864130 ("mm/slub: defer freelist construction until after bulk allocation from a new slab")
> > Reported-by: kernel test robot <oliver.sang@xxxxxxxxx>
> > Closes: https://lore.kernel.org/oe-lkp/202604301428.e2b8d3dd-lkp@xxxxxxxxx
> > Signed-off-by: Shengming Hu <hu.shengming@xxxxxxxxxx>
> > ---
>
> When the patch did not land the mainline yet (torvalds/linux), we don't
> create a separate fix patch because commiting a broken patch and then
> adding a fix for that creates unnecessary history. We can avoid that
> as it did not land yet.
>
> Could you please send a v8 of the original patch?
>
> In that case no need for Reported-by: Fixes: Closes: tag.
> (But a Link: to the thread would be still nice to add)
>
OK, I will proceed with sending v8 of the original patch and
include a Link: to the discussion thread.
> > mm/slub.c | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/mm/slub.c b/mm/slub.c
> > index f96bac36229c..af942753d495 100644
> > --- a/mm/slub.c
> > +++ b/mm/slub.c
> > @@ -3690,6 +3690,15 @@ static void *alloc_single_from_new_slab(struct kmem_cache *s, struct slab *slab,
> > needs_add_partial = (slab->objects > 1);
> > build_slab_freelist(s, slab, &iter);
> >
> > + /*
> > + * alloc_debug_processing() still checks @object as a free object
> > + * before returning it to the caller. Since @object was emitted
> > + * directly from a fresh slab and skipped by build_slab_freelist(), give
> > + * it the same next pointer it would have had in the old prebuilt
> > + * freelist path.
> > + */
>
> This is probably too long ;)
>
> I think one line (something like e.g.,
> "/* alloc_debug_processing() always expects a valid free pointer */")
> should be enough (and some detail can be included in the changelog
> instead)
>
> I was thinking the FP would be NULL but either way looks fine to me.
>
> Thanks for addressing it!
>
I agree with your suggestion to simplify it. ;-)
Thanks again for the helpful feedback!
> > + set_freepointer(s, object, slab->freelist);
> > +
> > if (!alloc_debug_processing(s, slab, object, orig_size)) {
> > /*
> > * It's not really expected that this would fail on a
> > --
> > 2.25.1
>
> --
> Cheers,
> Harry / Hyeonggon
--
With Best Regards,
Shengming