🇰🇷 한글 설명
Linux 커널의 virtio-net GSO 패킷 처리 로직에서, 네트워크 헤더가 초기화되지 않은 상태로 GSO 패킷을 검증하지 않아 발생하는 취약점입니다. 잘못된 형식의 패킷이 검증을 우회하여 skb_gso_transport_seglen()에서 slab 범위를 벗어난 메모리 읽기가 발생할 수 있습니다. 커널이 해당 수정 사항을 포함하도록 패치되었습니다.
💡 쉬운 설명
가상 네트워크 장치가 특정 형태의 악성 패킷을 제대로 검사하지 않아 커널이 잘못된 메모리를 읽게 되는 문제입니다. 이로 인해 시스템 불안정이나 정보 유출, 권한 상승으로 이어질 가능성이 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
net: always dissect GSO packets in __virtio_net_hdr_to_skb()
Commit 9e8db5913264 ("net: avoid false positives in untrusted gso
validation") added a '&& skb->network_header' check before flow-dissecting
GSO packets without VIRTIO_NET_HDR_F_NEEDS_CSUM in
__virtio_net_hdr_to_skb(), because some callers (such as tun_get_user(),
tun_xdp_one(), virtnet_receive_done(), and raw_verify_header()) called
virtio_net_hdr_*_to_skb() before initializing skb->network_header and
skb->dev.
Because __alloc_skb() and __build_skb_around() zero-initialize
skb->network_header to 0 (unlike mac_header and transport_header which
are initialized to ~0U), those four callers always had
skb->network_header == 0 and bypassed flow dissection in
__virtio_net_hdr_to_skb(). More generally, skb->network_header is an
offset from skb->head (where 0 is also a valid offset whenever
skb_headroom(skb) is 0), not a boolean flag.
Whenever the 'if (gso_type && skb->network_header)' branch was skipped,
the fallback 'else if (gso_type)' only pulled nh_min_len + thlen (40 bytes
for TCPv4) without dissecting the packet, without validating ip_proto or
n_proto, and without setting skb->transport_header.
If the packet has a malformed network header, it is not rejected and a
subsequent skb_probe_transport_header() also fails, leaving
skb->transport_header at ~0U (0xffff). Similarly, if an IPv4 packet
carries IP options (ihl > 5) or an IPv6 packet carries extension headers,
pulling only nh_min_len + thlen can leave the TCP header outside
skb->head. In both cases, tcp_hdrlen(skb) in skb_gso_transport_seglen()
reads out-of-bounds:
BUG: KASAN: slab-out-of-bounds in skb_gso_transport_seglen
Read of size 2 by task poc/133
skb_gso_transport_seglen (net/core/gso.c:155)
skb_gso_validate_mac_len (net/core/gso.c:270)
tbf_enqueue (net/sched/sch_tbf.c:260)
dev_qdisc_enqueue (net/core/dev.c:4227)
__dev_queue_xmit (net/core/dev.c:4884)
In addition, checking virtio_net_hdr_match_proto() only inside
'if (!skb->protocol)' before flow dissection both skipped validation when
skb->protocol was pre-set by the caller and rejected VLAN-tagged frames
whose outer L2 protocol is ETH_P_8021Q or ETH_P_8021AD.
Fix this by:
1. Initializing skb->dev and skb->network_header (plus skb->protocol for
IFF_TUN) before virtio_net_hdr_*_to_skb() in tun_get_user(),
tun_xdp_one(), virtnet_receive_done(), and raw_verify_header(). In
tun_get_user(), drop the redundant skb_reset_mac_header(skb) in the
IFF_TUN case since __virtio_net_hdr_to_skb() unconditionally resets
mac_header.
2. Removing '&& skb->network_header' and the unvalidated
'else if (gso_type)' fallback in __virtio_net_hdr_to_skb() so all GSO
packets without VIRTIO_NET_HDR_F_NEEDS_CSUM are flow-dissected, have
their transport header pulled into linear data, and have
skb->transport_header set.
3. Moving the virtio_net_hdr_match_proto() check to after
skb_flow_dissect_flow_keys_basic(), validating keys.basic.n_proto
against hdr_gso_type.
📍 영향받는 시스템
패치가 적용되지 않은 Linux 커널 (virtio-net, tun 드라이버를 사용하는 버전; 정확한 영향 버전은 공식 advisory 확인 필요)
⚔️ 공격 벡터
로컬 사용자 또는 가상 네트워크 인터페이스로 전달되는 조작된 GSO 패킷을 통해 커널 메모리 범위 밖 읽기를 유발
🛡️ 대응 방법
배포판 벤더가 제공하는 최신 커널 보안 업데이트를 적용하고 시스템을 재부팅
🔧 검증 코드
출력된 커널 버전을 배포판 보안 공지에서 해당 CVE의 수정 버전과 비교하여, 같거나 높으면 패치된 것이고 낮으면 업데이트가 필요합니다.