Sync symlink/ownership hardening from upstream - #85
Merged
Merged
Conversation
Backports two security fixes merged upstream (intel/gprofiler) after our last CVE sync (origin #80, which covered up to intel#1046): - intel#1047: restore ownership validation in mkdir_owned_root and add symlink checks to both mkdir_owned_root and mkdir_owned_root_wrapper. Our fork had already removed the erroneous dead-code 'return' via an assert-is-root rewrite; this layers in the missing symlink/ownership hardening while preserving that customization. - intel#1050: harden safe_copy (O_EXCL atomic temp creation + dst symlink check + fd-leak fix) and add safe_read_text (O_NOFOLLOW) to prevent symlink escape (CWE-59); use safe_read_text in java _read_ap_log. Co-authored-by: Cursor <cursoragent@cursor.com>
prashantbytesyntax
approved these changes
Oct 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR continues our upstream CVE/security sync. Our previous sync (#80) backported dependency fixes up to
intel/gprofiler#1046, but two code-level security fixes had already landed upstream (intel/gprofiler) before then and were intentionally out of scope for that dependency-focused PR. A fresh scan of upstreammasterconfirms these are still the only security fixes missing from our fork. Each change below mirrors upstream, reconciled against our fork's divergence.Changes & rationale
1. Restore ownership validation + add symlink checks in
mkdir_owned_rootBackports intel/gprofiler#1047.
is_owned_by_current_user()and, inmkdir_owned_root_wrapper()(non-root path), validates the directory is owned by the current user instead of merely writable.mkdir_owned_root()andmkdir_owned_root_wrapper(), before and after creation, to prevent symlink attacks.returnthat made the ownership check dead code (introduced in5285bef7). Our fork had already fixed that dead-code bug via anassert is_root()rewrite ofmkdir_owned_root(), so this change layers in only the missing symlink/ownership hardening while preserving our fork'sassert is_root()design andshutil.rmtree-and-recreate behavior.2. Fix symlink escape vulnerabilities in
safe_copyand log reading (CWE-59)Backports intel/gprofiler#1050.
safe_copy(): usesO_EXCLfor atomic temp-file creation (defeats symlink redirection of writes), adds a defense-in-depthdstsymlink check beforerename, and fixes an fd leak ifos.fdopen()fails.safe_read_text(): reads files withO_NOFOLLOWso the kernel atomically rejects symlinks at open time; fixes an fd leak onos.fdopen()failure. Adds_O_NOFOLLOWwith agetattrfallback for portability.gprofiler/profilers/java.py:_read_ap_log()now usessafe_read_text()for the async-profiler log path.These close two container-escape vectors:
libasyncProfiler.socopy destination to overwrite arbitrary host files.Notes
gprofiler/utils/fs.pyhas diverged from upstream (theassert is_root()rewrite ofmkdir_owned_rootandrmtreebehavior). The security hardening was reconciled by hand; agit diff --no-indexagainst upstreammasterpost-Fix symlink escape vulnerabilities in safe_copy and log file reading (CWE-59) intel/gprofiler#1050 shows the result is identical except for those intentional fork differences.Test plan
python -m py_compile gprofiler/utils/fs.py gprofiler/profilers/java.pypasses.fs.pyverified against upstream/master (post-Fix symlink escape vulnerabilities in safe_copy and log file reading (CWE-59) intel/gprofiler#1050) viagit diff --no-index; only the intentionalassert is_root()fork customizations differ.