【发布时间】:2021-06-10 02:32:09
【问题描述】:
我正在开发内核实时补丁,实时补丁模块中的一些代码如下所示:
void list_checker() {
struct list_head *head, *iter;
head = (struct list_head *)kallsyms_lookup_name("module_name:symbol_name");
for (iter = head->next; iter != head; iter = iter->next) {
// do something.
}
}
此代码获取内核符号的地址(类型为struct list_head)并尝试迭代列表。但是由于某些原因,链表中的某些节点可能会被破坏,导致某些节点的next 指针无效(如NULL、0xABABABAB 或其他随机数),取消引用next 指针可能会导致内核崩溃。
那么有没有办法检查指针是否可以安全访问?
我已经检查了之前的两个答案:
How to check a memory address is valid inside Linux kernel?
How can I tell if a virtual address has valid mapping in ARM linux kernel?
他们告诉我使用virt_addr_valid。我有一些肯定可以访问的地址,例如 0xFFFFFFFFA032C040,但 virt_addr_valid 总是返回 false,这使我无法区分实时补丁模块中的“可访问”和“不可访问”地址。
【问题讨论】:
-
我现在不能调查这么多,但是 1) 我认为 arch/x86/mm/physaddr.c 是 virt_addr_valid 所在的位置。您可以尝试使用它来查看为什么它对所有内容都返回 False。 2) 查找 copy_to/from_user() 函数。它们可能会帮助您确定内核如何在复制之前验证地址是否合法。
-
我的地址是0x 0xFFFFFFFFA032C040(在模块区),virt_addr_valid检查一个地址是否属于0xFFFFFFFF80000000 - 0xFFFFFFFFA0000000(base + 512M)(在内核映像区),所以返回false。跨度>
-
列表在您迭代时会动态变化吗?这可以解释不好的指针。在这种情况下,仅仅因为指针看起来可以安全访问,并不意味着它实际上指向了一个有效的列表条目。
-
是的,我会将 printk 语句插入到 virt_addr_valid 函数中,以检查指针地址是否保持不变并且仍然被函数拒绝。可以让您了解正在发生的事情。
-
添加支票是真正的问题。你显然有竞争条件,代码被破坏了。
标签: linux memory-management linux-kernel patch kernel-module