CVE-2026-99009 in Linux
Сводка
по VulDB • 23.10.2026
В ядре Linux была устранена следующая уязвимость:
Bluetooth: RFCOMM — подключение сокета сессии без rfcomm_mutex
Вызов функции connect() в протоколе RFCOMM во время аутентификации ссылки BR/EDR приводит к тому, что lockdep сообщает о циклической зависимости. Сообщенный цикл представляет собой реальную ситуацию AB/BA (взаимной блокировки) между rfcomm_mutex и hdev->lock.
Функция rfcomm_security_cfm() вызывается из пути обработки событий HCI, который уже удерживает 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]
в то время как вызов connect() в RFCOMM из пространства пользователя захватывает те же два блокировки в обратном порядке:
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() и hci_encrypt_change_evt() достигают обратного вызова тем же путем.
Оба порядка захвата блокировок должны наблюдаться в рамках одной загрузки системы, поэтому одного только соединения BR/EDR недостаточно для его воспроизведения: сессия, установленная удаленной стороной, создается функцией rfcomm_accept_connection() в krfcommd, которая вызывает kernel_accept() и никогда не захватывает hdev->lock при удержании rfcomm_mutex. Подключение устройства, которое аутентифицирует и шифрует ссылку, с последующим вызовом connect() на сокете RFCOMM к любому адресу (соединение может быть неуспешным; порядок фиксируется до истечения таймаута страницы) будет сообщать об ошибке каждый раз.
Необходимо подключать только сокет сессии при удержании блокировки, но этого не происходит: никто другой не увидит сокет, пока он не будет добавлен в список сессий. Поэтому следует сначала выполнить подключение, а затем захватить rfcomm_mutex; это навсегда устраняет порядок rfcomm_mutex -> hdev->lock, вместо того чтобы исключать путь событий HCI из-под действия rfcomm_mutex.
Функция rfcomm_session_create() становится функцией rfcomm_session_connect(), которая возвращает подключенный сокет без изменения списка сессий, а rfcomm_dlc_open() добавляет сессию только после повторного захвата блокировки. Если другой процесс открытия добавил сессию для той же пары адресов в то время, когда этот сокет выполнял подключение, используется эта сессия, а данный сокет отбрасывается. Функция __rfcomm_dlc_open() теперь получает сессию, которую следует использовать, и проверка ее состояния выполняется после повторного захвата блокировки, поэтому DLC (Data Link Connection), который был открыт или закрыт в промежутке времени, все равно обрабатывается корректно.
При наличии существующей ссылки ACL соединение может завершиться до того, как сессия будет добавлена в список, и пробуждение от обратного вызова сокета тогда теряется; поэтому krfcommd пробуждается только после того, как сессия становится видимой.
Подключение без удержания блокировки создает окно возможностей, в течение которого сокет может быть закрыт. Поскольку DLC еще не находится на сессии, rfcomm_dlc_close() ничего не делает и возвращается, не затрагивая его, а rfcomm_dlc_open() затем попыталась бы прикрепить DLC, владелец которого уже отсутствует. Теперь функция rfcomm_dmic_close() помечает такой DLC флагом RFCOMM_CLOSED, а rfcomm_dmic_open() проверяет этот флаг после повторного захвата rfcomm_mutex и отбрасывает сокет вместо прикрепления DLC. Флаг сбрасывается при начале операции открытия, поэтому повторно используемый DLC не затрагивается. Это покрывает оба вызывающих объекта функции rfcomm_dlc_open(): сокет и слой TTY.
If you want to get best quality of vulnerability data, you may have to visit VulDB.