This is an automated email from the ASF dual-hosted git repository.

JorgeGzm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new c728586a48a wireless/bluetooth: Validate event length before parsing 
HCI events.
c728586a48a is described below

commit c728586a48ac9e57c649c5867034c048b2707488
Author: Alan Carvalho de Assis <[email protected]>
AuthorDate: Thu Sep 17 10:16:54 2026 -0300

    wireless/bluetooth: Validate event length before parsing HCI events.
    
    hci_event() consumed the event header and dispatched on the event code
    without checking that a header had been received, and hci_le_meta_event()
    did the same for the subevent code.  Each handler then cast the remaining
    buffer to its event structure and read fields out of it, so a short event
    was parsed from whatever followed it in memory - including the fields
    that identify a connection and carry its encryption state.
    
    Check that the header is present before reading it, that the parameters
    the event declares were actually received, and that enough parameters
    remain for the structure the selected handler casts to.  Events failing a
    check are dropped with a diagnostic rather than parsed.
    
    le_adv_report() continues to do its own checking, because the report
    count and the per-report lengths vary within that event.
    
    Ref: Core v6.0, Vol 4, Part E, 5.4.4 (HCI Event packets)
    Ref: Core v6.0, Vol 4, Part E, 7.7 (Events)
    Testing: builds for sim:bluetooth with Make; every commit in this series
    verified to build individually.  Not yet exercised at runtime - the
    scriptable controller injects truncated events separately.
    
    Signed-off-by: Alan C. Assis <[email protected]>
    Assisted-by: Claude Code Opus 5
---
 wireless/bluetooth/bt_hcicore.c | 127 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 114 insertions(+), 13 deletions(-)

diff --git a/wireless/bluetooth/bt_hcicore.c b/wireless/bluetooth/bt_hcicore.c
index 08089e587d2..8705a08fae6 100644
--- a/wireless/bluetooth/bt_hcicore.c
+++ b/wireless/bluetooth/bt_hcicore.c
@@ -42,6 +42,7 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -963,19 +964,72 @@ static int le_param_request(FAR struct bt_buf_s *buf)
           reply_buf, NULL);
 }
 
