mm/damon/stat: fix memory leak on damon_start() failure in damon_stat_start()
Subsystems (3)
PATCH 1/1 mm/damon/stat: fix memory leak on damon_start() failure in damon_stat_start()
From: Jackie Liu <[email protected]>
Destroy the DAMON context and reset the global pointer when damon_start() fails. Otherwise, the context allocated by damon_stat_build_ctx() is leaked, and the stale damon_stat_context pointer will be overwritten on the next enable attempt, making the old allocation permanently unreachable.
--- mm/damon/stat.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
mm/damon/stat.c +4 -1
@@ -249,8 +249,11 @@ static int damon_stat_start(void)if (!damon_stat_context)return -ENOMEM ; err =damon_start (&damon_stat_context,1 , true); -if (err) +if (err) { +damon_destroy_ctx (damon_stat_context); + damon_stat_context =NULL ;return err; + } damon_stat_last_refresh_jiffies = jiffies; call_control.data = damon_stat_context;
Signature · 1 line
2.51.1
SeongJae Park
maintainerRe: (sashiko review) [PATCH] mm/damon/stat: fix memory leak on damon_start() failure in damon_stat_start()
Forwarding Sashiko review for doing discussions via mails, in form of reply, and adding my comments inline.
TL; DR: No blocker for this patch.
The first one is nice finding but orthogonal to this patch (I start feeling sashiko might be useful at finding potential bugs in existing code, like static code analysis tools, more than reviewing patches).
The second one is just wrong.
Quoted 38 lines
# review url: https://sashiko.dev/#/patchset/[email protected] # start of sashiko.dev inline review commit 386810f9b0a1ae341b87a984b16b2a2e1bafab71 Author: Jackie Liu <[email protected]>
mm/damon/stat: fix memory leak ondamon_start()failure indamon_stat_start()This commit fixes a memory leak by destroying the DAMON context and resetting the global pointer when
damon_start()fails. This ensures the previously allocated context is not permanently lost on subsequent enable attempts.Quoted 6 lines
mm/damon/stat.c +0
-0@@ -249,8 +249,11 @@ static int damon_stat_start(void)if (!damon_stat_context)return -ENOMEM ;mm/damon/stat.c static int damon_stat_start(void) · line 259
Quoted 10 lines
mm/damon/stat.c +4
-1err =damon_start (&damon_stat_context,1 , true); -if (err) +if (err) { +damon_destroy_ctx (damon_stat_context); + damon_stat_context =NULL ;return err; + } damon_stat_last_refresh_jiffies = jiffies; call_control.data = damon_stat_context;Does this code still leak the context if the subsequent call to
damon_call()fails?If the newly spawned kdamond thread exits before the call gets processed (such as due to an internal allocation failure for
regions_score_histograminkdamond_fn()),damon_call()can return an error like-EINVALor-ECANCELED.When
damon_stat_start()returns this error to its caller, the caller resets enabled = false and propagates the error, skippingdamon_stat_stop().
Quoted 7 lines
Consequently,
damon_stat_contextis never destroyed, nor is the global pointer reset to NULL. The next time the module is enabled,damon_stat_start()overwritesdamon_stat_contextwith a new context, permanently leaking the previously allocated structdamon_ctx.To completely fix the memory leak, should the return value of
damon_call()be checked and cleaned up similarly to thedamon_start()error path?
This is correct, but orthogonal to this patch. I will work on this.
Quoted 9 lines
This isn't a bug introduced by this patch, but is there a race condition between
damon_stat_init()and the sysfs module parameter setterdamon_stat_enabled_store()?For loadable modules, sysfs parameter files are exposed to userspace before the module's init function completes. If the module is loaded with the parameter enabled=1,
damon_stat_init()will begin executingdamon_stat_start(), which allocatesdamon_stat_context.
This is not correct. damon_initialized() check in the middle is there for avoiding this.
Thanks,
SJ
Quoted 25 lines
Concurrently, if a userspace process writes 0 to the sysfs enabled parameter, this triggers
damon_stat_enabled_store(), which sets enabled = false and immediately callsdamon_stat_stop().Because
damon_stat_init()does not hold thekernel_param_lock, there is no mutual exclusion between these execution paths.damon_stat_stop()callsdamon_destroy_ctx(), which frees the newly allocateddamon_stat_context.The
damon_stat_start()function (still executing in the init thread) then proceeds to calldamon_start(&damon_stat_context, 1, true), dereferencing the freed context pointer and causing a use-after-free.# end of sashiko.dev inline review # review url: https://sashiko.dev/#/patchset/[email protected] # # hkml [1] generated a draft of this mail. It can be regenerated # using below command: # # hkml patch sashiko_dev --for_forwarding \ # [email protected] # # [1] https://github.com/sjp38/hackermail
+ [email protected]. Please Cc damon@ for all DAMON patches.
Hello Jackie,
Quoted 9 lines · On Tue, 31 Mar 2026 18:15:53 +0800 Jackie Liu <[email protected]> wrote:
From: Jackie Liu <[email protected]>
Destroy the DAMON context and reset the global pointer when
damon_start()fails. Otherwise, the context allocated bydamon_stat_build_ctx()is leaked, and the staledamon_stat_contextpointer will be overwritten on the next enable attempt, making the old allocation permanently unreachable.Fixes 369c415e6073 ("mm/damon: introduce DAMON_STAT module")
As this is a memory leak, let's add Cc: stable@ too.
Quoted 1 line
Signed-off-by Jackie Liu <[email protected]>
Thanks,
SJ
[...]