为什么 Linux 内核复制实现使用 AC 标志?

Som*_*ame 4 linux x86 assembly linux-kernel systems-programming

执行copy_user_enhanced_fast_string在Linux内核复制常规用途stac/clac在收尾和序言。perf annotate显示以下代码:

stac 
cmp  $0x40,%edx
jb   0xffffffff91281f5c
mov  %edx,%ecx
rep  movsb %ds:(%rsi),%es:(%rdi)
xor  %eax,%eax
clac
retq              
Run Code Online (Sandbox Code Playgroud)

AC 是“对齐检查(或访问控制)标志”。

是什么原因stac/clac在例程中使用?如果我们简单地删除它们会产生什么后果?

Ros*_*dge 8

通常,所有页面访问检查在主管模式下都是禁用的,内核可以读取或写入任何页面,无论其是只读页面还是标记为主管或用户页面。但是,如果启用了超级用户模式访问保护(CR4.SMAP = 1),则 AC 标志控制内核是否可以读取或写入用户模式页面。如果 EFLAGS.AC 为 0,则读取或写入用户模式页面将导致页面错误异常。如果 EFLAGS.AC 为 1,则允许内核读取和写入用户模式页面。

发明了 STAC 和 CLAC 指令以允许快速轻松地更改代码中的 AC 标志,例如您的示例。通过设置 EFLAGS.AC,允许 REP MOVSB 指令访问用户模式页面。通过最后清除 EFLAGS.AC,内核再次受到保护,防止可能被恶意代码利用的意外用户模式访问。

  • @SomeName 它可能不会导致内核恐慌,至少不会直接导致。该代码旨在捕获页面错误异常。内核源代码中的“_ASM_EXTABLE_UA(1b, 12b)”行为 REP MOVSB 指令(位于标签“1:”处)创建一个异常表条目,如果该指令导致执行标签“12:”处的代码,则会执行该异常表条目。页面错误。如果 AC 被清除,则执行 REP MOVSB 应该在第一次内存访问时出错,并且“copy_user_enhanced_fast_string”函数将返回 0,表明已复制 0 个字节。这可能最终导致内核恐慌。 (4认同)