-
Notifications
You must be signed in to change notification settings - Fork 12
Description
Summary
When ddprof runs as a non-root user with file capabilities (e.g. cap_ipc_lock,cap_perfmon,cap_sys_ptrace=+ep set via setcap), profiling targets that have their own file capabilities (e.g. nginx with cap_net_bind_service) causes the ddprof worker process to permanently lose ALL capabilities.
This breaks profiling silently — the worker continues running but can no longer call perf_event_open or mmap perf ring buffers.
Root Cause
The bug is in the UID elevation logic in open_proc_maps() (src/dso_hdr.cc:46-56) and open_proc_comm() (src/ddprof_process.cc:26-36).
When reading /proc/<pid>/maps for a target process fails (because the target has file capabilities, making it non-dumpable), these functions attempt UID elevation via user_override():
fopen("/proc/<pid>/maps")fails — target is non-dumpablestat()shows file owned by root (st_uid=0)user_override(0, 0, &old_uids)→setresuid(0, 0, -1)— UIDs become(0, 0, 1000)(saved UID stays at original)- Retry
fopen→ still fails (needsCAP_SYS_PTRACE, not just UID 0) user_override(old_uids.uid, old_uids.gid)→setresuid(1000, 1000, -1)— UIDs become(1000, 1000, 1000)- Capability clearing rule: all UIDs are now nonzero (after at least one was 0) → kernel clears ALL capabilities from permitted, effective, and ambient sets
- Worker permanently loses
CAP_IPC_LOCK+CAP_PERFMON→ profiling breaks
Why UID elevation is useless for non-root
For root users, the UID round-trip is safe because the saved UID stays at 0, so the "all nonzero" condition is never met.
For non-root users, the UID elevation to root via setresuid(0, 0, -1) requires CAP_SETUID. Even when this succeeds, it doesn't help read /proc/<pid>/maps of non-dumpable processes — that requires CAP_SYS_PTRACE regardless of UID (the kernel performs a ptrace_may_access() check).
So for non-root users, the UID elevation is both useless (doesn't grant access) and destructive (destroys all capabilities).
Environment
- ddprof 0.23.0 (current main)
- Non-root user (UID 1000) with file capabilities on the ddprof binary
- Target processes with file capabilities (e.g. nginx with
cap_net_bind_service=+ep) - Kubernetes containers with capabilities in the bounding set
Proposed Fix
Guard the UID elevation with is_root() (already defined in user_override.hpp) so that non-root users skip the elevation entirely:
// In open_proc_maps (src/dso_hdr.cc)
if (!f && is_root()) {
// UID elevation only works when running as root
...
}
// Same pattern in open_proc_comm (src/ddprof_process.cc)PR: #495