CVE-2026-31648: mm: filemap: fix nr_pages calculation overflow in filemap_map_pages()
In the Linux kernel, the following vulnerability has been resolved:
mm: filemap: fix nrpages calculation overflow in filemapmappages()
When running stress-ng on my Arm64 machine with v7.0-rc3 kernel, I encountered some very strange crash issues showing up as "Bad page state":
" [ 734.496287] BUG: Bad page state in process stress-ng-env pfn:415735fb [ 734.496427] page: refcount:0 mapcount:1 mapping:0000000000000000 index:0x4cf316 pfn:0x415735fb [ 734.496434] flags: 0x57fffe000000800(owner2|node=1|zone=2|lastcpupid=0x3ffff) [ 734.496439] raw: 057fffe000000800 0000000000000000 dead000000000122 0000000000000000 [ 734.496440] raw: 00000000004cf316 0000000000000000 0000000000000000 0000000000000000 [ 734.496442] page dumped because: nonzero mapcount "
After analyzing this page’s state, it is hard to understand why the mapcount is not 0 while the refcount is 0, since this page is not where the issue first occurred. By enabling the CONFIGDEBUGVM config, I can reproduce the crash as well and captured the first warning where the issue appears:
" [ 734.469226] page: refcount:33 mapcount:0 mapping:00000000bef2d187 index:0x81a0 pfn:0x415735c0 [ 734.469304] head: order:5 mapcount:0 entiremapcount:0 nrpagesmapped:0 pincount:0 [ 734.469315] memcg:ffff000807a8ec00 [ 734.469320] aops:ext4daaops ino:100b6f dentry name(?):"stress-ng-mmaptorture-9397-0-2736200540" [ 734.469335] flags: 0x57fffe400000069(locked|uptodate|lru|head|node=1|zone=2|lastcpupid=0x3ffff) ...... [ 734.469364] page dumped because: VMWARNONFOLIO((Generic((page + nrpages - 1), const struct page : (const struct folio )compoundhead(page + nrpages - 1), struct page : (struct folio )compoundhead(page + nrpages - 1))) != folio) [ 734.469390] ------------[ cut here ]------------ [ 734.469393] WARNING: ./include/linux/rmap.h:351 at folioaddfilermapptes+0x3b8/0x468, CPU#90: stress-ng-mlock/9430 [ 734.469551] folioaddfilermapptes+0x3b8/0x468 (P) [ 734.469555] setpterange+0xd8/0x2f8 [ 734.469566] filemapmapfoliorange+0x190/0x400 [ 734.469579] filemapmappages+0x348/0x638 [ 734.469583] dofaultaround+0x140/0x198 ...... [ 734.469640] el0t64sync+0x184/0x188 "
The code that triggers the warning is: "VMWARNONFOLIO(pagefolio(page + nrpages - 1) != folio, folio)", which indicates that setpterange() tried to map beyond the large folio’s size.
By adding more debug information, I found that 'nrpages' had overflowed in filemapmappages(), causing setpterange() to establish mappings for a range exceeding the folio size, potentially corrupting fields of pages that do not belong to this folio (e.g., page->mapcount).
After above analysis, I think the possible race is as follows:
CPU 0 CPU 1 filemapmappages() ext4setattr() //get and lock folio with old inode->isize nextuptodatefolio()
....... //shrink the inode->isize isizewrite(inode, attr->iasize);
//calculate the endpgoff with the new inode->isize fileend = DIVROUNDUP(isizeread(mapping->host), PAGESIZE) - 1; endpgoff = min(endpgoff, fileend);
...... //nrpages can be overflowed, cause xas.xaindex > endpgoff end = folionextindex(folio) - 1; nrpages = min(end, endpgoff) - xas.xaindex + 1;
...... //map large folio filemapmapfoliorange() ...... //truncate folios truncatepagecache(inode, inode->isize);
To fix this issue, move the 'endpgoff' calculation before nextuptodatefolio(), so the retrieved folio stays consistent with the file end to avoid ---truncated---
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Patch mm: filemap: fix nr_pages calculation overflow in filemap_map_pages() - Configuration
If reproducing or diagnosing the issue, enable CONFIG_DEBUG_VM to add the debug information mentioned in the report.
Linux kernel CONFIG_DEBUG_VM = enabled - Configuration
As part of the fix sequence, truncate the page cache with truncate_pagecache(inode, inode->i_size) after shrinking i_size (per the described flow).
ext4 (via kernel file truncation path) truncate_pagecache(inode, inode->i_size) = invoked
Event History
Frequently Asked Questions
What is the severity of CVE-2026-31648?
CVE-2026-31648 is classified as a high severity vulnerability affecting the Linux kernel.
How do I fix CVE-2026-31648?
To fix CVE-2026-31648, update your Linux kernel to the latest patched version that addresses this vulnerability.
What systems are affected by CVE-2026-31648?
CVE-2026-31648 affects systems running vulnerable versions of the Linux kernel, particularly Arm64 machines.
What are the potential impacts of CVE-2026-31648?
The vulnerability can lead to incorrect memory management which may cause system instability or crashes.
When was CVE-2026-31648 published?
CVE-2026-31648 was published in 2026 following its discovery and subsequent patching.