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

janc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git


The following commit(s) were added to refs/heads/master by this push:
     new 24a3d58c nimble/host: Fix possible overflow in 
ble_gatts_peer_cl_sup_feat_update
24a3d58c is described below

commit 24a3d58ce236d655ae4fd1caad04d68c33cbcecc
Author: Szymon Janc <[email protected]>
AuthorDate: Tue Jan 2 16:26:50 2024 +0100

    nimble/host: Fix possible overflow in ble_gatts_peer_cl_sup_feat_update
    
    This function would write pass conn->bhc_gatt_svr.peer_cl_sup_feat
    buffer. Since supported features are likely to be small (currently
    only 3 bits are defined) lets keep this simple and just make local
    copy before validation.
---
 nimble/host/src/ble_gatts.c | 59 +++++++++++++++++++++------------------------
 1 file changed, 28 insertions(+), 31 deletions(-)

diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c
index 2c18cc4a..bf50305f 100644
--- a/nimble/host/src/ble_gatts.c
+++ b/nimble/host/src/ble_gatts.c
@@ -1613,8 +1613,9 @@ int
 ble_gatts_peer_cl_sup_feat_update(uint16_t conn_handle, struct os_mbuf *om)
 {
     struct ble_hs_conn *conn;
+    uint8_t feat[BLE_GATT_CHR_CLI_SUP_FEAT_SZ] = {};
+    uint16_t len;
     int rc = 0;
-    int feat_idx = 0;
     int i;
 
     BLE_HS_LOG(DEBUG, "");
@@ -1623,46 +1624,42 @@ ble_gatts_peer_cl_sup_feat_update(uint16_t conn_handle, 
struct os_mbuf *om)
         return BLE_ATT_ERR_INSUFFICIENT_RES;
     }
 
+    /* RFU bits are ignored so we can skip any bytes larger than supported */
+    len = os_mbuf_len(om);
+    if (len > BLE_GATT_CHR_CLI_SUP_FEAT_SZ) {
+        len = BLE_GATT_CHR_CLI_SUP_FEAT_SZ;
+    }
+
+    if (os_mbuf_copydata(om, 0, len, feat) < 0) {
+        return BLE_ATT_ERR_UNLIKELY;
+    }
+
+    /* clear RFU bits */
+    for (i = 0; i < BLE_GATT_CHR_CLI_SUP_FEAT_SZ; i++) {
+        feat[i] &= (BLE_GATT_CHR_CLI_SUP_FEAT_MASK >> (8 * i));
+    }
+
     ble_hs_lock();
     conn = ble_hs_conn_find(conn_handle);
     if (conn == NULL) {
         rc = BLE_ATT_ERR_UNLIKELY;
         goto done;
     }
-    if (om->om_len == 0) {
-        /* Nothing to do */
-        goto done;
-    } else if (os_mbuf_len(om) > BLE_ATT_ATTR_MAX_LEN) {
-        rc = BLE_ATT_ERR_INSUFFICIENT_RES;
-        goto done;
-    }
-
-    while(om) {
-        for (i = 0; i < om->om_len; i++) {
-            /**
-             * Disabling already enabled features is not permitted
-             * (Vol. 3, Part F, 3.3.3)
-             * If value of saved octet, as uint8_t, is greatet than requested
-             * it means more bits are set.
-             */
-            if (conn->bhc_gatt_svr.peer_cl_sup_feat[feat_idx] >
-                om->om_data[i]) {
-                rc = BLE_ATT_ERR_VALUE_NOT_ALLOWED;
-                goto done;
-            }
-
-            /* All RFU bits should be unset */
-            if (feat_idx == 0) {
-                om->om_data[i] &= BLE_GATT_CHR_CLI_SUP_FEAT_MASK;
-            }
-
-            conn->bhc_gatt_svr.peer_cl_sup_feat[feat_idx] |= om->om_data[i];
 
-            feat_idx++;
+    /**
+     * Disabling already enabled features is not permitted
+     * (Vol. 3, Part F, 3.3.3)
+     */
+    for (i = 0; i < BLE_GATT_CHR_CLI_SUP_FEAT_SZ; i++) {
+        if ((conn->bhc_gatt_svr.peer_cl_sup_feat[i] & feat[i]) !=
+            conn->bhc_gatt_svr.peer_cl_sup_feat[i]) {
+            rc = BLE_ATT_ERR_VALUE_NOT_ALLOWED;
+            goto done;
         }
-        om = SLIST_NEXT(om, om_next);
     }
 
+    memcpy(conn->bhc_gatt_svr.peer_cl_sup_feat, feat, 
BLE_GATT_CHR_CLI_SUP_FEAT_SZ);
+
 done:
     ble_hs_unlock();
     return rc;

Reply via email to