From: syzbot <syzbot+e008db2ac01e282550ee@syzkaller.appspotmail.com>
To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com
Subject: Forwarded: [PATCH] mm/workingset: debug MGLRU shadow corruption leading to NULL deref
Date: Mon, 08 Dec 2025 21:44:54 -0800 [thread overview]
Message-ID: <6937b756.a70a0220.38f243.00c2.GAE@google.com> (raw)
In-Reply-To: <693540fe.a70a0220.38f243.004c.GAE@google.com>
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] mm/workingset: debug MGLRU shadow corruption leading to NULL deref
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
Add debug logging to trace shadow entry 0x41 that causes NULL pointer
dereference in lru_gen_test_recent().
Instruments:
- pack_shadow(): Detect when 0x41 is created
- lru_gen_eviction(): Show min_seq and token values
- unpack_shadow(): Detect when 0x41 is unpacked
- lru_gen_test_recent(): Detect NULL pgdat
- workingset_refault/lru_gen_refault(): Trace refault path
This will identify if MGLRU generation counters are uninitialized
(min_seq=0), causing corrupted shadow entries.
Link: https://syzkaller.appspot.com/bug?extid=e008db2ac01e282550ee
Reported-by: syzbot+e008db2ac01e282550ee@syzkaller.appspotmail.com
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
mm/workingset.c | 69 ++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 57 insertions(+), 12 deletions(-)
diff --git a/mm/workingset.c b/mm/workingset.c
index e9f05634747a..cebcf5e63f3b 100644
--- a/mm/workingset.c
+++ b/mm/workingset.c
@@ -199,28 +199,49 @@ static unsigned int bucket_order __read_mostly;
static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction,
bool workingset)
{
+ pr_err("PACK_SHADOW: CREATING SHADOW\n");
+ pr_err(" memcgid=%d node_id=%d eviction=0x%lx workingset=%d\n",
+ memcgid, pgdat->node_id, eviction, workingset);
eviction &= EVICTION_MASK;
eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid;
eviction = (eviction << NODES_SHIFT) | pgdat->node_id;
eviction = (eviction << WORKINGSET_SHIFT) | workingset;
-
- return xa_mk_value(eviction);
+ void *shadow = xa_mk_value(eviction);
+ pr_err(" Final packed shadow=0x%lx (raw eviction=0x%lx)\n",
+ (unsigned long)shadow, eviction);
+ if ((unsigned long)shadow == 0x41) {
+ pr_err("*** BUG: CREATED SHADOW 0x41! ***\n");
+ dump_stack();
+ }
+ return shadow;
}
static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
unsigned long *evictionp, bool *workingsetp)
{
+ pr_err("UNPACK_SHADOW: READING SHADOW\n");
+ pr_err(" shadow=0x%lx\n", (unsigned long)shadow);
unsigned long entry = xa_to_value(shadow);
int memcgid, nid;
bool workingset;
-
+ // CRITICAL: Detect if we're reading the bad 0x41 shadow!
+ if ((unsigned long)shadow == 0x41) {
+ pr_err("*** BUG: UNPACKING CORRUPTED SHADOW 0x41! ***\n");
+ dump_stack();
+ }
workingset = entry & ((1UL << WORKINGSET_SHIFT) - 1);
entry >>= WORKINGSET_SHIFT;
nid = entry & ((1UL << NODES_SHIFT) - 1);
entry >>= NODES_SHIFT;
memcgid = entry & ((1UL << MEM_CGROUP_ID_SHIFT) - 1);
entry >>= MEM_CGROUP_ID_SHIFT;
-
+ pr_err(" Unpacked: memcgid=%d nid=%d eviction=0x%lx workingset=%d\n",
+ memcgid, nid, entry, workingset);
+ pr_err(" NODE_DATA(%d)=%px\n", nid, NODE_DATA(nid));
+ if (nid >= MAX_NUMNODES || !NODE_DATA(nid)) {
+ pr_err("*** BUG: INVALID NODE ID %d! ***\n", nid);
+ dump_stack();
+ }
*memcgidp = memcgid;
*pgdat = NODE_DATA(nid);
*evictionp = entry;
@@ -231,6 +252,8 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
static void *lru_gen_eviction(struct folio *folio)
{
+ pr_err("LRU_GEN_EVICTION: ENTERED\n");
+ pr_err(" folio=%px node=%d\n", folio, folio_nid(folio));
int hist;
unsigned long token;
unsigned long min_seq;
@@ -250,11 +273,15 @@ static void *lru_gen_eviction(struct folio *folio)
lrugen = &lruvec->lrugen;
min_seq = READ_ONCE(lrugen->min_seq[type]);
token = (min_seq << LRU_REFS_WIDTH) | max(refs - 1, 0);
-
+ pr_err("LRU_GEN_EVICTION: min_seq=0x%lx refs=%d tier=%d\n",
+ min_seq, refs, tier);
+ pr_err(" token=0x%lx (will be eviction parameter)\n", token);
hist = lru_hist_from_seq(min_seq);
atomic_long_add(delta, &lrugen->evicted[hist][type][tier]);
-
- return pack_shadow(mem_cgroup_id(memcg), pgdat, token, workingset);
+ void *shadow = pack_shadow(mem_cgroup_id(memcg), pgdat, token, workingset);
+ pr_err("LRU_GEN_EVICTION: Returning shadow=0x%lx\n", (unsigned long)shadow);
+ return shadow;
+ //return pack_shadow(mem_cgroup_id(memcg), pgdat, token, workingset);
}
/*
@@ -270,7 +297,14 @@ static bool lru_gen_test_recent(void *shadow, struct lruvec **lruvec,
struct pglist_data *pgdat;
unpack_shadow(shadow, &memcg_id, &pgdat, token, workingset);
-
+ /*
+ * If pgdat is NULL, the shadow entry contains an invalid node ID.
+ * Set lruvec to NULL so caller can detect and skip processing.
+ */
+ if (unlikely(!pgdat)) {
+ *lruvec = NULL;
+ return false;
+ }
memcg = mem_cgroup_from_id(memcg_id);
*lruvec = mem_cgroup_lruvec(memcg, pgdat);
@@ -280,7 +314,7 @@ static bool lru_gen_test_recent(void *shadow, struct lruvec **lruvec,
return abs_diff(max_seq, *token >> LRU_REFS_WIDTH) < MAX_NR_GENS;
}
-static void lru_gen_refault(struct folio *folio, void *shadow)
+static void lru_gen_refault(struct folio *folio, void *shadow)
{
bool recent;
int hist, tier, refs;
@@ -292,11 +326,9 @@ static void lru_gen_refault(struct folio *folio, void *shadow)
int delta = folio_nr_pages(folio);
rcu_read_lock();
-
recent = lru_gen_test_recent(shadow, &lruvec, &token, &workingset);
- if (lruvec != folio_lruvec(folio))
+ if (!lruvec || lruvec != folio_lruvec(folio))
goto unlock;
-
mod_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + type, delta);
if (!recent)
@@ -533,6 +565,12 @@ bool workingset_test_recent(void *shadow, bool file, bool *workingset,
*/
void workingset_refault(struct folio *folio, void *shadow)
{
+ pr_err("WORKINGSET_REFAULT: ENTERED\n");
+ pr_err(" folio=%px shadow=0x%lx\n", folio, (unsigned long)shadow);
+ if ((unsigned long)shadow == 0x41) {
+ pr_err("*** BUG: WORKINGSET_REFAULT received corrupted shadow 0x41! ***\n");
+ dump_stack();
+ }
bool file = folio_is_file_lru(folio);
struct pglist_data *pgdat;
struct mem_cgroup *memcg;
@@ -543,9 +581,13 @@ void workingset_refault(struct folio *folio, void *shadow)
VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
if (lru_gen_enabled()) {
+ pr_err("WORKINGSET_REFAULT: LRU_GEN enabled, calling lru_gen_refault\n");
lru_gen_refault(folio, shadow);
+ pr_err("WORKINGSET_REFAULT: lru_gen_refault returned\n");
+
return;
}
+ pr_err("WORKINGSET_REFAULT: Using regular (non-LRU_GEN) path\n");
/*
* The activation decision for this folio is made at the level
@@ -562,6 +604,7 @@ void workingset_refault(struct folio *folio, void *shadow)
lruvec = mem_cgroup_lruvec(memcg, pgdat);
mod_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + file, nr);
+ pr_err("WORKINGSET_REFAULT: Calling workingset_test_recent\n");
if (!workingset_test_recent(shadow, file, &workingset, true))
return;
@@ -572,6 +615,7 @@ void workingset_refault(struct folio *folio, void *shadow)
/* Folio was active prior to eviction */
if (workingset) {
+ pr_err("WORKINGSET_REFAULT: Folio was workingset, restoring\n");
folio_set_workingset(folio);
/*
* XXX: Move to folio_add_lru() when it supports new vs
@@ -580,6 +624,7 @@ void workingset_refault(struct folio *folio, void *shadow)
lru_note_cost_refault(folio);
mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + file, nr);
}
+ pr_err("WORKINGSET_REFAULT: EXITING\n");
}
/**
--
2.43.0
next prev parent reply other threads:[~2025-12-09 5:44 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-07 8:55 [syzbot] [mm?] general protection fault in lru_gen_test_recent (2) syzbot
2025-12-07 12:44 ` Forwarded: [PATCH] mm/workingset: fix NULL pointer dereference in lru_gen_test_recent syzbot
2025-12-07 14:35 ` syzbot
2025-12-07 15:05 ` syzbot
2025-12-07 15:31 ` syzbot
2025-12-07 15:38 ` syzbot
2025-12-07 16:07 ` syzbot
2025-12-08 2:31 ` Forwarded: [PATCH] mm/workingset: fix NULL pointer dereference in lru_gen_test_recent() syzbot
2025-12-08 2:47 ` syzbot
2025-12-08 3:56 ` Forwarded: [PATCH] mm/workingset: add debug for corrupted shadow entry investigation syzbot
2025-12-08 4:49 ` Forwarded: [PATCH] mm/workingset: fix crash from corrupted shadow entries in lru_gen syzbot
2025-12-08 5:14 ` syzbot
2025-12-09 5:35 ` Forwarded: [PATCH] mm/workingset: add debug instrumentation for MGLRU shadow corruption syzbot
2025-12-09 5:44 ` syzbot [this message]
2025-12-09 6:28 ` Forwarded: [PATCH] mm/workingset: fix NULL deref from invalid node ID in shadow syzbot
2025-12-23 9:38 ` Forwarded: [PATCH] for test syzbot
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=6937b756.a70a0220.38f243.00c2.GAE@google.com \
--to=syzbot+e008db2ac01e282550ee@syzkaller.appspotmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=syzkaller-bugs@googlegroups.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.