원문 캡처 · github.com
원문 캡처 · github.com

csum_guard는 가상머신 게스트가 조작한 IPv4 패킷이 Linux 커널의 체크섬 처리 과정에서 IP 헤더를 덮어쓰는 문제를 완화하는 tc/eBPF 필터다. 커널을 다시 빌드하지 않고 적용할 수 있지만, Linux 6.3 이상과 BTF가 필요하며 커널 업데이트를 대신하지는 않는다. csum_guard 저장소

버그와 필터 작동 방식

IFF_VNET_HDR로 연 tun/tap 장치, vhost-net 게스트, 또는 PACKET_VNET_HDR를 사용하는 AF_PACKET 소켓은 virtio_net_hdr를 제어해 ip_summed == CHECKSUM_PARTIAL인 IPv4 패킷을 커널에 전달할 수 있다. 이때 csum_start가 IP 헤더 안이나 그 앞을 가리키면, 이후 IP 단편화·IPsec·nfqueue 등의 경로에서 skb_checksum_help()가 체크섬을 기록하며 네트워크 헤더를 덮어쓸 수 있다.

업스트림 커널 커밋 6785011f8b16은 체크섬을 처리하는 지점에서 csum_start가 IP 헤더의 끝보다 앞서는지 검사한다. 이 필터는 같은 조건을 패킷이 장치로 들어오는 tc ingress에서 검사하고, 문제가 있는 패킷을 TC_ACT_SHOT으로 버린다. IPv4이면서 CHECKSUM_PARTIAL인 패킷만 검사하며, 정상 패킷은 통과한다. 폐기 패킷 수는 CPU별 카운터에 기록한다.

필터는 전달, IPsec, netfilter 경로로 문제가 있는 패킷이 들어가는 것을 막는 추가 방어 수단이다. 장치로 들어오지 않는 호스트 자체 생성 패킷에는 적용되지 않는다. VM 게스트가 신뢰할 수 없는 송신자인 경우 tap의 ingress가 차단 지점이 된다.

빌드와 적용 조건

저장소는 사전 빌드한 CO-RE BPF 객체를 GitHub 릴리스에 게시한다. 소비자는 릴리스 태그와 SHA-256을 고정하고 객체를 내려받아 검증한 뒤 호스트에 붙일 수 있어, 호스트에 컴파일러가 필요하지 않다. CO-RE 객체는 로드 시 대상 호스트의 BTF에 맞춰 재배치되며 Linux 6.3 이상, x86_64와 aarch64에서 실행되도록 구성됐다.

직접 빌드하려면 저장소에서 다음 명령을 사용할 수 있다. make test와 make bench는 root 권한이 필요하다.

text
make
make dist
make test
make bench

라이브 호스트에서는 VM 네임스페이스 안의 tap 장치에 필터를 붙이거나 제거한다.

text
./attach.sh <tap> <vm-netns>
./attach.sh <tap> <vm-netns> --detach

폐기 카운터는 bpftool map dump pinned /sys/fs/bpf/csum_guard_<netns>_<dev>/maps/counters로 확인한다. 로드 시 log_drops=1을 설정하면 폐기마다 trace_pipe에 기록한다.

검증과 성능

저장소의 테스트는 MTU 576인 veth로 연결한 두 네트워크 네임스페이스에서 단편화를 유도하고, 게스트처럼 IFF_VNET_HDR tap을 통해 프레임을 주입한다. Linux 6.18에서 가드가 꺼진 상태로 잘못된 패킷을 전달하면 출발지 주소가 10.0.0.2에서 71.31.0.2로 손상됐다. 가드를 켜면 해당 패킷은 폐기됐고, 정상 패킷은 가드 유무와 관계없이 그대로 전달됐다.

Ubicloud의 4 vCPU, 2.1 GHz Xeon VM과 Linux 6.18에서 측정한 프로그램 자체의 추가 비용은 IPv4 CHECKSUM_PARTIAL 패킷에서 약 2.4ns, 체크섬 오프로드가 없는 IPv4에서 약 1.3ns, 비 IPv4 패킷에서 약 0ns였다. 다만 tc 프로그램을 붙이는 훅 자체는 이 시험의 저렴한 패킷 처리 경로에서 패킷당 약 20~40ns, 전체의 3~7%를 더했다. 필터 로직과 빈 tc 프로그램의 차이는 측정 오차 범위에서 구분되지 않았다. 실제 전달·conntrack·IPsec 처리가 뒤따르면 상대적인 비용은 더 작고, tap에 이미 clsact 프로그램이 있다면 그 프로그램에 로직을 추가해 두 번째 디스패치를 피할 수 있다고 저장소는 설명한다.

제약도 있다. bpf_cast_to_kern_ctx를 제공하는 Linux 6.3 이상과 /sys/kernel/btf/vmlinux의 BTF가 필요하다. 커널이 패치된 뒤에는 --detach로 필터를 제거해야 하며, 이 완화책은 커널 업데이트와 함께 사용해야 한다.

부록: 원문 예시

원문에 실린 예시 1

text
mode=bad  guard=off : 71.31.0.2 -> 10.1.0.2 ...   # source address corrupted mode=bad  guard=on  : (none)                       # dropped, counters [3,0] mode=good guard=off : 10.0.0.2  -> 10.1.0.2 ...    # intact mode=good guard=on  : 10.0.0.2  -> 10.1.0.2 ...    # intact, counters [0,0]