LWN: 终结 /dev/kmem!
关注了就能看到更多这么棒的文章哦~
Killing off /dev/kmem
By Jonathan Corbet
April 5, 2021
DeepL assisted translation
https://lwn.net/Articles/851531/
David Hildenbrand 最近提出一个建议,希望取消对/dev/kmem 这个特殊文件的支持。这个建议没有引起多少讨论。也许这是因为如今的年轻人缺乏对历史的了解,不清楚这个文件到底是什么,从而不知道这件事为什么重要。有可能大家并不会怀念这个 /dev/kmem 接口,但它的消逝,也就代表着 Unix kernel interface 中的一个古老接口的消逝。
/dev/kmem 提供了访问内核地址空间的方法;它可以像普通文件一样被读取或写入,也可以被映射(map)到进程的地址空间。不用说,提供这样的访问能力肯定会带来一些安全问题。哪怕是对这个文件的普通 read 操作,也可能会暴露密码从而允许攻击者接管系统。因此,对/dev/kmem 的保护总是倾向于尽量加以限制的,但它仍然是一个可被利用来进入内核的公开后门,这让所有担心安全性的人更加更加担心了。
现在只有很少的 Linux 系统仍然缺省打开/dev/kmem 了。从 2008 年 7 月发布的 2.6.26 版内核开始,内核只有在启用 CONFIG_DEVKMEM 配置选项时才会创建这个特殊的文件。在 2021 年,人们很难找到一个启用了这个选项的 Linux 发行版。大多数发行版提供商在多年前就禁用了它。因此,它从内核中消失,可能不会带来太多的麻烦。
值得注意的是,Linux 系统仍然支持/dev/mem(没有 "k"),这个接口此前曾经用类似的方法,提供了对系统中所有 memory 的访问能力。很早以前,它就被限于 I/O memory 了,system RAM 是不允许的。偶尔有一些用户空间的设备驱动程序仍然需要利用/dev/mem 来生效,但其他很少有什么地方会用到它了。
人们可能会想,为什么当初会有/dev/kmem 这样危险的接口存在。内核不惜一切代价向系统其他部分隐藏内存内容,因此创建一个特殊文件来避开这种保护似乎是一个完全错误的决策。简而言之,原因是过去没有其他方法可以从内核中获取许多必要信息。
举个例子,我们来看看 top、uptime 或 w 等命令所输出的 "load average(平均负载)"数字,这些数字表示 CPU 运行队列(run queues)在 1 分钟、5分钟和 15 分钟期间的队列平均长度。在很久以前,计算机很少见,于是经常需要在同一台机器上运行许多任务,如果 load average 过高,那么那些不太紧急的任务就可能会根据 load average 值比较高这个信息来决定自己的工作推迟。这种做法会很受机器上其他用户的感激,因为这个系统上可能会有几十个用户。
但是如何确定当前的 load average 呢?Unix 内核几十年来一直在维护这些统计数据,但他们最初是把这些信息留在内核里自己用的。用户空间的代码如果想知道这个数值,就得做这些工作:
从当前内核的可执行文件中读取到符号表(symbol table)来确定 avenrun 数组的位置
打开/dev/kmem 并找到该位置。
将 avenrun 数组读到 user-space buffer 里。
那个时代的代码很难找到了,但是如果真的想看看的话,可以从早期 GNU make 版本中的 getloadavg() 函数的最底下,仔细检查那一大堆 #ifdef 就可以找到。在目前的 Linux 系统中,就只需要从/proc/loadavg 中读取一行即可。
这种在 kernel memory 中的搜索、读取,并不局限于 load average 数组这一处。还有很多需要获取更加复杂数据的工具也必须在/dev/kmem 中进行检索和读取,比如 2.9BSD 中实现的 ps 工具就是这样。那个时代都是这么做的。
要通过内核的 memory 内容来获取系统信息,除了需要实现/dev/kmem 之外,还有很多问题。内核的改变会给用户空间带来许多意想不到的影响。此外,通常需要多次读取才能得到一组完整的信息,但这组完整信息可能会在读取的同时已经发生变化了,这就导致了更多的意外情况。因此后续开始从/dev/kmem 转向了深思熟虑之后定义出来的 kernel interfaces,比如 /proc、sysfs 和各种系统调用,这样就解决了这些问题,并使得我们可以考虑禁用/dev/kmem 了。
现在,看起来 /dev/kmem 将彻底消失。Linus Torvalds 说他会 "很乐意在下一个合并窗口中这样做",但他希望确认各个发行版提供商现在确实没有再继续使用它了。已经得到了一些特定发行版的回应,不过目前看来没有人还在使用/dev/kmem。如果有谁在使用这个接口,希望能在近期告知社区。如果没有的话,这个访问内核内存的后门很快就会被完全移除。不过,编者曾经在 2.6.14 的时候就预测它要被移除了,所以没准还会有意外出现。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~