Meltdown and Spectre

meltdown과 spectre 기본 아이디어는 모두 speculative execution 기술을 바탕으로 microarchitectural level의 연산과정에서 캐시에 로드된 정보를 얻어낼 수 있다는 것. meltdown은 speculative execution시 주소 접근 권한을 확인하지 않아야 한다는 전제가 필요하고, spectre는 분기 예측 시스템에 도메인이 분리되어 있지 않아야 함.

Meltdown

/*
x = 값을 알아내고자 하는 목적 주소
k = 목적 값
64 = 캐시 라인 사이즈
*/
uint8_t arr[256 * 64];
flush_cache();
k = *(uint8_t *)x; /* fault 발생 */
t = arr[k * 64];

for (i = 0; i < 256; i++) {
	time_stamp = get_tick();
	t = arr[i * 64];
	time_elapsed = get_tick() - time_stamp;
}
  1. 캐시를 비우는 것으로 작업을 준비한다
  2. 그리고 임의의 커널주소로 접근해 fault를 유도한다
  3. 권한이 없어서 접근이 거절되더라도 speculative excution으로부터 이미 해당 결과가 캐시에 로드된 상태가 된다
  4. 모든 경우의 수(256개)를 시도해 캐시 히트인지 미스인지 확인한다

초기에 캐시를 flush했기 때문에 위 루프에서 1/256개의 캐시라인만 히트하게 되고 따라서 히트한 위치가 목적한 주소의 실제 값이 된다(해당 값을 인덱스로 사용함). 히트와 미스의 구분은 접근 속도로 결정된다. 히트된 경우 미스의 경우보다 접근 속도가 훨씬 빠르기 때문.

전제된 조건들:

Spectre

Variant 1, Bounds check bypass

/*
x = 목적 주소
array1_size = not cached
array1 = cached
*/
if (x < array1_size) {
	y = array2[array1[x] * 256];
}
  1. 조건이 만족하도록 CPU를 유도
  2. array1_size가 로드되는 동안 array1[x] 결과가 캐시에 로드됨

Variant 2, Branch target injection

참고자료