Skip to content

[CXF-9227] Fix SecurityManager permission regressions introduced in 4…#3256

Open
ffang wants to merge 1 commit into
apache:mainfrom
ffang:CXF-9227
Open

[CXF-9227] Fix SecurityManager permission regressions introduced in 4…#3256
ffang wants to merge 1 commit into
apache:mainfrom
ffang:CXF-9227

Conversation

@ffang

@ffang ffang commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

….1.7

Summary

Fixes three SecurityManager permission regressions introduced in CXF 4.1.7
that break deployments running under a tight SecurityManager policy (reported
by the WildFly team during their 4.1.6 → 4.1.7 upgrade CI checks).

Root Cause

Issue 1 — NetPermission("getProxySelector") (introduced by #3154)

ProxyFactory.getSystemProxy() calls ProxySelector.getDefault() without
doPrivileged, forcing all callers including user deployments to hold this
permission.

Issues 2 & 3 — RuntimePermission("org.apache.cxf.permission") and
SocketPermission
(introduced by #3157)

Setting ACCESS_EXTERNAL_SCHEMA="" on SchemaFactory routes all schema
resolution through SchemaLSResourceResolverExtendedURIResolver
URIResolver.tryFileSystem() — a code path never previously reached in this
context under a SecurityManager. This exposed two pre-existing gaps:

  • SecurityActions.fileExists() called sm.checkPermission() outside
    doPrivileged, walking the full call stack into user deployment code.
  • URIResolver.createInputStream() called url.openConnection() without
    doPrivileged, requiring callers to hold SocketPermission.

Fix

File Change
ProxyFactory.java Wrap ProxySelector.getDefault() in doPrivileged
SecurityActions.java Move sm.checkPermission() inside the doPrivileged block so the stack walk stops at the CXF privilege boundary (confused-deputy guard preserved)
URIResolver.java Wrap url.openConnection() in doPrivileged

// context is checked, preserving the confused-deputy guard.
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
sm.checkPermission(permission);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@ffang I do understand the motivation for this change but I believe it significantly changes the (intended?) security posture and behavior. Essentially, any caller will be granted the permission assuming cxf-core has it, why do we have to change it now? Thanks!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@reta You're absolutely right — thank you for catching this. Moving sm.checkPermission() inside doPrivileged does weaken the caller-check semantics and is not a good fix.

The root cause of Issues 2 & 3 is that PR #3157's ACCESS_EXTERNAL_SCHEMA="" change routes schema resolution through SchemaLSResourceResolver → ExtendedURIResolver → URIResolver.tryFileSystem() — a code path that was never reached in this context before. When the JAXP schema validator (JDK code) drives that resolution under a SecurityManager, sm.checkPermission(RESOLVE_URI) walks all the way up through the JDK validator frames, which don't hold a CXF-internal permission, causing the failure.

The correct fix is to leave SecurityActions.fileExists() untouched — worth noting that SecurityActions is a package-private class so only CXF's own code in org.apache.cxf.resource can call into it directly(So any caller in your concern is restricted in CXF code, though we still should avoid it). Instead we wrap the resolver.resolve() call in SchemaLSResourceResolver.resolveResource() with AccessController.doPrivileged(). That establishes the boundary at CXF's own code: the sm.checkPermission(RESOLVE_URI) stack walk stops there, finds that CXF's JARs hold the permission, and passes — without granting any privilege to the JAXP/user frames above.

Will push a revised commit shortly.

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