* [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub
@ 2026-06-26 12:43 Breno Leitao
2026-06-26 13:56 ` Joshua Hahn
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Breno Leitao @ 2026-06-26 12:43 UTC (permalink / raw)
To: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Andrew Morton
Cc: Michal Hocko, cgroups, linux-mm, linux-kernel, kernel-team,
stable, Breno Leitao
mem_cgroup_oom() passes an uninitialized "locked" to memcg1_oom_prepare()
and reads it back in memcg1_oom_finish():
bool locked, ret;
...
if (!memcg1_oom_prepare(memcg, &locked))
return false;
ret = mem_cgroup_out_of_memory(memcg, mask, order);
memcg1_oom_finish(memcg, locked);
This relies on memcg1_oom_prepare() setting *locked whenever it returns
true. The CONFIG_MEMCG_V1=y version does, but the stub used when
CONFIG_MEMCG_V1=n returns true without touching *locked, so
memcg1_oom_finish() consumes an uninitialized value. On a memcg OOM this
is reported by UBSAN:
UBSAN: invalid-load in mm/memcontrol.c:1932:27
load of value 0 is not a valid value for type 'bool' (aka '_Bool')
Initialize *locked to false in the stub; with cgroup v1 compiled out
there is no OOM lock to take.
Fixes: e93d4166b40a ("mm: memcg: put cgroup v1-specific code under a config option")
Cc: stable@vger.kernel.org
Signed-off-by: Breno Leitao <leitao@debian.org>
---
mm/memcontrol-v1.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/mm/memcontrol-v1.h b/mm/memcontrol-v1.h
index f92f81108d5ed..4fa6e2bc8413f 100644
--- a/mm/memcontrol-v1.h
+++ b/mm/memcontrol-v1.h
@@ -107,7 +107,11 @@ static inline void memcg1_remove_from_trees(struct mem_cgroup *memcg) {}
static inline void memcg1_soft_limit_reset(struct mem_cgroup *memcg) {}
static inline void memcg1_css_offline(struct mem_cgroup *memcg) {}
-static inline bool memcg1_oom_prepare(struct mem_cgroup *memcg, bool *locked) { return true; }
+static inline bool memcg1_oom_prepare(struct mem_cgroup *memcg, bool *locked)
+{
+ *locked = false;
+ return true;
+}
static inline void memcg1_oom_finish(struct mem_cgroup *memcg, bool locked) {}
static inline void memcg1_oom_recover(struct mem_cgroup *memcg) {}
---
base-commit: 4e5dfb7c84012007c3c7061126491bbc92d71bf1
change-id: 20260626-memcg-oom-uninit-locked-5ec79dff4396
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub
2026-06-26 12:43 [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub Breno Leitao
@ 2026-06-26 13:56 ` Joshua Hahn
2026-06-26 14:23 ` Breno Leitao
2026-06-26 18:53 ` Johannes Weiner
2026-06-27 0:25 ` Shakeel Butt
2 siblings, 1 reply; 6+ messages in thread
From: Joshua Hahn @ 2026-06-26 13:56 UTC (permalink / raw)
To: Breno Leitao
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Andrew Morton, Michal Hocko, cgroups, linux-mm,
linux-kernel, kernel-team, stable
Hi Breno, I hope you are doing well : -)
Woah, thank you for finding and fixing this bug!
> Fixes: e93d4166b40a ("mm: memcg: put cgroup v1-specific code under a config option")
> Cc: stable@vger.kernel.org
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> mm/memcontrol-v1.h | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/mm/memcontrol-v1.h b/mm/memcontrol-v1.h
> index f92f81108d5ed..4fa6e2bc8413f 100644
> --- a/mm/memcontrol-v1.h
> +++ b/mm/memcontrol-v1.h
> @@ -107,7 +107,11 @@ static inline void memcg1_remove_from_trees(struct mem_cgroup *memcg) {}
> static inline void memcg1_soft_limit_reset(struct mem_cgroup *memcg) {}
> static inline void memcg1_css_offline(struct mem_cgroup *memcg) {}
>
> -static inline bool memcg1_oom_prepare(struct mem_cgroup *memcg, bool *locked) { return true; }
> +static inline bool memcg1_oom_prepare(struct mem_cgroup *memcg, bool *locked)
> +{
> + *locked = false;
> + return true;
> +}
> static inline void memcg1_oom_finish(struct mem_cgroup *memcg, bool locked) {}
> static inline void memcg1_oom_recover(struct mem_cgroup *memcg) {}
Part of me wonders if we should just initialize locked = false in the
caller (mem_cgroup_oom) as to not make the stub have side effects,
but your chnage looks correct and this is a fix so perhaps that is
not so important.
Looks good to me! Thank you again Breno : -)
Reviewed-by: Joshua Hahn <joshua.hahnjy@gmail.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub
2026-06-26 13:56 ` Joshua Hahn
@ 2026-06-26 14:23 ` Breno Leitao
0 siblings, 0 replies; 6+ messages in thread
From: Breno Leitao @ 2026-06-26 14:23 UTC (permalink / raw)
To: Joshua Hahn
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Andrew Morton, Michal Hocko, cgroups, linux-mm,
linux-kernel, kernel-team, stable
Hello Joshua,
On Fri, Jun 26, 2026 at 06:56:11AM -0700, Joshua Hahn wrote:
> Part of me wonders if we should just initialize locked = false in the
> caller (mem_cgroup_oom) as to not make the stub have side effects,
> but your chnage looks correct and this is a fix so perhaps that is
> not so important.
Nice, your approach seems to be even better than my silly one. I will
wait for further review and respin with your approach.
Thanks,
--breno
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub
2026-06-26 12:43 [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub Breno Leitao
2026-06-26 13:56 ` Joshua Hahn
@ 2026-06-26 18:53 ` Johannes Weiner
2026-06-27 0:04 ` SeongJae Park
2026-06-27 0:25 ` Shakeel Butt
2 siblings, 1 reply; 6+ messages in thread
From: Johannes Weiner @ 2026-06-26 18:53 UTC (permalink / raw)
To: Breno Leitao
Cc: Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song,
Andrew Morton, Michal Hocko, cgroups, linux-mm, linux-kernel,
kernel-team, stable
On Fri, Jun 26, 2026 at 05:43:02AM -0700, Breno Leitao wrote:
> mem_cgroup_oom() passes an uninitialized "locked" to memcg1_oom_prepare()
> and reads it back in memcg1_oom_finish():
>
> bool locked, ret;
> ...
> if (!memcg1_oom_prepare(memcg, &locked))
> return false;
> ret = mem_cgroup_out_of_memory(memcg, mask, order);
> memcg1_oom_finish(memcg, locked);
>
> This relies on memcg1_oom_prepare() setting *locked whenever it returns
> true. The CONFIG_MEMCG_V1=y version does, but the stub used when
> CONFIG_MEMCG_V1=n returns true without touching *locked, so
> memcg1_oom_finish() consumes an uninitialized value. On a memcg OOM this
> is reported by UBSAN:
>
> UBSAN: invalid-load in mm/memcontrol.c:1932:27
> load of value 0 is not a valid value for type 'bool' (aka '_Bool')
>
> Initialize *locked to false in the stub; with cgroup v1 compiled out
> there is no OOM lock to take.
>
> Fixes: e93d4166b40a ("mm: memcg: put cgroup v1-specific code under a config option")
> Cc: stable@vger.kernel.org
> Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
I prefer this way over the idea to initialize in the caller. For the
actual implementation, the protocol is that the thing is initialized
when the function returns true. This version of the fix maintains that
for the dummy as well:
> ---
> mm/memcontrol-v1.h | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/mm/memcontrol-v1.h b/mm/memcontrol-v1.h
> index f92f81108d5ed..4fa6e2bc8413f 100644
> --- a/mm/memcontrol-v1.h
> +++ b/mm/memcontrol-v1.h
> @@ -107,7 +107,11 @@ static inline void memcg1_remove_from_trees(struct mem_cgroup *memcg) {}
> static inline void memcg1_soft_limit_reset(struct mem_cgroup *memcg) {}
> static inline void memcg1_css_offline(struct mem_cgroup *memcg) {}
>
> -static inline bool memcg1_oom_prepare(struct mem_cgroup *memcg, bool *locked) { return true; }
> +static inline bool memcg1_oom_prepare(struct mem_cgroup *memcg, bool *locked)
> +{
> + *locked = false;
> + return true;
> +}
> static inline void memcg1_oom_finish(struct mem_cgroup *memcg, bool locked) {}
> static inline void memcg1_oom_recover(struct mem_cgroup *memcg) {}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub
2026-06-26 18:53 ` Johannes Weiner
@ 2026-06-27 0:04 ` SeongJae Park
0 siblings, 0 replies; 6+ messages in thread
From: SeongJae Park @ 2026-06-27 0:04 UTC (permalink / raw)
To: Johannes Weiner
Cc: SeongJae Park, Breno Leitao, Michal Hocko, Roman Gushchin,
Shakeel Butt, Muchun Song, Andrew Morton, Michal Hocko, cgroups,
linux-mm, linux-kernel, kernel-team, stable
On Fri, 26 Jun 2026 14:53:20 -0400 Johannes Weiner <hannes@cmpxchg.org> wrote:
> On Fri, Jun 26, 2026 at 05:43:02AM -0700, Breno Leitao wrote:
> > mem_cgroup_oom() passes an uninitialized "locked" to memcg1_oom_prepare()
> > and reads it back in memcg1_oom_finish():
> >
> > bool locked, ret;
> > ...
> > if (!memcg1_oom_prepare(memcg, &locked))
> > return false;
> > ret = mem_cgroup_out_of_memory(memcg, mask, order);
> > memcg1_oom_finish(memcg, locked);
> >
> > This relies on memcg1_oom_prepare() setting *locked whenever it returns
> > true. The CONFIG_MEMCG_V1=y version does, but the stub used when
> > CONFIG_MEMCG_V1=n returns true without touching *locked, so
> > memcg1_oom_finish() consumes an uninitialized value. On a memcg OOM this
> > is reported by UBSAN:
> >
> > UBSAN: invalid-load in mm/memcontrol.c:1932:27
> > load of value 0 is not a valid value for type 'bool' (aka '_Bool')
> >
> > Initialize *locked to false in the stub; with cgroup v1 compiled out
> > there is no OOM lock to take.
> >
> > Fixes: e93d4166b40a ("mm: memcg: put cgroup v1-specific code under a config option")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Breno Leitao <leitao@debian.org>
>
> Acked-by: Johannes Weiner <hannes@cmpxchg.org>
>
> I prefer this way over the idea to initialize in the caller. For the
> actual implementation, the protocol is that the thing is initialized
> when the function returns true. This version of the fix maintains that
> for the dummy as well:
I agree. I also feel the caller code is _slightly_ easier to read as is, than
adding the initialization there. If it is initialized there, I would assume it
will be used somewhere. But after finding out it is not used for early return
cases including memcg1_oom_prepare() reuturning false case, I would be confused
about the inefficiency. Using a variable after passing its pointer to a
function depending on the function's return value makes me assume the variable
will be set inside the function.
The code is simple enough to read in any way, and my taste is sometimes just
weird, though.
Anyway nice fix, thank you!
Reviewed-by: SeongJae Park <sj@kernel.org>
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub
2026-06-26 12:43 [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub Breno Leitao
2026-06-26 13:56 ` Joshua Hahn
2026-06-26 18:53 ` Johannes Weiner
@ 2026-06-27 0:25 ` Shakeel Butt
2 siblings, 0 replies; 6+ messages in thread
From: Shakeel Butt @ 2026-06-27 0:25 UTC (permalink / raw)
To: Breno Leitao
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Muchun Song,
Andrew Morton, Michal Hocko, cgroups, linux-mm, linux-kernel,
kernel-team, stable
On Fri, Jun 26, 2026 at 05:43:02AM -0700, Breno Leitao wrote:
> mem_cgroup_oom() passes an uninitialized "locked" to memcg1_oom_prepare()
> and reads it back in memcg1_oom_finish():
>
> bool locked, ret;
> ...
> if (!memcg1_oom_prepare(memcg, &locked))
> return false;
> ret = mem_cgroup_out_of_memory(memcg, mask, order);
> memcg1_oom_finish(memcg, locked);
>
> This relies on memcg1_oom_prepare() setting *locked whenever it returns
> true. The CONFIG_MEMCG_V1=y version does, but the stub used when
> CONFIG_MEMCG_V1=n returns true without touching *locked, so
> memcg1_oom_finish() consumes an uninitialized value.
On CONFIG_MEMCG_V1=n, memcg1_oom_finish() is an empty function and I assume
compiler will just remove it completely. Maybe on CONFIG_UBSAN=y kernel,
compiler is not removing memcg1_oom_finish90.
> On a memcg OOM this
> is reported by UBSAN:
>
> UBSAN: invalid-load in mm/memcontrol.c:1932:27
> load of value 0 is not a valid value for type 'bool' (aka '_Bool')
>
> Initialize *locked to false in the stub; with cgroup v1 compiled out
> there is no OOM lock to take.
>
> Fixes: e93d4166b40a ("mm: memcg: put cgroup v1-specific code under a config option")
> Cc: stable@vger.kernel.org
> Signed-off-by: Breno Leitao <leitao@debian.org>
Anyways, this is not a performance critical code path, so this is fine.
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-06-27 0:25 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-26 12:43 [PATCH] mm: memcg: initialize *locked in memcg1_oom_prepare() stub Breno Leitao
2026-06-26 13:56 ` Joshua Hahn
2026-06-26 14:23 ` Breno Leitao
2026-06-26 18:53 ` Johannes Weiner
2026-06-27 0:04 ` SeongJae Park
2026-06-27 0:25 ` Shakeel Butt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox