다시봐도 좋은 양질의 글들을 모아놓는 게시판입니다.
Date 2018/01/10 02:04:22
Name 나일레나일레
Link #1 https://spectreattack.com/
Subject CPU 취약점 분석 - 멜트다운 (수정됨)
자유게시판에는 처음 글을 쓰게 되네요.

사실 이걸로 글까지 쓸 생각은 없었는데, 네이버 메인에 잘못된 정보가 올라와 있는 걸 보고 글을 쓰려고 마음먹었습니다.

잘못된 정보가 올라온 링크는 다음과 같습니다.

https://blog.naver.com/tech-plus/221180348386


얼마나 쉽게 설명할 수 있을지는 모르겠지만, 그리고 제 설명과 링크의 설명이 다른 것을 이해하실 분들이 얼마나 계실지는 모르겠지만, 잘못된 정보는 바로잡아야겠다 싶네요.

그럼 시작하겠습니다.

----------------------------

0. 들어가며

이번에 발표된 CPU 취약점 버그는 서로 다른 2개입니다. 멜트다운(Meltdown)과 스펙터(Spectre) 버그죠.

두 개는 서로 다른 메커니즘으로 하드웨어 취약점을 파고들기 때문에, 같이 설명하기는 힘들고, 이번에는 좀더 민감한 멜트다운에 대해서만 살펴보겠습니다.

멜트다운 버그를 간략하게나마 이해하기 위해서는 하드웨어와 OS에 대한 이해를 필요로 하는데, 최대한 간략히 살펴보도록 하겠습니다.

다만 진짜 설명에 들어가기에 앞서, 본 글은 이해를 돕기 위해 상당히 간략화시켜서 설명을 진행하므로, 실제 CPU가 동작하는 방식과 세부적인 사항이 조금 다를 수 있다는 점을 유의하시기 바랍니다.


1. 파이프라인 (Pipeline)

main-qimg-970a6dbf2d2b62128380819dddd49842

파이프라인을 이해하기 위해서는 자동차 공장의 컨베이어 벨트를 생각해보시면 됩니다.

만약 CPU가 파이프라인 구조로 설계되지 않는다면 제시된 그림의 위와 같이 실행하게 될겁니다.

명령 하나를 읽어오고, 해석하고, 실행하고, 결과를 저장한 다음에, 그 다음 명령을 읽어오고 해석하고, 실행하고, 결과를 저장하겠죠.

마치 자동차를 조립할 때, 한 대를 처음부터 끝까지 조립한 후에, 다음 자동차 조립을 또다시 처음부터 실행하는 것처럼요.

이는 매우 비효율적입니다.

그래서 도입한 것이 파이프라인입니다. 아래에 있는 그림이죠.

컨베이어 벨트에 자동차가 돌아가면, 어떤 기계는 바퀴만 끼우고, 어떤 기계는 엔진만 끼우고, ... 하는 식으로요.

CPU도 비슷합니다.

명령어를 읽어오는 유닛 (Fetch unit)은 줄창 명령어만 읽어서 다음으로 넘기고,

명령어를 해석하는 유닛 (decode unit)은 앞에서 넘겨준 명령어를 줄창 해석만 하는 식이죠.

당연히 동일한 시간에 더 많은 명령어를 실행할 수 있습니다.

예제에서는 4단계 파이프라인이지만, 대부분의 현대 CPU는 파이프라인이 최소 10단계는 훌쩍 넘으며, 실행하는 명령어의 타입에 따라 수십 단계의 파이프라인이 적용되는 경우도 있습니다.

작업이 쪼개지면 쪼개질수록 작업 하나를 실행하는 시간은 줄어들고, 결국 작업 하나를 처리할 수 있는 최소 시간 단위인 클럭(clock)이 올라갈 수 있거든요.


2. 비순차 실행 (Out of order execution)

예전에는 CPU가 순차 실행을 했습니다.
(요즘도 저전력/저성능 CPU는 순차 실행을 합니다.)

순차 실행은 명령어가 들어오는 순서대로 처리하는 거죠. 프로그래머가 작성한대로요.

그리고 프로그래머가 의도한대로 동작하기 위해서는 순차 실행을 해야만 합니다.

그러나 순차 실행은 큰 문제가 있습니다.

파이프라인을 효율적으로 사용하지 못한다는 문제점이죠.


보통 CPU는 여러 개의 명령어를 동시에 처리할 수 있는 연산 유닛을 갖추고 있습니다.

위에서 설명한 파이프라인이 하나가 아니라 여러 개 있는 거죠.

한번에 하나만 처리하는 것보다 한번에 여러 개를 처리하는 것이 당연히 빠르니까요.

그러나 단순히 파이프라인의 개수를 늘린다고 성능이 증가하는 것은 아닙니다.

간단히 그림으로 보겠습니다. 그림은 파이프라인이 3개라고 가정합니다.

slide_7.jpg

앞쪽에 시간이 오래 걸리는 명령어가 있으면 어떻게 될까요?

보통 나눗셈, 곱셈 연산은 시간이 오래 걸립니다. 메모리에서 데이터를 읽어오는 것도 매우 오랜 시간이 걸리고요.

또한 명령어 간에는 의존성(dependency)이 존재합니다.

예제에서 (1)은 r4를 r7로 나누어서 r1에 저장하는 명령이고, (2)는 r1과 r2를 더해서 r8에 저장하는 명령입니다.

그런데 (1)의 r4 / r7의 계산이 끝나지 않았는데, (2)의 r1 + r2를 실행할 수는 없습니다. r1의 값을 모르니까요.

따라서 (2)의 명령어는 파이프라인이 남더라도 실행할 수 없습니다.

예제에서는 (1)-(2), (3)-(5), (4)-(5), (2)-(6), (5)-(6) 명령어 간 의존성이 있죠.

이렇게 시간이 오래 걸리는 연산이 (1)에 있는데, 순서를 지켜서 실행해야 한다면 어떻게 될까요.

(1)의 실행이 끝나야만 (2),(3),(4)의 명령어가 파이프라인에서 실행되고, (1)의 실행이 끝나기 전까지는 다른 두 개의 파이프라인은 놀게 됩니다.

