第48期 | 别信那张纸条
一、别信那张纸条:内核为什么从不直接碰用户内存
用户程序调 read(fd, buf, 100)。buf 是个指针——一张纸条,上面写着"去我家这个地址拿东西"。
内核的第一纪律:纸条先验后用,永不直接伸手。
为什么?纸条可能是假的。野指针、没映射过的地址,内核要是闭眼照着去,能把自己绊一个跟头——用户进程摔了只死一个,内核摔了整机陪葬。纸条写的是用户家的地址,内核家住高地址,两套门牌不能混。更阴的是第三种:纸条在半路被换掉。验完还没用,另一个线程把内存改了——TOCTOU,验了个寂寞。
所以搬运只走一条路:copy_from_user、copy_to_user¹。这两个函数有个怪脾气:返回的不是成功失败,而是"没搬成的字节数"——0 才算全搬完。验货缺斤少两,退的是差数,不是整单。搬不动,就退 EFAULT(14 号错误),man read(2) 写得冷冰冰:"buf is outside your accessible address space"²——纸条上的地址,不在你的地盘。
2012 年,Intel 把这条纪律焊进了 CPU:SMAP³。CR4 寄存器里的一位,置上之后,内核态伸手碰用户内存,硬件直接 page fault。只有 STAC、CLAC 两条指令能临时开禁。H. Peter Anvin 把它接进 3.7 内核(2012 年 12 月)。连 CPU 都不相信内核会老实——不信,才是常态。
反例在 2009 年 8 月。CVE-2009-2692⁴⁵:sock_sendpage 里一个没初始化的函数指针,空指针解引用。从 2001 年 5 月起,所有 2.4、2.6 内核都带着这个病,潜伏八年。Julien Tinnes 和 Tavis Ormandy 披露了它:mmap 零页,往零页里放代码,再调一个没实现的 socket 操作——内核照着空纸条跳进去,跳进了攻击者的代码,本地提权。门没验纸条,纸条是空的。
照见一层平时看不见的。硬约束:验纸条的税必须交,因为代价不对称。谁买单:每一次 copy 的 CPU 开销,和满内核的验货代码。被大家默认的前提是错的:"指针就是地址,地址就能用"。不,指针只是一句声称,声称需要验。
二、意图也得验:AI 时代的纸条更难验
如果 AI 的操作系统先出现,agent 递进来的不再是内存地址,是引用:一段文件 URI、一组工具参数、一句自然语言指令。验纸条升级成验意图:引用有效吗?过期了吗?权限够吗?参数里藏着 prompt injection 吗?
今天的 copy_from_user,对应明天的输入校验层。AI 时代的第一条内核纪律,照抄这条:永远不要信任 agent 递进来的字符串。
零拷贝是这条纪律的另一面。io_uring 的固定 buffer、GPU 的用户态提交——数据根本不进内核,内核连验的机会都没有。信任边界上移:从"验每一次搬运",变成"验谁有资格注册这块 buffer"。门还在,只是安检口搬了地方。
香农 1948 年就把这事说透了⁶(思想化用):指针是地址信息,搬运是信道,copy_from_user 是带校验的信道编码。门里门外的数据流,全是他的地盘。
三、今晚,给内核递一张假纸条
手边任何一台 Linux 机器,三行 Python,亲手验:
import ctypes
libc = ctypes.CDLL(None, use_errno=True)
ret = libc.write(1, 0xdeadbeef, 100)
print(ret, ctypes.get_errno())
输出 -1,14。0xdeadbeef 是张假纸条,内核看一眼就打回:EFAULT。再用 strace 看现场:
strace -e trace=write python3 fake_note.py
write(1, 0xdeadbeef, 100) = -1 EFAULT (Bad address)。(本机实测跑通。)
注意它没崩。纸条是假的,使者不斩——EFAULT 就是"纸条是假的"的官方说法。
落点:写内核模块或 eBPF 程序的人,用户指针先验后用,这是铁律;做 agent 网关的人,agent 传进来的文件路径和工具参数先验后用——同一条纪律,换了身衣服。
觉 然 小 注
凡所有相,皆是虚妄。指针是相,验过才是实在——化用《金刚经》第五分"如理实见分"的思想。(思想化用)
引 用 与 出 处
- [1] Love, R. Linux Kernel Development, 3rd ed. Addison-Wesley(出版社), 2010.
- [2] Linux man-pages 项目. read(2)(EFAULT:"buf is outside your accessible address space"). https://manpages.ubuntu.com/manpages/noble/en/man2/read.2.html
- [3] Corbet, J. Supervisor mode access prevention. LWN.net, 2012-09-26. https://lwn.net/Articles/517475/
- [4] CVE-2009-2692. MITRE(存档站), 2009. http://cve.mitre.org/cgi-bin/cvename.cgi?name=2009-2692
- [5] Leyden, J. Bug exposes eight years of Linux kernel. The Register, 2009-08-14. https://www.theregister.com/2009/08/14/critical_linux_bug
- [6] Shannon, C. E. A Mathematical Theory of Communication. Bell System Technical Journal(期刊), 1948. (思想化用)
- [7] 鸠摩罗什 译. 《金刚般若波罗蜜经》第五分"如理实见分". 后秦弘始年间(约402年)译本. ("凡所有相,皆是虚妄"一句,思想化用)
· · ·