Linux kernel 鼓励CPU执行熔毁测试的无序执行

Linux kernel 鼓励CPU执行熔毁测试的无序执行,linux-kernel,x86,intel,cpu-architecture,exploit,Linux Kernel,X86,Intel,Cpu Architecture,Exploit,我试图利用英特尔Core-i5 4300MCPU上未修补的内核4.8.0-36在Ubuntu 16.04上的熔毁安全漏洞 首先,我使用内核模块将机密数据存储在内核空间的一个地址: static\uuuu init int initialize\u proc(void){ char*key_val=“abcd”; printk(“机密数据地址=%p\n”,密钥值); printk(“在%p处的值=%s\n”,键值,键值); } printk语句提供了机密数据的地址 Mar 30 07:00:49

我试图利用英特尔Core-i5 4300MCPU上未修补的内核4.8.0-36Ubuntu 16.04上的熔毁安全漏洞

首先,我使用内核模块将机密数据存储在内核空间的一个地址:

static\uuuu init int initialize\u proc(void){
char*key_val=“abcd”;
printk(“机密数据地址=%p\n”,密钥值);
printk(“在%p处的值=%s\n”,键值,键值);
}
printk语句提供了机密数据的地址

Mar 30 07:00:49 VM kernel: [62055.121882] Secret data address = fa2ef024
Mar 30 07:00:49 VM kernel: [62055.121883] Value at fa2ef024 = abcd
然后,我尝试访问此位置的数据,并在下一条指令中使用它缓存数组的元素

//无序执行
int-meldown(无符号长内核地址){
char data=*(char*)内核\u addr;//引发异常

数组[data*4096+DELTA]+=10;//我认为数据需要在L1d中,熔毁才能工作,并且尝试仅通过没有特权的TLB/页表条目读取数据不会将其带入L1d

当出现任何类型的不良结果时(页面错误,从非推测性内存类型加载,页面访问位=0),没有处理器启动取数据的非核心L2请求

除非我遗漏了什么,否则我认为只有当允许读取数据的内容将其带入L1d时,数据才容易崩溃。(直接或通过硬件预取)。我不认为重复的崩溃攻击可以将RAM中的数据带入L1d

尝试向您的模块中添加一个系统调用或其他内容,该模块对您的机密数据使用
READ_ONCE()
(或手动写入
*(volatile int*)&data;
,或将其设置为
volatile
,以便您可以轻松地触摸它),以将其从对该PTE具有权限的上下文带入缓存


另外:
add$0x01,%%eax
对于延迟失效是一个糟糕的选择。每个uop只有1个时钟周期的延迟,因此OoO exec只有约64个周期,从添加后的第一条指令进入调度程序(RS)并运行开始,直到它完成添加,故障负载达到失效


至少使用
imul
(3c延迟),或者更好地使用
xorps%xmm0,%xmm0
/重复
sqrtpd%xmm0,%xmm0
(单uop,Haswell上的16周期延迟).

在执行
attackChannel_x86
之前,您是否确保
数组
不驻留在CPU的缓存中?此外,将要偷看的字符串放在同一个(用户空间)中,可能更容易调试代码程序。一旦简化版本生效,您可以将字符串移回内核,确信您的基本熔毁实现是正确的。从缓存中清除它们由flushChannel()函数处理。我首先对它们进行操作,将它们加载到缓存中,然后使用_mm_clflush()使其无效。@undercat在字符串位于同一用户空间程序中时,80%的情况下都有效。两种情况下内存分配的唯一区别是,kthreads没有地址空间,直接写入内核空间内存,对吗?由于每个进程都映射了整个内核地址空间,因此当在用户空间中时,内核模块的地址也应该指向数据。或者我遗漏了什么?有没有办法检查CPU是否启用了预回迁支持?我正在尝试将地址预回迁到内核模块的缓存中,以使其在很长一段时间内进入一级缓存。我正在使用“内置”预回迁。@BenKenobi007:您通常可以假设HW预取已启用。它通常仅在执行微基准实验时被禁用。但是,如果您可以运行内核代码,您可以读取相关的MSR而不是写入它。
rdmsr
是一条特权指令,因此您不能从用户空间进行检查,而只能通过内核API进行检查。我已经做了e以下更改:1.在内核模块中添加预取命令2.使用sqrtd而不是Add 3.使用vmalloc而不是静态分配分配分配内存。CPU现在相当一致地吐出0。查看您链接的日志,这很可能是由于数据位于内存中而不是一级缓存中。是否有其他替代方法要预取以将数据带到缓存中?(我使用的是locality level=3)@BenKenobi007:是的,执行虚拟加载,比如Linux
READ\u ONCE(*key\u ptr)
(它只是将指针投射到
volatile T*
)。但是
内置预取(key\u ptr,0,3)
应该编译为
prefetcht0[rdi]
这也应该将数据带到L1d缓存中。您可能需要触发内核多次预取。例如,使用
静态字符键\u buf[]=“abcd”
全局变量,您可以从运行漏洞攻击的同一内核重复预取该变量。或者,如果您还没有这样做,可能您只需要
taskset-c 1
来确保modprobe和漏洞攻击都在内核1上运行。另一种让数据在L1d中保持热状态更长时间的更好方法是从内核写入数据。e.g.
static volatile char key_buf[]=“abcd”
在初始化函数中do
key_buf[1]=“x”;
~/.../MyImpl$ ./OutofOrderExecution 
Memory Access Violation
array[241*4096+DELTA]

~/.../MyImpl$ ./OutofOrderExecution 
Memory Access Violation
array[78*4096+DELTA]

~/.../MyImpl$ ./OutofOrderExecution 
Memory Access Violation
array[146*4096+DELTA]

~/.../MyImpl$ ./OutofOrderExecution 
Memory Access Violation
array[115*4096+DELTA]