🇰🇷 한글 설명
Zephyr Bluetooth AVRCP Target 역할에서 AVCTP 연결 해제 시 벤더 의존 응답 전송 워크와 대기 중인 버퍼를 정리하지 않아, 분할된 응답 도중 링크가 끊기면 전송 상태가 남아 이후 모든 벤더 의존 응답이 차단되는 문제입니다. 해제 시 워크를 취소하고 큐의 버퍼를 해제하도록 수정되었습니다.
💡 쉬운 설명
블루투스 기기와 연결이 끊어질 때 미처 보내지 못한 응답 데이터가 정리되지 않고 남아 있는 결함입니다. 이 상태가 지속되면 이후 연결에서도 응답이 전혀 전송되지 않아 재부팅 전까지 기능이 멈춥니다.
🇺🇸 원문 (English)
The AVRCP Target role in subsys/bluetooth/host/classic/avrcp.c keeps its vendor-dependent response transmit state in a per-connection object selected by connection index (get_avrcp_tg()), with the per-transfer context (tid, sent_len, and the BT_AVRCP_TG_FLAG_TX_ONGOING flag) stored in the user_data of the queued response net_buf. The AVCTP teardown handler avrcp_disconnected() did not cancel tg->vd_rsp_tx_work and did not release the buffers still queued on tg->vd_rsp_tx_pending, so a link drop in the middle of a fragmented response left the buffer on the list with TX_ONGOING still set.
A remote AVRCP Controller can trigger this deterministically: it issues a vendor-dependent command whose response exceeds one AVRCP fragment (for example GetElementAttributes or GetCapabilities), lets bt_avrcp_tg_vendor_tx_work() emit the START fragment, and then drops the ACL link instead of sending REQUEST_CONTINUING_RESPONSE. The AVCTP control channel requires an encrypted BR/EDR link (BT_SECURITY_L2), so the attacker must be a paired peer within radio range; no user interaction is needed.
Because the Target objects are static and reused, the next connection landing on the same connection index finds the stale buffer at the head of vd_rsp_tx_pending. Every run of the TX work sees TX_ONGOING and returns immediately, so all further vendor-dependent responses queue behind the stale head and are never sent — a persistent loss of AVRCP Target function that no timeout clears and only a reboot recovers. Each cycle also leaks one response buffer from a shallow application pool, and a new peer that sends REQUEST_CONTINUING_RESPONSE clears the stale TX_ONGOING via bt_avrcp_tg_process_continuing_cmd(), causing the un-sent remainder of the previous peer's response to be transmitted to it.
The fix cancels tg->vd_rsp_tx_work and unrefs every buffer on tg->vd_rsp_tx_pending in avrcp_disconnected(); since the TX context lives in the buffer user_data, releasing the buffers also resets the TX state machine. There is no memory corruption: the pre-fix buffer is leaked with a live reference, so no use-after-free arises.
📍 영향받는 시스템
Zephyr RTOS 블루투스 호스트 스택(subsys/bluetooth/host/classic/avrcp.c)을 사용하는 수정 이전 버전
⚔️ 공격 벡터
페어링된 인접 블루투스 AVRCP 컨트롤러가 분할 응답이 필요한 벤더 의존 명령을 보낸 뒤 연속 응답 요청 없이 ACL 링크를 끊어 상태를 고착시킴
🛡️ 대응 방법
Zephyr 보안 업데이트를 적용하여 avrcp_disconnected()에서 TX 워크를 취소하고 대기 버퍼를 해제하는 수정 버전으로 업그레이드
🔧 검증 코드
avrcp_disconnected() 함수 내부에 vd_rsp_tx_work 취소 및 vd_rsp_tx_pending 버퍼 unref 호출이 있으면 수정된 버전이며, 결과가 없거나 해당 호출이 없으면 취약한 버전으로 판단합니다.
grep -n 'vd_rsp_tx_work' $(find / -path '*subsys/bluetooth/host/classic/avrcp.c' 2>/dev/null | head -n1) | head -n5