文章摘要
Linux系统中/proc/self/mem文件具有特殊写入特性:即使目标内存被标记为不可写,通过该文件的写入操作仍能成功。这种"穿透"设计被Julia JIT编译器和rr调试器等工具实际应用,反映了操作系统内核可以绕过硬件内存保护机制的特殊能力,展现了系统内核与硬件权限控制的微妙关系。
文章总结
标题:Linux内核探秘:/proc/self/mem如何写入不可写内存
文章核心内容:
- 特殊现象揭示
- /proc/*/mem伪文件具有"穿透写入"特性,即使目标虚拟内存标记为不可写,仍能成功写入
- 该特性被Julia JIT编译器和rr调试器等项目实际应用
- 技术验证实验
- 通过C++代码演示如何修改只读内存页和libc代码段
- 成功将0x41414140写入只读内存并验证读取
- 通过写入0xCC触发SIGTRAP信号,证实成功修改libc的getchar函数
- 硬件机制分析
- x86-64通过CR0.WP(写保护位)和CR4.SMAP(管理模式访问防护)控制内核内存访问
- CR0.WP默认允许内核写入只读页,而SMAP完全禁用内核访问用户空间内存
- 实际系统启动时CR0.WP被启用,但内核可通过故障处理绕过限制
- 内核实现原理
- /proc/*/mem通过三层机制绕过MMU限制: a) 使用getuserpagesremote()进行物理帧查找(配合FOLLFORCE标志忽略写保护) b) 通过kmap()将物理帧映射到内核可写地址空间 c) 调用copytouser_page()执行实际写入操作
- 整个过程巧妙规避了CR0.WP限制,直接操作物理内存
- 关键认知突破
- 内存权限与虚拟地址绑定,而非物理内存本身
- 内核通过完全掌控虚拟内存系统,可自由重映射物理内存
- CPU提供的保护机制实际只能构成表面约束
- 行业影响
- 该技术被多个安全研究和漏洞分析引用,包括Dirty Cow漏洞分析等
- 揭示了操作系统与硬件间的微妙关系,展现内核绕过硬件限制的能力
文章通过具体代码示例、硬件原理分析和内核实现解读,系统性地阐释了这个看似违反内存保护机制的特性背后的技术原理,最终得出"CPU对内核的限制只是表面约束"的重要结论。
评论总结
这篇讨论围绕Linux内核如何绕过内存保护机制访问内存展开,主要观点如下:
- 内核绕过内存保护的能力
- 支持观点:内核拥有页表控制权,总能找到访问方法(评论1:"The kernel owns the page tables. It can always find another way in.")
- 技术细节:通过/proc/self/mem写入时,内核会绕过MMU进行软件模拟(评论3:"the kernel bypasses the MMU...allows it to disregard any memory protection")
- CPU内存保护机制的复杂性
- 技术补充:x86-64有多种内存保护设置,包括Memory Protection Keys、虚拟化NPT/EPT表等(评论2:"There are a couple more than two...SEV and SGX also have their own ways")
- 特殊案例:TDX模块等特殊物理地址范围也受保护(评论2:"the TDX module's range. You can't write there")
- 实现细节讨论
- 权限检查:代码仍会检查VMMAYWRITE标志(评论5:"it does still check VMMAYWRITE")
- 历史背景:Linus曾试图修改这个行为(评论4:"I'm still surprised I was the first one to notice")
- 文件系统批评
- 对比观点:Linux的/proc是对Plan9的拙劣模仿(评论6:"/proc it's a bad imitation of plan9's /proc")