🇰🇷 한글 설명
Linux 커널의 NFC LLCP 프로토콜 구현에서 nfc_llcp_recv_dm() 함수가 소켓 상태를 변경할 때 적절한 잠금(lock)을 사용하지 않고 리스트에서 제거하지 않아 발생하는 리스트 손상 및 참조 횟수 불일치 취약점입니다. 이로 인해 커널 소켓이 해제되지 않고 누수되어 메모리 고갈 및 서비스 거부(DoS) 상태를 유발할 수 있습니다.
💡 쉬운 설명
NFC 통신 과정에서 시스템 내부의 관리 목록이 꼬이면서 메모리가 계속 쌓이는 버그입니다. 공격자가 이를 이용하면 컴퓨터의 메모리를 모두 써버리게 만들어 시스템을 멈추게 할 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
nfc: llcp: Fix list corruption / refcount desync in nfc_llcp_recv_dm()
nfc_llcp_recv_dm() handles DM(NOBOUND)/DM(REJ) for a socket that is still
linked on local->connecting_sockets: it looks the socket up with
nfc_llcp_connecting_sock_get(), sets sk->sk_state = LLCP_CLOSED and
returns, without taking the socket lock and without unlinking the socket
from the connecting_sockets list.
llcp_sock_release() selects the list to unlink from by sk_state: a socket
in LLCP_CONNECTING is unlinked from connecting_sockets, otherwise from the
sockets list. Because recv_dm left the socket physically on
connecting_sockets but in the LLCP_CLOSED state, release() takes the else
branch and calls nfc_llcp_sock_unlink(&local->sockets, sk). That runs
sk_del_node_init() while holding sockets.lock, i.e. it removes the socket
from the connecting_sockets hlist under the wrong lock. A concurrent
connect() linking another socket onto connecting_sockets under
connecting_sockets.lock then mutates the same hlist unserialized, which
corrupts the list and desyncs the sk_add_node()/sk_del_node_init()
sock_hold()/__sock_put() pairing. An unprivileged local process holding
LLCP sockets, with the DM supplied by the remote peer over an established
LLCP link, can drive this to leak kernel sockets without bound (the
mis-decrement goes through the non-freeing __sock_put() path, so the
object is never released), leading to memory exhaustion / DoS.
This is the same class of bug that was fixed in the sibling handler
nfc_llcp_recv_cc() by commit b493ea2765cc ("nfc: llcp: Fix use-after-free
race in nfc_llcp_recv_cc()"); recv_dm did not receive the equivalent fix.
Fix it the same way: take lock_sock(), re-check that the socket is still
hashed (release() may have won the race), and for the NOBOUND/REJ case
unlink it from connecting_sockets before moving it to LLCP_CLOSED. The
unlink drops the connecting_sockets membership reference via
sk_del_node_init(), leaving the socket unhashed, so the later
nfc_llcp_sock_unlink() in llcp_sock_release() becomes a no-op and no
double put occurs.
📍 영향받는 시스템
Linux Kernel (NFC LLCP 관련 모듈 포함 버전)
⚔️ 공격 벡터
권한이 없는 로컬 프로세스가 원격 피어로부터 DM(NOBOUND/REJ) 패킷을 수신하도록 유도하여 발생
🛡️ 대응 방법
Linux 커널을 최신 보안 패치가 적용된 버전으로 업데이트하십시오.
🔧 검증 코드
출력된 커널 버전이 해당 취약점이 수정된 패치 버전 이후인지 확인하십시오.