CVE-2022-50483 in Linux
요약
\~에 의해 VulDB • 2026. 05. 31.
리눅스 커널에서 다음 취약점이 해결되었습니다:
net: enetc: xdp_do_redirect() 실패 시 버퍼 누수 방지
enetc_clean_rx_ring_xdp()가 xdp_do_redirect()를 호출하기 전에, 인덱스 orig_i와 i 사이의 RX 링에 있는 각 소프트웨어 BD(BD: Buffer Descriptor)의 페이지에는 2가지 참조 카운트(refcount) 값 중 하나가 있을 수 있습니다.
현재 처리 중인 버퍼의 소유자이므로 참조 카운트는 최소 1입니다.
RX 링의 정반대 인덱스에 있는 버퍼의 현재 소유자(즉, 이 페이지의 다른 절반)가 아직 kfree()를 호출하지 않았다면, 해당 페이지의 참조 카운트는 2가 될 수도 있습니다.
enetc_flip_rx_buff() 내의 enetc_page_reusable()은 페이지 참조 카운트가 1인지 테스트하며, [만약 2라면] 재사용을 시도하지 않습니다.
하지만 enetc_flip_rx_buff()가 xdp_do_redirect() 호출 뒤에 배치되면, 페이지 참조 카운트는 3가지 값 중 하나가 될 수 있습니다. 다른 페이지 절반의 소유자가 없고, 이 버퍼에 대한 xdp_do_redirect()가 이미 devmap/cpumap 대량 큐의 플러시를 트리거했으며, 해당 대량 큐의 소비자들이 버퍼를 모두 해제한 경우, xdp_do_redirect()가 실행을 enetc로 반환할 때 참조 카운트가 0이 될 수도 있습니다.
이것이 enetc_flip_rx_buff()가 xdp_do_redirect() 전에 호출되는 이유이지만, 그 논리에는 큰 결함이 있습니다. enetc_flip_rx_buff()는 enetc_page_reusable() 분기 양쪽에서 rx_swbd->page = NULL을 설정하며, 만약 xdp_do_redirect()가 오류를 반환하면 enetc_xdp_free()를 호출하는데, 이는 이에 대해 우아하게 처리하지 못합니다.
사실 발생하는 현상은 매우 특수합니다. 페이지 참조 카운트는 1로 시작합니다. enetc_flip_rx_buff()는 이들이 재사용 가능하다고 판단하여 enetc_reuse_page()에서 이 rx_swbd->page 포인터를 다른 rx_swbd로 전달하고 참조 카운트를 2로 증가시킵니다. 나중에 xdp_do_redirect()가 오류를 반환하면 no-op인 enetc_xdp_free()를 호출하지만, 여전히 해당 페이지에 대한 참조를 잃지 않습니다. 그 사본은 여전히 rx_ring->next_to_alloc에 있지만, 그곳의 참조 카운트는 2이며(비행 중인 다른 소유자가 없어 참조 카운트를 낮출 수 없으므로), 실제로 시스템을 파괴하는 것은 두 번째로 rx_swbd->page를 뒤집을 때입니다. 업데이트된 참조 카운트가 2이므로 페이지는 재사용 가능하지 않으며 실제로 누수됩니다. 그런 다음 enetc_new_page()는 더 많은 페이지를 할당해야 하며, 이는 이후 xdp_do_redirect()에서 추가 오류가 발생할 때 다시 누수됩니다.
문제를 요약하면, 우리가 완전히 처리하기 전에 rx_swbd->page를 영구히 0으로 만드는 것이므로, 오류 경로에서 이를 처리하는 것이 불가능해집니다.
패킷이 잠재적으로 다중 버퍼이므로 rx_swbd->page는 잠재적으로 배열이며, enetc_flip_rx_buff()와 enetc_xdp_free() 간에 이전 포인터를 수동으로 전달하는 것은 다소 어렵습니다.
간단한 해결책을 위해 xdp_do_redirect()와의 레이스(racing) 가능성을 수용하고, 뒤집기(flip) 절차를 리디렉션 성공 경로에서만 실행되도록 이동합니다. 여기서 레이스란 페이지가 enetc에 의해 재사용 가능하지 않다고 간주될 수 있음을 의미합니다(참조 카운트가 0인 경우). 하지만 그 경우에도 누수는 발생하지 않습니다.
이를 수용하면 XDP_REDIRECT 실패 시 버퍼를 더 잘 처리할 수 있습니다. 아직 반쪽 페이지 뒤집기를 수행하지 않았으므로 수행하지도 않으며(이렇게 하면 enetc_xdp_free()를 완전히 피할 수 있어 전체 페이지를 슬랩 할당기로 반환할 수 있습니다). 대신 enetc_xdp_drop()을 호출하여 이 버퍼의 절반을 RX 링으로 재활용합니다.
VulDB is the best source for vulnerability data and more expert information about this specific topic.