{
    "dataType": "CVE_RECORD",
    "dataVersion": "5.2",
    "cveMetadata": {
        "cveId": "CVE-2026-31398",
        "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "state": "PUBLISHED",
        "assignerShortName": "Linux",
        "dateReserved": "2026-03-09T15:48:24.085Z",
        "datePublished": "2026-04-03T15:16:02.334Z",
        "dateUpdated": "2026-08-05T12:22:08.041Z"
    },
    "containers": {
        "cna": {
            "providerMetadata": {
                "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
                "shortName": "Linux",
                "dateUpdated": "2026-08-05T12:22:08.041Z"
            },
            "descriptions": [
                {
                    "lang": "en",
                    "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nmm/rmap: fix incorrect pte restoration for lazyfree folios\n\nWe batch unmap anonymous lazyfree folios by folio_unmap_pte_batch.  If the\nbatch has a mix of writable and non-writable bits, we may end up setting\nthe entire batch writable.  Fix this by respecting writable bit during\nbatching.\n\nAlthough on a successful unmap of a lazyfree folio, the soft-dirty bit is\nlost, preserve it on pte restoration by respecting the bit during\nbatching, to make the fix consistent w.r.t both writable bit and\nsoft-dirty bit.\n\nI was able to write the below reproducer and crash the kernel. \nExplanation of reproducer (set 64K mTHP to always):\n\nFault in a 64K large folio.  Split the VMA at mid-point with\nMADV_DONTFORK.  fork() - parent points to the folio with 8 writable ptes\nand 8 non-writable ptes.  Merge the VMAs with MADV_DOFORK so that\nfolio_unmap_pte_batch() can determine all the 16 ptes as a batch.  Do\nMADV_FREE on the range to mark the folio as lazyfree.  Write to the memory\nto dirty the pte, eventually rmap will dirty the folio.  Then trigger\nreclaim, we will hit the pte restoration path, and the kernel will crash\nwith the trace given below.\n\nThe BUG happens at:\n\n\tBUG_ON(atomic_inc_return(&ptc->anon_map_count) > 1 && rw);\n\nThe code path is asking for anonymous page to be mapped writable into the\npagetable.  The BUG_ON() firing implies that such a writable page has been\nmapped into the pagetables of more than one process, which breaks\nanonymous memory/CoW semantics.\n\n[   21.134473] kernel BUG at mm/page_table_check.c:118!\n[   21.134497] Internal error: Oops - BUG: 00000000f2000800 [#1]  SMP\n[   21.135917] Modules linked in:\n[   21.136085] CPU: 1 UID: 0 PID: 1735 Comm: dup-lazyfree Not tainted 7.0.0-rc1-00116-g018018a17770 #1028 PREEMPT\n[   21.136858] Hardware name: linux,dummy-virt (DT)\n[   21.137019] pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)\n[   21.137308] pc : page_table_check_set+0x28c/0x2a8\n[   21.137607] lr : page_table_check_set+0x134/0x2a8\n[   21.137885] sp : ffff80008a3b3340\n[   21.138124] x29: ffff80008a3b3340 x28: fffffdffc3d14400 x27: ffffd1a55e03d000\n[   21.138623] x26: 0040000000000040 x25: ffffd1a55f7dd000 x24: 0000000000000001\n[   21.139045] x23: 0000000000000001 x22: 0000000000000001 x21: ffffd1a55f217f30\n[   21.139629] x20: 0000000000134521 x19: 0000000000134519 x18: 005c43e000040000\n[   21.140027] x17: 0001400000000000 x16: 0001700000000000 x15: 000000000000ffff\n[   21.140578] x14: 000000000000000c x13: 005c006000000000 x12: 0000000000000020\n[   21.140828] x11: 0000000000000000 x10: 005c000000000000 x9 : ffffd1a55c079ee0\n[   21.141077] x8 : 0000000000000001 x7 : 005c03e000040000 x6 : 000000004000ffff\n[   21.141490] x5 : ffff00017fffce00 x4 : 0000000000000001 x3 : 0000000000000002\n[   21.141741] x2 : 0000000000134510 x1 : 0000000000000000 x0 : ffff0000c08228c0\n[   21.141991] Call trace:\n[   21.142093]  page_table_check_set+0x28c/0x2a8 (P)\n[   21.142265]  __page_table_check_ptes_set+0x144/0x1e8\n[   21.142441]  __set_ptes_anysz.constprop.0+0x160/0x1a8\n[   21.142766]  contpte_set_ptes+0xe8/0x140\n[   21.142907]  try_to_unmap_one+0x10c4/0x10d0\n[   21.143177]  rmap_walk_anon+0x100/0x250\n[   21.143315]  try_to_unmap+0xa0/0xc8\n[   21.143441]  shrink_folio_list+0x59c/0x18a8\n[   21.143759]  shrink_lruvec+0x664/0xbf0\n[   21.144043]  shrink_node+0x218/0x878\n[   21.144285]  __node_reclaim.constprop.0+0x98/0x338\n[   21.144763]  user_proactive_reclaim+0x2a4/0x340\n[   21.145056]  reclaim_store+0x3c/0x60\n[   21.145216]  dev_attr_store+0x20/0x40\n[   21.145585]  sysfs_kf_write+0x84/0xa8\n[   21.145835]  kernfs_fop_write_iter+0x130/0x1c8\n[   21.145994]  vfs_write+0x2b8/0x368\n[   21.146119]  ksys_write+0x70/0x110\n[   21.146240]  __arm64_sys_write+0x24/0x38\n[   21.146380]  invoke_syscall+0x50/0x120\n[   21.146513]  el0_svc_common.constprop.0+0x48/0xf8\n[   21.146679]  do_el0_svc+0x28/0x40\n[   21.146798]  el0_svc+0x34/0x110\n[   21.146926]  el0t\n---truncated---"
                }
            ],
            "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 vulnerable path is reached through local memory-management syscalls and page faults such as mmap/write-fault, fork, madvise(MADV_DONTFORK/DOFORK/FREE), followed by reclaim. It is not reachable from network, adjacent, or physical input paths.\nAC:L - The attacker can construct the mixed writable/read-only PTE state and can induce reclaim via memory pressure; the root-only sysfs reclaim in the reproducer is only a shortcut. No uncontrollable race or rare victim state is required in a reasonable mTHP deployment.\nPR:L - The setup uses ordinary unprivileged process operations on the attacker's own anonymous memory. No real root capability or init-namespace administrative privilege is required.\nUI:N - Exploitation does not require a victim user to open a file, mount anything, or perform an interactive action. The local attacker can run the triggering process sequence directly.\nS:U - The bug affects Linux kernel memory-management enforcement for user page tables and does not cross a separate security authority such as a VM boundary. This is a standard local kernel impact with unchanged scope.\nC:H - The bug corrupts restored PTE permissions for CoW-shared anonymous large folios, allowing pages that should be private/read-only to become writable shared mappings. This can expose process memory across a kernel-enforced CoW boundary, so the confidentiality impact is high.\nI:H - The incorrect restoration can upgrade non-writable CoW PTEs to writable, allowing unauthorized modification of memory that should have remained isolated. This is a kernel-managed page-table permission corruption primitive, so integrity impact is high.\nA:H - With page_table_check enabled, the violated anonymous CoW invariant triggers a kernel BUG and oops/panic as shown in the fix commit. Even without that hardening check, the corrupted page-table state can destabilize the system."
                        }
                    ]
                }
            ],
            "affected": [
                {
                    "product": "Linux",
                    "vendor": "Linux",
                    "defaultStatus": "unaffected",
                    "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                    "programFiles": [
                        "mm/rmap.c"
                    ],
                    "versions": [
                        {
                            "version": "354dffd29575cdf13154e8fb787322354aa9efc4",
                            "lessThan": "99888a4f340ca8e839a0524556bd4db76d63f4e0",
                            "status": "affected",
                            "versionType": "git"
                        },
                        {
                            "version": "354dffd29575cdf13154e8fb787322354aa9efc4",
                            "lessThan": "a0911ccdba41b0871abbf8412857bafedec3dbe1",
                            "status": "affected",
                            "versionType": "git"
                        },
                        {
                            "version": "354dffd29575cdf13154e8fb787322354aa9efc4",
                            "lessThan": "29f40594a28114b9a9bc87f6cf7bbee9609628f2",
                            "status": "affected",
                            "versionType": "git"
                        }
                    ]
                },
                {
                    "product": "Linux",
                    "vendor": "Linux",
                    "defaultStatus": "affected",
                    "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                    "programFiles": [
                        "mm/rmap.c"
                    ],
                    "versions": [
                        {
                            "version": "6.15",
                            "status": "affected"
                        },
                        {
                            "version": "0",
                            "lessThan": "6.15",
                            "status": "unaffected",
                            "versionType": "semver"
                        },
                        {
                            "version": "6.18.20",
                            "lessThanOrEqual": "6.18.*",
                            "status": "unaffected",
                            "versionType": "semver"
                        },
                        {
                            "version": "6.19.10",
                            "lessThanOrEqual": "6.19.*",
                            "status": "unaffected",
                            "versionType": "semver"
                        },
                        {
                            "version": "7.0",
                            "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.15",
                                    "versionEndExcluding": "6.18.20"
                                },
                                {
                                    "vulnerable": true,
                                    "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                                    "versionStartIncluding": "6.15",
                                    "versionEndExcluding": "6.19.10"
                                },
                                {
                                    "vulnerable": true,
                                    "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                                    "versionStartIncluding": "6.15",
                                    "versionEndExcluding": "7.0"
                                }
                            ]
                        }
                    ]
                }
            ],
            "references": [
                {
                    "url": "https://git.kernel.org/stable/c/99888a4f340ca8e839a0524556bd4db76d63f4e0"
                },
                {
                    "url": "https://git.kernel.org/stable/c/a0911ccdba41b0871abbf8412857bafedec3dbe1"
                },
                {
                    "url": "https://git.kernel.org/stable/c/29f40594a28114b9a9bc87f6cf7bbee9609628f2"
                }
            ],
            "title": "mm/rmap: fix incorrect pte restoration for lazyfree folios",
            "x_generator": {
                "engine": "bippy-1.2.0"
            }
        }
    }
}