* [PATCH v2 0/2] module: Fix memory deallocation on error path in move_module()
@ 2025-06-18 12:26 Petr Pavlu
2025-06-18 12:26 ` [PATCH v2 1/2] " Petr Pavlu
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Petr Pavlu @ 2025-06-18 12:26 UTC (permalink / raw)
To: Luis Chamberlain, Petr Pavlu, Sami Tolvanen, Daniel Gomez
Cc: linux-modules, linux-kernel
The first patch is an actual fix. The second patch is a minor related
cleanup.
Changes since v1 [1]:
- Initialize t to MOD_MEM_NUM_TYPES in move_module(), instead of assigning
the value later.
- Merge the definitions of the variables i and ret in move_module().
[1] https://lore.kernel.org/linux-modules/20250607161823.409691-1-petr.pavlu@suse.com/
Petr Pavlu (2):
module: Fix memory deallocation on error path in move_module()
module: Avoid unnecessary return value initialization in move_module()
kernel/module/main.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
base-commit: 52da431bf03b5506203bca27fe14a97895c80faf
--
2.49.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] module: Fix memory deallocation on error path in move_module()
2025-06-18 12:26 [PATCH v2 0/2] module: Fix memory deallocation on error path in move_module() Petr Pavlu
@ 2025-06-18 12:26 ` Petr Pavlu
2025-06-18 14:02 ` Daniel Gomez
2025-06-30 12:09 ` Daniel Gomez
2025-06-18 12:26 ` [PATCH v2 2/2] module: Avoid unnecessary return value initialization " Petr Pavlu
2025-06-30 13:57 ` [PATCH v2 0/2] module: Fix memory deallocation on error path " Daniel Gomez
2 siblings, 2 replies; 7+ messages in thread
From: Petr Pavlu @ 2025-06-18 12:26 UTC (permalink / raw)
To: Luis Chamberlain, Petr Pavlu, Sami Tolvanen, Daniel Gomez
Cc: linux-modules, linux-kernel
The function move_module() uses the variable t to track how many memory
types it has allocated and consequently how many should be freed if an
error occurs.
The variable is initially set to 0 and is updated when a call to
module_memory_alloc() fails. However, move_module() can fail for other
reasons as well, in which case t remains set to 0 and no memory is freed.
Fix the problem by initializing t to MOD_MEM_NUM_TYPES. Additionally, make
the deallocation loop more robust by not relying on the mod_mem_type_t enum
having a signed integer as its underlying type.
Fixes: c7ee8aebf6c0 ("module: add stop-grap sanity check on module memcpy()")
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
---
kernel/module/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 413ac6ea3702..9ac994b2f354 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2697,7 +2697,7 @@ static int find_module_sections(struct module *mod, struct load_info *info)
static int move_module(struct module *mod, struct load_info *info)
{
int i;
- enum mod_mem_type t = 0;
+ enum mod_mem_type t = MOD_MEM_NUM_TYPES;
int ret = -ENOMEM;
bool codetag_section_found = false;
@@ -2776,7 +2776,7 @@ static int move_module(struct module *mod, struct load_info *info)
return 0;
out_err:
module_memory_restore_rox(mod);
- for (t--; t >= 0; t--)
+ while (t--)
module_memory_free(mod, t);
if (codetag_section_found)
codetag_free_module_sections(mod);
--
2.49.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] module: Avoid unnecessary return value initialization in move_module()
2025-06-18 12:26 [PATCH v2 0/2] module: Fix memory deallocation on error path in move_module() Petr Pavlu
2025-06-18 12:26 ` [PATCH v2 1/2] " Petr Pavlu
@ 2025-06-18 12:26 ` Petr Pavlu
2025-06-18 14:02 ` Daniel Gomez
2025-06-30 13:57 ` [PATCH v2 0/2] module: Fix memory deallocation on error path " Daniel Gomez
2 siblings, 1 reply; 7+ messages in thread
From: Petr Pavlu @ 2025-06-18 12:26 UTC (permalink / raw)
To: Luis Chamberlain, Petr Pavlu, Sami Tolvanen, Daniel Gomez
Cc: linux-modules, linux-kernel
All error conditions in move_module() set the return value by updating the
ret variable. Therefore, it is not necessary to the initialize the variable
when declaring it.
Remove the unnecessary initialization.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
---
kernel/module/main.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 9ac994b2f354..7822b91fca6b 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2696,9 +2696,8 @@ static int find_module_sections(struct module *mod, struct load_info *info)
static int move_module(struct module *mod, struct load_info *info)
{
- int i;
+ int i, ret;
enum mod_mem_type t = MOD_MEM_NUM_TYPES;
- int ret = -ENOMEM;
bool codetag_section_found = false;
for_each_mod_mem_type(type) {
--
2.49.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] module: Avoid unnecessary return value initialization in move_module()
2025-06-18 12:26 ` [PATCH v2 2/2] module: Avoid unnecessary return value initialization " Petr Pavlu
@ 2025-06-18 14:02 ` Daniel Gomez
0 siblings, 0 replies; 7+ messages in thread
From: Daniel Gomez @ 2025-06-18 14:02 UTC (permalink / raw)
To: Petr Pavlu, Luis Chamberlain, Sami Tolvanen, Daniel Gomez
Cc: linux-modules, linux-kernel
On 18/06/2025 14.26, Petr Pavlu wrote:
> All error conditions in move_module() set the return value by updating the
> ret variable. Therefore, it is not necessary to the initialize the variable
> when declaring it.
>
> Remove the unnecessary initialization.
>
> Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
> Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
> ---
> kernel/module/main.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 9ac994b2f354..7822b91fca6b 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2696,9 +2696,8 @@ static int find_module_sections(struct module *mod, struct load_info *info)
>
> static int move_module(struct module *mod, struct load_info *info)
> {
> - int i;
> + int i, ret;
> enum mod_mem_type t = MOD_MEM_NUM_TYPES;
> - int ret = -ENOMEM;
> bool codetag_section_found = false;
>
> for_each_mod_mem_type(type) {
Reviewed-by: Daniel Gomez <da.gomez@samsung.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] module: Fix memory deallocation on error path in move_module()
2025-06-18 12:26 ` [PATCH v2 1/2] " Petr Pavlu
@ 2025-06-18 14:02 ` Daniel Gomez
2025-06-30 12:09 ` Daniel Gomez
1 sibling, 0 replies; 7+ messages in thread
From: Daniel Gomez @ 2025-06-18 14:02 UTC (permalink / raw)
To: Petr Pavlu, Luis Chamberlain, Sami Tolvanen, Daniel Gomez
Cc: linux-modules, linux-kernel
On 18/06/2025 14.26, Petr Pavlu wrote:
> The function move_module() uses the variable t to track how many memory
> types it has allocated and consequently how many should be freed if an
> error occurs.
>
> The variable is initially set to 0 and is updated when a call to
> module_memory_alloc() fails. However, move_module() can fail for other
> reasons as well, in which case t remains set to 0 and no memory is freed.
>
> Fix the problem by initializing t to MOD_MEM_NUM_TYPES. Additionally, make
> the deallocation loop more robust by not relying on the mod_mem_type_t enum
> having a signed integer as its underlying type.
>
> Fixes: c7ee8aebf6c0 ("module: add stop-grap sanity check on module memcpy()")
> Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
> Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
> ---
> kernel/module/main.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 413ac6ea3702..9ac994b2f354 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2697,7 +2697,7 @@ static int find_module_sections(struct module *mod, struct load_info *info)
> static int move_module(struct module *mod, struct load_info *info)
> {
> int i;
> - enum mod_mem_type t = 0;
> + enum mod_mem_type t = MOD_MEM_NUM_TYPES;
> int ret = -ENOMEM;
> bool codetag_section_found = false;
>
> @@ -2776,7 +2776,7 @@ static int move_module(struct module *mod, struct load_info *info)
> return 0;
> out_err:
> module_memory_restore_rox(mod);
> - for (t--; t >= 0; t--)
> + while (t--)
> module_memory_free(mod, t);
> if (codetag_section_found)
> codetag_free_module_sections(mod);
Reviewed-by: Daniel Gomez <da.gomez@samsung.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] module: Fix memory deallocation on error path in move_module()
2025-06-18 12:26 ` [PATCH v2 1/2] " Petr Pavlu
2025-06-18 14:02 ` Daniel Gomez
@ 2025-06-30 12:09 ` Daniel Gomez
1 sibling, 0 replies; 7+ messages in thread
From: Daniel Gomez @ 2025-06-30 12:09 UTC (permalink / raw)
To: Petr Pavlu, Luis Chamberlain, Sami Tolvanen, Daniel Gomez
Cc: linux-modules, linux-kernel
On 18/06/2025 14.26, Petr Pavlu wrote:
> The function move_module() uses the variable t to track how many memory
> types it has allocated and consequently how many should be freed if an
> error occurs.
>
> The variable is initially set to 0 and is updated when a call to
> module_memory_alloc() fails. However, move_module() can fail for other
> reasons as well, in which case t remains set to 0 and no memory is freed.
>
> Fix the problem by initializing t to MOD_MEM_NUM_TYPES. Additionally, make
> the deallocation loop more robust by not relying on the mod_mem_type_t enum
> having a signed integer as its underlying type.
This is a follow up based on v1 discussion [1] regarding a way to reproduce
the leak.
[1]
https://lore.kernel.org/linux-modules/ae967353-71fa-4438-a84b-8f7e2815f485@kernel.org/
I tried using eBPF and moderr [2][3] to find a way to reproduce this. I run into
some issues but I applied some workarounds. If this is useful we can check at
how to solve this properly.
[2] moderr RFC:
https://lore.kernel.org/linux-modules/20250122-modules-error-injection-v1-0-910590a04fd5@samsung.com/
[3] updated moderr branch:
https://git.kernel.org/pub/scm/linux/kernel/git/da.gomez/linux.git/?h=b4%2Fmodules-error-injection
The logs below show an A/B test memory consumption comparison when a module
is loaded and leaked (A) because of the issue described in the commit log
vs when is correctly loaded/unloaded (B). Besides observing a huge leak,
kernel logs (dmesg) show the message "execmem: unable to allocate memory".
Note that we can't use kmemleak as we skip it with kmemleak_not_leak() in
module_memory_alloc(), except for is_rox memory.
Memory lost:
A test: 1220444 kB
B test: 892 kB
Thoughts?
Workflow to reproduce the issue (before applying this patchset):
1. Run moderr to return error in codetag_needs_module_section()
sudo moderr \
-modname=brd
--modfunc=module_codetag_needs_module_section \
--error=1
Note: We can also force codetag_alloc_module_section() with:
sudo moderr \
--modname=brd \
--modfunc=module_codetag_alloc_module_section \
--error=-22
2. Run a loop to probe a module with:
while true; do modprobe brd; done
3. Monitor memory before/after and check delta:
Note: this output it's a wrapper around the above loop.
[*] Dropping caches...
[*] Wait...
[*] Starting memory: 6758564 kB
[*] Loop 200s...
[*] Wait...
[*] Dropping caches...
[*] Wait...
[*] Ending memory: 5538120 kB
[*] Memory lost: 1220444 kB
--- meminfo_before.txt 2025-06-30 10:29:49.880661145 +0000
+++ meminfo_after.txt 2025-06-30 10:33:20.091501671 +0000
@@ -1,38 +1,38 @@
MemTotal: 8133036 kB
-MemFree: 6858820 kB
-MemAvailable: 6758652 kB
-Buffers: 2576 kB
-Cached: 73164 kB
+MemFree: 5620596 kB
+MemAvailable: 5538204 kB
+Buffers: 2552 kB
+Cached: 107256 kB
SwapCached: 0 kB
-Active: 25448 kB
-Inactive: 95272 kB
-Active(anon): 176 kB
-Inactive(anon): 45684 kB
-Active(file): 25272 kB
-Inactive(file): 49588 kB
+Active: 67688 kB
+Inactive: 95284 kB
+Active(anon): 184 kB
+Inactive(anon): 54028 kB
+Active(file): 67504 kB
+Inactive(file): 41256 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB
SwapFree: 0 kB
-Dirty: 468 kB
+Dirty: 2804 kB
Writeback: 0 kB
-AnonPages: 45192 kB
-Mapped: 72028 kB
-Shmem: 916 kB
-KReclaimable: 5816 kB
-Slab: 42336 kB
-SReclaimable: 5816 kB
-SUnreclaim: 36520 kB
-KernelStack: 1984 kB
-PageTables: 2652 kB
+AnonPages: 53556 kB
+Mapped: 105784 kB
+Shmem: 936 kB
+KReclaimable: 7468 kB
+Slab: 176080 kB
+SReclaimable: 7468 kB
+SUnreclaim: 168612 kB
+KernelStack: 2016 kB
+PageTables: 5472 kB
SecPageTables: 0 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 3542228 kB
-Committed_AS: 89960 kB
+Committed_AS: 92956 kB
VmallocTotal: 34359738367 kB
-VmallocUsed: 5112 kB
+VmallocUsed: 1041252 kB
VmallocChunk: 0 kB
Percpu: 1712 kB
AnonHugePages: 4096 kB
@@ -49,6 +49,6 @@
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 1048576 kB
-DirectMap4k: 30548 kB
-DirectMap2M: 3115008 kB
-DirectMap1G: 7340032 kB
+DirectMap4k: 730964 kB
+DirectMap2M: 3463168 kB
+DirectMap1G: 6291456 kB
4. Check kernel logs
[ 30.099667] tee (618): drop_caches: 3
[ 221.695667] execmem: unable to allocate memory
{...}
[ 226.701772] execmem_vmalloc: 1110 callbacks suppressed
{...}
[ 231.705976] execmem_vmalloc: 1099 callbacks suppressed
{...}
[ 231.742226] execmem: unable to allocate memory
[ 231.747107] execmem: unable to allocate memory
[ 240.109107] tee (92935): drop_caches: 3
Now, I repeated the test without error injection:
Loop:
while true; do modprobe brd && rmmod brd; done
[*] Dropping caches...
[*] Wait...
[*] Starting memory: 6747960 kB
Loop 100s...
[*] Wait...
[*] Dropping caches...
[*] Wait...
[*] Ending memory: 6747068 kB
[*] Memory lost: 892 kB
--- meminfo_before.txt 2025-06-30 11:21:44.922597662 +0000
+++ meminfo_after.txt 2025-06-30 11:23:35.023419139 +0000
@@ -1,38 +1,38 @@
MemTotal: 8133036 kB
-MemFree: 6853796 kB
-MemAvailable: 6747960 kB
-Buffers: 2920 kB
-Cached: 61976 kB
+MemFree: 6852956 kB
+MemAvailable: 6747244 kB
+Buffers: 2540 kB
+Cached: 62124 kB
SwapCached: 0 kB
-Active: 25968 kB
-Inactive: 83616 kB
-Active(anon): 176 kB
-Inactive(anon): 45744 kB
-Active(file): 25792 kB
-Inactive(file): 37872 kB
+Active: 26744 kB
+Inactive: 83120 kB
+Active(anon): 172 kB
+Inactive(anon): 46048 kB
+Active(file): 26572 kB
+Inactive(file): 37072 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB
SwapFree: 0 kB
-Dirty: 996 kB
+Dirty: 452 kB
Writeback: 0 kB
-AnonPages: 45116 kB
-Mapped: 54632 kB
-Shmem: 928 kB
-KReclaimable: 5680 kB
-Slab: 42392 kB
-SReclaimable: 5680 kB
-SUnreclaim: 36712 kB
-KernelStack: 1888 kB
-PageTables: 2468 kB
+AnonPages: 45372 kB
+Mapped: 59120 kB
+Shmem: 992 kB
+KReclaimable: 5940 kB
+Slab: 43056 kB
+SReclaimable: 5940 kB
+SUnreclaim: 37116 kB
+KernelStack: 1904 kB
+PageTables: 2460 kB
SecPageTables: 0 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 3542228 kB
-Committed_AS: 81484 kB
+Committed_AS: 81680 kB
VmallocTotal: 34359738367 kB
-VmallocUsed: 5056 kB
+VmallocUsed: 7112 kB
VmallocChunk: 0 kB
Percpu: 1632 kB
AnonHugePages: 2048 kB
@@ -49,6 +49,6 @@
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 1048576 kB
-DirectMap4k: 28500 kB
-DirectMap2M: 3117056 kB
-DirectMap1G: 7340032 kB
+DirectMap4k: 274260 kB
+DirectMap2M: 3919872 kB
+DirectMap1G: 6291456 kB
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/2] module: Fix memory deallocation on error path in move_module()
2025-06-18 12:26 [PATCH v2 0/2] module: Fix memory deallocation on error path in move_module() Petr Pavlu
2025-06-18 12:26 ` [PATCH v2 1/2] " Petr Pavlu
2025-06-18 12:26 ` [PATCH v2 2/2] module: Avoid unnecessary return value initialization " Petr Pavlu
@ 2025-06-30 13:57 ` Daniel Gomez
2 siblings, 0 replies; 7+ messages in thread
From: Daniel Gomez @ 2025-06-30 13:57 UTC (permalink / raw)
To: Luis Chamberlain, Sami Tolvanen, Petr Pavlu
Cc: Daniel Gomez, linux-modules, linux-kernel
From: Daniel Gomez <da.gomez@samsung.com>
On Wed, 18 Jun 2025 14:26:25 +0200, Petr Pavlu wrote:
> The first patch is an actual fix. The second patch is a minor related
> cleanup.
>
> Changes since v1 [1]:
> - Initialize t to MOD_MEM_NUM_TYPES in move_module(), instead of assigning
> the value later.
> - Merge the definitions of the variables i and ret in move_module().
>
> [...]
Applied, thanks!
[1/2] module: Fix memory deallocation on error path in move_module()
commit: caca01f251ac37807ff10380d5dafb9576cdfef0
[2/2] module: Avoid unnecessary return value initialization in move_module()
commit: f4e47f3ac79849846189058491ff885491223ab8
Best regards,
--
Daniel Gomez <da.gomez@samsung.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-06-30 13:57 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-18 12:26 [PATCH v2 0/2] module: Fix memory deallocation on error path in move_module() Petr Pavlu
2025-06-18 12:26 ` [PATCH v2 1/2] " Petr Pavlu
2025-06-18 14:02 ` Daniel Gomez
2025-06-30 12:09 ` Daniel Gomez
2025-06-18 12:26 ` [PATCH v2 2/2] module: Avoid unnecessary return value initialization " Petr Pavlu
2025-06-18 14:02 ` Daniel Gomez
2025-06-30 13:57 ` [PATCH v2 0/2] module: Fix memory deallocation on error path " Daniel Gomez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).