🇰🇷 한글 설명
Linux 커널 Bluetooth RFCOMM 서브시스템에서 연결 시 rfcomm_mutex와 hdev->lock 사이에 잠금 순서 교착(AB/BA 순환 의존성)이 발생하는 문제가 수정되었습니다. 세션 소켓을 잠금 없이 먼저 연결한 뒤 잠금을 획득하도록 변경하고, 연결 중 소켓이 닫히는 경우를 처리하는 RFCOMM_CLOSED 표시를 추가했습니다.
💡 쉬운 설명
블루투스 연결 중 두 개의 내부 잠금이 서로를 기다리며 멈출 수 있는 문제를 고쳤습니다. 이 교착 상태로 시스템이 멈추거나 불안정해질 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex
An RFCOMM connect() issued while a BR/EDR link is being authenticated
makes lockdep report a circular dependency, and the reported cycle is a
real AB/BA between rfcomm_mutex and hdev->lock.
rfcomm_security_cfm() is called from the HCI event path, which already
holds hdev->lock:
hci_rx_work()
hci_event_packet()
hci_cc_read_enc_key_size() [hdev->lock]
hci_encrypt_cfm() [hci_cb_list_lock]
rfcomm_security_cfm() [rfcomm_mutex]
while an RFCOMM connect() from userspace takes the same two locks the
other way round:
rfcomm_sock_connect()
rfcomm_dlc_open() [rfcomm_mutex]
__rfcomm_dlc_open()
rfcomm_session_create()
kernel_connect()
l2cap_sock_connect()
l2cap_chan_connect() [hdev->lock]
WARNING: possible circular locking dependency detected
kworker/u131:1/1128 is trying to acquire lock:
rfcomm_mutex, at: rfcomm_security_cfm+0x31/0x3e0 [rfcomm]
but task is already holding lock:
hci_cb_list_lock, at: hci_cc_read_enc_key_size+0x1d2/0xcc0
Chain exists of:
rfcomm_mutex --> &hdev->lock --> hci_cb_list_lock
hci_auth_complete_evt() and hci_encrypt_change_evt() reach the callback
the same way.
Both orders have to be seen in the same boot, which is why a BR/EDR
connection alone is not enough to show it: a session set up by the
remote side is created by rfcomm_accept_connection() in krfcommd, which
calls kernel_accept() and never takes hdev->lock under rfcomm_mutex.
Connecting a device that authenticates and encrypts the link and then
calling connect() on an RFCOMM socket towards any address - the connect
does not have to succeed, the order is recorded before the page timeout
- reports it every time.
Only the session socket has to be connected with the lock held, and it
does not: nothing else can see the socket before it is put on the
session list. So connect it first and take rfcomm_mutex afterwards,
which removes the rfcomm_mutex -> hdev->lock order for good, rather
than keeping the HCI event path out of rfcomm_mutex.
rfcomm_session_create() becomes rfcomm_session_connect(), which returns
the connected socket without touching the session list, and
rfcomm_dlc_open() adds the session once it holds the lock again. If
another opener added a session for the same pair while this socket was
connecting, that session is used and this socket is dropped.
__rfcomm_dlc_open() now takes the session it should use, and its state
check runs after the lock is re-acquired, so a DLC that was opened or
closed in the meantime is still handled.
Over an existing ACL link the connection can complete before the
session reaches the list, and the wakeup from the socket callback is
then lost, so krfcommd is woken once the session is visible.
Connecting without the lock opens a window in which the socket can be
closed. The DLC is not on a session yet, so rfcomm_dlc_close() finds
nothing to do and returns without touching it, and rfcomm_dlc_open()
would then attach a DLC whose owner is gone. rfcomm_dlc_close() now
marks such a DLC with RFCOMM_CLOSED, and rfcomm_dlc_open() checks the
mark once it holds rfcomm_mutex again and drops the socket instead of
attaching the DLC. The mark is cleared when an open starts, so a DLC
that is reused is not affected. This covers both callers of
rfcomm_dlc_open(), the socket and the tty layer.
📍 영향받는 시스템
패치 이전의 Linux 커널 (RFCOMM 블루투스 프로토콜을 사용하는 BR/EDR 블루투스 지원 시스템)
⚔️ 공격 벡터
CVSS 점수가 0.0으로 공개되었으며, 주로 로컬 사용자가 RFCOMM 소켓 연결을 시도하는 조건에서 교착 상태를 유발해 서비스 거부를 일으킬 수 있습니다.
🛡️ 대응 방법
배포판에서 제공하는 이 수정이 포함된 최신 Linux 커널로 업데이트하고 재부팅하십시오.
🔧 검증 코드
커널 버전을 배포판 보안 공지에서 해당 수정이 포함된 버전과 비교하고, 패치 이전 커널이라면 업데이트가 필요합니다. rfcomm 모듈이 로드되지 않았다면 이 취약점의 영향을 받지 않습니다.
uname -r && (lsmod | grep -E '^bluetooth|^rfcomm') 2>/dev/null