이렇게 파이프라인이 놀고 먹으면 당연히 성능이 떨어지고, 이를 성질급한 유저가 용납할 리가 없겠죠...

이러한 현상이 발생하는 것을 막기 위해 잔머리를 굴렸는데, 이것이 비순차 실행입니다.

비순차 실행은 의존성이 없는 명령어는 새치기를 해서 먼저 실행되도록 하는 방법입니다.

아래를 보면, (1)이 끝나기도 전에, (1)과 의존성이 없는 (3), (4)를 파이프라인에 우겨넣고 실행하고 있죠.

(2)는 어쩔 수 없이 (1)이 끝나야 실행이 가능하지만, (1)과 관련없는 연산은 (1)이 실행되는 도중에 미리 실행해버리는 겁니다.

결과적으로 실행 시간이 빨라집니다.

순차 실행과 비순차 실행의 성능차이는 생각보다 커서, 고성능을 요하는 대부분의 CPU는 비순차 실행을 기본으로 합니다.


그런데 순차 실행을 비순차 실행으로 바꿔서 실행했으니, 이제 다시 프로그램의 정확한 동작을 보장하기 위해서 비순차적으로 실행된 결과를 순차적으로 저장해야 하겠지요?

이를 위해서 일반적으로 Reorder buffer라는 유닛을 두고, 비순차적으로 먼저 실행한 명령의 결과값을 임시로 저장했다가, 앞 명령어의 실행이 끝나면 실제 CPU의 상태에 반영하게 됩니다.


3. 가상 주소 공간 (Virtual address space)과 운영체제 (OS)

일반적으로 프로세스는 가상 메모리 위에서 동작합니다.

가상 메모리가 필요한 이유는 여러 가지가 있는데, 대표적으로 프로그래머에게 일관된 실행 환경을 보장하고, 여러 프로세스가 사용하는 메모리공간을 분리하여 보안성을 제공하며, 실제 메모리 (RAM) 의 양보다 더 큰 메모리를 사용할 수 있도록 하는 등입니다.

정확히 설명하면 훨씬 더 많은 내용이 있으나, 그러면 글이 너무 길어지므로 자세한 동작 메커니즘은 본 글에서는 서술하지 않겠습니다.

220px-Virtual_memory.svg.png

가상 메모리는 프로세스 (윈도우 작업관리자에 뜨는 하나하나가 다 프로세스입니다) 마다 할당된 가상의 메모리 공간입니다.

이러한 가상 메모리 공간을 접근할 때는 가상 주소 (virtual address)를 이용합니다.

이러한 가상 메모리 공간을 흔히 RAM, 메인 메모리라 부르는 실제 메모리 공간(physical memory)과 매핑하여 사용합니다.

실제 메모리에 접근할 때는 물리 주소 (physical address)를 이용합니다.

실제 RAM은 물리 주소로 동작하며, 프로세서 위에서 동작하는 프로세스는 가상 주소로 동작하는데, 어떻게 프로세스가 RAM에 데이터를 저장하고 읽어 올 수 있을까요? 이게 어떻게 가능할까요?

이게 운영체제의 가장 핵심적인 기능이며 존재 이유입니다.

운영체제는 프로세스별로 존재하는 가상 메모리를 실제 물리 메모리에 매핑하고, 이러한 매핑 정보를 프로세스별로 따로따로 저장합니다.

그리고 가상 주소가 들어오면 프로세스의 매핑 테이블을 보고 가상 주소를 물리 주소로 변환하여 데이터를 읽거나 쓰게 되죠.


이걸 바꾸어 생각하면, 운영체제는 프로세스의 가상 주소를 물리 주소로 매핑해야 하니까, 모든 물리 주소에 어떤 프로세스가 사용하는 데이터가 있는지를 다 알고 있어야 합니다. 알아야 관리를 하죠.

그리고 이러한 정보들을 저장하고 관리하기 위해 운영체제 자신이 사용하는 메모리 영역이 필요합니다. 이것을 커널 영역이라고 합니다.


그런데 이러한 커널 영역을 사용자가 마음대로 수정할 수 있으면 시스템이 제대로 유지가 안 될겁니다.

그래서 CPU는 일반적으로 실행 모드를 유저 모드와 커널 모드 두 가지로 나눕니다.

일반적으로 프로세스를 실행할 때는 유저 모드로 실행합니다. 이 때는 커널 영역에 접근할 수 없습니다.

만약 예외 상황이 발생하거나, 시스템 콜을 발생시키는 명령어가 입력되거나 하면, CPU는 커널 모드로 변경됩니다. 커널 모드로 변경된 상태에서는 커널 영역에 접근할 수 있습니다.

그리고 대부분의 I/O 작업 또한 이러한 커널 영역에서 이루어지죠.

그러나 커널 모드는 시스템에 매우 민감한 정보를 담고 있는 영역에 접근하는 것이니만큼, OS에서 제공하는 매우 제한적인 기능만 수행할 수 있습니다.


4. 캐시 메모리 (Cache)

캐시 메모리는 CPU 내에 존재하는 작은 메모리입니다.

크기와 속도에 따라 L1, L2, L3, ... 로 나누죠. 여기서 L은 Level을 의미합니다. 낮을수록 용량이 작고 속도가 빠르며, 높을수록 용량이 크고 속도가 느리죠.

micron-klein-memory-hierarchy.jpg

컴퓨터는 메모리를 계층 구조로 관리합니다. 계층이 낮을수록 속도가 느리고 용량이 크며, 계층이 높을 수록 속도가 빠르고 용량이 작죠.

용량이 크고 속도가 빠른 메모리는 존재할 수 없습니다.

이해를 쉽게 하기 위해서 여러분이 집에 있는 책상에서 일을 하고 있다고 가정합니다.

여러분이 일을 하기 위해서는 여러 물건이 필요한데, 여러분이 일하고 있는 책상 위에 있는 물건들은 CPU 내에 있는 레지스터에 저장된 데이터입니다. 언제든지 바로바로 집어서 쓸 수 있죠.

그런데 책상 위의 공간에는 한계가 있습니다. 모든 물건을 책상 위에 놓고 작업할 수 없죠.

