ILD

stop kthread kernel panic
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2023-9-14 站点:Inside Linux Development

ipq5018卸载ecm加速模块的时候,出现kernel panic,内核版本4.4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = 862f4000
[00000000] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
Modules linked in: test(-)
CPU: 0 PID: 3248 Comm: rmmod Tainted: P                4.4.60 #0
Hardware name: Generic DT based system
task: 87a1a400 ti: 8a1c4000 task.ti: 8a1c4000
PC is at exit_creds+0x1c/0x7c
LR is at __put_task_struct+0x6c/0xb8
pc : [<8123cf8c>]    lr : [<81223378>]    psr: 20000013
sp : 8a1c5f28  ip : 00000090  fp : 00000000
r10: 00000000  r9 : 8a1c4000  r8 : 81209ce4
r7 : 00000081  r6 : 00000000  r5 : 86475f88  r4 : 86475f80
r3 : 00000000  r2 : ffffffff  r1 : 00000091  r0 : 00000000
Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c0383d  Table: 462f406a  DAC: 00000055
Process rmmod (pid: 3248, stack limit = 0x8a1c4210)
Stack: (0x8a1c5f28 to 0x8a1c6000)
5f20:                   86475f80 86475f88 00000000 81223378 86475f80 8123bdc0
5f40: 7f002140 76f616c0 7eb18f7f 00000081 81209ce4 8127ebe4 8f5b16e8 74736574
5f60: 00000000 812ca484 00000020 00000000 87a1a400 00000000 87a1a400 00000000
5f80: 817f05c0 00000006 81209ce4 8a1c4000 8a1c5fb0 00000006 81209ce4 00000000
5fa0: 00000000 81209b40 00000000 00000000 76f616c0 00000000 00000000 00000000
5fc0: 00000000 00000000 7eb18f7f 00000081 54b5dafc 54b6df10 00000001 00000000
5fe0: 7eb18da4 7eb18d88 54b5bf70 76f1b70c 20000010 76f616c0 e2800060 e59f2174
[<8123cf8c>] (exit_creds) from [<81223378>] (__put_task_struct+0x6c/0xb8)
[<81223378>] (__put_task_struct) from [<8123bdc0>] (kthread_stop+0x94/0x9c)
[<8123bdc0>] (kthread_stop) from [<8127ebe4>] (SyS_delete_module+0x11c/0x1e0)
[<8127ebe4>] (SyS_delete_module) from [<81209b40>] (ret_fast_syscall+0x0/0x34)
Code: e590031c e584331c f57ff05b f590f000 (e1902f9f)
---[ end trace 1049bc8959325377 ]---


查看代码,是结束一个内核线程的时候,出现了panic。结束内核线程使用kthread_stop()函数,怀疑是线程提前结束,调用kthread_stop导致kernel panic,写一个小demo验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
 
struct task_struct *k;
 
static int thread_fn(void *data)
{
        return 0;
}
 
static int __init test_init(void)
{
        k = kthread_run(thread_fn, NULL, "test thread");
        if (!k)
                return -1;
 
        return 0;
}
 
static void __exit test_exit(void)
{
        kthread_stop(k);
}
 
module_init(test_init);
module_exit(test_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jianpeng Yuan");
MODULE_DESCRIPTION("test module");


安装,然后卸载,复现了问题。thread_fn是自己结束的,内核会自动回收stask_struct结构体。再调用kthread_stop()将导致非法内存访问。


如果内核线程是判断kthread_should_stop()结束的,如下:

static int thread_fn(void *data)

{

        while (!kthread_should_stop()) {

                schedule_timeout_interruptible(10);

        }


        return 0;

}

那么,使用kthread_stop()是安全的。kthread_should_stop()非常简单,就是测试KTHREAD_SHOULD_STOP位。

test_bit(KTHREAD_SHOULD_STOP, &to_kthread(current)->flags);


而kthread_stop()会 set_bit(KTHREAD_SHOULD_STOP, &kthread->flags); 因此再kthread_stop()之前,内核线程不会退出。

这就保证了kthread_stop()是安全的。


如果内核线程有多种退出途径,比如:

static int thread_fn(void *data)

{

        while (!kthread_should_stop()) {

                schedule_timeout_interruptible(10);


                if(signal_pending(current))

                        break;

        }


        return 0;

}

如果有挂起的信号也退出,那么就可能在kthread_stop之前退出,此时直接使用kthread_stop也是不安全的。


此时的解决办法,是提前

获得task_struct的引用计数。kthread_stop()之后,再释放引用计数。这样可以保证即使线程再stop之前结束,也不会被释放。

static int __init test_init(void)

{

        k = kthread_create(thread_fn, NULL, "test thread");

        if (!k)

                return -1;


        get_task_struct(k);

        wake_up_process(k);


        return 0;

}


static void __exit test_exit(void)

{

        kthread_stop(k);

        put_task_struct(k);

}



参考

https://stackoverflow.com/questions/37842330/kthread-stop-crashes-the-kernel


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.