CVE-2026-98975 (GCVE-0-2026-98975)
Vulnerability from cvelistv5 – Published: 2026-10-23 12:19 – Updated: 2026-10-24 14:09
VLAI
EPSS
VEX
Title
xfs: stop exchanging reflink flags when exchanging mappings
Summary
In the Linux kernel, the following vulnerability has been resolved:
xfs: stop exchanging reflink flags when exchanging mappings
When an exchange covers both files from offset 0 to i_disk_size,
xmi_can_exchange_reflink_flags() assumes every mapping moved and hands
the reflink flag over to the other file.
That assumption is wrong. A file can still own shared blocks past
i_disk_size, e.g. after EXCHANGE_RANGE_TO_EOF sets a smaller size
without unmapping anything. The flag is cleared anyway, and the next
write to such a block happens in place instead of CoW, corrupting the
other file that shares it.
Commit a23eca88448e ("xfs: fix exchange-range reflink flag clearing
issue with INO1_WRITTEN") fixed one instance of this. Rather than add
another special case, stop moving the flags.
xfs_exchmaps_ensure_reflink() already sets the flag on both inodes
before the exchange, so both just keep it.
Nothing sets CLEAR_INO{1,2}_REFLINK anymore. Intents logged by older
kernels may still carry them; recovery already masks them off, so they
stay in the log format mask and are ignored.
XFS_IOC_SWAPEXT has the same problem: it moves the reflink flag from
one inode to the other along with the extents. Just removing that is
not enough here: the exchange path flags both inodes up front in
xfs_exchmaps_ensure_reflink(), but swapext has no such step, so the
inode receiving the shared extents would be left without the flag.
Set it on both inodes instead, and make sure both have a CoW fork,
since an inode with the reflink flag is expected to have one.
The flag now stays until FALLOC_FL_UNSHARE_RANGE, xfs_scrub, or a
truncate to zero removes it.
Severity
7.8 (High)
Assigner
References
Impacted products
2 products
| Vendor | Product | Version | CPE status | |
|---|---|---|---|---|
| Linux | Linux |
Affected:
f0bc4d134b46607967bda1205ce3226a1bd95f42 , < 1fa2f3a7ef7ee0f2503a4b0afe24bc8c9d0820be
(git)
Affected: f0bc4d134b46607967bda1205ce3226a1bd95f42 , < 7d3b9b2c9dc57f93f36c716ab752548cb4db9900 (git) Affected: f0bc4d134b46607967bda1205ce3226a1bd95f42 , < 4756c94260e69ce42612b8220c3614f02f7a11d5 (git) Affected: f0bc4d134b46607967bda1205ce3226a1bd95f42 , < d84d6c1a7f1e2de9e601703a326a4c1b7b421943 (git) |
guessed | |
| Linux | Linux |
Affected:
4.9
Unaffected: 0 , < 4.9 (semver) Unaffected: 6.12.114 , ≤ 6.12.* (semver) Unaffected: 6.18.57 , ≤ 6.18.* (semver) Unaffected: 7.2.11 , ≤ 7.2.* (semver) Unaffected: 7.3 , ≤ * (original_commit_for_fix) |
guessed |
{
"containers": {
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"product": "Linux",
"programFiles": [
"fs/xfs/libxfs/xfs_exchmaps.c",
"fs/xfs/libxfs/xfs_log_format.h",
"fs/xfs/xfs_bmap_util.c"
],
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
"vendor": "Linux",
"versions": [
{
"lessThan": "1fa2f3a7ef7ee0f2503a4b0afe24bc8c9d0820be",
"status": "affected",
"version": "f0bc4d134b46607967bda1205ce3226a1bd95f42",
"versionType": "git"
},
{
"lessThan": "7d3b9b2c9dc57f93f36c716ab752548cb4db9900",
"status": "affected",
"version": "f0bc4d134b46607967bda1205ce3226a1bd95f42",
"versionType": "git"
},
{
"lessThan": "4756c94260e69ce42612b8220c3614f02f7a11d5",
"status": "affected",
"version": "f0bc4d134b46607967bda1205ce3226a1bd95f42",
"versionType": "git"
},
{
"lessThan": "d84d6c1a7f1e2de9e601703a326a4c1b7b421943",
"status": "affected",
"version": "f0bc4d134b46607967bda1205ce3226a1bd95f42",
"versionType": "git"
}
]
},
{
"defaultStatus": "affected",
"product": "Linux",
"programFiles": [
"fs/xfs/libxfs/xfs_exchmaps.c",
"fs/xfs/libxfs/xfs_log_format.h",
"fs/xfs/xfs_bmap_util.c"
],
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
"vendor": "Linux",
"versions": [
{
"status": "affected",
"version": "4.9"
},
{
"lessThan": "4.9",
"status": "unaffected",
"version": "0",
"versionType": "semver"
},
{
"lessThanOrEqual": "6.12.*",
"status": "unaffected",
"version": "6.12.114",
"versionType": "semver"
},
{
"lessThanOrEqual": "6.18.*",
"status": "unaffected",
"version": "6.18.57",
"versionType": "semver"
},
{
"lessThanOrEqual": "7.2.*",
"status": "unaffected",
"version": "7.2.11",
"versionType": "semver"
},
{
"lessThanOrEqual": "*",
"status": "unaffected",
"version": "7.3",
"versionType": "original_commit_for_fix"
}
]
}
],
"cpeApplicability": [
{
"nodes": [
{
"cpeMatch": [
{
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
"versionEndExcluding": "6.12.114",
"versionStartIncluding": "4.9",
"vulnerable": true
},
{
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
"versionEndExcluding": "6.18.57",
"versionStartIncluding": "4.9",
"vulnerable": true
},
{
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
"versionEndExcluding": "7.2.11",
"versionStartIncluding": "4.9",
"vulnerable": true
},
{
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
"versionEndExcluding": "7.3",
"versionStartIncluding": "4.9",
"vulnerable": true
}
],
"negate": false,
"operator": "OR"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "In the Linux kernel, the following vulnerability has been resolved:\n\nxfs: stop exchanging reflink flags when exchanging mappings\n\nWhen an exchange covers both files from offset 0 to i_disk_size,\nxmi_can_exchange_reflink_flags() assumes every mapping moved and hands\nthe reflink flag over to the other file.\n\nThat assumption is wrong. A file can still own shared blocks past\ni_disk_size, e.g. after EXCHANGE_RANGE_TO_EOF sets a smaller size\nwithout unmapping anything. The flag is cleared anyway, and the next\nwrite to such a block happens in place instead of CoW, corrupting the\nother file that shares it.\n\nCommit a23eca88448e (\"xfs: fix exchange-range reflink flag clearing\nissue with INO1_WRITTEN\") fixed one instance of this. Rather than add\nanother special case, stop moving the flags.\nxfs_exchmaps_ensure_reflink() already sets the flag on both inodes\nbefore the exchange, so both just keep it.\n\nNothing sets CLEAR_INO{1,2}_REFLINK anymore. Intents logged by older\nkernels may still carry them; recovery already masks them off, so they\nstay in the log format mask and are ignored.\n\nXFS_IOC_SWAPEXT has the same problem: it moves the reflink flag from\none inode to the other along with the extents. Just removing that is\nnot enough here: the exchange path flags both inodes up front in\nxfs_exchmaps_ensure_reflink(), but swapext has no such step, so the\ninode receiving the shared extents would be left without the flag.\nSet it on both inodes instead, and make sure both have a CoW fork,\nsince an inode with the reflink flag is expected to have one.\n\nThe flag now stays until FALLOC_FL_UNSHARE_RANGE, xfs_scrub, or a\ntruncate to zero removes it."
}
],
"metrics": [
{
"cvssV3_1": {
"baseScore": 7.8,
"baseSeverity": "HIGH",
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"scenarios": [
{
"lang": "en",
"value": "AV:L - `ioctl(2)` runs `do_vfs_ioctl()`/`vfs_ioctl()` \u2192 `xfs_file_ioctl()` \u2192 `xfs_ioc_exchange_range()` \u2192 `xfs_exchange_mappings()` \u2192 patched `xfs_exchmaps_init_intent()`; all causal file descriptors, offsets, and flags are supplied locally.\nAC:L - On a reflink/exchange-range XFS, the attacker can clone a target block, use chosen `TO_EOF` offsets to strand it past `i_disk_size`, perform a full-range exchange so `xmi_can_exchange_reflink_flags()` clears the flag, and `pwrite` the shared block; no race or external event is required.\nPR:L - `xfs_exchange_range()` requires only read-write scratch-file descriptors and `remap_verify_area(..., true)`, with no `capable()` check; FICLONE requires only read access to the protected source and write access to an attacker-owned destination.\nUI:N - The attacker personally performs FICLONERANGE, the crafted `XFS_IOC_EXCHANGE_RANGE` operations, and the final `pwrite`; no victim must mount media, open a file, or take another action.\nS:U - `xfs_exchmaps_clear_reflink()` breaks CoW isolation between inodes on the same XFS host; using the resulting protected-file overwrite for root access is a standard local privilege escalation, not a VM, IOMMU, or other security-authority escape.\nC:H - The attacker can clone a readable SUID-root binary, then make the faulty non-CoW write alter its physical block without modifying its inode or clearing SUID metadata; executing the corrupted binary can yield root and unrestricted access to host-confidential data.\nI:H - After `xfs_exchmaps_clear_reflink()` removes the flag, `xfs_is_cow_inode()` is false and the iomap write path updates the still-shared block in place, permitting persistent attacker-controlled modification of readable protected files without write permission.\nA:H - The same in-place primitive can corrupt readable boot-critical executables, and overwriting a SUID-root binary can provide root control capable of stopping the host, supporting complete availability loss."
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-24T14:09:45.210Z",
"orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"shortName": "Linux"
},
"references": [
{
"url": "https://git.kernel.org/stable/c/1fa2f3a7ef7ee0f2503a4b0afe24bc8c9d0820be"
},
{
"url": "https://git.kernel.org/stable/c/7d3b9b2c9dc57f93f36c716ab752548cb4db9900"
},
{
"url": "https://git.kernel.org/stable/c/4756c94260e69ce42612b8220c3614f02f7a11d5"
},
{
"url": "https://git.kernel.org/stable/c/d84d6c1a7f1e2de9e601703a326a4c1b7b421943"
}
],
"title": "xfs: stop exchanging reflink flags when exchanging mappings",
"x_generator": {
"engine": "bippy-1.2.0"
}
}
},
"cveMetadata": {
"assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"assignerShortName": "Linux",
"cveId": "CVE-2026-98975",
"datePublished": "2026-10-23T12:19:48.379Z",
"dateReserved": "2026-09-25T10:25:14.383Z",
"dateUpdated": "2026-10-24T14:09:45.210Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"epss": {
"cve": "CVE-2026-98975",
"date": "2026-10-24",
"epss": "0.00209",
"percentile": "0.10526"
},
"microsoft_vex": {
"current_release_date": "2026-10-24T01:10:35.000Z",
"cve": "CVE-2026-98975",
"id": "msrc_CVE-2026-98975",
"initial_release_date": "2026-10-24T01:10:35.000Z",
"product_status:under_investigation": "1",
"source": "Microsoft CSAF VEX",
"status": "final",
"title": "xfs: stop exchanging reflink flags when exchanging mappings",
"url": "https://msrc.microsoft.com/csaf/vex/2026/msrc_cve-2026-98975.json",
"version": "1"
},
"nvd": {
"cve": {
"affected": [
{
"affectedData": [
{
"defaultStatus": "unaffected",
"product": "Linux",
"programFiles": [
"fs/xfs/libxfs/xfs_exchmaps.c",
"fs/xfs/libxfs/xfs_log_format.h",
"fs/xfs/xfs_bmap_util.c"
],
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
"vendor": "Linux",
"versions": [
{
"lessThan": "1fa2f3a7ef7ee0f2503a4b0afe24bc8c9d0820be",
"status": "affected",
"version": "f0bc4d134b46607967bda1205ce3226a1bd95f42",
"versionType": "git"
},
{
"lessThan": "7d3b9b2c9dc57f93f36c716ab752548cb4db9900",
"status": "affected",
"version": "f0bc4d134b46607967bda1205ce3226a1bd95f42",
"versionType": "git"
},
{
"lessThan": "4756c94260e69ce42612b8220c3614f02f7a11d5",
"status": "affected",
"version": "f0bc4d134b46607967bda1205ce3226a1bd95f42",
"versionType": "git"
},
{
"lessThan": "d84d6c1a7f1e2de9e601703a326a4c1b7b421943",
"status": "affected",
"version": "f0bc4d134b46607967bda1205ce3226a1bd95f42",
"versionType": "git"
}
]
},
{
"defaultStatus": "affected",
"product": "Linux",
"programFiles": [
"fs/xfs/libxfs/xfs_exchmaps.c",
"fs/xfs/libxfs/xfs_log_format.h",
"fs/xfs/xfs_bmap_util.c"
],
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
"vendor": "Linux",
"versions": [
{
"status": "affected",
"version": "4.9"
},
{
"lessThan": "4.9",
"status": "unaffected",
"version": "0",
"versionType": "semver"
},
{
"lessThanOrEqual": "6.12.*",
"status": "unaffected",
"version": "6.12.114",
"versionType": "semver"
},
{
"lessThanOrEqual": "6.18.*",
"status": "unaffected",
"version": "6.18.57",
"versionType": "semver"
},
{
"lessThanOrEqual": "7.2.*",
"status": "unaffected",
"version": "7.2.11",
"versionType": "semver"
},
{
"lessThanOrEqual": "*",
"status": "unaffected",
"version": "7.3",
"versionType": "original_commit_for_fix"
}
]
}
],
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
}
],
"cveTags": [],
"descriptions": [
{
"lang": "en",
"value": "In the Linux kernel, the following vulnerability has been resolved:\n\nxfs: stop exchanging reflink flags when exchanging mappings\n\nWhen an exchange covers both files from offset 0 to i_disk_size,\nxmi_can_exchange_reflink_flags() assumes every mapping moved and hands\nthe reflink flag over to the other file.\n\nThat assumption is wrong. A file can still own shared blocks past\ni_disk_size, e.g. after EXCHANGE_RANGE_TO_EOF sets a smaller size\nwithout unmapping anything. The flag is cleared anyway, and the next\nwrite to such a block happens in place instead of CoW, corrupting the\nother file that shares it.\n\nCommit a23eca88448e (\"xfs: fix exchange-range reflink flag clearing\nissue with INO1_WRITTEN\") fixed one instance of this. Rather than add\nanother special case, stop moving the flags.\nxfs_exchmaps_ensure_reflink() already sets the flag on both inodes\nbefore the exchange, so both just keep it.\n\nNothing sets CLEAR_INO{1,2}_REFLINK anymore. Intents logged by older\nkernels may still carry them; recovery already masks them off, so they\nstay in the log format mask and are ignored.\n\nXFS_IOC_SWAPEXT has the same problem: it moves the reflink flag from\none inode to the other along with the extents. Just removing that is\nnot enough here: the exchange path flags both inodes up front in\nxfs_exchmaps_ensure_reflink(), but swapext has no such step, so the\ninode receiving the shared extents would be left without the flag.\nSet it on both inodes instead, and make sure both have a CoW fork,\nsince an inode with the reflink flag is expected to have one.\n\nThe flag now stays until FALLOC_FL_UNSHARE_RANGE, xfs_scrub, or a\ntruncate to zero removes it."
}
],
"id": "CVE-2026-98975",
"lastModified": "2026-10-24T14:16:50.093",
"metrics": {
"cvssMetricV31": [
{
"cvssData": {
"attackComplexity": "LOW",
"attackVector": "LOCAL",
"availabilityImpact": "HIGH",
"baseScore": 7.8,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
},
"exploitabilityScore": 1.8,
"impactScore": 5.9,
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"type": "Secondary"
}
]
},
"published": "2026-10-23T13:17:19.157",
"references": [
{
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"url": "https://git.kernel.org/stable/c/1fa2f3a7ef7ee0f2503a4b0afe24bc8c9d0820be"
},
{
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"url": "https://git.kernel.org/stable/c/4756c94260e69ce42612b8220c3614f02f7a11d5"
},
{
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"url": "https://git.kernel.org/stable/c/7d3b9b2c9dc57f93f36c716ab752548cb4db9900"
},
{
"source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"url": "https://git.kernel.org/stable/c/d84d6c1a7f1e2de9e601703a326a4c1b7b421943"
}
],
"sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
"vulnStatus": "Received"
}
}
}
}
Loading…
Loading…
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Experimental. This forecast is provided for visualization only and may change without notice. Do not use it for operational decisions.
Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
Loading…
Loading…
The MITRE ATT&CK techniques below are AI-generated suggestions, inferred from the description of the
vulnerability by the CIRCL/vulnerability-attack-technique-classification-roberta-base
model, served locally by ML-Gateway.
They have not been verified by an analyst and are provided for guidance only.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Loading…
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.