L1 캐시는 여러분의 책상 서랍과 책장입니다. 조금 뒤져야 하고, 찾는 게 귀찮기는 하지만 그래도 빠른 시간 내에 물건을 집어서 작업을 재개할 수 있죠.

L2 캐시는 여러분의 방입니다. 방의 장롱이나 구석탱이에 있는 물건 정도가 되겠네요. 자리에서 일어나서 좀 움직여야 하는 귀찮음이 있지만, 그래도 아직까지는 꽤 빠릅니다.

L3캐시는 여러분의 집입니다. 원하는 물건을 가져오기 위해서는 다른 방이나 거실로 가서 좀 찾아야 되지만, 그래도 여기까지는 조금 번거롭긴 해도 꽤 빠르게 물건을 찾아올 수 있죠.

DRAM (메인 메모리)은 이제 집 밖으로 나가야 됩니다. 여러분 집에서 한 2~300m 떨어져 있는 슈퍼쯤 되겠네요.

이제부터는 뭔가 물건을 가져오기가 매우 귀찮고 오랜 시간이 걸립니다.

이게 SSD, HDD같은 스토리지까지 내려가면, 멀리 떨어진 슈퍼가 아니라, 아예 여러분이 사는 구, 심하면 도시 밖으로 벗어나서 물건을 찾아헤매야 되는 수준이 됩니다.


위에서 메모리에서 데이터를 읽어오는 건 매우 시간이 오래 걸리며, 그래서 비순차 실행을 한다고 말했었죠.

메모리 작업에 관련한 비순차 실행을 이 예에 비유한다면 이렇습니다. 일을 빨리 하기 위해 여러분이 직접 메모리까지 가서 데이터를 찾아오는 것이 아니라, 누군가에게 맡깁니다. 주소를 주고 여기 있는 물건이 필요한데, 네가 가서 찾아서 내 방에 갖다줘. 라는 식으로요.

그리고 나는 책상 위에 있는 물건으로 빨리 처리할 수 있는 다른 일을 합니다.

멀리 보낸 심부름꾼이 내가 원하던 물건을 가져올 때까지요.

심부름꾼이 내 방으로 물건을 갖다주면, 난 내 방에서 물건을 집어서 빠르게 일을 하는 겁니다.

물론 필요한 물건이 오지 않고, 더 이상 할 일도 없으면 놀게 되겠지요 :)


5. 멜트다운

위에서 일견 서로 다른 얘기를 주절주절 설명한 게 왜인가 하면, 위의 내용을 간략하게나마 이해하고 있어야 멜트다운이 왜 발생하는지를 이해할 수 있기 때문입니다.

다음과 같은 수도코드 (pseudo code)가 있다고 가정합니다.

(1) r1 <- Load data from secret address
(2) r2 <- Load data from array[r1]

(1)은 일반적으로 프로그램이 접근하면 안 되는 메모리 영역에 접근하여 데이터를 가져오려는 코드입니다.
(2)는 가져온 데이터를 인덱스로 이용해서 배열을 읽은 후, 읽은 결과를 r2에 저장하는 코드고요.

(1)을 CPU가 실행하려고 하면, 예외(exception)가 발생합니다. 왜냐면 프로그램이 접근할 수 없는 메모리 공간에 접근해서 데이터를 가져오려고 시도하기 때문입니다.

이러한 예외가 발생하면 CPU는 예외 처리 핸들러 (exception handler)를 호출하여 운영체제를 통해 이러한 예외상황에 대처하고자 합니다.

그런데 예외 처리 핸들러를 부르고 실행하는 데에는 긴 시간이 걸립니다.

그리고 명령어는 당장 비밀 데이터가 있는 주소로 가서 비밀 데이터를 읽으라고 되어 있습니다.

그러면 CPU는 일단 비밀 주소로 가서 비밀 데이터를 읽어오고 캐시에 저장합니다.

그리고 캐시에 저장된 데이터를 읽어 r1 레지스터에 저장합니다.

예를 들어 이 비밀 데이터를 3 이라고 가정합니다.

그리고 아직 예외 처리 핸들러의 실행이 끝나지 않았기 때문에, r1 레지스터의 값인 3을 인덱스로 활용해서 유저가 정의한 배열로 접근합니다.

배열이 사용하는 메모리 공간은 유저가 선언하고 사용하는 메모리 영역에 잡혀 있습니다.

여기서 비밀 데이터인 3을 배열의 인덱스로 사용한다는 점에 주목해야 합니다.

array[3]에 접근하게 되겠네요. 따라서 [array[3]에 존재하는 데이터는 캐시에 올라오게 됩니다].

그리고 캐시에 올라온 데이터를 읽어서 r2 레지스터에 저장합니다.

그런데 예외 처리 핸들러의 실행이 끝나서, 비밀 주소에 있는 값을 읽어오면 안 된다는 것이 밝혀졌습니다!

그러면 어떻게 될까요?

위에서 이야기한 Reorder buffer를 이용해서, 그 이후의 실행 결과를 실제 CPU 상태에 반영하지 않고 전부 버립니다.

따라서 r1 레지스터에 있는 3이라는 데이터도 폐기됩니다.

그리고 array[3]를 읽어서 r2 레지스터에 저장한 것도 폐기되죠. r2 레지스터는 아무런 값도 가지지 않습니다.

비밀 주소에 있는 값인 3은 캐시에 여전히 저장되어 있고 폐기되지 않습니다.

그러나 그 데이터에 CPU는 접근할 수 없습니다.

[네이버 메인에 올라온, 제가 읽은 링크에서는 이렇게 읽어온 비밀 데이터에 접근할 수 있는 것처럼 서술하고 있습니다.]
(이 글 본문 제일 처음에 올린 링크입니다)

아무리 그래도 이정도로 허술하게 CPU를 디자인하지는 않습니다. 당연히 이런 건 체크합니다.

캐시에 올라온 데이터에 접근 하려고 하면 주소를 체크한 후 기존과 동일하게 예외 처리 핸들러가 호출되고 접근이 안 됩니다.

그런데 이 과정에서 array[3]의 데이터가 캐시에 올라왔죠?

이렇게 캐시에 올라온 데이터는 폐기되지 않고 접근도 가능합니다!

