从 Linux 内核内部访问用户空间指针时会导致内核 OOP

从 Linux 内核内部访问用户空间指针时会导致内核 OOP

一些背景:

我有一个嵌入式Linux ARM 4.1.33系统,已经打了抢占实时补丁。该系统包含一些自定义修改的内核代码,并且偶尔会遇到内核错误。经过一番调试后发现,其中一位开发人员不理解内核空间和用户空间之间的区别,并且他们在不使用 uaccess.h 中定义的函数的情况下取消引用用户空间指针。

此后,我修改了有问题的函数以使用 uaccess.h 中定义的函数,以防止发生进一步的内核 oops。我现在正在尝试验证修复是否成功。然而,由于原始内核 oops 是随机发生的,有时一次几天都不会发生,所以我想找到一些方法来可靠地在原始代码中重新创建它,然后验证它是否不再出现在更新的代码中。

尽管有问题的函数错误地使用了指针,但它似乎确实使用指针正确地修改了用户空间值(不包括发生内核 oops 时)。这向我表明指针的地址在用户空间和内核空间中“意味着相同的事情”。鉴于这一事实,我知道这种取消引用可能导致内核错误的唯一原因是,如果包含该地址的页面被发送到交换,从而导致页面错误。然而,由于闪存的寿命有限,我们的系统已禁用交换,因此这种情况看起来不太可能发生。

问题:

与从内核空间内取消引用用户空间指针相关的 Linux 内核 oops 的潜在原因是什么?我怎样才能可靠地导致这样的内核错误发生,以验证它在应用修复后不再发生?

答案1

除了页面被换出的可能性之外,还有两个原因可能会导致此失败。

  1. 如果从用户地址读取,该页面必须可读。编写和执行也是如此。
  2. 用户空间地址不属于该进程。尽管内核地址与物理地址具有一致的一对一映射,但用户空间中的相同虚拟地址可能指向不同的物理地址,具体取决于当前进程。

答案2

可以编译 32 位内核,以便进程获得 4GB 地址空间(减去几页)。如果您这样做了,则所有用户空间指针在内核空间中都无效*。但你会知道你已经做到了这一点。

*它们可能不会崩溃;它们可能只是指向任意内核内存,但写入它们会导致 oops。

答案3

我目前无法检查是否存在,但我相信如果页面当前设置为“写入时复制”(可能是通过之前的fork()调用),它会哎呀。内核页面不应该是写时复制的。

相关内容