+/****************************************************************************
+ * Name: hci_evt_length_ok
+ *
+ * Description:
+ *   Verify that an event carries at least the parameters the handler for
+ *   it is going to read.  Everything reaching here comes from the
+ *   controller, which is a separate device on a serial line, a
+ *   co-processor or, in the simulator, another process, so the lengths it
+ *   declares are checked rather than trusted.
+ *
+ * Input Parameters:
+ *   buf    - The event buffer, positioned at the event parameters
+ *   minlen - Size of the structure the handler casts the parameters to
+ *   code   - Event or subevent code, for the diagnostic only
+ *
+ * Returned Value:
+ *   true if the handler may run.
+ *
+ ****************************************************************************/
+
+static bool hci_evt_length_ok(FAR struct bt_buf_s *buf, size_t minlen,
+                              uint8_t code)
+{
+  if (buf->len < minlen)
+    {
+      wlerr("ERROR: Event 0x%02x too short: %u, need %zu\n", code,
+            buf->len, minlen);
+      return false;
+    }
+
+  return true;
+}
+
 static void hci_le_meta_event(FAR struct bt_buf_s *buf)
 {
-  FAR struct bt_hci_evt_le_meta_event_s *evt = (FAR void *)buf->data;
+  FAR struct bt_hci_evt_le_meta_event_s *evt;
+  uint8_t subevent;
+
+  if (buf->len < sizeof(*evt))
+    {
+      wlerr("ERROR: Truncated LE meta event\n");
+      return;
+    }
+
+  evt      = (FAR void *)buf->data;
+  subevent = evt->subevent;
 
   bt_buf_consume(buf, sizeof(*evt));
 
-  switch (evt->subevent)
+  switch (subevent)
     {
       case BT_HCI_EVT_LE_CONN_COMPLETE:
-        le_conn_complete(buf);
+        if (hci_evt_length_ok(buf,
+                              sizeof(struct bt_hci_evt_le_conn_complete_s),
+                              subevent))
+          {
+            le_conn_complete(buf);
+          }
         break;
 
       case BT_HCI_EVT_LE_ADVERTISING_REPORT:
+
+        /* le_adv_report() checks the report count and every per-report
+         * length itself, since those vary within the event.
+         */
+
         le_adv_report(buf);
         break;
 
@@ -983,39 +1037,86 @@ static void hci_le_meta_event(FAR struct bt_buf_s *buf)
         break;
 
       case BT_HCI_EVT_LE_LTK_REQUEST:
-        le_ltk_request(buf);
+        if (hci_evt_length_ok(buf,
+                              sizeof(struct bt_hci_evt_le_ltk_request_s),
+                              subevent))
+          {
+            le_ltk_request(buf);
+          }
         break;
 
       case BT_HCI_EVT_LE_CONN_PARAM_REQ:
-        le_param_request(buf);
+        if (hci_evt_length_ok(
+              buf, sizeof(struct bt_hci_evt_le_rem_conn_param_req_s),
+              subevent))
+          {
+            le_param_request(buf);
+          }
         break;
 
       default:
-        wlinfo("Unhandled LE event %04x\n", evt->subevent);
+        wlinfo("Unhandled LE event %04x\n", subevent);
         break;
     }
 }
 
 static void hci_event(FAR struct bt_buf_s *buf)
 {
-  FAR struct bt_hci_evt_hdr_s *hdr = (FAR void *)buf->data;
+  FAR struct bt_hci_evt_hdr_s *hdr;
+  uint8_t evt;
 
-  wlinfo("event %u\n", hdr->evt);
+  if (buf->len < sizeof(*hdr))
+    {
+      wlerr("ERROR: Truncated event header\n");
+      return;
+    }
+
+  hdr = (FAR void *)buf->data;
+  evt = hdr->evt;
+
+  wlinfo("event %u\n", evt);
 
   bt_buf_consume(buf, sizeof(struct bt_hci_evt_hdr_s));
 
-  switch (hdr->evt)
+  /* The event declares its own parameter length.  If less than that was
+   * received the packet was truncated in transport and the parameters
+   * cannot be parsed.
+   */
+
+  if (buf->len < hdr->len)
+    {
+      wlerr("ERROR: Event 0x%02x declares %u parameters, got %u\n", evt,
+            hdr->len, buf->len);
+      return;
+    }
+
+  switch (evt)
     {
       case BT_HCI_EVT_DISCONN_COMPLETE:
-        hci_disconn_complete(buf);
+        if (hci_evt_length_ok(buf,
+                              sizeof(struct bt_hci_evt_disconn_complete_s),
+                              evt))
+          {
+            hci_disconn_complete(buf);
+          }
         break;
 
       case BT_HCI_EVT_ENCRYPT_CHANGE:
-        hci_encrypt_change(buf);
+        if (hci_evt_length_ok(buf,
+                              sizeof(struct bt_hci_evt_encrypt_change_s),
+                              evt))
+          {
+            hci_encrypt_change(buf);
+          }
         break;
 
       case BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE:
-        hci_encrypt_key_refresh_complete(buf);
+        if (hci_evt_length_ok(
+              buf, sizeof(struct bt_hci_evt_encrypt_key_refresh_complete_s),
+              evt))
+          {
+            hci_encrypt_key_refresh_complete(buf);
+          }
         break;
 
       case BT_HCI_EVT_LE_META_EVENT:
@@ -1023,7 +1124,7 @@ static void hci_event(FAR struct bt_buf_s *buf)
         break;
 
       default:
-        wlwarn("WARNING:  Unhandled event 0x%02x\n", hdr->evt);
+        wlwarn("WARNING:  Unhandled event 0x%02x\n", evt);
         break;
     }
 }

Reply via email to