왜냐면 array[3]은 유저가 생성한 배열에 있는 정상적인 데이터거든요.

그리고 array[3]에 저장된 데이터는 그 자체로는 아무런 의미도 지니지 않습니다.

여기서 진짜 중요한 정보는 3번째에 있는 데이터가 캐시에 올라왔다는 것입니다.

캐시에 올라온 데이터의 위치 자체가 비밀 정보가 되는 겁니다.


(3) r1 <- Load data from secret address
(4) r2 <- r1

만약 코드가 위와 같았다면 어땠을까요?

비밀 데이터를 읽어서 r1 레지스터에 저장하고, r1 레지스터의 값을 r2에 저장하겠죠.

예외 처리 핸들러의 실행이 끝나면, r1 레지스터와 r2 레지스터의 데이터가 모두 폐기되고, 읽어온 비밀 데이터는 캐시에 남아있지만, 여전히 접근할 수 없기 때문에 아무런 보안 문제가 없습니다.

그러나 위에서 제시된 (1), (2) 코드를 실행하면, array[0], array[1], array[2], array[4], ...의 데이터는 캐시에 없고, array[3]의 데이터만 캐시에 존재하게 됩니다.

다시 예를 들어 설명해 보면, 내가 일을 하다가, array[0], array[1], array[2], array[4], ... 에 있는 물건을 가져오라고 시켰습니다.

근데 가져오라고 시킨 심부름꾼들이 오지 않습니다. 왜냐면 매우 멀고 먼 메모리에 데이터가 존재하니까요. 매우 오랜 시간이 걸립니다.

그런데 array[3]을 읽으려고 하면 매우 빠르게 데이터를 가져옵니다. 이미 캐시에 올라와 있는 데이터이니까요.

그러니까 비밀 정보를 알아내기 위해서는 array[0], array[1], array[2], array[3], array[4], ... 에 있는 데이터를 가져오라고 각각 심부름꾼을 보냅니다. 여기서 3번 심부름꾼이 다른 애들에 비해서 매우 빨리 돌아왔네요.

그러면 비밀 데이터는 3인 겁니다!

멜트다운은 이와 같은 보안 취약점을 이용해서 일반적으로 유저가 접근할 수 없는 메모리 영역에 기록된 데이터를 가져오는 데에 사용할 수 있는 공격 방법입니다.


6. 멜트다운 패치

위와 같은 멜트다운을 방어하기 위해서는 어떻게 해야 할까요.

비밀 데이터를 접근할 수 없는 곳에 두면 됩니다.

일반적으로 성능을 위해서, 커널이 사용하는 메모리 영역도 프로세스의 가상 메모리 영역에 매핑됩니다.

왜 이렇게 하는가 하면, 문맥 전환 (context switching)에는 일반적으로 매우 긴 시간이 걸리기 때문입니다.

일반적으로 윈도우 작업관리자를 띄워 보면, 수많은 프로세스가 동시에 실행되고 있습니다.

프로세스의 개수는 CPU의 코어 개수보다 훨씬 많으며, 애초에 옛날 싱글코어 CPU일 때도 여러 개의 프로세스를 동시에 실행 가능했습니다.

이는 각 프로세스가 CPU를 시간에 따라 조금씩 나누어 실행하기 때문입니다.

A프로세스 조금 실행하고, 문맥 전환을 해서 B프로세스 조금 실행하고, 문맥 전환을 다시 해서 C프로세스를 조금 실행하는 식이죠.

각각의 프로세스는 전부 다른 CPU 상태를 가지고 있고, 서로 다른 가상 메모리 공간을 이용합니다.

따라서 A프로세스에서 B프로세스로 문맥 전환을 하기 위해서는, A 프로세스의 모든 CPU상태를 메모리에 저장하고, B프로세스의 모든 CPU상태를 메모리에서 읽어서 복원해야 합니다.

당연히 시간이 오래 걸리겠죠.

프로세스 실행 도중에 I/O 관련 작업, 인터럽트, 예외가 발생하면 전부 커널 공간에서 처리하기 위해서 문맥 전환이 발생하게 되는데, 이렇게 매번 문맥 전환을 하게 되면 속도가 느려집니다.

이것을 방지하기 위해, 운영체제에서 아예 커널 공간을 프로세스의 가상 메모리 공간에 매핑해 버립니다.

그러면 문맥 전환 비용 없이 손쉽게 커널 공간에 접근하고, 작업을 처리할 수 있게 되고, 성능이 올라가겠죠.

그리고 이러한 커널 공간은, 모든 프로세스에서 비슷하기 때문에, 같은 커널 공간이 서로 다른 프로세스의 가상 메모리에 동일하게 매핑됩니다.

똑같은 내용을 메모리에 여러 개 올릴 필요가 없으니까요.

성능을 올리기 위한 이러한 최적화와, 하드웨어 취약점이 맞물려서 멜트다운이 발생합니다.

그래서 심플하게, 멜트다운을 막기 위해 대부분의 커널 공간을 프로세스의 가상 메모리에 매핑하지 않는 패치가 이루어졌습니다.

그리고 그로 인한 성능 하락이 보고되고 있고요.

(물론 모든 커널 공간을 가상 메모리에 매핑하지 않는 것은 아닙니다. 일부는 어쩔 수 없이 매핑이 이루어지고 일부의 데이터는 유출될 수 있습니다.)

멜트다운을 연구해서 보고한 연구팀에 따르면, 이러한 취약점을 없애고, 예전의 성능을 회복하기 위한 하드웨어적인 솔루션도 제공하고 있습니다만, 하드웨어가 변경되어야 하므로 이미 출시된 제품에는 적용이 어렵겠지요.

운영체제의 패치만으로 성능 하락을 최소화하면서 멜트다운을 막을 수 있을지는 더 두고 봐야 하겠습니다.


7. Intel, AMD and ARM.

멜트다운에 가장 직격탄을 맞은 건 Intel 이고, AMD, ARM에서는 자사 CPU에는 이러한 문제가 없다고 하고 있는데, 사실 모를 일입니다.

멜트다운을 연구하고 보고한 연구팀에 따르면, Intel CPU외에 타 CPU에서 멜트다운을 통해 실제 민감한 정보를 유출할 수는 없었다고 합니다.

