Memory management 在PTE中更改PFN时延迟Linux内核死机

Memory management 在PTE中更改PFN时延迟Linux内核死机,memory-management,linux-kernel,Memory Management,Linux Kernel,我正在运行一个内核模块,当模块卸载时,我在一段时间后遇到了内核死机。 内核模块做了几件事。 1.virt_addr1=kmalloc(4096) 2.virt_addr2=kmalloc(4096) 3.查找virt_addr1和virt_addr2的PTE。 4.将virt_addr1的PFN设置为virt_addr2的PTE,这样virt_addr2和virt_addr1基本上指向相同的PFN和页面。 5.通过调用invlpg刷新TLB。 6.将virt_addr2的PTE更改回其原始PFN

我正在运行一个内核模块,当模块卸载时,我在一段时间后遇到了内核死机。
内核模块做了几件事。
1.virt_addr1=kmalloc(4096)
2.virt_addr2=kmalloc(4096)
3.查找virt_addr1和virt_addr2的PTE。
4.将virt_addr1的PFN设置为virt_addr2的PTE,这样virt_addr2和virt_addr1基本上指向相同的PFN和页面。
5.通过调用invlpg刷新TLB。
6.将virt_addr2的PTE更改回其原始PFN。
7.kfree(virt_adddr1)和kfree(virt_addr2)
8.卸载模块

在module dir中运行'make',然后内核死机,如下所示

[ 1980.579451] RIP: 0010:[<ffffffff811ff44a>]  [<ffffffff811ff44a>] getname_kernel+0xda/0x120
[ 1980.583728] RSP: 0018:ffff8804a596bd38  EFLAGS: 00010283
[ 1980.586396] RAX: 1111111111111111 RBX: 1111111111111111 RCX: 0000000000000000
[ 1980.590111] RDX: 000000000001bd58 RSI: 1111111111111111 RDI: 111111111111112d
[ 1980.593795] RBP: ffff8804a596bd58 R08: ffff8804a0dfbc00 R09: 0000000000000000
[ 1980.597418] R10: 2d3638782d78756e R11: 00322e6f732e3436 R12: 000000000000001c
[ 1980.601093] R13: fffffffffffffff4 R14: ffff8804a1380f20 R15: ffff8804a1bee038
[ 1980.604736] FS:  00007efd1517c700(0000) GS:ffff8804bd940000(0000) knlGS:0000000000000000
[ 1980.608942] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1980.611885] CR2: 00007fb42fc7ad0c CR3: 00000004a5864000 CR4: 00000000001406e0
[ 1980.615509] Stack:
[ 1980.616565]  ffff8800ba1fb380 ffff8804a0dfae00 00000000fffffff8 ffff8804a596c000
[ 1980.620540]  ffff8804a596bd78 ffffffff811f5b91 ffff8800ba1fb380 ffff8804a0dfae00
[ 1980.624527]  ffff8804a596be60 ffffffff81249e4c 0000000000000000 0000000000000000
[ 1980.628518] Call Trace:
[ 1980.629791]  [<ffffffff811f5b91>] open_exec+0x11/0x50
[ 1980.632362]  [<ffffffff81249e4c>] load_elf_binary+0x2bc/0x1710
[ 1980.635288]  [<ffffffff811a0222>] ? get_user_pages+0x52/0x60
[ 1980.638132]  [<ffffffff811f610e>] search_binary_handler+0x9e/0x1d0
[ 1980.641241]  [<ffffffff811f79dc>] do_execveat_common.isra.36+0x52c/0x710
[ 1980.645204]  [<ffffffff811f7e5a>] SyS_execve+0x3a/0x50
[ 1980.648518]  [<ffffffff81804ba5>] stub_execve+0x5/0x5
[ 1980.651829]  [<ffffffff8180491b>] ? entry_SYSCALL_64_fastpath+0x16/0x6a
[ 1980.655781] Code: 80 80 06 00 00 48 85 c0 74 0e 8b 00 85 c0 75 08 48 89 df e8 69 e7 f0 ff 49 89 dd 5b 4c 89 e8 41 5c 41 5d 41 5e 5d c3 48 8d 78 1c <48> 89 38 eb a3 48 8b 3d ca 34 d3 00 48 89 c6 49 c7 c5 dc ff ff  
[1980.579451]RIP:0010:[]getname\u内核+0xda/0x120
[1980.583728]RSP:0018:ffff8804a596bd38 EFLAGS:00010283
[1980.586396]RAX:1111111 RBX:1111111 RCX:0000000000000000
[1980.590111]RDX:000000000001bd58 RSI:1111111 RDI:11111111 2D
[1980.593795]RBP:ffff8804a596bd58 R08:ffff8804a0dfbc00 R09:0000000000000000
[1980.597418]R10:2d3638782d78756e R11:00322e6f732e3436 R12:00000000000000 1C
[1980.601093]R13:fffffffffffffff4 R14:ffff8804a1380f20 R15:FFFF8804A1038
[1980.604736]FS:00007efd1517c700(0000)GS:ffff8804bd940000(0000)KNLG:0000000000000000
[1980.608942]CS:0010 DS:0000 ES:0000 CR0:00000000 80050033
[1980.611885]CR2:00007fb42fc7ad0c CR3:0000000 4A5864000 CR4:0000000000 1406E0
[1980.615509]堆栈:
[1980.616565]ffff8800ba1fb380 ffff8804a0dfae00 00000000 FFFFFFF 8 ffff8804a596c000
[1980.620540]ffff8804a596bd78 ffffffff811f5b91 ffff8800ba1fb380 ffff8804a0dfae00
[1980.624527]ffff8804a596be60 ffffffff81249e4c 0000000000000000000000000000000000
[1980.628518]呼叫跟踪:
[1980.629791][]打开执行+0x11/0x50
[1980.632362][]加载elf二进制文件+0x2bc/0x1710
[ 1980.635288]  [] ? 获取用户页面+0x52/0x60
[1980.638132][]搜索二进制处理程序+0x9e/0x1d0
[1980.641241][]执行公用程序。isra.36+0x52c/0x710
[1980.645204][]系统执行+0x3a/0x50
[1980.648518][]存根执行+0x5/0x5
[ 1980.651829]  [] ? 条目\u系统调用\u 64\u快速路径+0x16/0x6a
[1980.655781]代码:80 80 06 00 48 85 c0 74 0e 8b 00 85 c0 75 08 48 89 df e8 69 e7 f0 ff 49 89 dd 5b 4c 89 e8 41 5c 41 5d 41 5e 5d c3 48 8d 78 1c 89 38 eb a3 48 8b 3d ca 34 d3 00 48 89 c6 49 c7 c5 dc ff ff

通过大量测试和重新启动,我想我找到了解决恐慌的方法。
介于
6.将virt_addr2的PTE更改回其原始PFN。
7.kfree(virt_adddr1)和kfree(virt_addr2)
将PTE更改回其原始PFN后,需要再次冲洗TLB

通过TLB冲洗,不再出现恐慌。

我不知道背后的原因,如果有人能分享更多细节,那就太好了。

virt\u addr1
virt\u addr2
页面对齐(也许这是个愚蠢的问题)?使用
\u获取免费页面()
免费页面()
有什么区别吗?这一点很好。我使用了kmalloc,virt_addr1和virt_addr2都是页面对齐的。我试图使用page的API,但我也遇到了同样的错误。我不知道PTE/page结构中是否有其他内核组件引用的内容,在更改PTE字段后可能会触发崩溃。