Skip to content

Hardened native libraries extraction - #2971

Merged
riccardobl merged 4 commits into
jMonkeyEngine:masterfrom
riccardobl:betternativeload
Sep 23, 2026
Merged

riccardobl merged 4 commits into
jMonkeyEngine:masterfrom
riccardobl:betternativeload

Conversation

@riccardobl

Copy link
Copy Markdown
Member

Supersedes #2764

  • always extracts natives on random temp directories
  • protect against other programs trying to replace the extracted libraries at runtime
  • fallback for noexec volumes
  • better handling for system cache folder

@jaime-jmebot jaime-jmebot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for picking this up — the hardening looks solid: a fresh random directory per run, CREATE_NEW extraction, private permissions and the symlink/poisoned-file rejection all remove the predictable-path attack surface, and the new tests cover the fallback chain and concurrency well.

A few things worth a look (details inline):

  • The noexec probe in NativeLibraryExtraction.checkExecutable() may be a no-op on Linux — if so the retry-on-UnsatisfiedLinkError path is doing the real work, and the noexec test would be skipped rather than exercising it.
  • setExtractNativeLibraries(false) without a custom folder can no longer find pre-extracted natives, since the folder is now random each run.
  • Minor cleanups: name the retry bound so it can't drift from the root list, and drop NativeLibraryLoader.isExtractingRequired() — this PR orphaned it (extraction no longer compares timestamps).

Comment on lines +80 to +84
for (AclEntry entry : view.getAcl()) {
if (entry.type() == AclEntryType.ALLOW && !entry.principal().equals(acl.get(0).principal())) {
throw new IOException("Cannot restrict native directory ACL: " + directory);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth double-checking this on Windows: both createTempDirectory(...) and setAcl(...) end up in SetFileSecurity(..., DACL_SECURITY_INFORMATION, ...), and the JDK never marks the DACL as protected (SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)), so Windows is free to merge the parent's inheritable ACEs (SYSTEM, Administrators, and possibly the local Users group under %TEMP%) back into the ACL. If it does, getAcl() returns more than your single owner entry, this loop throws, and every extraction root gets rejected — natives would not load at all on Windows.

Did the new createsUniquePrivateDirectories test actually pass for you on Windows? If yes, please ignore me — I only had Linux available to reason from. If it does reproduce, relaxing this to reject only foreign entries that grant write/delete (rather than any foreign ALLOW) would keep most of the protection.

@jaime-jmebot jaime-jmebot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turnaround — the earlier points all look addressed: extraction-disabled without a custom folder now fails explicitly (with a test), the retry bound is a named constant, isExtractingRequired() is gone, and the temp-folder lifetime is documented. The fallback chain and its tests read well.

  • First: my noexec remark was wrong — access(X_OK) does honour MS_NOEXEC on Linux, so checkExecutable() is meaningful (details in the thread). Sorry for the detour.
  • One open question on the Windows ACL path, inline: if the OS re-merges inherited ACEs there, the check rejects every root and nothing loads. A quick confirmation that the new test ran on Windows would close it.
  • Tiny leftover in getJmeUserCacheFolder(): Path base = null; if (base == null) { is always true, looks like a remnant of an earlier refactor.

@riccardobl
riccardobl merged commit 8be0d7b into jMonkeyEngine:master Sep 23, 2026
10 checks passed
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.

2 participants