최종 업데이트 07:57
소개 검색
SEOUL AI PRESS

AI와 기술을, 사실부터

강좌 강좌

투기적 실행 입문: CPU가 미리 해보는 계산이 왜 보안 문제가 되는가

투기적 실행은 프로세서가 속도를 높이려고 쓰는 예측 실행 기법입니다. 이 강좌에서는 뜻과 작동 순서를 살펴보고, 연구진이 공개한 BTR이라는 실제 사례를 처음부터 끝까지 따라가며 적용 조건과 한계까지 확인합니다.

한 문장으로 이해하기

투기적 실행(speculative execution)은 중앙처리장치(CPU)가 다음에 어떤 명령을 실행할지 확정되기 전에 “아마 이쪽일 것"이라고 예측해 미리 실행해 두는 기법입니다. 이 강좌를 마치면 (1) 투기적 실행의 뜻을 스스로 설명하고, (2) 작동 순서를 단계로 떠올리고, (3) 이 기법이 어떤 조건에서 보안 약점이 되는지 구분할 수 있습니다. 사전지식은 거의 필요하지 않습니다. 중앙처리장치가 명령을 처리하며 조건에 따라 다음 실행 위치가 달라질 수 있다는 점, 그리고 캐시(cache, 자주 쓰는 데이터를 가까이 두는 빠른 저장 공간) 상태와 접근 시간의 차이가 정보 추론에 이용될 수 있다는 점만 알면 충분합니다. 앞으로 연구진이 공개한 BTR이라는 실제 사례 하나를 끝까지 따라가며 설명하겠습니다.

왜 필요한가

프로그램에는 분기(branch), 즉 조건에 따라 다음에 갈 곳이 갈라지는 지점이 있습니다. 투기적 실행은 이 지점에서 예측한 명령을 미리 실행합니다. 잘못 예측해 수행한 결과는 폐기됩니다. 즉 “폐기할 수 있다"는 전제 위에 세운 속도 전략입니다.

문제는 폐기가 완전하지 않을 수 있다는 점입니다. 계산 결과는 취소되지만 그 과정에서 변한 캐시 상태 같은 흔적이 남을 수 있습니다. 2017년에 처음 알려진 Spectre는 바로 이 성질을 노리는 중앙처리장치 보안 취약점 부류입니다. 공격자는 투기적 실행을 악용해 민감한 데이터에 접근하게 만든 뒤, 캐시 접근 시간의 차이를 재서 그 데이터를 추론할 수 있습니다(c1). 이 강좌의 예시인 BTR은 Spectre의 한 갈래인 Spectre v2의 변종입니다(c3).

어떻게 이루어지는가

투기적 실행과 그 악용은 다음 순서로 이해하면 쉽습니다.

  1. 중앙처리장치가 분기 지점을 만납니다. 어디로 갈지 아직 확정되지 않았습니다.
  2. 분기 예측기(branch predictor)가 실행할 목적지를 예측합니다. 값에 따라 목적지가 정해지는 간접 분기의 목적지 기록은 분기 목표 버퍼(BTB, Branch Target Buffer)라는 내부 기록 공간에 저장됩니다.
  3. 중앙처리장치가 예측한 경로의 명령을 미리 실행합니다. 이 구간이 투기적 실행입니다.
  4. 잘못 예측해 수행한 결과는 폐기됩니다. 그러나 캐시 같은 내부 상태의 변화는 남을 수 있습니다.
  5. 공격자는 캐시 접근 속도를 측정해 폐기된 실행이 무엇을 읽었는지 거꾸로 알아냅니다(c1).

Spectre v2는 이 가운데 2단계를 겨냥합니다. 간접 분기 예측을 오염시켜 중앙처리장치가 공격자가 의도한 코드 조각을 투기적으로 실행하게 유도합니다(c2). 뒤에서 볼 BTR은 이 2단계에 남아 있는 “낡은 기록"을 이용합니다.

하나의 예시로 따라가기

공개된 BTR(Branch Target Reuse, 분기 목표 재사용)은 VUSec와 Scuola Superiore Sant’Anna 연구진이 발표한 Spectre v2 변종입니다. 표적은 JIT(Just-In-Time), 즉 프로그램이 돌아가는 중에 실행할 코드를 생성하는 방식의 엔진입니다(c3).

핵심 관찰은 이렇습니다. 실행 중에 코드가 바뀌어도 중앙처리장치는 오래된 간접 분기 예측 항목을 반드시 무효화하지는 않습니다(c4). 따라서 JIT 엔진이 어떤 코드 영역을 해제하고 같은 주소에 새 코드를 올리면, 중앙처리장치는 예전 목적지를 기억한 채 새 코드의 엉뚱한 위치를 투기적으로 실행할 수 있습니다.

연구진은 리눅스에서 권한이 없는 고전적 BPF(classic BPF, cBPF) 프로그램으로 이 과정을 재현했습니다. 특별한 권한 없이도 쓸 수 있는 프로그램 형식이라는 점이 중요합니다. 연구진은 먼저 분기 예측을 학습시키고, 원래 프로그램을 해제한 뒤 같은 메모리를 재사용했습니다. 낡은 목표 기록 때문에 중앙처리장치는 잘못 정렬된 위치의 명령을 투기적으로 실행했고, 남은 캐시 흔적으로 데이터를 한 바이트씩 추론할 수 있었습니다(c5).

