[bug report] Bluetooth: L2CAP: Fix corrupted list in hci_chan_del

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Luiz Augusto von Dentz,

Commit dd6367916d2d ("Bluetooth: L2CAP: Fix corrupted list in
hci_chan_del") from Feb 6, 2025 (linux-next), leads to the following
Smatch static checker warning:

	net/bluetooth/l2cap_core.c:7555 l2cap_recv_acldata()
	error: we previously assumed 'conn' could be null (see line 7459)

net/bluetooth/l2cap_core.c
    7442 void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
    7443 {
    7444         struct l2cap_conn *conn;
    7445         int len;
    7446 
    7447         /* Lock hdev to access l2cap_data to avoid race with l2cap_conn_del */
    7448         hci_dev_lock(hcon->hdev);
    7449 
    7450         conn = hcon->l2cap_data;
    7451 
    7452         if (!conn)
    7453                 conn = l2cap_conn_add(hcon);
    7454 
    7455         conn = l2cap_conn_hold_unless_zero(conn);
    7456 
    7457         hci_dev_unlock(hcon->hdev);
    7458 
    7459         if (!conn)
    7460                 goto drop;

Do you want to move drop after the unlock: or do you want to make this
a direct return?  Choices, choices...

	if (!conn) {
		kfree_skb(skb);
		return;
	}

    7461 
    7462         BT_DBG("conn %p len %u flags 0x%x", conn, skb->len, flags);
    7463 
    7464         mutex_lock(&conn->lock);
    7465 
    7466         switch (flags) {
    7467         case ACL_START:
    7468         case ACL_START_NO_FLUSH:
    7469         case ACL_COMPLETE:
    7470                 if (conn->rx_skb) {
    7471                         BT_ERR("Unexpected start frame (len %d)", skb->len);
    7472                         l2cap_recv_reset(conn);
    7473                         l2cap_conn_unreliable(conn, ECOMM);
    7474                 }
    7475 
    7476                 /* Start fragment may not contain the L2CAP length so just
    7477                  * copy the initial byte when that happens and use conn->mtu as
    7478                  * expected length.
    7479                  */
    7480                 if (skb->len < L2CAP_LEN_SIZE) {
    7481                         l2cap_recv_frag(conn, skb, conn->mtu);
    7482                         break;
    7483                 }
    7484 
    7485                 len = get_unaligned_le16(skb->data) + L2CAP_HDR_SIZE;
    7486 
    7487                 if (len == skb->len) {
    7488                         /* Complete frame received */
    7489                         l2cap_recv_frame(conn, skb);
    7490                         goto unlock;
    7491                 }
    7492 
    7493                 BT_DBG("Start: total len %d, frag len %u", len, skb->len);
    7494 
    7495                 if (skb->len > len) {
    7496                         BT_ERR("Frame is too long (len %u, expected len %d)",
    7497                                skb->len, len);
    7498                         l2cap_conn_unreliable(conn, ECOMM);
    7499                         goto drop;
    7500                 }
    7501 
    7502                 /* Append fragment into frame (with header) */
    7503                 if (l2cap_recv_frag(conn, skb, len) < 0)
    7504                         goto drop;
    7505 
    7506                 break;
    7507 
    7508         case ACL_CONT:
    7509                 BT_DBG("Cont: frag len %u (expecting %u)", skb->len, conn->rx_len);
    7510 
    7511                 if (!conn->rx_skb) {
    7512                         BT_ERR("Unexpected continuation frame (len %d)", skb->len);
    7513                         l2cap_conn_unreliable(conn, ECOMM);
    7514                         goto drop;
    7515                 }
    7516 
    7517                 /* Complete the L2CAP length if it has not been read */
    7518                 if (conn->rx_skb->len < L2CAP_LEN_SIZE) {
    7519                         if (l2cap_recv_len(conn, skb) < 0) {
    7520                                 l2cap_conn_unreliable(conn, ECOMM);
    7521                                 goto drop;
    7522                         }
    7523 
    7524                         /* Header still could not be read just continue */
    7525                         if (conn->rx_skb->len < L2CAP_LEN_SIZE)
    7526                                 break;
    7527                 }
    7528 
    7529                 if (skb->len > conn->rx_len) {
    7530                         BT_ERR("Fragment is too long (len %u, expected %u)",
    7531                                skb->len, conn->rx_len);
    7532                         l2cap_recv_reset(conn);
    7533                         l2cap_conn_unreliable(conn, ECOMM);
    7534                         goto drop;
    7535                 }
    7536 
    7537                 /* Append fragment into frame (with header) */
    7538                 l2cap_recv_frag(conn, skb, skb->len);
    7539 
    7540                 if (!conn->rx_len) {
    7541                         /* Complete frame received. l2cap_recv_frame
    7542                          * takes ownership of the skb so set the global
    7543                          * rx_skb pointer to NULL first.
    7544                          */
    7545                         struct sk_buff *rx_skb = conn->rx_skb;
    7546                         conn->rx_skb = NULL;
    7547                         l2cap_recv_frame(conn, rx_skb);
    7548                 }
    7549                 break;
    7550         }
    7551 
    7552 drop:
    7553         kfree_skb(skb);
    7554 unlock:
--> 7555         mutex_unlock(&conn->lock);
    7556         l2cap_conn_put(conn);
    7557 }

regards,
dan carpenter




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux