[PATCH v1] test_sysctl: unregister tables before freeing bitmap

Yibo Tan posted 1 patch 6 days, 4 hours ago
lib/test_sysctl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[PATCH v1] test_sysctl: unregister tables before freeing bitmap
Posted by Yibo Tan 6 days, 4 hours ago
The table registered for bitmap_0001 retains a pointer to
test_data.bitmap_0001. unregister_sysctl_table() prevents new handlers
from starting and waits for active handlers to finish.

test_sysctl_exit() currently frees the bitmap before unregistering the
table. A concurrent read during module removal can therefore enter
proc_do_large_bitmap() while the bitmap is freed. KASAN reports a
slab-use-after-free in _find_next_bit().

Unregister all tables before freeing the bitmap so the unregister rundown
provides the required lifetime boundary.

The unmodified module reproduced the use-after-free in three KASAN runs.
With this change, three runs each completed 100 load, read and unload race
rounds without a kernel diagnostic.

Fixes: 2ea622b887e7 ("tools/testing/selftests/sysctl/sysctl.sh: add proc_do_large_bitmap() test case")
Assisted-by: Codex:GPT-5
Signed-off-by: Yibo Tan <lhfff@tju.edu.cn>
---
 lib/test_sysctl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c
index 909cfcf76dbfc..dd795979558a2 100644
--- a/lib/test_sysctl.c
+++ b/lib/test_sysctl.c
@@ -321,11 +321,11 @@ module_init(test_sysctl_init);
 
 static void __exit test_sysctl_exit(void)
 {
-	kfree(test_data.bitmap_0001);
 	for (int i = 0; i < TEST_H_SIZE; i++) {
 		if (ctl_headers[i])
 			unregister_sysctl_table(ctl_headers[i]);
 	}
+	kfree(test_data.bitmap_0001);
 }
 
 module_exit(test_sysctl_exit);

base-commit: 40288c9206c17eb66a603262e06a58d300d0f279
-- 
2.39.5
Re: [PATCH v1] test_sysctl: unregister tables before freeing bitmap
Posted by Joel Granados 14 hours ago
On Sun, Sep 20, 2026 at 02:51:10AM +0800, Yibo Tan wrote:
> The table registered for bitmap_0001 retains a pointer to
> test_data.bitmap_0001. unregister_sysctl_table() prevents new handlers
> from starting and waits for active handlers to finish.
> 
> test_sysctl_exit() currently frees the bitmap before unregistering the
> table. A concurrent read during module removal can therefore enter
> proc_do_large_bitmap() while the bitmap is freed. KASAN reports a
> slab-use-after-free in _find_next_bit().
> 
> Unregister all tables before freeing the bitmap so the unregister rundown
> provides the required lifetime boundary.
> 
> The unmodified module reproduced the use-after-free in three KASAN runs.
> With this change, three runs each completed 100 load, read and unload race
> rounds without a kernel diagnostic.
> 
> Fixes: 2ea622b887e7 ("tools/testing/selftests/sysctl/sysctl.sh: add proc_do_large_bitmap() test case")
> Assisted-by: Codex:GPT-5

I'll change this to Assisted-by: LLM like it says in Documentation/process/coding-assistants.rst

> Signed-off-by: Yibo Tan <lhfff@tju.edu.cn>
> ---
>  lib/test_sysctl.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c
> index 909cfcf76dbfc..dd795979558a2 100644
> --- a/lib/test_sysctl.c
> +++ b/lib/test_sysctl.c
> @@ -321,11 +321,11 @@ module_init(test_sysctl_init);
>  
>  static void __exit test_sysctl_exit(void)
>  {
> -	kfree(test_data.bitmap_0001);
>  	for (int i = 0; i < TEST_H_SIZE; i++) {
>  		if (ctl_headers[i])
>  			unregister_sysctl_table(ctl_headers[i]);
>  	}
> +	kfree(test_data.bitmap_0001);
>  }
>  
>  module_exit(test_sysctl_exit);
> 
> base-commit: 40288c9206c17eb66a603262e06a58d300d0f279

I'll leave the Fixes tag but will add this to sysctl-next as opposed to
pushing it through as a fix for 7.3. Lets avoid making noise just for
the testing module.

Thx for the fix

Best

Re: [PATCH v1] test_sysctl: unregister tables before freeing bitmap
Posted by Joel Granados 11 hours ago
On Fri, Sep 25, 2026 at 11:03:31AM +0200, Joel Granados wrote:
> On Sun, Sep 20, 2026 at 02:51:10AM +0800, Yibo Tan wrote:
> > The table registered for bitmap_0001 retains a pointer to
> > test_data.bitmap_0001. unregister_sysctl_table() prevents new handlers
> > from starting and waits for active handlers to finish.
> > 
> > test_sysctl_exit() currently frees the bitmap before unregistering the
> > table. A concurrent read during module removal can therefore enter
> > proc_do_large_bitmap() while the bitmap is freed. KASAN reports a
> > slab-use-after-free in _find_next_bit().
> > 
> > Unregister all tables before freeing the bitmap so the unregister rundown
> > provides the required lifetime boundary.
> > 
> > The unmodified module reproduced the use-after-free in three KASAN runs.
> > With this change, three runs each completed 100 load, read and unload race
> > rounds without a kernel diagnostic.
> > 
> > Fixes: 2ea622b887e7 ("tools/testing/selftests/sysctl/sysctl.sh: add proc_do_large_bitmap() test case")
> > Assisted-by: Codex:GPT-5
> 
> I'll change this to Assisted-by: LLM like it says in Documentation/process/coding-assistants.rst

I'll also update the commit message header to sysctl: from test_sysctl:
> 
> > Signed-off-by: Yibo Tan <lhfff@tju.edu.cn>
> > ---
> >  lib/test_sysctl.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c
> > index 909cfcf76dbfc..dd795979558a2 100644
> > --- a/lib/test_sysctl.c
> > +++ b/lib/test_sysctl.c
> > @@ -321,11 +321,11 @@ module_init(test_sysctl_init);
> >  
> >  static void __exit test_sysctl_exit(void)
> >  {
> > -	kfree(test_data.bitmap_0001);
> >  	for (int i = 0; i < TEST_H_SIZE; i++) {
> >  		if (ctl_headers[i])
> >  			unregister_sysctl_table(ctl_headers[i]);
> >  	}
> > +	kfree(test_data.bitmap_0001);
> >  }
> >  
> >  module_exit(test_sysctl_exit);
> > 
> > base-commit: 40288c9206c17eb66a603262e06a58d300d0f279
> 
> I'll leave the Fixes tag but will add this to sysctl-next as opposed to
> pushing it through as a fix for 7.3. Lets avoid making noise just for
> the testing module.
> 
> Thx for the fix
> 
> Best
>