Linux 内核如何在 copy_from_user 中临时禁用 x86 SMAP?
Posted
技术标签:
【中文标题】Linux 内核如何在 copy_from_user 中临时禁用 x86 SMAP?【英文标题】:How does the Linux kernel temporarily disable x86 SMAP in copy_from_user? 【发布时间】:2020-08-09 22:50:31 【问题描述】:我想知道Linux内核在执行copy_from_user()
函数时如何禁用x86 SMAP。我试图在源代码中找到一些东西,但我失败了。
Supervisor Mode Access Prevention (SMAP) 是 x86 CPU 的一项安全功能,可防止内核访问意外的用户空间内存,有助于抵御各种攻击。
【问题讨论】:
如果您能告诉我相关代码,我将不胜感激 能否请您扩展“SMAP”的首字母缩写词? 管理模式访问保护 (SMAP) 是 Intel CPU 的一项安全功能,可防止内核访问意外的用户空间内存,进而帮助抵御各种攻击。 copy_from_user 函数将数据从用户空间复制到内核空间,但在 SMAP 保护下,在内核空间访问用户空间内存是非法的。所以当真正复制数据的时候,内核会暂时关闭SMAP保护,这样就可以从用户空间传输数据,当传输完成后,SMAP保护会再次开启。 更多信息可见en.wikipedia.org/wiki/Supervisor_Mode_Access_Prevention 【参考方案1】:如您链接的***页面中所述:
当内存分页处于活动状态并且 CR4 控制寄存器中的 SMAP 位被设置时,SMAP 被启用。通过设置 EFLAGS.AC(对齐检查)标志,可以暂时禁用 SMAP 以进行显式内存访问。
stac
(设置 AC 标志)和clac
(清除 AC 标志)指令可用于轻松设置或清除标志。
Linux 内核正是这样做来临时禁用 SMAP:它在复制数据之前使用stac
设置 EFLAGS.AC,然后在完成后使用clac
清除 EFLAGS.AC。
The AC flag 自 486 以来一直以alignment check for user-space load/store 存在; SMAP 重载了该标志位的含义。 stac
/clac
是 SMAP 的新功能,仅允许在内核模式下使用 (CPL=0);它们在用户空间出现故障(在没有 SMAP 的 CPU 上,也在内核模式下)。
理论上它很简单,但实际上 Linux 内核代码库是一个由函数、宏、内联汇编模板等组成的丛林。要确切了解这是如何完成的,我们可以查看源代码,从 @987654325 开始@:
当copy_from_user()
被调用时,它会快速检查内存范围是否有效,然后调用_copy_from_user()
...
...它会再做几次检查,然后调用raw_copy_from_user()
...
...在进行实际复制之前,它调用__uaccess_begin_nospec()
...
...这只是一个扩展为stac(); barrier_nospec()
的宏。
关注stac()
,这是一个简单的内联函数,我们有:
alternative("", __ASM_STAC, X86_FEATURE_SMAP);
alternative()
宏是一个非常复杂的宏,用于在内核启动时根据 CPU 支持选择指令的替代项。您可以检查定义它的源文件以获取更多信息。在这种情况下,它用于根据 CPU 支持来决定内核是否需要使用 stac
指令(旧的 x86 CPU 没有可用的 SMAP,因此没有指令:在那些 CPU 上,这只是变成无操作)。
看看我们看到的__ASM_STAC
宏:
#define __ASM_STAC ".byte 0x0f,0x01,0xcb"
这是组装的stac
操作码(以字节为单位)。这是使用.byte
指令而不是助记符定义的,因为即使在旧的工具链上也需要编译,而 binutils 的版本不知道这些指令。
在启动时,cpuid
指令用于检查X86_FEATURE_SMAP
(ebx
的第 20 位,当cpuid
与eax=7, ecx=0
一起执行以获得extended features),这告诉内核SMAP 是否可用(重写机器代码以使指令变为stac
)或不可用(保持无操作)。
一旦完成所有这些疯狂(实际上都归结为一条指令),从用户内存执行实际复制,然后使用__uaccess_end()
宏重新-启用 SMAP。这个宏使用alternative()
的方式和我们刚刚看到的一样,最终执行clac
(或nop
)。
【讨论】:
您删除了关于stac
/ clac
的“出于某种原因”评论,仅在 CPL0 上可用。它确实值得评论,因为您可以在任何模式下使用pushf
/popf
做同样的事情。如果我不得不猜测,那是为了性能,所以stac
可以在启用 SMAP 时切换权限检查,而不是对齐检查。 (AC的对齐检查效果只适用于用户空间,CPL3)。 IDK 如果它或 popf 序列化加载/存储;如果重命名 SMAP 状态,他们可能会这样做。以上是关于Linux 内核如何在 copy_from_user 中临时禁用 x86 SMAP?的主要内容,如果未能解决你的问题,请参考以下文章
[转] copy_to_user和copy_from_user两个函数的分析