
Linux 커널 Copy Fail(CVE-2026-31431) 취약점 분석 및 완화 - AF_ALG/splice 페이지 캐시 변이를 이용한 취약점, PoC 확인기, auditd 탐지 규칙, 커널 업데이트 확인 포함.
본 프로젝트는 Linux Kernel Copy Fail(CVE-2026-31431) 취약점의 동작 원리를 분석하고, 공개 PoC 레포지토리의 비파괴적 checker를 이용해 패치 전후 상태를 비교한 미니프로젝트입니다.
실제 setuid 바이너리 변조나 /etc/passwd 변조 exploit은 수행하지 않고, 임시 testfile 기반의 안전한 취약 여부 확인과 탐지/완화 관점의 분석에 초점을 두었습니다.
이 프로젝트의 목표는 단순히 exploit을 실행하는 것이 아니라, Linux 커널 취약점이 어떤 내부 구조의 조합으로 발생하는지 이해하고 운영 관점에서 어떻게 확인하고 대응할 수 있는지 정리하는 것입니다.
진행 범위는 다음과 같습니다.
취약점 원리 분석
↓
PoC 코드 구조 분석
↓
비파괴 checker 기반 실습
↓
패치 전후 비교
↓
탐지/완화 방안 정리
본 실습에서는 copy-fail-c 레포지토리의 vulnerable.c만 실행하였습니다.
| 구분 | 패치 전 | 패치 후 |
|---|---|---|
| OS | Ubuntu 24.04.2 LTS | Ubuntu 24.04.4 LTS |
| Kernel | 6.8.0-53-generic | 6.8.0-134-generic |
| 계정 | 일반 사용자 client | 일반 사용자 client |
| checker | vulnerable | vulnerable |
| 테스트 방식 | 임시 testfile 기반 비파괴 검사 | 동일 checker 재실행 |
패치 전 커널 정보:
Linux ubuntu-server 6.8.0-53-generic #55-Ubuntu SMP PREEMPT_DYNAMIC Fri Jan 17 15:37:52 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
패치 후 커널 정보:
Linux ubuntu-server 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
커널 패키지 변경 요약:
- linux-image-6.8.0-53-generic 6.8.0-53.55
- linux-image-generic 6.8.0-53.55+1
+ linux-image-6.8.0-134-generic 6.8.0-134.134
+ linux-image-generic 6.8.0-134.134
+ linux-generic 6.8.0-134.134
+ linux-headers-generic 6.8.0-134.134
Copy Fail은 Linux 커널의 AF_ALG AEAD 처리 경로와 splice() zero-copy 동작이 결합되면서, 읽기 전용 파일의 page cache가 잘못된 쓰기 대상으로 사용될 수 있는 취약점입니다.
핵심 구성 요소는 다음과 같습니다.
| 요소 | 역할 |
|---|---|
| Linux page cache | 디스크 파일 내용을 RAM에 캐싱하는 커널 메커니즘 |
splice() | 데이터를 사용자 공간으로 복사하지 않고 커널 내부에서 참조로 연결하는 zero-copy syscall |
AF_ALG | 사용자 공간에서 Linux kernel crypto API를 socket처럼 사용할 수 있게 하는 인터페이스 |
| AEAD in-place 처리 | 입력 버퍼와 출력 버퍼를 별도로 두지 않고 같은 버퍼에서 처리하는 최적화 |
authencesn | AEAD 처리 중 4바이트 scratch write가 발생하는 crypto template |
취약점의 핵심 흐름은 다음과 같습니다.
읽기 가능한 파일
↓
Linux page cache에 올라감
↓
splice()로 AF_ALG crypto 경로에 page cache reference 전달
↓
AEAD in-place 처리로 입력과 출력 scatterlist가 엮임
↓
authencesn 처리 중 4바이트 scratch write 발생
↓
별도 출력 버퍼가 아니라 page cache에 쓰기 발생
↓
page cache mutation 발생
즉, splice()는 page cache reference를 전달하고, AEAD in-place 처리는 입력과 출력을 같은 경로로 엮으며, authencesn은 실제 4바이트 쓰기를 발생시키는 역할을 합니다.
실습에 사용한 레포지토리 구조는 다음과 같다.
copy-fail-c/
├── exploit.c
├── exploit-passwd.c
├── vulnerable.c
├── payload.c
├── utils.c
├── utils.h
├── Makefile
└── nolibc/
| 파일 | 역할 | 본 실습에서의 사용 여부 |
|---|---|---|
utils.c, utils.h | AF_ALG/splice 기반 page cache mutation primitive 구현 | 분석 및 vulnerable 실행에 사용 |
vulnerable.c | 임시 testfile 기반 비파괴 취약 여부 확인 도구 | 실행 |
exploit.c | setuid root 바이너리 page cache 변조 variant | 실행하지 않음 |
exploit-passwd.c | /etc/passwd page cache 변조 variant | 실행하지 않음 |
payload.c | root 권한으로 실행될 payload | 실행하지 않음 |
Makefile | 빌드 자동화 | vulnerable target만 사용 |
nolibc/ | 작은 static ELF payload 빌드를 위한 경량 libc 대체 코드 | 분석만 수행 |
utils.cutils.c의 핵심은 patch_chunk() 계열의 page cache mutation primitive입니다. 이 함수는 AF_ALG와 splice()를 이용해 대상 파일의 page cache를 crypto 처리 경로에 연결하고, 취약한 커널에서는 AEAD 처리 중 page cache 일부가 덮어써지는지를 확인합니다.
vulnerable.cvulnerable.c는 실제 시스템 파일을 건드리지 않습니다. 현재 디렉터리에 임시 testfile을 만들고, 해당 파일의 page cache가 변조되는지 확인합니다.
본 프로젝트에서는 이 파일만 실행하였습니다.
커널 업데이트를 수행하기 전에 OS, 커널, 패키지 상태를 기록하였습니다.
mkdir -p ~/copyfail-mini/{before,after,logs}
cd ~/copyfail-mini
uname -a | tee before/uname.txt
cat /etc/os-release | tee before/os-release.txt
dpkg -l | grep -E 'linux-image|linux-headers|linux-generic|linux-virtual' | tee before/kernel-package.txt
git clone https://github.com/jihwan77/copy-fail-c.git
cd copy-fail-c
make clean
make vulnerable
본 실습에서는 기본 make로 exploit 바이너리를 함께 빌드하지 않고, vulnerable target만 사용하였습니다.
./vulnerable > ../before/vulnerable-output.txt 2>&1
echo $? >> ../before/vulnerable-output.txt
cat ../before/vulnerable-output.txt
패치 전 실행 결과:

