← Back to CVE Explorer

CVE-2026-10653

Full vulnerability record from the local CVENow database.

Description

The Zephyr net_buf library (lib/net_buf/buf.c) manipulated both of its reference counts -- the per-header buf->ref and the per-data-block ref_count at the start of each variable/heap data allocation -- with plain non-atomic C operators (buf->ref++, if (--buf->ref > 0), if (--(*ref_count))). The API is documented as self-synchronizing: callers may share one buffer across threads (e.g. via k_fifo) and each holder independently calls net_buf_unref() with no surrounding lock. Under true concurrency (SMP, or single-core preemption between the non-atomic load and store while another context unrefs the same buffer), two holders can both observe the same prior reference value and both conclude they are the last reference. For heap/variable-data pools (mem_pool_data_unref/heap_data_unref, used by zbus message subscribers, the IP stack RX/TX buffers when CONFIG_NET_BUF_FIXED_DATA_SIZE=n, capture, wireguard, ISO-TP and usbip) this produces a double k_heap_free()/k_free() of the same block -- heap-metadata corruption and a use-after-free on the heap-hardening poison pattern. For the per-header refcount the buffer is returned to the pool free LIFO twice for any pool type (including fixed-data pools used by Bluetooth and networking), corrupting the free list so a later allocation hands the same buffer to two owners. The fix converts both refcounts to atomic_inc/atomic_dec (overlaying buf->ref in an atomic_t-sized union and changing the data-block refcount from uint8_t to atomic_t). Impact is gated on genuine concurrency and on an application architecture that shares one buffer among multiple independent unref'ers; the trigger is a refcount/timing race rather than packet content, so an external attacker has at most weak indirect influence over the race window. Affects all Zephyr releases through v4.4.0. This fix is not being backported to v3.7-branch (LTS). The backport was attempted and closed unmerged (#111181): the v3.7 networking tree has diverged from main, and the new atomic word-packing -- together with the assertions it adds -- turns pre-existing v3.7-only reference-counting defects elsewhere in the stack into hard faults, so landing the change faithfully would mean pulling an open-ended set of additional v3.7-only fixes into an LTS branch. v3.7 remains affected. Applications on v3.7 that share one net_buf across threads should serialize their own net_buf_unref() calls rather than rely on the documented self-synchronizing behaviour. The fix is on main and has been backported to v4.3-branch (#110852) and v4.4-branch (#110853).