그래서 AMD, ARM에서는 이러한 문제가 전혀 없다고 얘기되고 있습니다.

멜트다운 연구팀은 왜 인텔 CPU에서만 멜트다운으로 인한 정보 유출이 발생하는지에 대해서는 아직 자기들도 정확히 모르고, 이런저런 이유가 있을 수 있다는 식으로만 언급하고 있네요.
단순히 자기들이 공격 프로그램을 너무 심플하게 짰고, 좀더 최적화를 하면 타사 CPU에서도 정보 유출이 발생할 수 있을 수도 있다느니... 여러 가지 주워섬기는데, 결국 자기들도 잘 모르겠다는 것이 결론입니다.

또한 논문에서는 AMD, ARM 프로세서에서도 멜트다운은 이론상 발생할 수 있으며, 멜트다운을 통해 민감한 데이터를 유출하지는 못했지만, 멜트다운을 발생시킬 수 있는 상황 자체는 다른 프로세서에서도 발생할 수 있다고 분명히 경고하고 있습니다.

실제로 어떨지는 지켜봐야겠지요.


간단히 쓰려고 생각했는데, 쓰다보니 너무 길어졌네요.

다시 말씀드리지만, 위의 예제는 제가 이해를 돕기 위해 지나치게 간략화한 부분이 많습니다.

실제 하드웨어 동작과 정확히 들어맞지 않는 점이 있습니다. 다만 개념적으로 이렇다는 정도만 이해해 주시면 됩니다.


* 라벤더님에 의해서 자유 게시판으로부터 게시물 복사되었습니다 (2018-06-29 16:55)
* 관리사유 : 좋은 글 감사합니다.

통합규정 1.3 이용안내 인용

"Pgr은 '명문화된 삭제규정'이 반드시 필요하지 않은 분을 환영합니다.
법 없이도 사는 사람, 남에게 상처를 주지 않으면서 같이 이야기 나눌 수 있는 분이면 좋겠습니다."
나일레나일레
18/01/10 02:06
수정 아이콘
그림이 안나와서 수정했습니다.
프로피씨아
18/01/10 02:13
수정 아이콘
메모리 접근시간을 이용한 타이밍 어택은 고전적이지만 회피하기 참 어려운 방법이지요.. 성능 최적화를 해서는 안 된다는 의미라서.

AMD도 공격방법이 좀 더 복잡해지기는 하겠지만 어딘가에 비슷한 구멍이 있지 않을까 생각은 합니다.
설사왕
18/01/10 02:16
수정 아이콘
선추천 후감상
18/01/10 02:20
수정 아이콘
우선 정성스러운 글 감사합니다.
최초 링크로 주신 글도 읽어봤는데요. 전자신문에서 쓴 글인데, 어떤 점이 잘못 설명된 것인지도 함께 알려주시면 더욱 이해하기 좋을 것 같습니다.
멜트다운에 대한 설명은, 적어주신 것에 비하면 과도하게 압축되어 있긴 하지만, 결국 실행되지 않은 프로세스의 데이터가 캐시메모리에 남아있고, 이는 접근권한이 없는 경우에도 접근이 된다는 내용이라,,
적어주신 내용과 실 사용자 입장에서 느끼기에 크게 다른 것은 아니지 않나 싶기도 해서요.
나일레나일레
18/01/10 02:27
수정 아이콘
(수정됨) 네. 이게 쓰다보니 너무 늘어져서 그냥 간략하게만 설명하고 많이 쳐냈습니다.

기존 링크에서 잘못 서술된 부분은, 말씀해주신대로 실행되지 않은 프로세스의 데이터, 혹은 커널 영역의 데이터가 캐시 메모리에 남아있으며, 접근 권한이 없는 경우에도 접근이 된다는 내용입니다.
그런데 실제로는 데이터에 접근이 안 되거든요.

데이터를 직접 접근하는 것이 아니라 유저 메모리에 선언된 배열에 저장된 값을, 비밀 데이터의 실제 값을 배열 인덱스로 활용해서 캐시에 올려 두고, 메모리 접근 시간을 이용해서 저장된 데이터가 뭔지 유추해 내는 것이 멜트다운이라서, 조금 세부적인 내용이 다릅니다.

사실 실 사용자 입장에서는 어느 쪽이든 데이터가 유출된 것이니까 그닥 다를 것은 없습니다.

관련 일하는 공돌이만 이해할 세부사항이 다른 거죠. 다만 다른 건 다른 것이니까 논문 본 것 정리할 겸해서 써 봤습니다.
나일레나일레
18/01/10 02:29
수정 아이콘
네. 그냥 논문에서도 자기들이 AMD 프로세서에서 보안 취약점을 이용해서 데이터를 추출하는 데에 실패했을 뿐이지, 이런 취약점이 있긴 있다고 지적하고 있습니다.

말씀하신대로 굉장히 고전적이고, 회피하기 어려운 방법이죠.
18/01/10 02:30
수정 아이콘
늦은 시간에 상세하게 알려주셔서 감사합니다!
도망가지마
18/01/10 03:03
수정 아이콘
(수정됨) 방금까지 심심해서 위키에서 읽고 온게 side channel attack이었는데, 야밤에 pgr에서 이런 글을 만나니 매우 반갑네요.
그런데 exception handler 만나면 바로 OOE를 뭠추면 되지 않았을까도 생각이 드는데, Intel은 왜 지금과 같이 했는지와 AMD와 ARM의 방법은 무엇이었는지 궁금해지네요.

좋은 글 감사합니다.
크림샴푸
18/01/10 03:07
수정 아이콘
무슨말인지 하나도 모르겠는 39살 문과출신 아재이지만 정성글이라 추천 누르고 갑니다
나일레나일레
18/01/10 03:37
수정 아이콘
말씀하신대로 exception handler를 만나면 비순차 실행을 멈추는 것도 하나의 방법이겠으나, 하드웨어가 복잡해지는 문제가 있어서 아무래도 선호하지 않는 것 같습니다. 그리고 exception handling 자체도 비순차 실행을 하면 성능이 떨어질 테니까요.