판단:
exit code 100
→ page cache mutation 확인
→ 패치 전 커널에서 Copy Fail primitive 동작 확인
패치 전 결과를 저장한 뒤, Ubuntu 패키지 업데이트를 수행하였습니다.
sudo apt update
sudo apt full-upgrade -y
sudo reboot
재부팅 후 커널은 다음과 같이 변경되었습니다.
Before: 6.8.0-53-generic
After : 6.8.0-134-generic
cd ~/copyfail-mini/copy-fail-c
make clean
make vulnerable
./vulnerable > ../after/vulnerable-output.txt 2>&1
echo "exit_code=$?" >> ../after/vulnerable-output.txt
cat ../after/vulnerable-output.txt
패치 후 실행 결과:

결과 비교:
| 항목 | 패치 전 | 패치 후 |
|---|---|---|
| Kernel | 6.8.0-53-generic | 6.8.0-134-generic |
| Checker 결과 | VULNERABLE | authencesn template not registered |
| Exit Code | 100 | 2 |
| Page cache mutation | 확인됨 | checker가 mutation 단계까지 진행하지 못함 |
| 해석 | Copy Fail primitive 동작 | PoC가 요구하는 AEAD/authencesn 경로 진입 실패 |
패치 후 exit_code=2는 단순히 “취약하지 않음”을 의미하지 않습니다. 정확히는 다음과 같습니다.
AF_ALG의 authencesn(hmac(sha256),cbc(aes)) template이 등록되어 있지 않아,
checker가 취약 여부를 직접 판정하지 못한 상태
추가 확인 결과, Ubuntu 업데이트 후 algif_aead 모듈 로드가 차단되어 있었습니다.
lsmod | grep -E 'af_alg|algif_aead'
결과:
af_alg 32768 0
algif_aead는 로드되어 있지 않았습니다.
sudo modprobe algif_aead
결과:
modprobe: ERROR: ../libkmod/libkmod-module.c:1084 command_do() Error running install command '/bin/false' for module algif_aead: retcode 1
modprobe: ERROR: could not insert 'algif_aead': Invalid argument
차단 설정 확인:
grep -R "algif_aead" /etc/modprobe.d /lib/modprobe.d 2>/dev/null
결과:
/etc/modprobe.d/disable-algif_aead.conf:# Disable algif_aead module due to CVE-2026-31431 (AKA copy.fail)
/etc/modprobe.d/disable-algif_aead.conf:install algif_aead /bin/false
따라서 패치 후 결과는 다음처럼 해석하는 것이 정확합니다.
Ubuntu 보안 업데이트 이후 커널이 6.8.0-134-generic으로 변경되었고,
kmod 기반 algif_aead 모듈 차단 완화가 적용되었습니다.
그 결과 copy-fail-c의 vulnerable checker는
PoC가 요구하는 authencesn(hmac(sha256),cbc(aes)) AF_ALG template에 bind하지 못했고,
page cache mutation 단계까지 진행되지 않았습니다.
즉, 본 실습에서 확인한 것은 “커널 코드 패치만의 효과”가 아니라, Ubuntu 보안 업데이트 이후 커널 업데이트와 algif_aead 모듈 차단 완화가 적용되어 동일 PoC 경로가 진행되지 않는 상태입니다.
Copy Fail은 디스크 파일을 직접 수정하지 않고 page cache를 변조할 수 있으므로, 파일 해시 기반 탐지만으로는 한계가 있습니다. 따라서 syscall 행위 기반 탐지가 중요합니다.
본 실습에서는 auditd를 이용해 다음 syscall을 관찰하였습니다.
sudo auditctl -a always,exit -F arch=b64 -S socket -F a0=38 -k copyfail_afalg
sudo auditctl -a always,exit -F arch=b64 -S bind -k copyfail_bind
sudo auditctl -a always,exit -F arch=b64 -S splice -k copyfail_splice
sudo auditctl -a always,exit -F arch=b64 -S sendmsg -k copyfail_sendmsg
socket(AF_ALG) 탐지로그에서 vulnerable 프로세스가 AF_ALG socket을 생성한 것이 확인되었습니다.
comm=vulnerable
syscall=socket
success=yes
a0=alg
key=copyfail_afalg
bind() 실패 탐지패치 후/완화 후 환경에서는 vulnerable 프로세스가 authencesn template에 bind하려 했지만 실패하였습니다.
comm=vulnerable
syscall=bind
success=no
exit=ENOENT(No such file or directory)
saddr_fam=alg
key=copyfail_bind
이는 패치 후 환경에서 PoC가 AF_ALG socket 생성까지는 수행했지만, authencesn(hmac(sha256),cbc(aes)) template bind 단계에서 실패했음을 의미합니다.
splice() / sendmsg() 로그 해석패치 후에는 bind() 단계에서 실패했기 때문에, checker가 splice()와 sendmsg() 단계까지 진행하지 못했습니다. 따라서 해당 syscall 로그에서는 vulnerable 실행 흐름이 의미 있게 관찰되지 않았습니다.