그 결과 연구진은 실행 중인 su 프로세스의 메모리에서 최고 관리자 계정(root)의 비밀번호 해시를 초당 8바이트 속도로 읽었습니다. 걸린 시간은 두 시험 환경에서 각각 Raptor Cove 평균 3분, Lion Cove 평균 5분이었습니다(c6). 또한 기본 보호가 켜진 완전 패치 상태의 인텔 시스템에서, 공격 준비부터 데이터 추론까지 전 과정을 구현한 공격(종단간 공격) 두 가지가 리눅스 커널을 대상으로 구현됐습니다(c7).

언제 쓰고 언제 쓰지 않는가

투기적 실행은 성능을 위한 설계 기법이므로 “쓸지 말지"보다 “어떤 조건에서 위험이 현실화되는지"가 중요합니다. 연구진은 자신들이 시험한 인텔·AMD·Arm 중앙처리장치 모두에서 관련 동작을 확인했다고 밝혔습니다(c14). 이는 시험한 제품 범위에서의 확인이며 해당 회사의 모든 제품이 취약하다는 뜻은 아닙니다.

악용 조건은 까다롭습니다. BTR이 성립하려면 JIT 엔진이 기존 코드 영역을 해제한 뒤에도 오래된 BTB 항목이 무효화되거나 대체되지 않아야 하고, 분기 예측기가 바로 그 항목을 선택해야 합니다(c8). 실제로 자바 계열 프로그램을 실행하는 런타임인 GraalVM 실험에서는 프로그램을 제한된 영역에 가두는 검사(샌드박스 검사)를 투기적으로 건너뛸 가능성이 확인됐습니다. 그러나 코드 컴파일과, 쓰지 않는 메모리를 자동 회수하는 작업(가비지 컬렉션)이 오래된 분기 항목을 지워 공격이 완성되지 못했습니다(c9). 파이어폭스의 자바스크립트 엔진인 SpiderMonkey 개념증명에서는 코드 재사용 뒤에도 오래된 예측이 남는 현상까지는 확인됐지만 완전한 브라우저 공격은 구현되지 않았습니다(c10).

한계와 오해도 구분해야 합니다. 비밀번호 해시 유출은 평문 비밀번호 획득과 같지 않으며, 해시를 풀 수 있는지는 해싱 알고리즘과 비밀번호 강도에 좌우됩니다(c11). 또 BTR은 JIT 엔진을 대상으로 하지만, 운영체제 커널도 cBPF 같은 JIT 엔진을 실행할 수 있어 범위가 아주 좁다고만 보기는 어렵습니다(c12). 대응은 소프트웨어 쪽에서 이뤄졌습니다. 관련 문제에는 공개 취약점 식별 번호(CVE)인 CVE-2026-64507과 CVE-2026-64508이 부여됐고 완화책이 리눅스 커널에 병합됐습니다. GraalVM은 JIT 코드 캐시 위치를 무작위화하며, 모질라는 사이트마다 처리 공간을 분리하는 사이트 격리의 완료를 우선하고 있습니다(c13). 사용자에게는 운영체제와 펌웨어(장치의 기본 동작을 제어하는 소프트웨어) 업데이트, 최신 리눅스 커널 적용이 권고됐습니다(c14).

핵심 정리와 확인문제

투기적 실행은 속도를 위해 미리 실행하고 잘못 예측한 결과는 폐기하는 기법이지만, 폐기가 내부 상태까지 지우지 못할 수 있어 정보 누출의 통로가 됩니다. BTR은 코드가 바뀌어도 낡은 분기 목표 기록이 남는다는 틈을 파고든 사례입니다.

확인문제

  1. 투기적 실행에서 예측이 틀렸을 때 중앙처리장치는 무엇을 버리고 무엇이 남을 수 있나요?
  2. BTR이 표적으로 삼는 소프트웨어 구성요소는 무엇이며, 그 이유는 무엇인가요?
  3. BTR 공격이 실패할 수 있는 조건을 하나 말해 보세요.

정답과 해설

  1. 정답: 계산 결과를 버리지만 캐시 같은 내부 상태 변화는 남을 수 있습니다. 해설: 공격자는 캐시 접근 시간 차이를 측정해 남은 흔적에서 데이터를 추론합니다.
  2. 정답: JIT 엔진입니다. 해설: JIT는 실행 중에 코드를 만들고 해제하므로 같은 주소에 새 코드가 올라갈 수 있고, 중앙처리장치가 예전 분기 목표를 기억하면 엉뚱한 위치가 투기적으로 실행됩니다.
  3. 정답: 오래된 BTB 항목이 무효화되거나 다른 항목으로 대체되면 실패합니다. 해설: GraalVM 실험이 그 예로, 코드 컴파일과 가비지 컬렉션이 오래된 기록을 먼저 지웠습니다.

참고자료