Skip to content

Expose process_vm_access attempt telemetry - #428

Draft
Aegrah wants to merge 3 commits into
process-vm-access-corefrom
process-vm-access-public
Draft

Aegrah wants to merge 3 commits into
process-vm-access-corefrom
process-vm-access-public

Conversation

@Aegrah

@Aegrah Aegrah commented Sep 16, 2026

Copy link
Copy Markdown

Part 2 of 3, bottom-up: private probespublic event and testsGo bindings.

Summary

Expose one process_vm_access attempt per observed syscall exit, including signed result, flags and explicit target/snapshot validity. Capacities are present only for complete checked snapshots of at most eight vectors. The first remote vector is labeled as a snapshot, not a transfer range or total. Unresolved attempts retain the original signed PID and caller PID namespace.

Add four regression tests covering failures, partial transfer, namespace/TID identity, compat entry, concurrency, map pressure and cleanup. Public event/queue bit 17 avoids mprotect and pending file-access allocations. Quark-mon, loss statistics and documentation describe the contract.

Issue: https://github.com/elastic/endpoint-dev/issues/21204

Validation

Preflight: 20260916-pva-v2-release-final. Fleet acceptance: 20260916T172021Z-process-vm-access, accepted build endpoint-9.4.2-5564d77d41a8132d (Stack/Agent/Endpoint 9.4.2). Main integration was validated separately. Full persona-volume gate explicitly waived by the user; no production-volume claim.

Native x64/ARM64, forced eBPF kprobe attachment, RHEL 8 and exact Rocky 9.3 pass. A small enabled/disabled getpid benchmark measured ~53 ns extra per syscall on the shared builder; this does not establish general production overhead.

local_snapshot_status=0 remote_snapshot_status=0 local_capacity=8 remote_capacity=8

Companions: elastic/endpoint-package#800 · https://github.com/elastic/endpoint-dev/pull/22027

Add the optional eBPF-only queue flag, public event payload, dump output and map-failure statistics. Preserve parent-child operations and suppress only resolved same-group access. Test native/ia32/x32 availability, namespace and nonleader identity, real permission denial, partial transfers, vector failures, concurrency, map pressure, cleanup and lineage-specific timestamps.
…not host

The Buildkite valgrind job failed all four process_vm_access tests. The
first cause is valgrind itself: the nonleader-thread target was created
with clone(CLONE_VM | CLONE_SIGHAND | CLONE_THREAD), and valgrind only
hosts the pthread-shaped flag set ("Unsupported clone() flags: 0x10900"),
so the child died before the handshake. Use the same flags as
clone_start() does. The remaining cases are kernel work valgrind's process
model does not run or reports as errors of its own: int $0x80 and x32
syscalls from an amd64 client, a fork inside a fresh pid namespace with a
credential drop, state-map pressure, concurrent children, and the
scenarios that hand the kernel an unaddressable, uninitialised or
oversized local vector on purpose (valgrind's syscall checker flags those
before the kernel can reject them). Skip those under valgrind, like
t_trusted_pid does, and keep the plain read/write/failure scenarios of
t_process_vm_access under it, where the event parsing is exercised.
@Aegrah

Aegrah commented Sep 16, 2026

Copy link
Copy Markdown
Author

Buildkite was red on the valgrind job only. Reproduced on a builder: valgrind refuses the nonleader-thread target's clone(CLONE_VM | CLONE_SIGHAND | CLONE_THREAD) (Unsupported clone() flags: 0x10900), so the child died before the handshake; and its syscall checker counts the deliberately invalid local vectors (unaddressable lvec, iovcnt beyond the array, ~0 length) as errors before the kernel can reject them. Fix-up 3c18711 (fast-forward): the thread target uses the pthread-shaped flag set that clone_start() already uses, and under valgrind the test skips the compat-ABI cases, those three argument-validation scenarios, and the identity/state/concurrent tests (pid namespaces, credential drops, map pressure, concurrent children) the way t_trusted_pid does. The plain read/write/failure scenarios still run under valgrind, where the event parsing is. Plain run: all four tests pass on 6.8; merged forward to #429.

CI's centos7 container (gcc 4.8, -Werror=missing-braces) rejects
`int seen[8][64] = { 0 };` in t_process_vm_access_concurrent; newer
compilers accept it. Spell it `{{ 0 }}`.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant