Skip to content

feat(libkernel): report the guest address-space map through kern.proc.vmmap - #7070

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
milescoviello:feat/kern-proc-vmmap
Oct 19, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
milescoviello:feat/kern-proc-vmmap

Conversation

@milescoviello

@milescoviello milescoviello commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

What

sysctl {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, pid} (MIB 1.14.32.pid) threw unsupported MIB. It now returns the calling process's map as packed FreeBSD 11 kinfo_vmentry records, the format kinfo_getvmmap reads: a size query with no buffer, then the records, each with kve_structsize set to its packed size.

  • Source: one record per used range of the guest address-space arena (GuestArena's used map), in address order. That map is what a guest mmap is placed against: guest mappings and reservations, plus host mappings and the system-reserved range inside the arena. GuestArena gains GuestArenaNextUsed_nid_no_patch, which returns the used range at or after an address.
  • Fields: start and end, and the protection sceKernelVirtualQuery reports for the range's first page (0 where it reports none). The type is KVME_TYPE_DEFAULT. Offset, object, resident counts, flags and path are 0, so each record is 144 bytes.
  • Errors: only the caller's pid is accepted; other pids get ESRCH, including -1, as FreeBSD's pget gives for this node (unlike kern.proc.pathname). A write returns EPERM, a MIB of the wrong length EINVAL, and a short buffer ENOMEM with the bytes that fit.
  • Debt: what the console reports is unverified, so the entry is in docs/dev/debt/libkernel.md.

Ranges outside the arena are not reported, because guest code cannot map there: a fixed anonymous guest mmap outside the arena is refused with EINVAL.

Tested

Ubuntu 24.04, GCC 13.3, Release, RTX 4070 Ti (NVIDIA 595.99.02).

  • New CheckVmmapSysctl in guest_system_configuration:
    • It maps 64 KiB read/write through the guest mmap and requires a record that covers the mapping with read and write protection.
    • After munmap, it requires that no record overlaps the range.
    • Every record must be at least 144 bytes, 8-byte aligned and NUL-terminated within its size, and records must be in order without overlap.
    • It also checks a short buffer (ENOMEM, nothing written past it), a write (EPERM), a foreign pid and -1 (ESRCH), and 3- and 5-element MIBs (EINVAL).
    • With main's SystemConfiguration.cpp the test aborts on sysctl_nid_postfix: unsupported MIB 1.14.32.<pid>. With this change it passes 3 of 3.
  • Area suite: the 401 tests matching ^guest_|libc pass.
  • Forever Launcher (PPSA99030, 01.000.012, catalog build). Its Wine runtime calls sysctl(1.14.32.getpid(), NULL, &len), allocates len + len / 4, reads the records and walks kve_start/kve_end (offsets 8 and 16) by kve_structsize. It records the 64 KiB-aligned gaps in [0x10000, 0x68000000) as free ranges.
  • Windows (run by @screamm): Windows 11 Pro, Ryzen 7 5700X, WinLibs GCC 15.2.0, Release, on main c9e6c45. guest_system_configuration passes 3 of 3, and with main's SystemConfiguration.cpp and GuestArena.cpp it aborts on unsupported MIB 1.14.32.<pid>. They also compiled FreeBSD 11.0's struct kinfo_vmentry next to GuestVmEntry, and every offset matches. None of their four local titles issues kern.proc.vmmap in 60 s.
  • Later commit c8b5cec changes only the debt entry. It notes that the walk takes the arena lock once per range, where FreeBSD holds the map lock for the whole walk (@screamm's point).

Checklist

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 7541 core/libs/prx/libkernel/System/src/SystemConfiguration.cpp L75
docs/dev/debt/libkernel.md L163-164
PR 7554 core/libs/tests/GuestSystemConfiguration.cpp L380, L492
PR 7556 core/libs/prx/libkernel/System/src/SystemConfiguration.cpp L75

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 1835 core/libs/prx/libc/src/GuestArena.cpp
PR 5021 core/libs/prx/libc/src/GuestArena.cpp
docs/dev/debt/libkernel.md
PR 6044 core/libs/tests/GuestSystemConfiguration.cpp
PR 6149 docs/dev/debt/libkernel.md
PR 6446 docs/dev/debt/libkernel.md
PR 6469 core/libs/prx/libc/src/GuestArena.cpp
docs/dev/debt/libkernel.md
PR 6519 docs/dev/debt/libkernel.md
PR 6740 docs/dev/debt/libkernel.md
PR 6879 core/libs/prx/libc/src/GuestArena.cpp
PR 6936 docs/dev/debt/libkernel.md
PR 6977 docs/dev/debt/libkernel.md
PR 7049 docs/dev/debt/libkernel.md
PR 7105 docs/dev/debt/libkernel.md
PR 7135 docs/dev/debt/libkernel.md
PR 7149 docs/dev/debt/libkernel.md
PR 7201 core/libs/prx/libc/src/GuestArena.cpp
PR 7332 core/libs/prx/libc/src/GuestArena.cpp
docs/dev/debt/libkernel.md
PR 7473 core/libs/prx/libc/include/GuestArena.hpp
core/libs/prx/libc/src/GuestArena.cpp
PR 7509 docs/dev/debt/libkernel.md

@screamm

screamm commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Windows run of head 68bd39751, merged onto main c9e6c45de (clean; also stacked with #7068).

  • Host: Windows 11 Pro 26220, Ryzen 7 5700X, RTX 4070 (driver 596.21), WinLibs MinGW-w64 GCC 15.2.0 r7, Ninja, Release.
  • Build: the full build and libs pass, no warnings in SystemConfiguration.cpp or GuestArena.cpp.
  • guest_system_configuration (with CheckVmmapSysctl): 3/3 pass with --repeat until-fail:3.
  • Negative control: with SystemConfiguration.cpp and GuestArena.cpp reverted to main and the test kept, guest_system_configuration aborts with what(): sysctl_nid_postfix: unsupported MIB 1.14.32.<pid>. With the sources restored it passes 3/3.
  • Layout: I compiled FreeBSD 11.0 struct kinfo_vmentry (sys/sys/user.h, PATH_MAX 1024) and the PR's GuestVmEntry side by side. Every offset is identical (kve_structsize 0, kve_type 4, kve_start 8, kve_end 16, kve_protection 56, kve_path 136). FreeBSD writes offsetof(kve_path) + strlen + 1 rounded up to 8 with KERN_VMMAP_PACK_KINFO, which is 144 for an empty path, as in the PR. FreeBSD has no end record either: the reader (kinfo_getvmmap.c) walks kve_structsize up to the returned length, and the PR returns the length of the whole records.
  • Errors against kern_proc.c: EPERM for a write (the node is read-only), ESRCH for another pid and for -1 (pget), ENOMEM with the bytes that fit for a short buffer. The EINVAL for a MIB of 3 or 5 elements is not from FreeBSD (its handler does not check the length) but is the usual contract here.
  • Non-GPU suite (ctest -j8 --timeout 120 -E '^agc_driver_|^video_out_flip'): 884 tests (my throwaway probe included), 872 pass, 2 skipped, 10 failed on the first pass: the conventions_function_bodies scan and its 5 shards, hardware_oracle_compare, guest_none_relocations and tls_function_coverage_register_address_loads timed out under load, and guest_sce_net aborted once at -j8. All pass on serial reruns (shard 4 on its second serial try, 20.5 s against its 30 s limit; guest_sce_net 5/5). None of them touches code from these PRs
  • tools/check_conventions.py --base c9e6c45de and git diff --check pass. There are no new exports.

Titles. sysctl is imported by 43 of my local relinked titles and sysctlbyname by 23. I ran Ruffle PPSA68091, RetroArch PPSA99169 (the picker and the process it starts), PPSA99203 and PPSA01153 for 60 s each on main and on this PR, with a local diagnostic libkernel that logs every sysctl MIB (with buffer and length) and every sysctlbyname name:

Title sysctl sysctlbyname MIB 1.14.32
PPSA68091 Ruffle 0 0 0
PPSA99169 RetroArch 0 0 0
PPSA99203 0 0 0
PPSA01153 1 (1.37, kern.arandom) 0 0

So no local title issues kern.proc.vmmap: on main none hits unsupported MIB 1.14.32.<pid>, and on this PR none runs the new branch. The Ruffle and RetroArch runs make no sysctl call at all in 60 s, so I cannot confirm that they probe the map. The Forever Launcher run in the description (PPSA99030) is not among my titles, so the only title evidence for this change is the author's. No stop line in any run (all killed at the limit).

Small points from the diff, none blocking: the records are collected one range at a time under the arena lock, not under one lock for the whole walk, so a concurrent mmap can change the list between two steps (FreeBSD holds the map lock for the walk). That could go in the debt entry next to the unverified type and path.

Not checked: Linux, macOS, PS5 hardware, PPSA99030.

Written with Claude Code assistance (validation by a subagent, reviewed in this session).

@milescoviello

Copy link
Copy Markdown
Contributor Author

Thanks @screamm, the side-by-side compile against FreeBSD 11's kinfo_vmentry and the negative control are both useful. Good point on the lock. The walk takes the arena lock once per range, so a concurrent mmap or munmap can change the list between two records. FreeBSD holds the map lock for the whole walk. I added that to the debt entry (c8b5cec, doc only) rather than holding the lock across the walk, which would mean exposing a whole-walk API from GuestArena. I added your run to the description.

AI-assisted: yes (Claude Code)

milescoviello and others added 2 commits October 17, 2026 20:43
….vmmap

sysctl {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, pid} for the calling process
returns packed FreeBSD 11 kinfo_vmentry records, one per used range of the
guest arena, with the protection sceKernelVirtualQuery reports. Other pids
return ESRCH, a write EPERM, a short buffer ENOMEM. GuestArena gains a
query for the used range at or after an address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the unblocks title Names a title ID on the Unblocks line label Oct 18, 2026
@adriadam10 adriadam10 self-assigned this Oct 19, 2026
@adriadam10
adriadam10 merged commit a77e40f into boykopovar:main Oct 19, 2026
15 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the kinfo_vmentry layout (static_assert on offsets 8/16/56/136, 144 bytes), the errno set (EPERM, EINVAL, ESRCH for other pids and -1, ENOMEM on a short buffer) and that CheckVmmapSysctl aborts on main without the change (also confirmed by @screamm's Windows run); the debt entry is accurate; merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs libc libkernel unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants