Harden program-cache permissions, binary-path resolution, and coredump helper lifetime#2399
Open
rparolin wants to merge 14 commits into
Open
Harden program-cache permissions, binary-path resolution, and coredump helper lifetime#2399rparolin wants to merge 14 commits into
rparolin wants to merge 14 commits into
Conversation
…er lifetime - cuda.core: create the on-disk program cache tree owner-only (0o700) and re-assert restrictive perms on POSIX, so cached device code cannot be read or planted by other local users regardless of the inherited umask. - cuda.pathfinder: absolutize the resolved binary-utility path to honor the documented absolute-path contract; surface AddDllDirectory failures on Windows with GetLastError instead of silently swallowing them. - cuda.bindings: retain the caller's bytes in _HelperCUcoredumpSettings so the borrowed pointer cannot outlive its backing buffer, and free the getter's 1 KiB buffer in __dealloc__; clarify get_buffer_pointer's lifetime contract. Adds regression tests for the cache permissions, path absolutization, and coredump helper lifetime. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
rparolin
marked this pull request as ready for review
July 21, 2026 20:41
Shorten the explanatory comments to a line or two each and drop the internal issue-number references (which don't resolve in this repo). No code changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
It didn't actually guard the two lifetime fixes: the driver copies the path during the set call (so the NVIDIA#379 latent UAF can't trigger), and a missing free leaks silently (so NVIDIA#381 wouldn't fail the test either). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The test pre-creates a 0o777 cache dir to verify the loader tightens it to 0o700; the permissive mask is the point of the test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The abspath change makes find_nvidia_binary_utility return a drive-qualified path on Windows (C:\... ), so the three search-order tests must compare against os.path.abspath(expected). No-op on Linux; fixes the Windows CI failures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ting The c_int/c_byte param feeders silently narrowed an out-of-range Python int (e.g. 2**32+5 -> 5). Range-check in the feeder and raise OverflowError; declare feed() as 'except? -1' so Cython propagates the exception instead of swallowing it. Addresses Glasswing V9.1 (leofang chose the raise option over matching ctypes' silent wrap). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per Leo's review: on 3.13+ PyLong_AsInt converts and range-checks in one call (raising OverflowError itself), so gate the manual INT_MIN/INT_MAX check to pre-3.13 only. c_byte keeps the manual check (no 8-bit CPython equivalent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…flow Per Leo's follow-up: use a single code path on all supported Pythons instead of version-gating PyLong_AsInt. PyLong_AsLongAndOverflow flags out-of-long values via its overflow out-param (no exception set), then we bounds-check the 32-bit (c_int) / 8-bit (c_byte) target range and raise OverflowError. Drops the PY_VERSION_HEX gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#2402) The out-of-range c_int/c_byte -> OverflowError change is a distinct behavior change; moved to a standalone PR so it can be reviewed separately from this hardening batch. No functional change to the remaining hardening work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
leofang
reviewed
Jul 22, 2026
leofang
reviewed
Jul 22, 2026
Per @leofang's review on PR NVIDIA#2399: - _file_stream.py: only the tmp/ staging dir is created owner-only (0o700). root/ and entries/ now inherit the umask / any pre-existing permissions so a deliberately shared kernel cache (e.g. group-writable on a compute cluster) keeps working. Dropped the post-mkdir chmod that would have re-tightened an existing shared directory. 0o700 in mkdir mode needs no chmod: umask only clears bits. - _internal/utils.pyx: revert the get_buffer_pointer docstring change; that is cybind code and is out of scope for this PR. - Tests updated to match: assert only tmp is 0o700, and that a pre-existing 0o777 shared root is used as-is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record the residual risk from narrowing the cache-permission hardening (glasswing NVIDIA#359/NVIDIA#375) per PR NVIDIA#2399 review: committed entry files stay 0o600 (contents owner-only via mkstemp+os.replace), tmp/ is owner-only to protect in-flight writes, but root/entries inherit the umask so shared caches keep working. In a group-writable shared cache a group member could replace a cached kernel; tamper-proofing that path needs load-time integrity checks and is out of scope here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Heads-up on the security posture after narrowing the cache-permission fix (details in the updated PR description under Security scope):
@leofang flagging for sign-off on accepting that residual risk (mitigated for single-user; shared-cache tampering accepted). |
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Ready for another look — pushed changes addressing the review: @leofang (cuda.core / cuda.bindings)
@rwgk (cuda.pathfinder)
Thanks! |
leofang
reviewed
Jul 22, 2026
Comment on lines
73
to
+86
| # Add the DLL directory to the native search path. AddDllDirectory only | ||
| # affects the LOAD_LIBRARY_SEARCH_USER_DIRS search; PATH is updated | ||
| # unconditionally below to also cover legacy dependent-DLL resolution. | ||
| kernel32.AddDllDirectory(dirpath) | ||
| cookie = kernel32.AddDllDirectory(dirpath) | ||
| if not cookie: | ||
| # Warn instead of failing silently; the PATH update below is a weaker | ||
| # fallback that newer loaders may ignore. | ||
| error_code = ctypes.GetLastError() # type: ignore[attr-defined] | ||
| warnings.warn( | ||
| f"AddDllDirectory({dirpath!r}) failed (error code: {error_code}); " | ||
| "falling back to process-global PATH mutation for dependent-DLL resolution.", | ||
| RuntimeWarning, | ||
| stacklevel=2, | ||
| ) |
Member
There was a problem hiding this comment.
Q: Why wouldn't we just call os.add_dll_directory()? What is (was, apparently it's already there) the reason that we call win32 API directly?
Member
|
cuda.core LGTM! |
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.
Small safety fixes across three areas, each with a test. All hardening — no intentional behavior change.
What changed
cuda.core
tmp/staging area (where in-flight writes land before the atomic rename intoentries/) is now created owner-only (0o700) so other local users can't read or replace device code mid-write. Per review,root/andentries/intentionally inherit the umask / any pre-existing permissions so a deliberately shared kernel cache (e.g. group-writable on a compute cluster) keeps working — an existing directory is used as-is, never re-tightened.cuda.pathfinder
find_nvidia_binary_utilitynow always returns a full absolute path, as the docs promise (it could return a relative one before).AddDllDirectoryfails, we now warn instead of failing silently.cuda.bindings
_HelperCUcoredumpSettings): it kept a pointer to bytes it didn't own (dangling pointer), and never freed a 1 KB buffer (leak).Security scope
This started as "make the whole cache tree owner-only regardless of umask." Per review it was narrowed to keep shared caches working, so the residual posture is:
mkstemp(0o600) andos.replacepreserves that mode, so cached kernel contents stay owner-readable even thoughentries/inherits the umask. Other local users can list entry filenames (key hashes) but can't read the code.entries/, so no one can plant a kernel this process later loads.entries/could replace a cached kernel. Tamper-proofing that path needs load-time integrity checks (a separate change), so it's out of scope here. Flagging for sign-off.Tests
Added tests for the
tmp/permissions (and that a shared root is preserved), the absolute path, and the coredump helper. Directory-permission logic verified locally; full suite on RTX 5880.Reviewers: @leofang (core/bindings), @rwgk (pathfinder).