struct hci_ev_conn_complete *ev = data;
        struct hci_conn *conn;
 
+       if (__le16_to_cpu(ev->handle) > HCI_CONN_HANDLE_MAX) {
+               bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for invalid handle");
+               return;
+       }
+
        bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
 
        hci_dev_lock(hdev);
                }
        }
 
+       /* The HCI_Connection_Complete event is only sent once per connection.
+        * Processing it more than once per connection can corrupt kernel memory.
+        *
+        * As the connection handle is set here for the first time, it indicates
+        * whether the connection is already set up.
+        */
+       if (conn->handle != HCI_CONN_HANDLE_UNSET) {
+               bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
+               goto unlock;
+       }
+
        if (!ev->status) {
                conn->handle = __le16_to_cpu(ev->handle);
 
                return;
        }
 
+       if (__le16_to_cpu(ev->handle) > HCI_CONN_HANDLE_MAX) {
+               bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete for invalid handle");
+               return;
+       }
+
        bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
 
        hci_dev_lock(hdev);
                        goto unlock;
        }
 
+       /* The HCI_Synchronous_Connection_Complete event is only sent once per connection.
+        * Processing it more than once per connection can corrupt kernel memory.
+        *
+        * As the connection handle is set here for the first time, it indicates
+        * whether the connection is already set up.
+        */
+       if (conn->handle != HCI_CONN_HANDLE_UNSET) {
+               bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete event for existing connection");
+               goto unlock;
+       }
+
        switch (ev->status) {
        case 0x00:
-               /* The synchronous connection complete event should only be
-                * sent once per new connection. Receiving a successful
-                * complete event when the connection status is already
-                * BT_CONNECTED means that the device is misbehaving and sent
-                * multiple complete event packets for the same new connection.
-                *
-                * Registering the device more than once can corrupt kernel
-                * memory, hence upon detecting this invalid event, we report
-                * an error and ignore the packet.
-                */
-               if (conn->state == BT_CONNECTED) {
-                       bt_dev_err(hdev, "Ignoring connect complete event for existing connection");
-                       goto unlock;
-               }
-
                conn->handle = __le16_to_cpu(ev->handle);
                conn->state  = BT_CONNECTED;
                conn->type   = ev->link_type;
        struct smp_irk *irk;
        u8 addr_type;
 
+       if (handle > HCI_CONN_HANDLE_MAX) {
+               bt_dev_err(hdev, "Ignoring HCI_LE_Connection_Complete for invalid handle");
+               return;
+       }
+
        hci_dev_lock(hdev);
 
        /* All controllers implicitly stop advertising in the event of a
                cancel_delayed_work(&conn->le_conn_timeout);
        }
 
+       /* The HCI_LE_Connection_Complete event is only sent once per connection.
+        * Processing it more than once per connection can corrupt kernel memory.
+        *
+        * As the connection handle is set here for the first time, it indicates
+        * whether the connection is already set up.
+        */
+       if (conn->handle != HCI_CONN_HANDLE_UNSET) {
+               bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
+               goto unlock;
+       }
+
        le_conn_update_addr(conn, bdaddr, bdaddr_type, local_rpa);
 
        /* Lookup the identity address from the stored connection