Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Prakash Gupta <prakash.gupta@oss.qualcomm.com>
To: Muchun Song <muchun.song@linux.dev>
Cc: Johannes Weiner <hannes@cmpxchg.org>,
	Michal Hocko <mhocko@kernel.org>,
	Roman Gushchin <roman.gushchin@linux.dev>,
	Shakeel Butt <shakeel.butt@linux.dev>,
	Andrew Morton <akpm@linux-foundation.org>,
	Kefeng Wang <wangkefeng.wang@huawei.com>,
	"Matthew Wilcox (Oracle)" <willy@infradead.org>,
	linux-arm-msm@vger.kernel.org, cgroups@vger.kernel.org,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: Re: [PATCH] mm/memcg: fix NULL nodeinfo[] dereference on late-onlined nodes
Date: Tue, 11 Aug 2026 10:46:14 +0530	[thread overview]
Message-ID: <53e05300-b84c-4a04-a7b4-5022285bcbdc@oss.qualcomm.com> (raw)
In-Reply-To: <5059A780-9C10-4171-A254-38944464F1AC@linux.dev>



On 8/10/2026 1:28 PM, Muchun Song wrote:
> 
> 
>> On Aug 10, 2026, at 13:46, Prakash Gupta <prakash.gupta@oss.qualcomm.com> wrote:
>>
>> memcg->nodeinfo[] entries are allocated only for nodes present at
>> css_alloc time. When a node is onlined after a memcg is created its
>> nodeinfo[] slot remains NULL. Two call sites dereference these slots
>> unconditionally:
> 
> I don't think the premise of this patch is correct.
> 
> memcg->nodeinfo[] is not allocated only for nodes that are present or
> online at css_alloc time. mem_cgroup_alloc() allocates per-node info with
> for_each_node(), and for_each_node() iterates N_POSSIBLE nodes:
> 
>         for_each_node(node)
>                 alloc_mem_cgroup_per_node_info(memcg, node);
> 

You are right. I rechecked and nodeinfo[] is allocated for all possible
nodes at mem_cgroup_alloc() time, not just currently online ones.

> If memcg->nodeinfo[nid] is NULL on your system, that looks like a
> violation of this invariant, or possibly a downstream-specific change,
> bad nid, allocation/lifetime issue, or memory corruption. I don't think
> the generic explanation that "the node was onlined after the memcg was
> created" is sufficient.
> 
Agreed. I will investigate further before resubmitting that part.