Severity
HIGH
CVSS score
8.1 (v3.1)
Vulnerability status
Modified
Source identifier
Published
2026-06-30 17:16:20.160000
Last modified
2026-10-25 21:10:00.770000
View original CVE JSON
{
  "id": "CVE-2026-10653",
  "sourceIdentifier": "[email protected]",
  "published": "2026-06-30T17:16:20.160",
  "lastModified": "2026-10-25T21:10:00.770",
  "vulnStatus": "Modified",
  "cveTags": [],
  "descriptions": [
    {
      "lang": "en",
      "value": "The Zephyr net_buf library (lib/net_buf/buf.c) manipulated both of its reference counts -- the per-header buf->ref and the per-data-block ref_count at the start of each variable/heap data allocation -- with plain non-atomic C operators (buf->ref++, if (--buf->ref > 0), if (--(*ref_count))).\n\nThe API is documented as self-synchronizing: callers may share one buffer across threads (e.g. via k_fifo) and each holder independently calls net_buf_unref() with no surrounding lock. Under true concurrency (SMP, or single-core preemption between the non-atomic load and store while another context unrefs the same buffer), two holders can both observe the same prior reference value and both conclude they are the last reference.\n\nFor heap/variable-data pools (mem_pool_data_unref/heap_data_unref, used by zbus message subscribers, the IP stack RX/TX buffers when CONFIG_NET_BUF_FIXED_DATA_SIZE=n, capture, wireguard, ISO-TP and usbip) this produces a double k_heap_free()/k_free() of the same block -- heap-metadata corruption and a use-after-free on the heap-hardening poison pattern.\n\nFor the per-header refcount the buffer is returned to the pool free LIFO twice for any pool type (including fixed-data pools used by Bluetooth and networking), corrupting the free list so a later allocation hands the same buffer to two owners.\n\nThe fix converts both refcounts to atomic_inc/atomic_dec (overlaying buf->ref in an atomic_t-sized union and changing the data-block refcount from uint8_t to atomic_t).\n\nImpact is gated on genuine concurrency and on an application architecture that shares one buffer among multiple independent unref'ers; the trigger is a refcount/timing race rather than packet content, so an external attacker has at most weak indirect influence over the race window. Affects all Zephyr releases through v4.4.0.\n\nThis fix is not being backported to v3.7-branch (LTS). The backport was attempted and closed unmerged (#111181): the v3.7 networking tree has diverged from main, and the new atomic word-packing -- together with the assertions it adds -- turns pre-existing v3.7-only reference-counting defects elsewhere in the stack into hard faults, so landing the change faithfully would mean pulling an open-ended set of additional v3.7-only fixes into an LTS branch. v3.7 remains affected. Applications on v3.7 that share one net_buf across threads should serialize their own net_buf_unref() calls rather than rely on the documented self-synchronizing behaviour. The fix is on main and has been backported to v4.3-branch (#110852) and v4.4-branch (#110853)."
    },
    {
      "lang": "es",
      "value": "La biblioteca Zephyr net_buf (lib/net_buf/buf.c) manipulaba sus dos contadores de referencia -- el buf  ->  ref por cabecera y el ref_count por bloque de datos al inicio de cada asignación de datos de variable/montón -- con operadores C no atómicos simples (buf  ->  ref++, if (--buf  ->  ref > 0), if (--(ref_count))). La API está documentada como auto-sincronizante: los llamadores pueden compartir un búfer entre hilos (p. ej., a través de k_fifo) y cada poseedor llama independientemente a net_buf_unref() sin un bloqueo circundante. Bajo verdadera concurrencia (SMP, o expropiación de un solo núcleo entre la carga y el almacenamiento no atómicos mientras otro contexto desreferencia el mismo búfer), dos poseedores pueden observar el mismo valor de referencia anterior y ambos concluyen que son la última referencia. Para pools de datos de montón/variable (mem_pool_data_unref/heap_data_unref, utilizados por los suscriptores de mensajes zbus, los búferes RX/TX de la pila IP cuando CONFIG_NET_BUF_FIXED_DATA_SIZE=n, captura, wireguard, ISO-TP y usbip) esto produce un doble k_heap_free()/k_free() del mismo bloque -- corrupción de metadatos del montón y un uso después de liberación en el patrón de envenenamiento de endurecimiento del montón. Para el contador de referencia por cabecera, el búfer se devuelve a la LIFO libre del pool dos veces para cualquier tipo de pool (incluyendo pools de datos fijos utilizados por Bluetooth y redes), corrompiendo la lista libre de modo que una asignación posterior entrega el mismo búfer a dos propietarios. La solución convierte ambos contadores de referencia a atomic_inc/atomic_dec (superponiendo buf  ->  ref en una unión de tamaño atomic_t y cambiando el contador de referencia del bloque de datos de uint8_t a atomic_t). El impacto está condicionado a la concurrencia genuina y a una arquitectura de aplicación que comparte un búfer entre múltiples desreferenciadores independientes; el disparador es una condición de carrera de contador de referencia/tiempo en lugar del contenido del paquete, por lo que un atacante externo tiene como máximo una influencia indirecta débil sobre la ventana de la carrera. Afecta a todas las versiones de Zephyr hasta la v4.4.0."
    }
  ],
  "affected": [
    {
      "source": "[email protected]",
      "affectedData": [
        {
          "vendor": "zephyrproject",
          "product": "zephyr",
          "defaultStatus": "unaffected",
          "collectionURL": "https://github.com/zephyrproject-rtos/zephyr",
          "packageName": "zephyr",
          "programFiles": [
            "include/zephyr/net_buf.h",
            "lib/net_buf/buf.c",
            "subsys/net/ip/net_pkt.c"
          ],
          "versions": [
            {
              "version": "2.7.0",
              "lessThan": "4.3.1",
              "versionType": "semver",
              "status": "affected"
            },
            {
              "version": "4.4.0",
              "lessThan": "4.4.2",
              "versionType": "semver",
              "status": "affected"
            }
          ]
        }
      ]
    }
  ],
  "metrics": {
    "cvssMetricV31": [
      {
        "source": "[email protected]",
        "type": "Secondary",
        "cvssData": {
          "version": "3.1",
          "vectorString": "CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H",
          "baseScore": 6.4,
          "baseSeverity": "MEDIUM",
          "attackVector": "ADJACENT_NETWORK",
          "attackComplexity": "HIGH",
          "privilegesRequired": "NONE",
          "userInteraction": "NONE",
          "scope": "UNCHANGED",
          "confidentialityImpact": "LOW",
          "integrityImpact": "LOW",
          "availabilityImpact": "HIGH"
        },
        "exploitabilityScore": 1.6,
        "impactScore": 4.7
      },
      {
        "source": "[email protected]",
        "type": "Primary",
        "cvssData": {
          "version": "3.1",
          "vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
          "baseScore": 8.1,
          "baseSeverity": "HIGH",
          "attackVector": "NETWORK",
          "attackComplexity": "HIGH",
          "privilegesRequired": "NONE",
          "userInteraction": "NONE",
          "scope": "UNCHANGED",
          "confidentialityImpact": "HIGH",
          "integrityImpact": "HIGH",
          "availabilityImpact": "HIGH"
        },
        "exploitabilityScore": 2.2,
        "impactScore": 5.9
      }
    ],
    "ssvcV203": [
      {
        "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
        "ssvcData": {
          "timestamp": "2026-06-30T16:41:03.581627Z",
          "id": "CVE-2026-10653",
          "options": [
            {
              "exploitation": "none"
            },
            {
              "automatable": "no"
            },
            {
              "technicalImpact": "partial"
            }
          ],
          "role": "CISA Coordinator",
          "version": "2.0.3"
        }
      }
    ]
  },
  "weaknesses": [
    {
      "source": "[email protected]",
      "type": "Secondary",
      "description": [
        {
          "lang": "en",
          "value": "CWE-415"
        }
      ]
    }
  ],
  "configurations": [
    {
      "nodes": [
        {
          "operator": "OR",
          "negate": false,
          "cpeMatch": [
            {
              "vulnerable": true,
              "criteria": "cpe:2.3:o:zephyrproject:zephyr:*:*:*:*:*:*:*:*",
              "versionStartIncluding": "2.7.0",
              "versionEndIncluding": "4.4.1",
              "matchCriteriaId": "377DB2C9-BF5F-4608-BCE8-4EF2552ACCA8"
            }
          ]
        }
      ]
    }
  ],
  "references": [
    {
      "url": "https://github.com/zephyrproject-rtos/zephyr/commit/9bb2878319d5f46c29ab5fe855a378d87cd75fc3",
      "source": "[email protected]",
      "tags": [
        "Patch"
      ]
    },
    {
      "url": "https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-284j-5jm9-55hh",
      "source": "[email protected]",
      "tags": [
        "Exploit",
        "Patch",
        "Vendor Advisory"
      ]
    }
  ]
}