AMD, ARM에서도 이론적으로 멜트다운 문제는 발생할 수 있습니다.
실제로 연구팀도 멜트다운을 발생시킬수 있는 상황 자체는 실험적으로 만들 수 있다고 말하고 있습니다.
다만 그걸 사용해서 민감한 정보를 추출하는 데에는 실패했다는 거죠.

타사 CPU에서 이런 문제가 발생하지 않는 이유에 대해서는 여러 가지 가설만 제시하고 있는데, 본질적으로 멜트다운은 exception handling 과 load간의 data race 상황이고, 구조상 AMD CPU 등에서는 파이프라인의
깊이 등이 달라서 로드가 완료되기 전에 exception handling 이 끝났다거나 하는 상황이 있을 수 있다는 정도로만 서술되어 있네요.
18/01/10 03:45
수정 아이콘
예외 핸들러를 만나기 이전부터 해당 명령어들은 OOO로 실행되었기 때문에 그렇습니다. 물론 실행하기 전부터 특정 명령어에서 예외가 발생한다는 사실을 알 수 있으면야 좋겠지만 그건 이론적으로 불가능합니다. (정지 문제와 등가) AMD의 경우는 이런 식의 OOO를 하는 경우에도 커널 메모리에 대한 권한 체크를 합니다만, 이 경우 인텔은 그걸 제대로 하지 않았죠. 아마 하긴 할텐데 이렇게 유저->커널 모드로 전환되는 상황까지 생각이 미치지 못했거나 혹은 어차피 상태는 롤백되니까 상관 없을거라고 생각했던 모양인데... 진실은 그 쪽 엔지니어들만 알 듯.
18/01/10 03:51
수정 아이콘
좋은글감사합니다.컴알못인데 조금이나마 이해가되네요..
맥핑키
18/01/10 05:48
수정 아이콘
5. 멜트다운
에서 25번째 줄 정도에 막혔는데 두 번 읽으니 기적적으로 이해가 되었습니다. 36번째 줄 부터 이해가 다시 되기 시작하면서 두 번 읽으니 이해가 되네요.
좋은 글 감사합니다. 무엇이 어떻게 문제가 된 것인지 아주 쉽게 이해할 수 있었습니다.
좋은하루되세요
18/01/10 08:06
수정 아이콘
정말 멋진글 감사드립니다.

기껏 프로세스를 간소화를 시켰더니, 간소화를 역이용해서 공격을 하다니 아이러니하네요.
MicroStation
18/01/10 08:38
수정 아이콘
좋은 글 잘 읽었습니다.
18/01/10 08:42
수정 아이콘
절반밖에 이해를 못했습니다만 그것만으로도 충분히 배웠습니다. 감사합니다!
도망가지마
18/01/10 08:45
수정 아이콘
제가 질문을 좀 간략하게 했는데 security 관련하여 exception handling이 발생할만한 branch나 memory load point등 에서는 ooe를 하지 않거나 security 결과까지의 시간이 monitor window를 넘는다면 bubble처리하는 식이라면 구현 불가능할 정도는 아닐 것 같아요.

어쨋거나 저도 그쪽 엔지니어들이 진실을 밝혀주면 좋겠네요. 흐흐
CoMbI COLa
18/01/10 08:56
수정 아이콘
좋은 글 감사합니다.
대부분 이해했는데 (혹은 이해했다고 착각...) 6번에서 커널 메모리가 프로세스의 가상 메모리 영역에 저장된다는 부분에서, 프로세스는 사용자가 접근할 수 있기 때문에 멜트다운이 가능한 것이고, 이를 패치를 해서 커널 메모리 자체를 다른 곳으로 옮겨 사용자가 아예 손댈 수 없도록 한다... 가 맞나요?
18/01/10 09:21
수정 아이콘
문과는 무쓸모..추천드립니다
교자만두
18/01/10 09:24
수정 아이콘
좋은글 감사합니다.
18/01/10 09:31
수정 아이콘
많이 어렵지만 이제 조금 이해가 되기 시작하네요
정성 들어간 좋은 글 감사합니다
18/01/10 09:35
수정 아이콘
제가 이해한바로는
(1) r1 <- Load data from secret address
(2) r2 <- Load data from array[r1]
이 부분에서 원래는 r1에 데이터를 일단 넣고(프로세스가 이미 알고있으니까) 예외처리를 기다렸다면
패치 후에는 r1에 데이터 자체를 못넣어서(프로세스가 아예 값을 모르므로) (2)로 못넘어간다는 의미로 이해했는데
이게 맞는지는 잘 모르겠네요
저도 이 부분을 좀더 상세히 여쭤보고 싶긴 했습니다
프로피씨아
18/01/10 09:39
수정 아이콘
그.. 브랜치 프레딕션과 메모리 스페큘레이션이 성능 최적화에 미치는 영향이 엄청 커서 그런 식으로는 어렵죠
18/01/10 10:12
수정 아이콘
사이드 체널 어택이 참 신기하더라구요. 이번 기회에 많이 배우고 있어요.
-안군-
18/01/10 10:38
수정 아이콘
이과만세! 공대만세!
어렴풋이 알고 있긴 했지만, 구체적으로 어떻게 해킹이 가능한지에 대해서는 잘 몰랐는데, 좋은 글 감사합니다.
문제는, 이런 문제가 있다는 걸 알게 되면, 해커들이 어떻게든 이용하려 들 텐데, 서버들이 걱정이군요. 특히나 클라우드 서버들...
해커들이란, "우린 어떻게든 방법을 찾아낼 것이다" 라는 집단인지라...
마스터충달
18/01/10 10:46
수정 아이콘
아아... 겨우라도 이해한 자신에게 감사!
그리고 이해할 수 있도록 쉽게 쓴 글쓴이에게 감사x100!!
닉네임세탁기
18/01/10 11:06
수정 아이콘
분명 한글인데....... 지나가면서 막 읽을만한 글은 아니군요.
나중에 잘 읽어보도록 하겠습니다!
프로피씨아
18/01/10 11:14
수정 아이콘
이미 아마존 같은 클라우드 업체들은 일괄적으로 패치를 완료했죠.. 문제는 퍼포먼스 드롭이 엄청 커서 기존과 같은 수준의 트렌젝션 처리를 위해 비용을 몇 배로 내야 한다는 것....
스타듀밸리
18/01/10 11:19
수정 아이콘
멜트다운 연구팀 정도면 어느정도 수준일까요? 구글 면접자 싸대기 때려도 입사되는 수준일런지..
암튼 덕분에 멜트다운에 관해서는 남들한테 아는 체 할 수 있게 되었습니다. 감사합니다.
잉크부스
18/01/10 12:15
수정 아이콘
(수정됨) 맞는듯 합니다.
거기에 대한 결과는 프로세스 권한이 확인될때 까지 미리 케슁(파이프라이닝)하는 동작을 할 수 없고
결과적으로 시퓨가 권한을 확인하는동안 수행한 파이프라인 길이 만큼 공싸이클(노는)도는 일이 발생하겠죠.
(파이프라인 길이에 따라 10이면 10배까지 느려지겠네요)
커널 공간과 유저공간을 빈번하게 교차 접근하는 연산에서 특히나 느려질듯 합니다.(네트워크라던가 등등의 I/O 작업들)
운영체제 프로그래밍 손 놓은지가 오래되서 가물가물 합니다.
나일레나일레
18/01/10 13:22
수정 아이콘
사실 상세히 설명하려면 너무 더 설명해야 할 내용이 많아져서, 제가 간략히만 설명하고 넘어갔습니다.

