CVE-2026-10646
Full vulnerability record from the local CVENow database.
Description
Zephyr's BSD-sockets getaddrinfo() implementation (subsys/net/lib/sockets/getaddrinfo.c) passes a pointer to a stack-allocated state object (struct getaddrinfo_state ai_state) as the user_data of an asynchronous DNS resolver query. The socket layer waits on a semaphore with a timeout deliberately set slightly longer than the resolver's own per-query timeout. When that semaphore wait nonetheless times out (-EAGAIN) - which can occur when the resolver's timeout work is delayed by workqueue contention, or in the documented multi-retry configuration where CONFIG_NET_SOCKETS_DNS_TIMEOUT exceeds CONFIG_NET_SOCKETS_DNS_BACKOFF_INTERVAL - the pre-fix code retries the query (goto again) without cancelling the previous one and without resetting the semaphore. The previous query slot remains active in the resolver with its callback and the stack pointer as user_data, and ai_state->dns_id is overwritten so the stale query can no longer be cancelled. A subsequent DNS response delivered over UDP and matched by its 16-bit transaction id (in dispatcher_cb()/dns_read()), or the resolver's own delayed query-timeout work, then invokes dns_resolve_cb() against the now out-of-scope stack frame, writing through the stale pointer (state->status, state->idx, state->ai_arr[], and k_sem_give()). Because the triggering response is network-delivered and its 16-bit id is spoofable/replayable by an on- or off-path attacker, this is a network-influenceable use-after-return that can corrupt reused stack memory, leading to crashes/denial of service or memory corruption. The fix cancels the timed-out query by name and type before retrying and resets the local semaphore, eliminating the stale callback path. Affected: Zephyr v4.0.0 through v4.4.0.
View original CVE JSON
{
"id": "CVE-2026-10646",
"sourceIdentifier": "[email protected]",
"published": "2026-06-28T05:16:21.083",
"lastModified": "2026-10-25T17:10:00.197",
"vulnStatus": "Modified",
"cveTags": [],
"descriptions": [
{
"lang": "en",
"value": "Zephyr's BSD-sockets getaddrinfo() implementation (subsys/net/lib/sockets/getaddrinfo.c) passes a pointer to a stack-allocated state object (struct getaddrinfo_state ai_state) as the user_data of an asynchronous DNS resolver query. The socket layer waits on a semaphore with a timeout deliberately set slightly longer than the resolver's own per-query timeout. When that semaphore wait nonetheless times out (-EAGAIN) - which can occur when the resolver's timeout work is delayed by workqueue contention, or in the documented multi-retry configuration where CONFIG_NET_SOCKETS_DNS_TIMEOUT exceeds CONFIG_NET_SOCKETS_DNS_BACKOFF_INTERVAL - the pre-fix code retries the query (goto again) without cancelling the previous one and without resetting the semaphore.\n\nThe previous query slot remains active in the resolver with its callback and the stack pointer as user_data, and ai_state->dns_id is overwritten so the stale query can no longer be cancelled. A subsequent DNS response delivered over UDP and matched by its 16-bit transaction id (in dispatcher_cb()/dns_read()), or the resolver's own delayed query-timeout work, then invokes dns_resolve_cb() against the now out-of-scope stack frame, writing through the stale pointer (state->status, state->idx, state->ai_arr[], and k_sem_give()).\n\nBecause the triggering response is network-delivered and its 16-bit id is spoofable/replayable by an on- or off-path attacker, this is a network-influenceable use-after-return that can corrupt reused stack memory, leading to crashes/denial of service or memory corruption.\n\nThe fix cancels the timed-out query by name and type before retrying and resets the local semaphore, eliminating the stale callback path. Affected: Zephyr v4.0.0 through v4.4.0."
},
{
"lang": "es",
"value": "La implementación de getaddrinfo() de los sockets BSD de Zephyr (subsys/net/lib/sockets/getaddrinfo.c) pasa un puntero a un objeto de estado asignado en la pila (struct getaddrinfo_state ai_state) como el user_data de una consulta asíncrona del resolvedor DNS. La capa de sockets espera en un semáforo con un tiempo de espera (timeout) establecido deliberadamente un poco más largo que el tiempo de espera por consulta propio del resolvedor. Cuando esa espera del semáforo, no obstante, agota su tiempo (-EAGAIN) - lo que puede ocurrir cuando el trabajo de tiempo de espera del resolvedor se retrasa por contención de la cola de trabajo, o en la configuración de múltiples reintentos documentada donde CONFIG_NET_SOCKETS_DNS_TIMEOUT excede CONFIG_NET_SOCKETS_DNS_BACKOFF_INTERVAL - el código anterior a la corrección reintenta la consulta (goto again) sin cancelar la anterior y sin reiniciar el semáforo. La ranura de consulta anterior permanece activa en el resolvedor con su callback y el puntero de pila como user_data, y ai_state-dns_id es sobrescrito de modo que la consulta obsoleta ya no puede ser cancelada. Una respuesta DNS subsiguiente entregada a través de UDP y emparejada por su ID de transacción de 16 bits (en dispatcher_cb()/dns_read()), o el propio trabajo de tiempo de espera de consulta retrasado del resolvedor, entonces invoca dns_resolve_cb() contra el marco de pila ahora fuera de alcance, escribiendo a través del puntero obsoleto (state-status, state-idx, state-ai_arr[], y k_sem_give()). Debido a que la respuesta desencadenante es entregada por la red y su ID de 16 bits es falsificable/reproducible por un atacante en la ruta o fuera de ella, esto es un uso después de retorno influenciable por la red que puede corromper la memoria de pila reutilizada, lo que lleva a fallos/denegación de servicio o corrupción de memoria. La corrección cancela la consulta con tiempo agotado por nombre y tipo antes de reintentar y reinicia el semáforo local, eliminando la ruta de callback obsoleta. Afectado: Zephyr v4.0.0 hasta 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/dns_resolve.h",
"subsys/net/lib/sockets/getaddrinfo.c"
],
"versions": [
{
"version": "3.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:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H",
"baseScore": 7.4,
"baseSeverity": "HIGH",
"attackVector": "NETWORK",
"attackComplexity": "HIGH",
"privilegesRequired": "NONE",
"userInteraction": "NONE",
"scope": "UNCHANGED",
"confidentialityImpact": "NONE",
"integrityImpact": "HIGH",
"availabilityImpact": "HIGH"
},
"exploitabilityScore": 2.2,
"impactScore": 5.2
}
],
"ssvcV203": [
{
"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"ssvcData": {
"timestamp": "2026-06-29T13:46:37.688522Z",
"id": "CVE-2026-10646",
"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-416"
}
]
}
],
"configurations": [
{
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:zephyrproject:zephyr:*:*:*:*:*:*:*:*",
"versionStartIncluding": "4.0.0",
"versionEndIncluding": "4.4.1",
"matchCriteriaId": "CFE70C6A-CD31-49A0-BAC4-20595278999F"
}
]
}
]
}
],
"references": [
{
"url": "https://github.com/zephyrproject-rtos/zephyr/commit/cd27da58eedb8d0fe380dd340b81ca5afa35de45",
"source": "[email protected]",
"tags": [
"Patch"
]
},
{
"url": "https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-h752-vhmf-29w6",
"source": "[email protected]",
"tags": [
"Exploit",
"Patch",
"Vendor Advisory"
]
}
]
}