Ignore collector library environment variables in privilege-elevated processes - #246
Conversation
|
The PR closes an env-var-controlled library injection hole in ITT API on setuid-root binaries (attacker sets INTEL_LIBITTNOTIFY64=evil.so, runs a setuid program they're allowed to run, evil.so executes as root). The fix detects the privilege boundary (uid != euid) and ignores the env var in that case — correct and safe, but as a side effect it also silently disables the legitimate use of that env var by an authorized user profiling a setuid binary, since ITT can't tell "attacker's evil.so" from "operator's own tested collector.so" just by looking at the path. The fix doesn't warn when it does this, so a legitimate user just gets no profiling output with no clue why. Example: Legitimate case: user1 wants to profile exe1 with their own tested collector Attack case: attacker points at their own malicious library, same command shape Both cases produce identical behavior (silent no-op) because the check can't distinguish intent from a path string — it can only detect that a privilege boundary was crossed. Security-wise that's the right call; the missing piece is a diagnostic message so user1 isn't left debugging the wrong thing. Recommendation: report this case through ITT's existing __itt_report_error() mechanism (same pattern already used for __itt_error_env_too_long/__itt_error_cant_read_env) — e.g. a new __itt_error_ignored_env_privileged code raised at the point the env var is dropped. This stays silent by default (the handler only fires if one is registered) but gives anyone who wires up ITT's error handler a way to see "the env var was ignored for security reasons" instead of just getting no data. |
INTEL_LIBITTNOTIFY64env var is passed straight todlopen()/LoadLibraryA()when__itt_api_initis called, so an unprivileged local user can inject a library into any privileged process linking ITT API.Added
__itt_is_secure_execution_context()method that does:getauxval(AT_SECURE)on Linux/Androidissetugid()on macOS/BSDgetuid() != geteuid() || getgid() != getegid()as fallbackWhen true, we skip environment read by
__itt_get_env_var(), soinit_ittlib()never callsdlopenSame pattern in the JIT agent loader and the Advisor annotation headers.