[PATCH] mm/slub: initialize allocated object's freepointer before debug check

hu.shengming@zte.com.cn posted 1 patch 1 month, 2 weeks ago
mm/slub.c | 9 +++++++++
1 file changed, 9 insertions(+)
[PATCH] mm/slub: initialize allocated object's freepointer before debug check
Posted by hu.shengming@zte.com.cn 1 month, 2 weeks ago
From: Shengming Hu <hu.shengming@zte.com.cn>

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@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202604301428.e2b8d3dd-lkp@intel.com
Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
---
 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.
+	 */
+	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
Re: [PATCH] mm/slub: initialize allocated object's freepointer before debug check
Posted by Harry Yoo (Oracle) 1 month, 2 weeks ago
On Thu, Apr 30, 2026 at 04:35:04PM +0800, hu.shengming@zte.com.cn wrote:
> From: Shengming Hu <hu.shengming@zte.com.cn>
> 
> 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@intel.com>
> Closes: https://lore.kernel.org/oe-lkp/202604301428.e2b8d3dd-lkp@intel.com
> Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
> ---

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)

>  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!

> +	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
Re: [PATCH] mm/slub: initialize allocated object's freepointer before debug check
Posted by hu.shengming@zte.com.cn 1 month, 2 weeks ago
Harry wrote:
> On Thu, Apr 30, 2026 at 04:35:04PM +0800, hu.shengming@zte.com.cn wrote:
> > From: Shengming Hu <hu.shengming@zte.com.cn>
> >
> > 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@intel.com>
> > Closes: https://lore.kernel.org/oe-lkp/202604301428.e2b8d3dd-lkp@intel.com
> > Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
> > ---
>
> 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