{ "dataType": "CVE_RECORD", "dataVersion": "5.2", "cveMetadata": { "cveId": "CVE-2025-21896", "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "state": "PUBLISHED", "assignerShortName": "Linux", "dateReserved": "2024-12-29T08:45:45.783Z", "datePublished": "2025-04-01T15:26:49.200Z", "dateUpdated": "2026-08-05T11:55:13.304Z" }, "containers": { "cna": { "providerMetadata": { "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "shortName": "Linux", "dateUpdated": "2026-08-05T11:55:13.304Z" }, "descriptions": [ { "lang": "en", "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nfuse: revert back to __readahead_folio() for readahead\n\nIn commit 3eab9d7bc2f4 (\"fuse: convert readahead to use folios\"), the\nlogic was converted to using the new folio readahead code, which drops\nthe reference on the folio once it is locked, using an inferred\nreference on the folio. Previously we held a reference on the folio for\nthe entire duration of the readpages call.\n\nThis is fine, however for the case for splice pipe responses where we\nwill remove the old folio and splice in the new folio (see\nfuse_try_move_page()), we assume that there is a reference held on the\nfolio for ap->folios, which is no longer the case.\n\nTo fix this, revert back to __readahead_folio() which allows us to hold\nthe reference on the folio for the duration of readpages until either we\ndrop the reference ourselves in fuse_readpages_end() or the reference is\ndropped after it's replaced in the page cache in the splice case.\nThis will fix the UAF bug that was reported." } ], "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 bug is reached by mounting a FUSE filesystem and reading a file on it, with the attacker-controlled userspace FUSE server replying over /dev/fuse; this requires local system access (mount + syscalls), not network reachability.\nAC:L - The attacker controls both halves of the trigger — their own FUSE daemon chooses SPLICE_F_MOVE splice replies with page-aligned stealable buffers, and their own reader process drives readahead — making the refcount underflow deterministic rather than racy.\nPR:L - Only an unprivileged local account is needed: fuse_fs_type sets FS_USERNS_MOUNT so FUSE can be mounted inside an unprivileged user namespace (unshare -Urm), and distros also ship setuid fusermount3 for direct unprivileged mounts.\nUI:N - The attacker's own processes perform both the mount/server role and the file read; no action by any other user is required.\nS:U - The corruption stays within the kernel's own security authority — standard local kernel memory corruption with no VM, IOMMU, or hypervisor boundary crossed.\nC:H - The over-decremented folio is returned to the page allocator while still referenced by ap->folios[] and potentially the LRU, so it can be reallocated to another security context and its contents read back through the stale mapping — an arbitrary kernel/page-cache read primitive.\nI:H - fuse_readpages_end() writes folio flags (folio_end_read) into the already-freed and possibly reallocated page, and the extra folio_put() constitutes a double free — a page-level UAF that is groomable into an arbitrary write and control-flow hijack.\nA:H - In practice this produced refcount-underflow BUG splats and kernel oopses for ordinary users (Arch and openSUSE crash reports), and the UAF/double-free reliably panics the machine." } ] } ], "affected": [ { "product": "Linux", "vendor": "Linux", "defaultStatus": "unaffected", "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "programFiles": [ "fs/fuse/dev.c", "fs/fuse/file.c" ], "versions": [ { "version": "3eab9d7bc2f4ae7f3f9c9c7852ff61600df79856", "lessThan": "60db11f1b7fba4a66b117ea998d965818784a98d", "status": "affected", "versionType": "git" }, { "version": "3eab9d7bc2f4ae7f3f9c9c7852ff61600df79856", "lessThan": "0c67c37e1710b2a8f61c8a02db95a51fe577e2c1", "status": "affected", "versionType": "git" } ] }, { "product": "Linux", "vendor": "Linux", "defaultStatus": "affected", "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "programFiles": [ "fs/fuse/dev.c", "fs/fuse/file.c" ], "versions": [ { "version": "6.13", "status": "affected" }, { "version": "0", "lessThan": "6.13", "status": "unaffected", "versionType": "semver" }, { "version": "6.13.6", "lessThanOrEqual": "6.13.*", "status": "unaffected", "versionType": "semver" }, { "version": "6.14", "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.13", "versionEndExcluding": "6.13.6" }, { "vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.13", "versionEndExcluding": "6.14" } ] } ] } ], "references": [ { "url": "https://git.kernel.org/stable/c/60db11f1b7fba4a66b117ea998d965818784a98d" }, { "url": "https://git.kernel.org/stable/c/0c67c37e1710b2a8f61c8a02db95a51fe577e2c1" } ], "title": "fuse: revert back to __readahead_folio() for readahead", "x_generator": { "engine": "bippy-1.2.0" } } } }