2026년 6월 18일, Ingo Blechschmidt라는 수학자가 Mastodon에 글을 올렸다. 첫 문장은 이랬다. 「지난 며칠 동안 나는 흥미롭고 극도로 보람 있으면서도 동시에 극도로 소름 끼치는 디버깅 여정에 깊이 빠져 있었다.」 그리고 그는 한 가지 사실을 공개했다. 2024년 5월 Linux 커널 6.9 출시 이후, 만 2년이 넘는 시간 동안, 그의 암호화된 하드디스크는 노트북 덮개를 닫고 난 후에도 복호화 키가 메모리 안에 그대로 남아 있었다는 것이다.
다르게 말하면, 그의 전체 디스크 암호화는 아무 의미도 없었다.
이 게시물은 며칠 후 기술 커뮤니티 Hacker News에 올라왔고, 순식간에 379포인트, 182개의 댓글이 달렸다. 필자는 전체 토론 체인과 관련 커널 커밋 기록을 읽고 난 후, 이 사건이 표면보다 훨씬 복잡하다는 것을 깨달았다. 이것은 엄청난 대형 취약점이 아니며, 바로 그 「대형 취약점이 아니다」라는 점 때문에 더욱 많은 생각을 불러일으킨다.
사진: Linux 전체 디스크 암호화(LUKS)는 메모리상의 키에 의존해 하드 데이터를 복호화한다. 키가 삭제되지 않으면 물리적 공격자가 추출할 수 있다. 출처: hacknjill.com
먼저 비유 하나: 당신의 캐리어 비밀번호
이 일을 이해하는 데 프로그래밍 지식은 필요 없다. 일상의 비유로 시작하자.
당신에게 비밀번호 잠금 장치가 달린 캐리어가 있다고 치자. 안의 모든 물건은 암호화되어 있어서, 남이 가방을 손에 넣어도 비밀번호를 모르면 열 수 없다. 이 비밀번호(컴퓨터에서는 「키」라고 부른다)는 평소 당신의 머릿속(컴퓨터에서는 「메모리」)에 보관된다.
당신이 캐리어를 닫을 때마다(「노트북 덮개를 닫는 것」에 해당), 가장 먼저 해야 할 일은 머릿속에서 비밀번호를 지우는 것이다. 그래야 누군가 당신이 없는 틈에 가방을 훔쳐 가도 열 수 없다. 당신이 돌아와서 다시 가방을 쓸 때 비밀번호를 다시 입력하면 된다.
이것이 바로 LUKS(Linux 전체 디스크 암호화 표준)의 luksSuspend 기능이 하는 일이다. 노트북이 절전 모드에 진입하기 전에, 먼저 메모리 속 복호화 키를 깨끗이 지운다. 깨어난 후 시스템은 당신에게 다시 비밀번호를 요구하고, 키가 다시 로드되어 하드 접근이 복원된다.
이 로직은 아름답고도 결정적이다. 노트북은 덮개를 닫았다고 해서 전원이 꺼지는 게 아니기 때문이다. 메모리는 여전히 전력을 공급받고 있고, 데이터는 그 안에 있다. 키가 지워지지 않으면, 어떤 의도를 가진 사람이 당신의 노트북을 손에 넣기만 하면(전원이 켜진 상태를 유지하며) 이른바 「콜드 부트 공격」을 통해 — 메모리 칩을 냉동시킨 후 분리해 데이터를 읽어 내거나, Thunderbolt/USB 인터페이스를 통해 직접 메모리에 접근해 — 암호화 키를 훔칠 수 있다.
그리고 Ingo Blechschmidt의 발견은 이랬다. 2024년 5월부터, luksSuspend의 이 삭제 동작이 조용히 실패하고 있었다.
사진: 암호화 키는 메모리(RAM) 칩에 저장된다. 시스템이 절전 시 삭제하지 않으면, 공격자는 물리적 수단으로 키를 직접 추출할 수 있다. 출처: sesamedisk.com
「합리적인」 커널 리팩토링이 어떻게 보안 구멍을 냈는가
Ingo는 git bisect — 코드 버전 히스토리에서 반자동으로 문제의 원인을 찾아내는 도구 — 를 사용했다. 그가 추적해 낸 문제의 커밋(commit)은 a28d893eb327, 제목은 「md: port block device access to file」, 번역하면 「블록 디바이스 접근 방식을 파일로 이식」이다.
이 커밋 자체에는 어떤 악의도 없고, 저급한 실수도 아니다. 이것은 Linux 커널 개발자가 수행한 합리적이고 유용한 리팩토링이었다. 커널 내에서 하드디스크 읽기·쓰기를 처리하는 방식을 구형 인터페이스에서 신형 인터페이스로 이관하는 작업이다. 집의 전기 배선을 구형 알루미늄선에서 동선으로 교체하는 것과 비슷하다. 논리적으로 「더 깔끔하고 더 현대적」이다.
문제는, 이 리팩토링이 겉보기에 무관해 보이는 하부 메커니즘 하나를 건드렸다는 점이다. 스레드 키링(thread keyring)의 생명 주기 관리다.
여기서 「키링」이 무엇인지 설명이 필요하다. Linux 커널 안에서, 암호화 키는 「키링」이라는 전용 데이터 구조에 저장된다. 메모리 구석에 아무렇게나 던져 두는 방식이 아니다. 스레드 키링은 특수한 키링으로, 하나의 프로그램 스레드에 바인딩되어, 스레드가 종료되면 키링도 함께 소멸되고 그 안의 키도 당연히 사라져야 한다.
luksSuspend의 설계는 바로 이 특성에 의존하고 있었다. 하드 암호화 키를 임시 스레드 키링에 업로드하고, 그 스레드가 종료되면 키링이 자동으로 소멸되고 키도 함께 사라지는 방식이다.
커널 문서에는 명백하게 명시되어 있다. 이것이 공식적인 보증이다. 그런데 6.9 버전에서 도입된 그 리팩토링이, 우연의 일치로, 스레드 키링이 특정 상황에서 더 이상 소멸되지 않도록 만들어 버렸다. 스레드는 종료되었지만, 키링은 유령처럼 메모리에 계속 매달려 있게 된 것이다. 그 안의 하드 복호화 키도 함께.
가장 아이러니한 점은, 이 취약점을 고치는 데 단 한 줄의 코드면 충분했다는 것이다.
그렇다. 단 한 줄. Ingo는 취약점 발견 후 커널 메일링 리스트에 패치를 제출했는데, 수정은 극히 작아서 어떤 구조체에 필요한 정리 호출을 하나 추가하는 정도였다. 구체적으로 어떤 문장인지 궁금하다면, 논리는 이렇다. 어떤 커널 함수 안에 key_put(key) 한 줄을 추가하여, 더 이상 사용되지 않는 키 참조가 올바르게 해제되도록 하는 것이다.
그러나 Ingo는 자신의 글에서 이렇게 솔직히 인정하기도 했다. 「형식 검증 없이는, 내 패치가 올바르다고 단언할 수 없다. 나 자신의 장기적 상호작용을 유발하지 않을지도 확실하지 않다…」 이것이야말로 진정한 엔지니어가 하는 말이다.
NixOS의 테스트 인프라가 아니었다면, 이 취약점은 영원히 발견되지 않았을지도 모른다
이 이야기에는 또 하나의 핵심 캐릭터가 있다. NixOS다.
NixOS를 모르는 사람을 위해 간단히 설명하면, 「재현 가능한」 Linux 배포판이다. 시스템 전체의 구성이 하나의 파일에 적혀 있고, Git으로 버전 관리가 가능하며, 다른 머신에 복사해 붙여 넣으면 완전히 동일한 시스템이 재구축된다. NixOS 커뮤니티의 자동화 테스트에 대한 투자는 Linux 세계에서도 정평이 나 있다.
발견자 Ingo 자신이 NixOS 커뮤니티 출신이다. 그는 취약점을 발견한 후 가장 먼저 한 일은, NixOS 코드 저장소에 자동화된 통합 테스트를 제출하는 것이었다(PR #532499). 이 테스트는 앞으로 커널이 업데이트될 때마다 자동으로 실행된다. LUKS 암호화 하드 시뮬레이션 → luksSuspend 실행 → 메모리에 키 잔류 여부 확인.
다시 말해, 그는 자신의 머신을 고치면서 동시에 이 취약점이 절대 다시 돌아오지 못하게 만든 것이다.
여기서 끝이 아니다. Ingo는 cryptsetup 프로젝트에도 또 다른 패치를 제출했다(MR #936). luksSuspend 명령이 실패할 때 더 이상 「무음 실패」로 끝나지 않도록 한 것이다. 지난 2년 동안 이 명령은 조용히 키를 삭제하지 않고 있었지만, 어떤 오류도 보고하지 않았다. 이제는 삭제에 실패하면 명시적으로 경고를 발한다.
이 두 가지 작업이 굴절시켜 보여 주는 것은 하나의 공학적 사고방식이다. 문제를 하나 발견하면, 그것이 재현되지 않도록 테스트를 하나 추가한다. 무음 실패를 하나 발견하면, 그것이 시끄러운 실패가 되도록 만든다. 이것이야말로 어떤 기술적 과시보다도 진정한 좋은 엔지니어링 프랙티스를 대표한다.
영향 범위: 누가 긴장해야 하는가
여기까지 읽으면 이런 질문이 나올 수 있다. 나는 Windows/Mac을 쓰는데, 이거 나랑 상관없는 이야기지? Linux 노트북을 쓰는데, 지금 당장 전원을 꺼야 하나?
대답은 상황에 따라 다르다.
첫째, 이 취약점은 Debian 계열 배포판(Debian, Ubuntu, Linux Mint 등)을 사용하면서 동시에 cryptsetup-suspend 패키지를 설치한 사용자에게만 영향을 미친다. luksSuspend 기능 자체가 Debian 커뮤니티가 자체 개발한 확장 기능으로, Linux 업스트림 기본 동작이 아니기 때문이다. 다른 많은 배포판(예를 들어 Arch Linux의 기본 설치, Fedora의 기본 설치)에는 이 기능이 전혀 없으며, 암호화 키는 절전 중에도 원래 계속 메모리에 남아 있다. 취약점이 아니라, 설계 의도다.
둘째, 영향을 받더라도 취약점은 「덮개 닫고 절전」 시나리오에서만 존재한다. 매번 정상적으로 전원을 끄면(덮개만 닫고 가는 대신), 키는 전원 차단 시 올바르게 삭제된다. 문제는 오직 「절전」(suspend) 모드에서만 발생한다.
셋째, 공격에는 물리적 접촉이 필요하다. 원격 해커가 네트워크를 통해 당신의 메모리 속 키를 훔치는 것은 불가능하다. 실제 사람이 당신의 아직 전원이 꺼지지 않은 컴퓨터를 손에 넣은 다음, 콜드 부트, DMA 공격, 혹은 기타 물리적 수단으로 추출해야 한다. 보통 사람에게 이 위협은 크지 않다. 당신의 컴퓨터를 훔쳐 가는 사람은 대개 중고로 팔 생각이지, 메모리 포렌식 따위에는 관심이 없다. 그러나 변호사, 기자, 반체제 인사, 국경을 넘나드는 비즈니스맨 등 「고가치 표적」 그룹에게는 물리적 공격이 실재하는 위협이다.
Ingo는 HN 답글에서도 일부러 명확히 밝혔다. 「이것은 표준 구성을 사용하는 사람들에게는 영향을 미치지 않는다. 이유는 간단하다 — 그들은 애초에 절전 중에도 키가 안전할 것이라고 기대하지 않기 때문이다.」 그러나 이 기능의 전체 설계 의도 자체가 바로 절전 중 키를 보호하는 것이었다. 2년 동안, 이 메커니즘을 신뢰했던 사람들은 배신당한 셈이다.
더 깊은 교훈: 배포판이 직접 패치하는 위험
이 취약점 뒤에는 사실 두 개의 빌런이 있다.
첫 번째 빌런은 그 커널 리팩토링이다. 선의의 코드 정리가, 전체에 미치는 영향에 대한 충분한 이해 부족으로 보안 구멍을 냈다. 이것은 소프트웨어 공학의 거의 고전적 비극이다. 코드가 「나쁜」 것이 아니라, 단지 아무도 그 연쇄 반응을 완전히 꿰뚫어 볼 수 없을 만큼 복잡했을 뿐이다.
두 번째 빌런이 더 흥미롭다. 배포판이 자체 패치를 적용함으로써 발생하는 유지 보수 리스크다.
luksSuspend는 Debian 커뮤니티가 직접 만든 기능으로, Linux 커널 업스트림에서 공식적으로 제공하는 것이 아니다. 이는 곧 그 정확성(correctness)을 Linus Torvalds와 그의 커널 메인테이너 팀이 책임지지 않는다는 뜻이다. 업스트림 커널의 어떤 하부 메커니즘이 변경될 때(예를 들어 6.9에서의 스레드 키링 행동 변화), Debian의 패치가 이에 맞춰 적응되었는가? 아무도 보장할 수 없다. 업스트림 개발자는 이 패치의 존재조차 모르기 때문이다.
이 말은 배포판이 자체 패치를 만들어선 안 된다는 뜻이 아니다. 정반대로, 많은 Linux 배포판의 뛰어난 기능들은 바로 「자체 패치」에서 시작되었다. 그러나 이 사건은 하나의 쉽게 간과되는 현실을 상기시킨다. 모든 비업스트림 패치는 하나의 「기술 부채」다. 오늘은 작동하지만, 내일 커널이 업그레이드되면 바로 망가질 수 있다. 만약 이 패치가 보안 기능이라면, 그것이 「망가졌다」는 대가는 단순한 기능 고장이 아니라 신뢰의 붕괴다.
Ingo가 Mastodon 원문에서 인용한 말로 정리하자. 「신뢰할 수 있는 저자가 제출한 기술적 논증은, 검사하기 어렵고, 게다가 알려진 올바른 논증과 비슷해 보이면, 거의 결코 상세히 검사되지 않는다.」 코드도 마찬가지다.