{ "dataType": "CVE_RECORD", "dataVersion": "5.2", "cveMetadata": { "cveId": "CVE-2025-21661", "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "state": "PUBLISHED", "assignerShortName": "Linux", "dateReserved": "2024-12-29T08:45:45.732Z", "datePublished": "2025-01-21T12:18:16.902Z", "dateUpdated": "2026-08-05T11:53:26.900Z" }, "containers": { "cna": { "providerMetadata": { "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "shortName": "Linux", "dateUpdated": "2026-08-05T11:53:26.900Z" }, "descriptions": [ { "lang": "en", "value": "In the Linux kernel, the following vulnerability has been resolved:\n\ngpio: virtuser: fix missing lookup table cleanups\n\nWhen a virtuser device is created via configfs and the probe fails due\nto an incorrect lookup table, the table is not removed. This prevents\nsubsequent probe attempts from succeeding, even if the issue is\ncorrected, unless the device is released. Additionally, cleanup is also\nneeded in the less likely case of platform_device_register_full()\nfailure.\n\nBesides, a consistent memory leak in lookup_table->dev_id was spotted\nusing kmemleak by toggling the live state between 0 and 1 with a correct\nlookup table.\n\nIntroduce gpio_virtuser_remove_lookup_table() as the counterpart to the\nexisting gpio_virtuser_make_lookup_table() and call it from all\nnecessary points to ensure proper cleanup." } ], "metrics": [ { "cvssV3_1": { "version": "3.1", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "baseScore": 7.8, "baseSeverity": "HIGH" }, "scenarios": [ { "lang": "en", "value": "AV:L - The vulnerability is reached exclusively through configfs mkdir/rmdir/write operations under /sys/kernel/config/gpio-virtuser/, which require local access to the system. There is no network or adjacent-network path to gpio-virtuser.\nAC:L - The attacker fully controls every step — the bad lookup key that forces probe failure, the removal of the configfs entry that frees the string still referenced by the leaked lookup table, the heap grooming (key length and content are attacker-chosen kstrdup allocations), and the re-activation that dereferences it. It is a deterministic shell-command sequence with no race and no dependence on uncontrolled state.\nPR:L - Write access to the gpio-virtuser configfs subtree is required, which on the realistic deployments for this testing driver (embedded/CI/GPIO test rigs and CAP_SYS_ADMIN containers) is delegated to an ordinary unprivileged test account rather than requiring init-namespace root. Choosing the higher-severity option where reachability depends on local policy, this is Low.\nUI:N - The entire sequence — create device, fail the probe, drop the lookup entry, re-activate — is performed by the attacker alone. No victim action or cooperation is needed.\nS:U - The stale lookup table, the freed strings, and the resulting corruption all live within the kernel's own security authority. No VM, IOMMU, or sandbox boundary is crossed.\nC:H - The dangling key/con_id pointers are consumed by strcmp(), gpio_name_to_desc(), gpio_device_find_by_label() and, critically, by dev_warn(\"cannot find GPIO chip %s\", p->key), which copies freed slab contents into dmesg — a directly observable kernel heap disclosure. With attacker-chosen allocation sizes the freed slot can be reclaimed by other kernel objects, yielding an arbitrary-ish heap read primitive.\nI:H - This is a use-after-free whose freed slab slot the attacker can reclaim with controlled data, which per standard kernel UAF assessment is exploitable for heap grooming and control-flow/data corruption. Even without full exploitation, a reclaimed key string causes gpiod_find() to bind a GPIO line other than the one requested, silently altering GPIO state on the affected device.\nA:H - Dereferencing the freed key/con_id pointers (strcmp on poisoned or unmapped memory) oopses the kernel, and every failed activation permanently leaks an entire gpiod_lookup_table onto the global gpio_lookup_list, giving an unbounded attacker-driven memory leak plus ever-growing traversal of a list taken under gpio_lookup_lock by every gpiod_get() in the system." } ] } ], "affected": [ { "product": "Linux", "vendor": "Linux", "defaultStatus": "unaffected", "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "programFiles": [ "drivers/gpio/gpio-virtuser.c" ], "versions": [ { "version": "91581c4b3f29e2e22aeb1a62e842d529ca638b2d", "lessThan": "d72d0126b1f6981f6ce8b4247305f359958c11b5", "status": "affected", "versionType": "git" }, { "version": "91581c4b3f29e2e22aeb1a62e842d529ca638b2d", "lessThan": "a619cba8c69c434258ff4101d463322cd63e1bdc", "status": "affected", "versionType": "git" } ] }, { "product": "Linux", "vendor": "Linux", "defaultStatus": "affected", "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "programFiles": [ "drivers/gpio/gpio-virtuser.c" ], "versions": [ { "version": "6.11", "status": "affected" }, { "version": "0", "lessThan": "6.11", "status": "unaffected", "versionType": "semver" }, { "version": "6.12.10", "lessThanOrEqual": "6.12.*", "status": "unaffected", "versionType": "semver" }, { "version": "6.13", "lessThanOrEqual": "*", "status": "unaffected", "versionType": "original_commit_for_fix" } ] } ], "cpeApplicability": [ { "nodes": [ { "operator": "OR", "negate": false, "cpeMatch": [ { "vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.11", "versionEndExcluding": "6.12.10" }, { "vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.11", "versionEndExcluding": "6.13" } ] } ] } ], "references": [ { "url": "https://git.kernel.org/stable/c/d72d0126b1f6981f6ce8b4247305f359958c11b5" }, { "url": "https://git.kernel.org/stable/c/a619cba8c69c434258ff4101d463322cd63e1bdc" } ], "title": "gpio: virtuser: fix missing lookup table cleanups", "x_generator": { "engine": "bippy-1.2.0" } }, "adp": [ { "metrics": [ { "cvssV3_1": { "scope": "UNCHANGED", "version": "3.1", "baseScore": 5.5, "attackVector": "LOCAL", "baseSeverity": "MEDIUM", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", "integrityImpact": "NONE", "userInteraction": "NONE", "attackComplexity": "LOW", "availabilityImpact": "HIGH", "privilegesRequired": "LOW", "confidentialityImpact": "NONE" } }, { "other": { "type": "ssvc", "content": { "id": "CVE-2025-21661", "role": "CISA Coordinator", "options": [ { "Exploitation": "none" }, { "Automatable": "no" }, { "Technical Impact": "partial" } ], "version": "2.0.3", "timestamp": "2025-10-01T19:52:33.900455Z" } } } ], "problemTypes": [ { "descriptions": [ { "lang": "en", "type": "CWE", "cweId": "CWE-401", "description": "CWE-401 Missing Release of Memory after Effective Lifetime" } ] } ], "title": "CISA ADP Vulnrichment", "providerMetadata": { "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "shortName": "CISA-ADP", "dateUpdated": "2025-10-01T19:57:13.331Z" } } ] } }