{"dataType":"CVE_RECORD","dataVersion":"5.2","cveMetadata":{"cveId":"CVE-2024-26759","assignerOrgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","state":"PUBLISHED","assignerShortName":"Linux","dateReserved":"2024-02-19T14:20:24.170Z","datePublished":"2024-04-03T17:00:43.288Z","dateUpdated":"2026-08-05T11:27:02.143Z"},"containers":{"cna":{"providerMetadata":{"orgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","shortName":"Linux","dateUpdated":"2026-08-05T11:27:02.143Z"},"descriptions":[{"lang":"en","value":"In the Linux kernel, the following vulnerability has been resolved:\n\nmm/swap: fix race when skipping swapcache\n\nWhen skipping swapcache for SWP_SYNCHRONOUS_IO, if two or more threads\nswapin the same entry at the same time, they get different pages (A, B). \nBefore one thread (T0) finishes the swapin and installs page (A) to the\nPTE, another thread (T1) could finish swapin of page (B), swap_free the\nentry, then swap out the possibly modified page reusing the same entry. \nIt breaks the pte_same check in (T0) because PTE value is unchanged,\ncausing ABA problem.  Thread (T0) will install a stalled page (A) into the\nPTE and cause data corruption.\n\nOne possible callstack is like this:\n\nCPU0                                 CPU1\n----                                 ----\ndo_swap_page()                       do_swap_page() with same entry\n<direct swapin path>                 <direct swapin path>\n<alloc page A>                       <alloc page B>\nswap_read_folio() <- read to page A  swap_read_folio() <- read to page B\n<slow on later locks or interrupt>   <finished swapin first>\n...                                  set_pte_at()\n                                     swap_free() <- entry is free\n                                     <write to page B, now page A stalled>\n                                     <swap out page B to same swap entry>\npte_same() <- Check pass, PTE seems\n              unchanged, but page A\n              is stalled!\nswap_free() <- page B content lost!\nset_pte_at() <- staled page A installed!\n\nAnd besides, for ZRAM, swap_free() allows the swap device to discard the\nentry content, so even if page (B) is not modified, if swap_read_folio()\non CPU0 happens later than swap_free() on CPU1, it may also cause data\nloss.\n\nTo fix this, reuse swapcache_prepare which will pin the swap entry using\nthe cache flag, and allow only one thread to swap it in, also prevent any\nparallel code from putting the entry in the cache.  Release the pin after\nPT unlocked.\n\nRacers just loop and wait since it's a rare and very short event.  A\nschedule_timeout_uninterruptible(1) call is added to avoid repeated page\nfaults wasting too much CPU, causing livelock or adding too much noise to\nperf statistics.  A similar livelock issue was described in commit\n029c4628b2eb (\"mm: swap: get rid of livelock in swapin readahead\")\n\nReproducer:\n\nThis race issue can be triggered easily using a well constructed\nreproducer and patched brd (with a delay in read path) [1]:\n\nWith latest 6.8 mainline, race caused data loss can be observed easily:\n$ gcc -g -lpthread test-thread-swap-race.c && ./a.out\n  Polulating 32MB of memory region...\n  Keep swapping out...\n  Starting round 0...\n  Spawning 65536 workers...\n  32746 workers spawned, wait for done...\n  Round 0: Error on 0x5aa00, expected 32746, got 32743, 3 data loss!\n  Round 0: Error on 0x395200, expected 32746, got 32743, 3 data loss!\n  Round 0: Error on 0x3fd000, expected 32746, got 32737, 9 data loss!\n  Round 0 Failed, 15 data loss!\n\nThis reproducer spawns multiple threads sharing the same memory region\nusing a small swap device.  Every two threads updates mapped pages one by\none in opposite direction trying to create a race, with one dedicated\nthread keep swapping out the data out using madvise.\n\nThe reproducer created a reproduce rate of about once every 5 minutes, so\nthe race should be totally possible in production.\n\nAfter this patch, I ran the reproducer for over a few hundred rounds and\nno data loss observed.\n\nPerformance overhead is minimal, microbenchmark swapin 10G from 32G\nzram:\n\nBefore:     10934698 us\nAfter:      11157121 us\nCached:     13155355 us (Dropping SWP_SYNCHRONOUS_IO flag)\n\n[kasong@tencent.com: v4]"}],"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 race is reached through ordinary page faults on the attacker's own swapped-out anonymous memory (`handle_mm_fault() → do_swap_page()`), requiring the ability to execute code on the machine. There is no network-reachable path into the swapin fast path.\nAC:L - The attacker controls both sides of the race — the threads faulting on the same swap entry and the thread forcing swapout via `madvise(MADV_PAGEOUT)` — and can widen the window arbitrarily because `vma_alloc_folio()` and `mem_cgroup_swapin_charge_folio(GFP_KERNEL)` sit between the `__swap_count()` check and `swap_read_folio()` and block in direct reclaim under attacker-created memory pressure. The upstream reproducer triggers data loss within minutes on stock 6.8.\nPR:L - Only the ability to run unprivileged code is needed: mmap anonymous memory, spawn threads, and call `madvise()`. No capabilities, no user namespace, and no privileged device access are involved.\nUI:N - The attacker's own threads drive the entire sequence through page faults and madvise; no action by any other user is required.\nS:U - The corruption is confined to memory managed by the kernel's own security authority — page tables and swap slots — with no crossing of a hypervisor, IOMMU, or other authority boundary.\nC:H - The unpinned `swap_read_folio()` is a use-after-free read of a swap slot that may already have been reallocated from the global swap pool to another task, so another user's swapped-out anonymous/shmem page content can be read in and mapped into the racing address space; installing a stale folio also resurrects page content that had already been overwritten or sanitized in memory.\nI:H - The ABA defeats the `pte_same()` guard and installs a stale or foreign page into a live PTE, silently destroying committed writes and rolling back arbitrary anonymous memory to an earlier state — an undetectable corruption primitive over any process's data, including security-relevant in-memory state.\nA:H - Silent corruption of arbitrary anonymous pages under memory pressure crashes or hangs the affected processes, and corrupted state flushed to persistent storage by system services propagates the failure; the swap-slot use-after-free additionally leaves swap accounting and page content inconsistent."}]}],"affected":[{"product":"Linux","vendor":"Linux","defaultStatus":"unaffected","repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["include/linux/swap.h","mm/memory.c","mm/swap.h","mm/swapfile.c"],"versions":[{"version":"0bcac06f27d7528591c27ac2b093ccd71c5d0168","lessThan":"2dedda77d4493f3e92e414b272bfa60f1f51ed95","status":"affected","versionType":"git"},{"version":"0bcac06f27d7528591c27ac2b093ccd71c5d0168","lessThan":"305152314df82b22cf9b181f3dc5fc411002079a","status":"affected","versionType":"git"},{"version":"0bcac06f27d7528591c27ac2b093ccd71c5d0168","lessThan":"d183a4631acfc7af955c02a02e739cec15f5234d","status":"affected","versionType":"git"},{"version":"0bcac06f27d7528591c27ac2b093ccd71c5d0168","lessThan":"13ddaf26be324a7f951891ecd9ccd04466d27458","status":"affected","versionType":"git"}]},{"product":"Linux","vendor":"Linux","defaultStatus":"affected","repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["include/linux/swap.h","mm/memory.c","mm/swap.h","mm/swapfile.c"],"versions":[{"version":"4.15","status":"affected"},{"version":"0","lessThan":"4.15","status":"unaffected","versionType":"semver"},{"version":"6.1.80","lessThanOrEqual":"6.1.*","status":"unaffected","versionType":"semver"},{"version":"6.6.19","lessThanOrEqual":"6.6.*","status":"unaffected","versionType":"semver"},{"version":"6.7.7","lessThanOrEqual":"6.7.*","status":"unaffected","versionType":"semver"},{"version":"6.8","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":"4.15","versionEndExcluding":"6.1.80"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"4.15","versionEndExcluding":"6.6.19"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"4.15","versionEndExcluding":"6.7.7"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"4.15","versionEndExcluding":"6.8"}]}]}],"references":[{"url":"https://git.kernel.org/stable/c/2dedda77d4493f3e92e414b272bfa60f1f51ed95"},{"url":"https://git.kernel.org/stable/c/305152314df82b22cf9b181f3dc5fc411002079a"},{"url":"https://git.kernel.org/stable/c/d183a4631acfc7af955c02a02e739cec15f5234d"},{"url":"https://git.kernel.org/stable/c/13ddaf26be324a7f951891ecd9ccd04466d27458"}],"title":"mm/swap: fix race when skipping swapcache","x_generator":{"engine":"bippy-1.2.0"}},"adp":[{"title":"CISA ADP Vulnrichment","metrics":[{"other":{"type":"ssvc","content":{"id":"CVE-2024-26759","role":"CISA Coordinator","options":[{"Exploitation":"none"},{"Automatable":"no"},{"Technical Impact":"partial"}],"version":"2.0.3","timestamp":"2024-04-08T14:03:53.009974Z"}}}],"providerMetadata":{"orgId":"134c704f-9b21-4f2e-91b3-4a467353bcc0","shortName":"CISA-ADP","dateUpdated":"2024-06-04T17:49:35.865Z"}},{"providerMetadata":{"orgId":"af854a3a-2127-422b-91ae-364da2661108","shortName":"CVE","dateUpdated":"2024-08-02T00:14:13.279Z"},"title":"CVE Program Container","references":[{"url":"https://git.kernel.org/stable/c/2dedda77d4493f3e92e414b272bfa60f1f51ed95","tags":["x_transferred"]},{"url":"https://git.kernel.org/stable/c/305152314df82b22cf9b181f3dc5fc411002079a","tags":["x_transferred"]},{"url":"https://git.kernel.org/stable/c/d183a4631acfc7af955c02a02e739cec15f5234d","tags":["x_transferred"]},{"url":"https://git.kernel.org/stable/c/13ddaf26be324a7f951891ecd9ccd04466d27458","tags":["x_transferred"]}]}]}}