말씀대로 패치 이후에는, 커널 영역에 접근하려면 문맥 전환이 발생하기 때문에, 비순차 실행을 통해 미리 메모리에 접근하는 일도 발생하지 않고, 결과적으로 정보가 유출될 가능성을 최소화시키는 것입니다.
나일레나일레
18/01/10 13:24
수정 아이콘
네. 저도 이번에 살펴보면서 새로 알게 된 내용이 많습니다. 전공자지만 어째 공부는 해도 해도 끝이 없다는 생각이 드네요.
4막1장
18/01/10 13:36
수정 아이콘
스펙터 버그도 좀... 부탁요
굽신굽신 ^^;;;
나일레나일레
18/01/10 13:49
수정 아이콘
여유가 생기면 스펙터 버그에 대해서도 조금 다뤄보도록 하겠습니다.
18/01/10 14:40
수정 아이콘
와 저도 컴공출신에 OS를 좋아합니다만.. 이렇게 친절하고 쉽게 설명하지는 못하겠네요. 추천드립니다.
도망가지마
18/01/10 14:42
수정 아이콘
(수정됨) exception handling+특정 instruction 수행할 때만 뭠추는거라 전체 성능에서는 penalty가 크지 않을 것 같아요.
게다가 이런 security관련된 error는 bus에서 response로 올라올텐데 exception check하는 stage를 최대한 당길 수 있을테고 그러면 penalty가 더더욱 줄어들겠죠.
18/01/10 14:57
수정 아이콘
제가 이해한대로 비유를 해보자면

기밀자료와 공용자료를 모두 다루는 도서관 사서가 있는데
사서는 모든 사용자의 기밀자료 접근권한을 알지는 못하기 때문에
사용자의 기밀자료 요청이 오면 접근권한을 알아오라고 비서1에게 시키고 비서2와 함께 기밀을 포함한 작업을 일단 진행하고
비서1이 기밀자료 접근권한이 있다고 알려주면 그대로 진행,
접근권한이 없다고 알려주면 그동안 한 작업을 다시 원상복구 시키면서 "너 권한없잖아 안알랴줌"
하는 방식으로 기밀자료 누출을 막으면서도 작업속도를 유지해왔는데

어느날 잔머리 굴리는 사용자한명이
기밀자료의 첫글자(숫자)를 사서에게 물어보고(예를들어 5), 사서에게 그 숫자에 해당하는 슬램덩크 권수를 공용책장에서 꺼내달라고 요구하자
사서는 늘 하던대로 비서1에게 이놈이 기밀접근권한이 있는지 알아보라 시키고 숫자5를 메모지에 적어서 비서2에게 슬램덩크5권을 공용책장에서 꺼내서 옆에 책상에 일단 올려놓으라고 시킴
비서2는 시키는대로 슬램덩크5권을 책상에 올려놓고 잠시후 비서1이 "저놈 권한 없던데요?" 하자 늘 하던대로 숫자5가 적힌 메모지를 파쇄
슬램덩크는 어차피 공용자료니까 그대로 책상위에 올려둠
그때 사용자가 다시 슬램덩크 1~10권 다 갖다주세요 라고 요청하자 사서는 비서2에게 슬램덩크를 꺼내오라고 다시 지시하고
마침 책상위에 이미 꺼내져있던 5권을 발견한 비서2는 사용자에게 5권을 먼저 던져주고 나머지 아홉권을 찾으러 나감.
사용자는 5권을 먼저 던져주는걸 보고 "미리 꺼내놓은걸 보니 아까 기밀숫자가 5번이구나" 라고 알게 됨

저는 이정도로 이해했네요. 적절한 비유일진 모르겠지만 전문용어 없이 이해하는데 도움이 될까 싶어 적어봅니다
프로피씨아
18/01/10 15:24
수정 아이콘
어떤 branch와 ld op이 문제가 될지 일단 가서 읽어보기 전에 미리 알 수가 없는데 미리 알아내서 OOE 안 하면 되는거 아니냐고 하시면... 음..
도망가지마
18/01/10 15:39
수정 아이콘
(수정됨) memory op 에 dep가 걸려한번 stall된 instruction은 ooe를 안하면 됩니다.
위의 예제를 다시보시면 2번 instruction은 어차피 1번 instruction이 완료되기 전까지는 ooe가 수행될 수 없습니다. 1번 instruction이 완료되고 exception check전까지 ooe가 수행되는 것이 문제죠. security error같은 것은 1번 instruction이 완료되는 순간 바로 알 수 있는 요소중 하나이니 exception체크 후 진행해도 penalty가 별로 없을 것 같다는 생각이었습니다.

그런데 이런건 일반인들끼리 생각하는 가설 가능성일 뿐이고 진실은 인텔/AMD 당사자들만 알겠죠
나일레나일레
18/01/10 15:58
수정 아이콘
네 이해하신 것이 맞습니다.

