mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
bluetooth pull request for net:
- hci_ll: Fix firmware leak on error path - hci_sync: annotate data-races around hdev->req_status - L2CAP: Fix null-ptr-deref on l2cap_sock_ready_cb - L2CAP: Validate PDU length before reading SDU length in l2cap_ecred_data_rcv() - L2CAP: Fix regressions caused by reusing ident - L2CAP: Fix stack-out-of-bounds read in l2cap_ecred_conn_req - MGMT: Fix dangling pointer on mgmt_add_adv_patterns_monitor_complete - SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold -----BEGIN PGP SIGNATURE----- iQJNBAABCgA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmm8SHgZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKblnD/9BEGzP5EGkrV8b7xoWzAhl MBXnlHm4euetPx89B3xkQ7lN9wOA4jAPkwzL2OlLw87CSi3+VkgklH/6H3LyK5hf SNfcuEyTE/Y2zgPeBeUQ8V9WgZFrIvgiqcyAInTD0GLrN7h5sG7ABJupgHnwTeZa mV7dkHbznIRY4n9hpmZQx6WQi2EY/KpRKh3a4RvMsS5fTTH29EacYxAgsRMZmrMA vxcFbLLNOlE4Oj4Pxttrddx4C1ewFuY61FQ7dH9n/crmyN/p7yiweGfCdXaLGNjn CYMQJg1IUv0L4yxYYamInJ2eWBA4A2Ml3geeULPSO0bciCSzEvLMYXVKOkRgIki0 l82uol3KHrf6L5cYZmMhB2AIjKiXcEDmpM+eRf/O9QjXSAq3xNdBkGDFSTZgScox BlugMSI9eehB4frfmuFFZlhVNz5z7KDbbQYskwi5uucYPJKswKi2k+2mhvbu3fCV I35xDz7JPvU++yfJ87haxRSSRM8yC6FfqUr7jZKAPrZFuT/9eWNMZXTDRFX0ps6a gvRyI7muCA1RF1fLY+GUANpaLt9Ws/EAjMGX5hqPL6r2TbPHvmX5JxehqViE1+mp aqSAZxfR/n18M4SdomBDSLcoAn2JReDX/jthOJ8Ahal3Hp43N12VA7WPk6fX2UUB Ad3wLkQN7dv6KAkzmCq3LQ== =FvaP -----END PGP SIGNATURE----- Merge tag 'for-net-2026-03-19' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - hci_ll: Fix firmware leak on error path - hci_sync: annotate data-races around hdev->req_status - L2CAP: Fix null-ptr-deref on l2cap_sock_ready_cb - L2CAP: Validate PDU length before reading SDU length in l2cap_ecred_data_rcv() - L2CAP: Fix regressions caused by reusing ident - L2CAP: Fix stack-out-of-bounds read in l2cap_ecred_conn_req - MGMT: Fix dangling pointer on mgmt_add_adv_patterns_monitor_complete - SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold * tag 'for-net-2026-03-19' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: L2CAP: Fix regressions caused by reusing ident Bluetooth: L2CAP: Fix null-ptr-deref on l2cap_sock_ready_cb Bluetooth: hci_ll: Fix firmware leak on error path Bluetooth: hci_sync: annotate data-races around hdev->req_status Bluetooth: MGMT: Fix dangling pointer on mgmt_add_adv_patterns_monitor_complete Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold Bluetooth: L2CAP: Validate PDU length before reading SDU length in l2cap_ecred_data_rcv() Bluetooth: L2CAP: Fix stack-out-of-bounds read in l2cap_ecred_conn_req ==================== Link: https://patch.msgid.link/20260319190455.135302-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
57ce3b2e9c
|
|
@ -541,6 +541,8 @@ static int download_firmware(struct ll_device *lldev)
|
|||
if (err || !fw->data || !fw->size) {
|
||||
bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s",
|
||||
err, bts_scr_name);
|
||||
if (!err)
|
||||
release_firmware(fw);
|
||||
return -EINVAL;
|
||||
}
|
||||
ptr = (void *)fw->data;
|
||||
|
|
|
|||
|
|
@ -658,6 +658,7 @@ struct l2cap_conn {
|
|||
struct sk_buff *rx_skb;
|
||||
__u32 rx_len;
|
||||
struct ida tx_ida;
|
||||
__u8 tx_ident;
|
||||
|
||||
struct sk_buff_head pending_rx;
|
||||
struct work_struct pending_rx_work;
|
||||
|
|
|
|||
|
|
@ -3095,7 +3095,7 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
|
|||
* hci_connect_le serializes the connection attempts so only one
|
||||
* connection can be in BT_CONNECT at time.
|
||||
*/
|
||||
if (conn->state == BT_CONNECT && hdev->req_status == HCI_REQ_PEND) {
|
||||
if (conn->state == BT_CONNECT && READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
|
||||
switch (hci_skb_event(hdev->sent_cmd)) {
|
||||
case HCI_EV_CONN_COMPLETE:
|
||||
case HCI_EV_LE_CONN_COMPLETE:
|
||||
|
|
|
|||
|
|
@ -4126,7 +4126,7 @@ static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
if (hdev->req_status == HCI_REQ_PEND &&
|
||||
if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND &&
|
||||
!hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) {
|
||||
kfree_skb(hdev->req_skb);
|
||||
hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
|
|||
{
|
||||
bt_dev_dbg(hdev, "result 0x%2.2x", result);
|
||||
|
||||
if (hdev->req_status != HCI_REQ_PEND)
|
||||
if (READ_ONCE(hdev->req_status) != HCI_REQ_PEND)
|
||||
return;
|
||||
|
||||
hdev->req_result = result;
|
||||
hdev->req_status = HCI_REQ_DONE;
|
||||
WRITE_ONCE(hdev->req_status, HCI_REQ_DONE);
|
||||
|
||||
/* Free the request command so it is not used as response */
|
||||
kfree_skb(hdev->req_skb);
|
||||
|
|
@ -167,20 +167,20 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
|
|||
|
||||
hci_cmd_sync_add(&req, opcode, plen, param, event, sk);
|
||||
|
||||
hdev->req_status = HCI_REQ_PEND;
|
||||
WRITE_ONCE(hdev->req_status, HCI_REQ_PEND);
|
||||
|
||||
err = hci_req_sync_run(&req);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = wait_event_interruptible_timeout(hdev->req_wait_q,
|
||||
hdev->req_status != HCI_REQ_PEND,
|
||||
READ_ONCE(hdev->req_status) != HCI_REQ_PEND,
|
||||
timeout);
|
||||
|
||||
if (err == -ERESTARTSYS)
|
||||
return ERR_PTR(-EINTR);
|
||||
|
||||
switch (hdev->req_status) {
|
||||
switch (READ_ONCE(hdev->req_status)) {
|
||||
case HCI_REQ_DONE:
|
||||
err = -bt_to_errno(hdev->req_result);
|
||||
break;
|
||||
|
|
@ -194,7 +194,7 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
|
|||
break;
|
||||
}
|
||||
|
||||
hdev->req_status = 0;
|
||||
WRITE_ONCE(hdev->req_status, 0);
|
||||
hdev->req_result = 0;
|
||||
skb = hdev->req_rsp;
|
||||
hdev->req_rsp = NULL;
|
||||
|
|
@ -665,9 +665,9 @@ void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
|
|||
{
|
||||
bt_dev_dbg(hdev, "err 0x%2.2x", err);
|
||||
|
||||
if (hdev->req_status == HCI_REQ_PEND) {
|
||||
if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
|
||||
hdev->req_result = err;
|
||||
hdev->req_status = HCI_REQ_CANCELED;
|
||||
WRITE_ONCE(hdev->req_status, HCI_REQ_CANCELED);
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work);
|
||||
}
|
||||
|
|
@ -683,12 +683,12 @@ void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err)
|
|||
{
|
||||
bt_dev_dbg(hdev, "err 0x%2.2x", err);
|
||||
|
||||
if (hdev->req_status == HCI_REQ_PEND) {
|
||||
if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
|
||||
/* req_result is __u32 so error must be positive to be properly
|
||||
* propagated.
|
||||
*/
|
||||
hdev->req_result = err < 0 ? -err : err;
|
||||
hdev->req_status = HCI_REQ_CANCELED;
|
||||
WRITE_ONCE(hdev->req_status, HCI_REQ_CANCELED);
|
||||
|
||||
wake_up_interruptible(&hdev->req_wait_q);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -926,16 +926,39 @@ int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator)
|
|||
|
||||
static int l2cap_get_ident(struct l2cap_conn *conn)
|
||||
{
|
||||
u8 max;
|
||||
int ident;
|
||||
|
||||
/* LE link does not support tools like l2ping so use the full range */
|
||||
if (conn->hcon->type == LE_LINK)
|
||||
return ida_alloc_range(&conn->tx_ida, 1, 255, GFP_ATOMIC);
|
||||
|
||||
max = 255;
|
||||
/* Get next available identificator.
|
||||
* 1 - 128 are used by kernel.
|
||||
* 129 - 199 are reserved.
|
||||
* 200 - 254 are used by utilities like l2ping, etc.
|
||||
*/
|
||||
return ida_alloc_range(&conn->tx_ida, 1, 128, GFP_ATOMIC);
|
||||
else
|
||||
max = 128;
|
||||
|
||||
/* Allocate ident using min as last used + 1 (cyclic) */
|
||||
ident = ida_alloc_range(&conn->tx_ida, READ_ONCE(conn->tx_ident) + 1,
|
||||
max, GFP_ATOMIC);
|
||||
/* Force min 1 to start over */
|
||||
if (ident <= 0) {
|
||||
ident = ida_alloc_range(&conn->tx_ida, 1, max, GFP_ATOMIC);
|
||||
if (ident <= 0) {
|
||||
/* If all idents are in use, log an error, this is
|
||||
* extremely unlikely to happen and would indicate a bug
|
||||
* in the code that idents are not being freed properly.
|
||||
*/
|
||||
BT_ERR("Unable to allocate ident: %d", ident);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_ONCE(conn->tx_ident, ident);
|
||||
|
||||
return ident;
|
||||
}
|
||||
|
||||
static void l2cap_send_acl(struct l2cap_conn *conn, struct sk_buff *skb,
|
||||
|
|
@ -5081,14 +5104,14 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
|||
cmd_len -= sizeof(*req);
|
||||
num_scid = cmd_len / sizeof(u16);
|
||||
|
||||
/* Always respond with the same number of scids as in the request */
|
||||
rsp_len = cmd_len;
|
||||
|
||||
if (num_scid > L2CAP_ECRED_MAX_CID) {
|
||||
result = L2CAP_CR_LE_INVALID_PARAMS;
|
||||
goto response;
|
||||
}
|
||||
|
||||
/* Always respond with the same number of scids as in the request */
|
||||
rsp_len = cmd_len;
|
||||
|
||||
mtu = __le16_to_cpu(req->mtu);
|
||||
mps = __le16_to_cpu(req->mps);
|
||||
|
||||
|
|
@ -6690,6 +6713,11 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
if (!chan->sdu) {
|
||||
u16 sdu_len;
|
||||
|
||||
if (!pskb_may_pull(skb, L2CAP_SDULEN_SIZE)) {
|
||||
err = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
sdu_len = get_unaligned_le16(skb->data);
|
||||
skb_pull(skb, L2CAP_SDULEN_SIZE);
|
||||
|
||||
|
|
|
|||
|
|
@ -1698,6 +1698,9 @@ static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
|
|||
struct sock *sk = chan->data;
|
||||
struct sock *parent;
|
||||
|
||||
if (!sk)
|
||||
return;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
parent = bt_sk(sk)->parent;
|
||||
|
|
|
|||
|
|
@ -5355,7 +5355,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
|
|||
* hci_adv_monitors_clear is about to be called which will take care of
|
||||
* freeing the adv_monitor instances.
|
||||
*/
|
||||
if (status == -ECANCELED && !mgmt_pending_valid(hdev, cmd))
|
||||
if (status == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
|
||||
return;
|
||||
|
||||
monitor = cmd->user_data;
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
|
|||
struct sock *sk;
|
||||
|
||||
sco_conn_lock(conn);
|
||||
sk = conn->sk;
|
||||
sk = sco_sock_hold(conn);
|
||||
sco_conn_unlock(conn);
|
||||
|
||||
if (!sk)
|
||||
|
|
@ -410,11 +410,15 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
|
|||
BT_DBG("sk %p len %u", sk, skb->len);
|
||||
|
||||
if (sk->sk_state != BT_CONNECTED)
|
||||
goto drop;
|
||||
goto drop_put;
|
||||
|
||||
if (!sock_queue_rcv_skb(sk, skb))
|
||||
if (!sock_queue_rcv_skb(sk, skb)) {
|
||||
sock_put(sk);
|
||||
return;
|
||||
}
|
||||
|
||||
drop_put:
|
||||
sock_put(sk);
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user