Copy Fail – CVE-2026-31431

6 hours ago 4
  • 비특권 로컬 사용자가 authencesn, AF_ALG, splice()를 연결해 읽기 가능한 파일의 페이지 캐시 4바이트 쓰기를 만들고, 이를 통해 root 권한까지 올릴 수 있음
  • 커널별 오프셋이나 레이스 조건 없이 732바이트 Python 스크립트 하나로 여러 Linux 배포판에서 그대로 동작하며, 같은 익스플로잇으로 root shell 획득이 가능함
  • 영향 범위는 패치 전까지의 주요 Linux 배포판 대부분이며, 기본 설정에서 활성화된 AF_ALG 때문에 2017년부터 패치 시점까지 넓게 노출돼 있음
  • 멀티테넌트 호스트, Kubernetes / 컨테이너 클러스터, CI 러너, 사용자 코드 실행형 Cloud SaaS에서는 일반 계정이나 pod 하나가 호스트 root로 이어질 수 있어 우선 패치가 필요함
  • 대응은 메인라인 커밋 a664bf3d603d가 포함된 커널 패치가 우선이며, 패치 전에는 algif_aead 비활성화와 신뢰되지 않은 워크로드에 대한 AF_ALG 차단이 중요함

취약점 개요

  • 직선형 로직 결함 하나를 authencesn, AF_ALG, splice()로 연결해 페이지 캐시 4바이트 쓰기까지 이어지는 로컬 권한 상승이 가능함
  • 커널별 오프셋이나 레이스 윈도 없이 732바이트 Python 스크립트 하나로 2017년 이후 배포된 Linux 배포판 전반에서 동일하게 동작함
  • 같은 익스플로잇 바이너리가 수정 없이 여러 배포판에서 root shell을 획득함
  • 비특권 로컬 계정만 있으면 되고, 네트워크 접근이나 커널 디버깅 기능, 사전 설치된 다른 프리미티브는 필요하지 않음

영향 범위

  • 패치 전까지의 커널을 쓰는 주요 Linux 배포판 대부분이 범위에 들어감
  • 기본 설정에서 커널 암호화 API의 AF_ALG 가 사실상 모든 메인스트림 배포판에 활성화돼 있어 2017년부터 패치 시점까지 바로 노출됨
  • 직접 검증한 배포판은 Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL 14.3, SUSE 16임
  • Debian, Arch, Fedora, Rocky, Alma, Oracle, 임베디드 계열도 영향을 받는 커널을 쓰면 동일하게 동작함

우선 패치가 필요한 환경

  • 멀티테넌트 Linux 호스트에서는 여러 사용자가 같은 커널을 공유하므로 임의 사용자 계정이 곧바로 root가 될 수 있음
  • Kubernetes / 컨테이너 클러스터에서는 페이지 캐시가 호스트 전체에 공유돼 pod 하나가 노드를 장악하고 테넌트 경계를 넘을 수 있음
  • CI 러너와 빌드 팜에서는 일반 사용자 권한으로 실행된 신뢰되지 않은 PR 코드가 러너에서 root가 될 수 있음
  • 사용자 코드 실행형 Cloud SaaS에서는 테넌트가 올린 컨테이너나 스크립트가 호스트 root로 이어질 수 있음
  • 단일 테넌트 서버는 내부 LPE 성격이 강하고 웹 RCE나 탈취된 자격증명과 연결될 수 있음
  • 단일 사용자 노트북과 워크스테이션은 긴급도가 더 낮지만, 로컬 코드 실행이 곧 root 승격으로 이어질 수 있음

공개된 PoC와 사용 방식

  • PoC는 방어 측이 시스템 검증과 벤더 패치 확인에 활용할 수 있도록 공개돼 있음
  • copy_fail_exp.py 는 Python 3.10+ 표준 라이브러리 os, socket, zlib만 사용함
  • 기본 대상은 /usr/bin/su 이며 argv[1]로 다른 setuid 바이너리를 넘길 수 있음
  • 페이지 캐시 안의 setuid 바이너리를 수정하며, 변경은 재부팅 후 유지되지 않지만 획득한 root shell은 실제로 동작함
  • Issue tracker

완화 방법

  • 가장 먼저 커널 패치가 필요하며, 메인라인 커밋 a664bf3d603d 가 포함된 배포판 커널로 업데이트해야 함
  • 이 패치는 2017년 도입된 algif_aead의 in-place 최적화를 되돌려 페이지 캐시 페이지가 writable destination scatterlist에 들어가지 않게 만듦
  • 패치 전에는 algif_aead 모듈 비활성화가 권장됨
    • echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
    • rmmod algif_aead 2>/dev/null || true
  • 신뢰되지 않은 워크로드를 돌리는 컨테이너, 샌드박스, CI에서는 패치 여부와 무관하게 seccomp로 AF_ALG 소켓 생성 차단이 필요함

비활성화 시 영향

  • 대부분의 시스템에서는 측정 가능한 영향이 거의 없음
  • dm-crypt / LUKS, kTLS, IPsec/XFRM, in-kernel TLS, OpenSSL/GnuTLS/NSS 기본 빌드, SSH, kernel keyring crypto는 영향을 받지 않음
    • 이들은 커널 암호화 API를 직접 사용하며 AF_ALG 경로를 통과하지 않음
  • OpenSSL에서 afalg 엔진을 명시적으로 켠 경우, 일부 임베디드 암호화 오프로딩 경로, aead/skcipher/hash 소켓을 직접 바인딩하는 애플리케이션은 영향을 받을 수 있음
    • lsof | grep AF_ALG 또는 ss -xa 로 확인 가능함
  • AF_ALG를 꺼도 원래 그것을 호출하지 않던 대상은 느려지지 않으며, 사용하던 대상은 일반적인 userspace 암호화 라이브러리로 되돌아감

