Copy Fail: 리눅스 커널 LPE


요약
Copy Fail(CVE-2026-31431)은 Linux kernel의 algif_aead 경로에서 AF_ALG와 splice()를 조합해 읽기 가능한 파일의 page cache에 쓰기 효과를 만드는 취약점으로 설명된다. 공개 자료 기준 핵심은 authencesn 처리 중 생기는 4바이트 scratch write와 in-place 경로의 결합이다. 공개 PoC는 732바이트 Python 스크립트이며, 기본 대상은 /usr/bin/su다.
공개 타임라인은 2026-04-01 mainline patch, 2026-04-22 CVE 할당, 2026-04-29 공개로 정리된다. NVD는 CISA KEV 추가일을 2026-05-01, due date를 2026-05-15로 적고, CERT-EU와 KISA도 같은 취약점을 2026-04-30 전후로 공지했다.
| 항목 | 내용 |
|---|---|
| CVE | CVE-2026-31431 |
| 별칭 | Copy Fail |
| 범주 | Linux kernel local privilege escalation |
| 취약 지점 | algif_aead, AF_ALG, splice(), authencesn |
| 핵심 primitive | readable file page cache에 대한 4-byte write |
| 공개 PoC | 732-byte Python 3.10+ 스크립트, 기본 대상 /usr/bin/su |
| 패치 방향 | algif_aead의 in-place 동작을 되돌리고 AD만 복사 |
| KEV | 2026-05-01 추가, 2026-05-15 due date |
기술 분석
문제의 중심은 algif_aead의 in-place 최적화다. 공개 분석에 따르면 splice()가 읽기 가능한 파일의 page cache page를 crypto scatterlist에 직접 연결하고, authencesn의 decrypt 경로가 dst[assoclen + cryptlen]에 4바이트 scratch write를 남긴다. 이 경로에서 req->src = req->dst가 유지되면 tag page가 writable destination chain에 붙는다.
upstream fix a664bf3d603d는 이 결합을 끊는 쪽으로 바뀐다. 핵심은 in-place 동작을 되돌리고, associated data만 복사하도록 만드는 것이다. 공개 자료 기준으로는 algif_aead의 직접적인 scratch write가 파일 page cache에 닿지 않게 정리된 것으로 볼 수 있다.
PoC 흐름도 같은 순서를 따른다. socket(38, 5, 0)으로 AF_ALG에 들어가고, bind(("aead", "authencesn(hmac(sha256),cbc(aes))")), sendmsg(), splice(), recv()를 이어 붙인다. 기본 대상 파일은 /usr/bin/su이며, 4바이트 단위로 page cache를 건드린 뒤 su를 실행한다. 공개 코드 수준에서 확인되는 primitive는 파일 내용 변조보다 page cache 오염에 가깝다.
영향 범위
| 구분 | 공개 자료에 적힌 범위 |
|---|---|
| NVD | 4.14 이후 여러 브랜치를 affected로 묶음 |
| 고정 기준선 | 5.10.254, 5.15.204, 6.1.170, 6.6.137, 6.12.85, 6.18.22, 6.19.12 |
| Ubuntu | 26.04 이전 릴리스 vulnerable로 표시 |
| SUSE | 다수 enterprise 라인을 affected 또는 released 상태로 갱신 |
| KISA | Linux Kernel 공지에서 6.18.22 미만과 6.19.12 미만을 영향 대상으로 기재 |
버전 문자열만으로 끝내면 안 되고, 배포판 backport와 패키지 상태를 같이 봐야 한다. 같은 커널 버전이라도 vendor package에 수정이 이미 들어갔을 수 있다.
패치와 완화
패치가 우선이다. vendor kernel package에 a664bf3d603d가 들어간 빌드로 올려야 한다. 공개 자료 기준으로는 algif_aead를 막는 완화도 가능하지만, 해당 모듈을 실제로 쓰는 워크로드가 있는지 먼저 확인해야 한다.
Warning
algif_aead 차단은 영향 범위가 넓을 수 있다. 먼저 AF_ALG를 쓰는 서비스가 있는지 보고, 해당 노드부터 패치하거나 차단한다.
uname -r
grep -E 'CONFIG_CRYPTO_USER_API_AEAD|CONFIG_CRYPTO_AUTHENC|CONFIG_CRYPTO_SEQIV' /boot/config-$(uname -r) || true
lsmod | grep -E '^(algif_aead|af_alg|authenc)\b' || true
modprobe -n -v algif_aead 2>/dev/null || true
printf '%s\n' 'install algif_aead /bin/false' > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null || true
auditctl -a always,exit -F arch=b64 -S socket -F a0=38 -k af_alg_socket
ausearch -k af_alg_socket
임시 완화는 algif_aead 로드 차단과 untrusted sandbox에서의 AF_ALG socket 생성 제한이다. 패키지 업데이트 전에는 seccomp나 커널 정책 기반 차단을 같이 둬야 한다.
탐지 포인트
공격 시작점은 네트워크가 아니라 로컬 syscall 흐름이다. 그래서 패킷 기반 탐지보다 호스트 단에서 AF_ALG와 splice() 조합을 봐야 한다.
| 계층 | 관측 신호 | 해석 |
|---|---|---|
| 프로세스 | socket(AF_ALG, SOCK_SEQPACKET, 0) 이후 bind("aead", "authencesn(hmac(sha256),cbc(aes))") | 공개 PoC의 진입점 |
| syscall | 같은 프로세스 트리에서 sendmsg() → splice() → recvmsg()가 짧은 간격으로 반복 | page cache write primitive 생성 시도 |
| 후속 실행 | 직후 /usr/bin/su 같은 setuid 바이너리 실행 | 공개 PoC의 기본 후속 단계 |
| 호스트 상태 | algif_aead 로드/언로드, af_alg socket 생성 증가 | 로컬 트리거 흔적 |
uname -r만 보면 놓칠 수 있다. vendor changelog와 advisory를 함께 봐야 한다. page cache 오염은 디스크 파일 해시만으로는 안 보일 수 있다.
참고 자료
- Copy Fail — CVE-2026-31431
- Copy Fail: 732 Bytes to Root on Every Major Linux Distribution
- NVD - CVE-2026-31431
- Security Advisory 2026-005
- Known Exploited Vulnerabilities Catalog
- CVE-2026-31431 | Ubuntu
- Fixes available for CVE-2026-31431 (Copy Fail) Linux Kernel Local Privilege Escalation Vulnerability
- CVE-2026-31431 Common Vulnerabilities and Exposures | SUSE
- 보안공지 > 알림마당 : KISA 보호나라&KrCERT/CC
- copy-fail-CVE-2026-31431/copy_fail_exp.py at main · theori-io/copy-fail-CVE-2026-31431 · GitHub