🇰🇷 한글 설명
Linux 커널의 net/handshake 모듈에서 네트워크 네임스페이스 종료 시 대기 중인 요청을 제대로 처리하지 못하는 취약점이 발견되었습니다. 함수 인자 순서 오류로 인해 대기 중인 요청이 해제되지 않고 메모리 참조를 유지하며, 이로 인해 리스트 손상 및 레이스 컨디션(Race Condition)이 발생할 수 있습니다.
💡 쉬운 설명
컴퓨터의 네트워크 관리 공간이 닫힐 때 처리되지 못한 작업들이 메모리에 찌꺼기처럼 남게 되는 문제입니다. 이 과정에서 시스템이 엉뚱한 메모리 주소를 참조하게 되어 시스템이 충돌하거나 보안 문제가 생길 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
net/handshake: Drain pending requests at net namespace exit
The arguments to list_splice_init() in handshake_net_exit() are
reversed. The call moves the local empty "requests" list onto
hn->hn_requests, leaving the local list empty, so the subsequent
drain loop runs zero iterations. Pending handshake requests that
had not yet been accepted are not torn down when the net namespace
is destroyed; each one keeps a reference on a socket file and on
the handshake_req allocation.
Pass the source and destination in the documented order
(list_splice_init(list, head) moves list onto head) so the pending
list is transferred to the local scratch list and drained through
handshake_complete().
Fixing the splice direction exposes a list-corruption race. After
the splice each req->hr_list still has non-empty link pointers,
threading the stack-local scratch list rather than hn_requests.
A concurrent handshake_req_cancel() -- for example, from sunrpc's
TLS timeout on a kernel socket whose netns reference was not
taken -- finds the request through the rhashtable, calls
remove_pending(), and sees !list_empty(&req->hr_list).
__remove_pending_locked() then list_del_init()s an entry off the
scratch list while the drain iterates, corrupting it. The same
call arriving after the drain loop has run list_del() on an
entry hits LIST_POISON instead.
Have remove_pending() check HANDSHAKE_F_NET_DRAINING under
hn_lock and report not-found when drain is in progress. The
drain has already taken ownership; handshake_complete()'s existing
test_and_set on HANDSHAKE_F_REQ_COMPLETED still arbitrates
between drain and cancel for who calls the consumer's hp_done. Use
list_del_init() rather than list_del() in the drain so req->hr_list
does not carry LIST_POISON after drain releases the entry.
The DRAINING guard in remove_pending() makes cancel return false,
but cancel still falls through to test_and_set_bit on
HANDSHAKE_F_REQ_COMPLETED and drops the request's hr_file reference.
Without another pin, if that is the last reference, sk_destruct frees
the request while it is still linked on the drain loop's local list.
Pin each request's hr_file under hn_lock before releasing the list,
and drop that drain pin after the loop finishes with the request.
📍 영향받는 시스템
Linux Kernel (net/handshake 모듈을 사용하는 버전)
⚔️ 공격 벡터
네트워크 네임스페이스를 생성하고 삭제하는 과정에서 발생하는 레이스 컨디션을 이용한 메모리 오염 및 시스템 불안정 유도
🛡️ 대응 방법
Linux 커널을 최신 보안 패치가 적용된 버전으로 업데이트하여 list_splice_init() 인자 수정 및 DRAINING 가드 로직을 적용해야 합니다.
🔧 검증 코드
출력된 커널 버전을 확인하여 해당 취약점이 해결된 최신 패치 버전인지 확인합니다.