일반적인 Linux LPE와 다른 점

  • 보통의 Linux LPE와 달리 레이스 조건이 없고 배포판별 오프셋도 필요하지 않음
  • 신뢰성도 단발 100% 로 제시되며, 좁은 커널 버전 범위가 아니라 2017년부터 2026년까지의 긴 기간을 덮음
  • Python 표준 라이브러리만 쓰는 732바이트 크기라서 컴파일된 페이로드나 별도 의존성이 없음
  • 쓰기 경로가 VFS를 우회하고 손상된 페이지가 dirty로 표시되지 않아 디스크에는 아무것도 기록되지 않음
  • 페이지 캐시가 호스트 전체에 공유되므로 단순 LPE를 넘어 컨테이너 탈출 프리미티브로도 작동함

동작 원리와 탐지 특성

  • 비특권 로컬 사용자가 Linux 시스템의 읽기 가능한 파일 페이지 캐시에 제어 가능한 4바이트를 쓸 수 있고, 이를 root 획득에 활용할 수 있음
  • 디스크의 실제 파일이 아니라 메모리 내 페이지 캐시가 표적이며, /usr/bin/su의 캐시 복사본을 바꾸면 execve 관점에서는 바이너리 자체를 바꾼 것과 같아짐
  • 디스크에 변화가 없으므로 inotify가 울리지 않고, 재부팅이나 캐시 축출 후에는 원본 파일이 다시 로드됨
  • sha256sum, AIDE, Tripwire 같은 일반 해시 도구는 read()를 통해 페이지 캐시를 읽으므로 캐시에 손상이 남아 있는 동안에는 기준 해시와 달라질 수 있음
  • 캐시가 축출되거나 재부팅되면 해시가 다시 원래와 일치하고, 디스크 포렌식 이미지에도 수정되지 않은 파일만 남음
  • IMA appraisal enforcing mode 에서 every-read measurement가 켜져 있으면 손상된 바이너리가 실행되기 전 execve 시점에 잡을 수 있음

다른 취약점과의 차이

  • Dirty Pipe 와 같은 계열로, 비특권 userspace에서 페이지 캐시를 손상시키고 디스크 변경 없이 setuid 바이너리에 써서 root를 얻는다는 점은 같음
  • 메커니즘은 다르며 Dirty Pipe는 pipe buffer flags 를 악용했고, Copy Fail은 chained scatterlist 경계를 넘는 AEAD scratch write 를 악용함
  • Dirty Pipe는 특정 패치가 들어간 커널 5.8 이상이 필요했지만, Copy Fail은 2017년부터 2026년까지의 창을 덮음
  • Dirty Cow 와 달리 TOCTOU 기반 COW 레이스를 이길 필요가 없고, 여러 차례 시도하거나 시스템을 불안정하게 만들지 않음

추가 세부 사항

  • /usr/bin/su 가 필수는 아니며, 사용자가 읽을 수 있는 setuid-root 바이너리 라면 passwd, chsh, chfn, mount, sudo, pkexec도 가능함
  • 원격 취약점은 아니고, 일반 사용자 권한의 로컬 코드 실행이 먼저 필요함
  • 웹 RCE가 비특권 서비스 계정으로 떨어지는 경우, SSH foothold, CI 러너의 악성 PR 같은 경로와 결합하면 root로 이어질 수 있음
  • 패치는 algif_aead의 in-place 최적화를 되돌려 req->src와 req->dst를 다시 분리된 scatterlist로 만듦
  • 페이지 캐시 페이지는 읽기 전용 source에만 남고, 암호화가 쓸 수 있는 대상은 사용자 버퍼만 남게 됨

공개 일정과 후속 자료

  • 2026-03-23 Linux 커널 보안팀에 보고됨
  • 2026-03-24 초기 확인이 이뤄짐
  • 2026-03-25 패치가 제안되고 리뷰됨
  • 2026-04-01 메인라인에 패치가 커밋됨
  • 2026-04-22 CVE-2026-31431 이 할당됨
  • 2026-04-29 https://copy.fail/ 에서 공개됨
  • Xint blog 기술 분석
    • root cause, scatterlist 다이어그램, 2011→2015→2017 연혁, 익스플로잇 워크스루를 담고 있음
    • Kubernetes 컨테이너 탈출을 다루는 Part 2는 추후 공개될 예정임

Xint Code 관련 정보

  • AI-assisted 방식으로 찾았으며, 출발점은 splice()가 페이지 캐시 페이지를 crypto subsystem에 넘긴다는 점과 scatterlist의 페이지 출처가 덜 탐색된 버그 클래스일 수 있다는 인간 연구였음
  • 이후 Xint Code 가 Linux crypto/ subsystem 전체 감사를 약 1시간 규모로 확장했고, 그 결과 중 가장 심각한 항목이 Copy Fail이었음
  • Xint Code
    • Xint blog write-up
    • 같은 스캔에서 다른 고위험 버그들도 발견됐고, 이들은 아직 coordinated disclosure 중임
Read Entire Article