>>
>> lruvec_stat_mod_folio() calls mem_cgroup_lruvec() which reads
>> memcg->nodeinfo[pgdat->node_id] without a NULL check. On a system
>> where a node is onlined after the memcg is created, any folio stat
>> update for that node crashes with a NULL pointer dereference:
>>
>>  Unable to handle kernel paging request at virtual address ffffffbebf7e1908
>>  pc : lruvec_stat_mod_folio+0xf0/0x444   [6.18.21-android17-5]
>>  lr : lruvec_stat_mod_folio+0x88/0x444
>>  Call trace:
>>   lruvec_stat_mod_folio+0xf0/0x444
>>   folio_add_new_anon_rmap+0xac/0x2b8
>>   do_wp_page+0x768/0xc80
>>   handle_mm_fault+0x37c/0x8c4
>>   do_page_fault+0x140/0xa1c
>>   do_mem_abort+0x54/0x74
>>   el0_da+0x48/0x8c
>>   el0t_64_sync_handler+0x20/0x130
>>   el0t_64_sync+0x1c4/0x1c8
>>
>> __invalidate_reclaim_iterators() iterates for_each_node() and reads
>> from->nodeinfo[nid]->iter without checking for NULL. for_each_node()
>> visits all possible nodes, so this is reachable whenever a node is
>> onlined after the memcg was created.
>>
>> Fix lruvec_stat_mod_folio() by checking nodeinfo[pgdat->node_id]
>> directly and falling back to mod_node_page_state() when NULL, mirroring
>> the existing !memcg early-return path. The fallback must not go through
>> mod_lruvec_state() since that calls mod_memcg_lruvec_state() which uses
>> container_of() to recover the mem_cgroup_per_node from the lruvec
>> pointer; passing &pgdat->__lruvec there produces a garbage pointer.
>> When nodeinfo[nid] is NULL the memcg has no per-node accounting
>> structure for that node, so node-level accounting is correct.
>>
>> Fix __invalidate_reclaim_iterators() by skipping NULL nodeinfo[] slots.
>>
>> Also switch lruvec_stat_mod_folio() to folio_memcg_check() which uses
>> READ_ONCE() to safely read folio->memcg_data in an unlocked context.
>>
>> Fixes: 6c77b607ee26 ("mm: kill lock|unlock_page_memcg()")
> 
> The Fixes tag also seems odd. 6c77b607ee26 ("mm: kill
> lock|unlock_page_memcg()") only removed/renamed the lock_page_memcg()
> wrappers and does not appear to change nodeinfo[] allocation or memory
> hotplug handling. Could you explain how that commit introduced the NULL
> nodeinfo condition?
> 

It did not. It seems I picked up the commit based on git blame on
function as there were two related bugs reports that I was conflating
into one patch as listed below, will fix that in v2.

Variant A (missed to mentioned in commit msg) — NULL dereference:

    Unable to handle kernel NULL pointer dereference
      at virtual address 0000000000000528
    ESR = 0x0000000096000005 (read fault)
    Workqueue: events delayed_fput
    pc : lruvec_stat_mod_folio+0x5c/0x444  [6.18.21-android17-5]
    lr : lruvec_stat_mod_folio+0x2c/0x444

As you suggested this may need more investigation.

Variant B (the crash included in the patch) — stale pointer:

    Unable to handle kernel paging request
      at virtual address ffffffbebf7e1908
    ESR = 0x0000000096000045 (write fault)
    pc : __lruvec_stat_mod_folio+0xf0/0x444  [6.18.21-android17-5]
    lr : __lruvec_stat_mod_folio+0x88/0x444
    Call trace:
      __lruvec_stat_mod_folio+0xf0/0x444
      folio_add_new_anon_rmap+0xac/0x2b8
      do_wp_page+0x768/0xc80
      handle_mm_fault+0x37c/0x8c4
      do_page_fault+0x140/0xa1c

__lruvec_stat_mod_folio+0xf0 places it after the !memcg NULL check.This
is consistent with folio_memcg() returning a stale memcg pointer that
passes the NULL check.

folio_memcg_check() uses READ_ONCE(folio->memcg_data) which seems the
correct API for unlocked contexts. folio_memcg_check() has been
available since becacb04fdd4 ("mm: memcg: add folio_memcg_check()")
but lruvec_stat_mod_folio() was never updated to use it.

I should also note that this crash is difficult to reproduce in a
controlled environment — the analysis is based on crashdump inspection.
I have not been able to construct a reliable reproducer so far.

let me know your thoughts on this, accordingly I can send a v2 to cover
only Variant B fix as explained above.

>> Cc: stable@vger.kernel.org
>> Assisted-by: pi:claude-sonnet-4-5
> 
> Given the Assisted-by tag, I assume some of the analysis may have been
> tool-assisted. That's fine, but the author still needs to validate the
> reasoning against the actual code before submission.
> 
Agree, I will be more careful in next submission.

> Did you confirm that the relevant allocation and hotplug paths were
> manually checked against the affected tree? In particular, I wonder
> whether this behavior depends on downstream changes around
> mem_cgroup_alloc(), for_each_node(), node_possible_map setup, or memory
> hotplug nid validation.
> 
I checked all four paths against the affected tree
(6.18.21-android17-5). Only difference in
mem_cgroup_alloc() are cosmetic and do not touch the nodeinfo[]
allocation path. The NULL nodeinfo[nid] in Variant A is not explained
by any downstream change — the root cause remain unknown.

Thank you for the review.

Thanks,
Prakash



  reply	other threads:[~2026-08-11  5:16 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-10  5:46 [PATCH] mm/memcg: fix NULL nodeinfo[] dereference on late-onlined nodes Prakash Gupta
2026-08-10  7:58 ` Muchun Song
2026-08-11  5:16   ` Prakash Gupta [this message]
2026-08-11  6:19     ` Muchun Song

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=53e05300-b84c-4a04-a7b4-5022285bcbdc@oss.qualcomm.com \
    --to=prakash.gupta@oss.qualcomm.com \
    --cc=akpm@linux-foundation.org \
    --cc=cgroups@vger.kernel.org \
    --cc=hannes@cmpxchg.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mhocko@kernel.org \
    --cc=muchun.song@linux.dev \
    --cc=roman.gushchin@linux.dev \
    --cc=shakeel.butt@linux.dev \
    --cc=stable@vger.kernel.org \
    --cc=wangkefeng.wang@huawei.com \
    --cc=willy@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox