Linux内核如何临时禁用copy_from_user中的x86 SMAP?

问题描述 投票:0回答:1

我想知道Linux内核在执行copy_from_user()函数时如何禁用x86 SMAP。我试图在源代码中找到某些内容,但失败了。

[Supervisor Mode Access Prevention (SMAP)是x86 CPU的一项安全功能,可以防止内核访问意外的用户空间内存,这有助于抵御各种攻击。

security linux-kernel x86 operating-system kernel
1个回答
1
投票

如您链接的Wikipedia页面中所述:

当内存分页处于活动状态并且CR4控制寄存器中的SMAP位置1时,启用SMAP。通过设置EFLAGS.AC(对齐检查)标志,可以暂时禁用SMAP进行显式内存访问。 stac(设置AC标志)和clac(清除AC标志)指令可用于轻松设置或清除标志。

Linux内核确实这样做是为了暂时禁用SMAP:它在复制数据之前使用stac设置EFLAGS.AC,然后在完成后使用clac清除EFLAGS.AC。

理论上很简单,但实际上Linux内核代码库是函数,宏,内联汇编模板等的丛林。要确切地了解如何完成操作,我们可以从copy_from_user()开始看源代码。 :

  1. copy_from_user()被调用时,它会快速检查内存范围是否有效,然后调用copy_from_user() ...

  2. ...这会再进行两次检查,然后调用_copy_from_user() ...

  3. ...,在进行实际复制之前,调用_copy_from_user() ...

  4. ...这只是一个扩展为raw_copy_from_user()的宏。

  5. 关注raw_copy_from_user(),这是一个简单的内联函数,我们有:

    __uaccess_begin_nospec()

__uaccess_begin_nospec()宏是一个非常复杂的宏,用于基于CPU支持在运行时为指令选择替代方案。您可以检查在其中定义了源文件的更多信息。在这种情况下,它用于基于CPU支持来有条件地决定是否执行stac(); barrier_nospec()指令(旧的x86 CPU没有SMAP,因此没有该指令:在那些CPU上,这变成了无操作)。

查看stac()宏,我们看到:

stac()

哪个是汇编的alternative("", __ASM_STAC, X86_FEATURE_SMAP); 操作码,以字节为单位。这是用alternative()指令而不是助记符定义的,因为同样,即使在不存在该指令的旧CPU上,也需要编译该指令。在运行时,alternative()指令用于检查stac(当用__ASM_STAC执行__ASM_STAC以获取#define __ASM_STAC ".byte 0x0f,0x01,0xcb" 时,stac的第20位),这告诉内核SMAP是否可用(使指令变为.byte)(或保持无操作状态)。

一旦完成所有这些疯狂操作(实际上全部都归结为一条指令),就会执行来自用户内存的实际复制,然后使用cpuid宏重新启用SMAP。此宏以与我们刚看到的相同的方式使用X86_FEATURE_SMAP,并最终执行ebx 如果需要

© www.soinside.com 2019 - 2024. All rights reserved.