혹시 제 설명이 이해가 안되시는 분은 이 비유로 이해하시면 될 것 같네요. 감사합니다.
18/01/10 17:34
수정 아이콘
훌륭합니다.
18/01/10 17:42
수정 아이콘
정성글엔 추천이야! - 추천드렸습니다.

좀 찾아봐도 당췌 무슨소린지 모르겠어서 그냥 그런가부다 하고 있었는데 나일레나일레님의 글을 보니 궁금증이 한가지 생기는데요,
본문에서 [심플하게, 멜트다운을 막기 위해 대부분의 커널 공간을 프로세스의 가상 메모리에 매핑하지 않는 패치 -> 성능 하락]인 거면, CPU가 어디 꺼든 OS에 해당 패치가 이루어진 거니 유독 인텔만 성능 하락으로 떠들썩하지 않아야 할 것 같아서요. OS에서 커널 공간을 가상 메모리에 매핑하지 않겠다는데, 이걸 CPU 제조사에 따라 다르게 처리하진 않을 것 같은데...아, 성능으로 떠들썩한 건 결국 스펙터때문인가요?!
나일레나일레
18/01/10 19:56
수정 아이콘
저도 그 부분이 궁금해서 조금 찾아봤는데, AMD는 멜트다운 버그를 통한 공격에서 상대적으로 자유롭기 때문에, AMD 프로세서를 사용할 경우에는 해당 패치가 비활성화됩니다.

성능 문제가 되는건 멜트다운을 방지하기 위한 패치가 맞습니다.
18/01/10 20:02
수정 아이콘
답변 감사드립니다. CPU 제조사에 따라 매핑을 하거나, 하지 않게 되는 게 맞았군요 그럼;; 헐..

본문 써주신 글도 그렇고, 위 도서관 사서 예시도 그렇고 멜트다운 취약점이 무엇인지, 그리고 왜 문제인지까지에 대해서는 확실히 인지가 되었는데도 불구하고 '근데 왜 인텔만..?!' 에서의 물음표는 여전하네요ㅠ
18/01/12 03:42
수정 아이콘
뭐 충분히 많은 자원을 들이면 그런 예측을 하는 것도 어느 정도 가능은 하겠습니다만, 현실적으로 볼 때 가성비가 좋은 엔지니어링은 아닐 것 같습니다. 문제가 100% 해결되는 것도 아니고요. AMD같이 엄격하게 권한 체크를 하는 것이 멜트다운에 대한 올바른 해법이겠죠. 근데 스펙터는 또 다른 문제라 현세대 성능 개선에 활용되어 온 기법 전반을 재점검할 필요가 있는 것은 맞습니다.
18/07/01 11:25
수정 아이콘
저걸로 익스플로잇한 사례가 있나요?
나일레나일레
18/07/02 00:10
수정 아이콘
저는 설명을 위해 간략하게만 적어두었는데, 논문 작성한 애들이 실제로 멜트다운을 이용해 접근할 수 없는 정보를 보여주는 데모를 시연한 바 있습니다.

https://www.youtube.com/watch?v=RbHbFkh6eeE

실제 활용예는 사실 꽤 많을 수 있는데, 저는 아키텍처 하는 사람이고 보안 하는 사람은 아니라서 실 활용예를 들어드리기는 어렵네요.
18/07/02 01:58
수정 아이콘
오 아키하시는분이 있군요 반갑습니다
자루스
18/07/05 12:35
수정 아이콘
아니 이런 소프트웨어 전공인데 감탄사가~!
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회
2945 내가 얘기하긴 좀 그런 이야기 [41] Secundo10879 18/03/27 10879
2944 태조 왕건 알바 체험기 [24] Secundo9468 18/03/27 9468
2943 요즘 중학생들이란... [27] VrynsProgidy13340 18/03/26 13340
2942 부정적인 감정 다루기 [14] Right7159 18/03/25 7159
2941 세번째는 아니 만났어야 좋았을 것이다 [28] 삭제됨13641 18/03/11 13641
2940 고기의 모든 것, 구이학개론 #13 [44] BibGourmand9253 18/03/10 9253
2939 일본은 왜 한반도 평화를 싫어할까? <재팬패싱>이란? [57] 키무도도16347 18/03/10 16347
2938 더 늦기 전에, 이미 늦어버린 은혜를 갚아야지. [10] 헥스밤9602 18/03/04 9602
2937 우울의 역사 [56] 삭제됨9117 18/03/02 9117
2936 억울할 때만 눈물을 흘리는 누나였다. [32] 현직백수16289 18/02/21 16289
2935 올림픽의 영향들 [50] 한종화13956 18/02/19 13956
2934 지금 갑니다, 당신의 주치의. (5) [22] 자몽쥬스5863 18/02/11 5863
2933 세상의 끝, 남극으로 떠나는 여정.01 [데이터 주의] [41] 로각좁6321 18/01/31 6321
2932 [알아둬도 쓸데없는 언어학 지식] 왜 미스터 '킴'이지? [43] 조이스틱8205 18/01/24 8205
2931 무쇠팬 vs 스테인레스팬 vs 코팅팬 [94] 육식매니아18034 18/01/22 18034
2930 역사를 보게 되는 내 자신의 관점 [38] 신불해10850 18/01/20 10850
2929 CPU 취약점 분석 - 멜트다운 [49] 나일레나일레11272 18/01/10 11272
2928 황금빛 내인생을 보다가 [14] 파란토마토7624 18/01/07 7624
2927 나는 왜 신파에도 불구하고 <1987>을 칭찬하는가? [76] 마스터충달7930 18/01/04 7930
2926 조기 축구회 포메이션 이야기 [93] 목화씨내놔13107 18/01/04 13107
2925 마지막 수업 [385] 쌀이없어요19197 17/12/18 19197
2924 삼국지 잊혀진 전쟁 - 하북 최강자전 [41] 신불해12543 17/12/15 12543
2923 [잡담] 피자 [29] 언뜻 유재석6803 17/12/14 6803
목록 이전 다음
댓글

+ : 최근 6시간내에 달린 댓글
+ : 최근 12시간내에 달린 댓글
맨 위로