Lightweight OpenBSD process mitigation visibility tool β looks at pledge, unveil, and W^X status per process.
PMV stands for Process Mitigation Viewer. The name was deliberate β this is a viewer, not an auditor, not a security scanner, not a vulnerability finder. It shows whether kernel mitigations are present per process and is upfront about what the kernel does and doesn't expose.
PMV is a minimal utility for inspecting process-level mitigation state on OpenBSD.
It reads kernel-exposed process metadata through kvm(3) and struct kinfo_proc to check whether active processes use pledge(2), unveil(2), and W^X policy.
All classification comes from kernel-reported state. PMV doesn't do runtime analysis, syscall tracing, or behavioral detection.
Let's be clear about scope: PMV doesn't try to replace ktrace(1), btrace(8), or any other OpenBSD introspection tool. It reads what the kernel exposes and formats it readably. The kernel tells you whether pledge(2) and unveil(2) were called β not which promises were made or which paths were unveiled. PMV doesn't pretend otherwise. That's a platform constraint, not a missing feature.
- Kernel process table inspection via
libkvm pledge(2)state detection (called / not called)unveil(2)state detection (called / not called)- W^X-related indicators
- PID filtering (
--pid) β inspect a single process and its children - Parent process mapping (PPID) β shows parent PID and process name
- Per-process scoring based on kernel-reported mitigation state
- Self-hardening β PMV applies
pledge(2)andunveil(2)to itself at runtime - Self-audit β automatic W^X memory verification of its own process on startup
- Structured export (JSON, CSV)
- Diff mode (
--diff) β compare current state against a previous snapshot - W^X memory scan (
--scan-wx) β per-region protection analysis with violation summary - Built-in help (
--help/-h) β usage reference for all flags
PID PPID PROCESS PARENT PLEDGE UNVEIL W^X SCORE
-----------------------------------------------------------------------------------------------------
89905 57770 pmv ksh PRESENT PRESENT ok 5
80996 57770 ksh xfce4-terminal PRESENT NONE ok 3
96837 1 xfce4-terminal init NONE NONE ok 0
<PID> 38074 firefox firefox PRESENT NONE ok 3
18100 <PID> firefox firefox NONE NONE ok 0
79750 1 accounts-daemon init NONE NONE ok 0
Output reflects kernel-reported mitigation state. PRESENT confirms the syscall was called β it does not indicate policy depth or scope.
PMV uses libkvm to access the kernel process table in read-only mode. For each process it reads struct kinfo_proc and checks:
- Whether
pledge(2)was called (p_psflags & PS_PLEDGE) - Whether
unveil(2)was called (p_psflags & PS_UNVEIL) - Whether W^X enforcement is active (
p_psflags & PS_WXNEEDED) - Whether the process is chrooted (
p_flag & P_CHROOT)
Known limitation: the kernel only exposes a boolean for pledge and unveil β presence or absence. The specific promises passed to pledge(2) or paths passed to unveil(2) aren't available. PMV can't report what the kernel doesn't provide.
Each process gets a score from -2 to 6 based on what the kernel reports:
| Criteria | Value | Description |
|---|---|---|
pledge(2) called |
+3 | Syscall restriction active (depth unknown) |
unveil(2) called |
+2 | Filesystem restriction active (scope unknown) |
chroot jail |
+1 | Additional filesystem containment |
| W^X violation (WXNEEDED) | -2 | Penalty β writable+executable memory pages |
| Score Range | Color | Meaning |
|---|---|---|
| 4 β 6 | Green | Multiple mitigations detected |
| 1 β 3 | Yellow | Partial mitigation |
| β€ 0 | Red | No mitigations detected |
When you run PMV on a default OpenBSD install, some warnings might pop up. That's normal β it's OpenBSD being defensive.
[!] VMMAP sysctl failed for PID XXXXX: KERN_PROC_VMMAP is restricted...
Technical context: OpenBSD blocks userland from inspecting raw process memory maps (KERN_PROC_VMMAP) by default. This prevents local info leaks that could bypass ASLR. If you're in a lab environment and want to test deep memory auditing (--scan-wx), you can temporarily allow it:
doas sysctl kern.allowkmem=1[!] PLEDGE/UNVEIL shows PRESENCE only β kernel does not expose policy depth.
Technical context: The kernel uses internal bitmask flags in the process structure (p_psflags) to track whether a mitigation is active. It doesn't maintain a verbose string array for userland about which paths were unveiled or which promises were requested. PRESENT means the binary calls pledge or unveil. That's all the kernel gives us.
# Clone the repository
git clone https://github.com/jeffersoncesarantunes/PMV.git
cd PMV
# Build
make
# (Optional) Clean rebuild from scratch
make clean && make
# Run (full system scan)
doas ./pmv
# Show usage reference
doas ./pmv --help
# Filter by PID (show <PID> and its children)
doas ./pmv --pid <PID>
# Structured output
doas ./pmv --format json --quiet
doas ./pmv --format csv --quiet
# Diff mode β compare against previous snapshot
doas ./pmv --diff
# W^X memory scan with per-region detail and violation summary
doas ./pmv --scan-wx <PID>| File | Description |
|---|---|
output.json |
Structured export (machine-readable) |
output.csv |
Tabular export (spreadsheet-friendly) |
.pmv_snapshot |
Internal diff snapshot (auto-generated) |
Interactive runtime state scan showing the live process table and real-time security scoring.
Process filtering with --pid, targeting specific subtrees and recalculating scope-specific metrics.
Forensic automation: quiet mode (--quiet) for data dumping and differential audit (--diff) against historical snapshots.
PMV is designed for safe forensic use:
- Read-only kernel access via
libkvm - No process interaction or
ptrace(2)usage - Self-hardened with
pledge(2)andunveil(2)at runtime - Graceful handling of restricted entries
- OpenBSD (release or -current)
- libkvm
- BSD make
- doas or root privileges
PMV needs kernel memory access via libkvm(3), which means elevated privileges. The recommended way to run it is with doas. make install puts the binary in place without setuid root (-m 755). This follows OpenBSD's philosophy of explicit privilege elevation rather than implicit setuid escalation. If you want setuid, adjust the mode manually after install.
βββ docs/
β βββ ARCHITECTURE.md
β βββ BENCHMARKS.md
β βββ SECURITY_MODEL.md
βββ Images/
β βββ pmv-runtime-scan-v2.png
β βββ pmv-pid-filter-v2.png
β βββ pmv-diff-audit-v2.png
βββ include/
β βββ pmv.h
βββ src/
β βββ engine.c
β βββ main.c
βββ .gitignore
βββ LICENSE
βββ Makefile
βββ SECURITY.md
βββ README.md
- Language: C (C11)
- Kernel Interface: libkvm
- Data Source: struct kinfo_proc
- Build Tool: BSD make
- Platform: OpenBSD
- Core mitigation state engine
-
pledge(2)/unveil(2)presence detection - W^X-related policy indicators per process
- Kernel state extraction via
libkvm(3)/struct kinfo_proc - Parent process mapping (PPID)
- Per-process security scoring (-2 to 6)
- PID filtering (
--pid) - W^X memory region scan (
--scan-wx) - Self-hardening at runtime (
pledge+unveil) - Self-audit on startup (W^X integrity check)
- Structured export (JSON / CSV)
- Diff mode (
--diff) β change detection across runs - Silent mode (
--quiet)


