Skip to content

fix(syswrap): return the client's auxv from prctl(PR_GET_AUXV) - #49

Open
lvaroqui wants to merge 2 commits into
cod-3818-bring-upstream-valgrind-3271-to-valgrind-codspeedfrom
cod-3810-valgrind-codspeed-leaks-the-host-auxv-through
Open

lvaroqui wants to merge 2 commits into
cod-3818-bring-upstream-valgrind-3271-to-valgrind-codspeedfrom
cod-3810-valgrind-codspeed-leaks-the-host-auxv-through

Conversation

@lvaroqui

@lvaroqui lvaroqui commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Under valgrind, prctl(PR_GET_AUXV) (Linux 6.4+) reached the kernel unchanged and returned the auxv the kernel saved when it exec'd the valgrind tool, not the program's. getauxval() and /proc/self/auxv already report the program's auxv, so the two disagreed.

AT_EXECFN came back as .../callgrind-amd64-linux, which breaks multicall binaries that pick their behavior from it. rust-coreutils 0.8.0, shipped with Ubuntu 26.04, failed every command under valgrind with coreutils: unknown program 'callgrind-amd64-linux'. Its 0.10.0 update no longer reads its name this way, but any program calling PR_GET_AUXV is affected, on any distro.

The prctl wrapper now answers PR_GET_AUXV itself and keeps the kernel's contract:

  • It returns a copy of the client's auxv taken at startup, where the fake /proc/self/auxv is created, like the kernel's copy saved at exec. Writing to, protecting or unmapping the original stack afterwards does not affect it.
  • It returns the kernel's own buffer size, asked with a zero-size call, and zero-pads after the auxv, so the return value matches native (448 bytes on amd64 here).
  • It copies at most the caller's size.
  • Nonzero arg4/arg5 fail with EINVAL, and a buffer the caller cannot write (unmapped or read-only) with EFAULT. Kernels without PR_GET_AUXV return their own EINVAL.

The wrapper completes the call itself, so it clears SfMayBlock: syswrap-main asserts that a call completed successfully in the pre-handler does not carry it.

callgrind/tests/prctl_get_auxv checks AT_EXECFN, that the whole vector equals the one on the stack and later writes to the stack copy do not show, that the size equals the kernel's (taken from a native run) with zero padding up to it, short buffers, EINVAL for arg4/arg5, and EFAULT for unmapped and read-only buffers. It passes natively, fails without this fix, and is skipped outside Linux and on kernels without PR_GET_AUXV. Under memcheck the only report is the test's deliberate unmapped buffer, so the copied bytes are marked defined. Only amd64 was verified locally.

Stacked on #48.

Closes COD-3810

@lvaroqui
lvaroqui added this pull request to stack #50 October 9, 2026 11:59
@codspeed

codspeed Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 84 untouched benchmarks
⏩ 60 skipped benchmarks1


Comparing cod-3810-valgrind-codspeed-leaks-the-host-auxv-through (c6556e9) with cod-3818-bring-upstream-valgrind-3271-to-valgrind-codspeed (0e0d232)

Open in CodSpeed

Footnotes

  1. 60 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@lvaroqui
lvaroqui marked this pull request as ready for review October 9, 2026 12:24
@greptile-apps

greptile-apps Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the previous stack-access crash is fixed.

Summary

PR_GET_AUXV now returns a private copy of the client's startup vector rather than reading the original stack.

  • Later stack changes cannot change the returned vector.
  • The added test changes a stack value and checks that the saved vector stays unchanged.
  • The previous stack-access finding is fixed. No new actionable issues were found.

Diagram

sequenceDiagram
    participant Startup as Valgrind startup
    participant Saved as Private saved vector
    participant Client as Client program
    participant Wrapper as prctl wrapper
    participant Kernel as Linux kernel
    Startup->>Saved: Copy client's initial vector
    Client->>Wrapper: PR_GET_AUXV(buffer, size)
    Wrapper->>Kernel: Query supported operation and buffer size
    Kernel-->>Wrapper: Size or error
    Wrapper->>Saved: Read startup copy
    Wrapper-->>Client: Bounded copy, zero padding, full size
Loading

Reviews (3) · Last reviewed commit: "fix(syswrap): answer PR_GET_AUXV from a ..." · Reviewed by Greptile

Comment thread coregrind/m_syswrap/syswrap-linux.c Outdated
Comment thread callgrind/tests/prctl_get_auxv.vgtest Outdated
Comment thread callgrind/tests/prctl_get_auxv.c Outdated
The kernel answers PR_GET_AUXV (Linux 6.4+) with the auxv it saved when
it exec'd the Valgrind tool, so a program reading its auxv this way got
the tool's entries, including AT_EXECFN (e.g. .../callgrind-amd64-linux),
while getauxval() and /proc/self/auxv already report the client's.
Multicall binaries that pick their behavior from AT_EXECFN, such as
rust-coreutils 0.8.0 shipped with Ubuntu 26.04, failed with "unknown
program 'callgrind-amd64-linux'".

Handle PR_GET_AUXV in the prctl wrapper: copy the client auxv, zero-padded
to the size the kernel reports, into the caller's buffer and return that
size. Keep the kernel's EINVAL for nonzero arg4/arg5 and on kernels
without the option, and EFAULT for an unaddressable buffer.

Closes COD-3810
Co-Authored-By: Claude <noreply@anthropic.com>
@lvaroqui
lvaroqui force-pushed the cod-3810-valgrind-codspeed-leaks-the-host-auxv-through branch from 305a73e to 8df58f1 Compare October 9, 2026 12:45
Comment thread coregrind/m_syswrap/syswrap-linux.c Outdated
The PR_GET_AUXV handler read the auxv from the client's initial stack on
every call. A program that writes to those pages got the modified
vector, and one that unmaps or protects them after switching stacks made
Valgrind fault while reading them, where the kernel answers from the
copy it saved at exec. Copy the client auxv at startup, where the fake
/proc/self/auxv is created, and answer PR_GET_AUXV from that copy.

The regression test now also writes to the stack auxv and checks that
PR_GET_AUXV still returns the saved vector.

Refs COD-3810
Co-Authored-By: Claude <noreply@anthropic.com>
@lvaroqui
lvaroqui requested a review from not-matthias October 9, 2026 15:19
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