
AF_ALG/splice 기반 Linux Page Cache 변조 취약점 분석 및 대응 실습
본 프로젝트는 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에 올라감
↓
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.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
패치 후 실행 결과:

결과 비교:
패치 후 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 실행 흐름이 의미 있게 관찰되지 않았습니다.
운영 환경에서 Copy Fail류 취약점을 관찰할 때는 다음 행위 조합을 볼 수 있습니다.
본 실습에서는 socket(AF_ALG)와 bind() 실패 이벤트를 auditd로 확인하였습니다.
가장 기본적인 대응은 배포판 보안 업데이트를 적용하는 것입니다.
sudo apt update
sudo apt full-upgrade -y
sudo reboot
본 실습에서는 업데이트 후 Ubuntu 24.04.4 / kernel 6.8.0-134-generic 환경으로 변경되었습니다.
algif_aead 모듈 차단Ubuntu 업데이트 후 다음 설정이 확인되었습니다.
/etc/modprobe.d/disable-algif_aead.conf
install algif_aead /bin/false
이 설정은 algif_aead 모듈 로드를 차단하여 PoC가 요구하는 AF_ALG AEAD 경로 진입을 막습니다.
일반적인 서버 애플리케이션에서 AF_ALG를 직접 사용하는 경우는 많지 않을 수 있으므로, socket(AF_ALG) 호출은 탐지 포인트로 활용할 수 있습니다.
본 실습 결과는 다음과 같이 정리할 수 있습니다.
패치 전:
Ubuntu 24.04.2 / kernel 6.8.0-53-generic
vulnerable checker exit code 100
page cache mutation 확인
→ Copy Fail primitive 동작 확인
패치 후:
Ubuntu 24.04.4 / kernel 6.8.0-134-generic
vulnerable checker exit code 2
authencesn template bind 실패
algif_aead 모듈 차단 설정 확인
→ 동일 PoC 경로가 page cache mutation 단계까지 진행되지 않음
따라서 본 프로젝트의 결론은 다음과 같습니다.
패치 전 커널에서는 Copy Fail의 page cache mutation primitive가 실제로 동작하였다.
이후 Ubuntu 보안 업데이트를 적용하자 커널이6.8.0-134-generic으로 변경되었고,kmod기반으로 보이는algif_aead모듈 차단 설정이 적용되었다.
그 결과 PoC가 요구하는authencesn(hmac(sha256),cbc(aes))AF_ALG template에 bind하지 못해 동일 checker가 page cache mutation 단계까지 진행되지 않았다.
즉, 본 실습 결과에서는 “커널 코드 패치 자체가 page cache mutation을 직접 차단했다”고 할 수 없지만, 현재까지의 로그 및 결과로 확실히 말할 수 있는 것은 Ubuntu 보안 업데이트 이후 algif_aead 모듈 차단 완화가 적용되어 PoC 경로가 차단되었다는 점입니다.
Ubuntu Security Notice - USN-8226-1: kmod update
https://ubuntu.com/security/notices/USN-8226-1
Ubuntu Blog - Fixes available for CVE-2026-31431 Copy Fail
https://ubuntu.com/blog/copy-fail-vulnerability-fixes-available
copy-fail-c PoC repository
https://github.com/jihwan77/copy-fail-c
이 프로젝트를 통해 확인한 핵심은 다음과 같습니다.
1. Copy Fail은 AF_ALG, splice(), AEAD in-place, authencesn, page cache가 결합된 커널 취약점이다.
2. 패치 전 Ubuntu 24.04.2 / kernel 6.8.0-53 환경에서 비파괴 checker가 page cache mutation을 확인했다.
3. 패치 후 Ubuntu 24.04.4 / kernel 6.8.0-134 환경에서는 authencesn bind 단계에서 실패했다.
4. 추가 확인 결과 algif_aead 모듈 로드가 /bin/false 설정으로 차단되어 있었다.
5. auditd를 통해 socket(AF_ALG) 및 bind 실패 이벤트를 관찰할 수 있었다.
6. 운영 대응은 커널/보안 패키지 업데이트, algif_aead 제한, AF_ALG syscall 모니터링, setuid 바이너리 점검으로 정리할 수 있다.
| 요소 | 역할 |
|---|
| 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 |
| 파일 | 역할 | 본 실습에서의 사용 여부 |
|---|
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 대체 코드 | 분석만 수행 |
| 항목 | 패치 전 | 패치 후 |
|---|
| 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 경로 진입 실패 |
| 탐지 대상 | 의미 |
|---|
socket(AF_ALG, ...) | 커널 crypto API 사용 시도 |
bind() with authencesn | AEAD/authencesn crypto template 사용 시도 |
splice() | 파일 page cache reference를 커널 내부 경로로 전달 |
sendmsg() / recvmsg() | AF_ALG crypto request 수행 |
| setuid binary 실행 | 권한 상승 cashout 가능성 |