Skip to content

Commit 845afdc

Browse files
Proper getStackAccessControlContext implementation
Fix imports and warnings in SecuritySubstitutions
1 parent a97353a commit 845afdc

File tree

5 files changed

+169
-77
lines changed

5 files changed

+169
-77
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java

Lines changed: 86 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828

2929
import java.net.URL;
3030
import java.security.AccessControlContext;
31-
import java.security.AccessControlException;
3231
import java.security.CodeSource;
33-
import java.security.DomainCombiner;
3432
import java.security.Permission;
3533
import java.security.PermissionCollection;
3634
import java.security.Permissions;
@@ -41,6 +39,8 @@
4139
import java.security.ProtectionDomain;
4240
import java.security.Provider;
4341
import java.security.SecureRandom;
42+
import java.util.Deque;
43+
import java.util.LinkedList;
4444
import java.util.List;
4545
import java.util.Map;
4646
import java.util.concurrent.atomic.AtomicReference;
@@ -50,6 +50,7 @@
5050
import org.graalvm.nativeimage.hosted.Feature;
5151
import org.graalvm.word.Pointer;
5252

53+
import com.oracle.svm.core.SubstrateUtil;
5354
import com.oracle.svm.core.annotate.Alias;
5455
import com.oracle.svm.core.annotate.AutomaticFeature;
5556
import com.oracle.svm.core.annotate.Delete;
@@ -59,6 +60,7 @@
5960
import com.oracle.svm.core.annotate.Substitute;
6061
import com.oracle.svm.core.annotate.TargetClass;
6162
import com.oracle.svm.core.annotate.TargetElement;
63+
import com.oracle.svm.core.thread.Target_java_lang_Thread;
6264
import com.oracle.svm.core.util.VMError;
6365
import com.oracle.svm.util.ReflectionUtil;
6466

@@ -77,102 +79,108 @@
7779
final class Target_java_security_AccessController {
7880

7981
@Substitute
80-
private static <T> T doPrivileged(PrivilegedAction<T> action) throws Throwable {
81-
try {
82-
return action.run();
83-
} catch (Throwable ex) {
84-
throw AccessControllerUtil.wrapCheckedException(ex);
85-
}
82+
public static <T> T doPrivileged(PrivilegedAction<T> action) throws Throwable {
83+
return AccessControllerUtil.executePrivileged(action, null, Target_jdk_internal_reflect_Reflection.getCallerClass());
8684
}
8785

8886
@Substitute
89-
private static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) throws Throwable {
90-
try {
91-
return action.run();
92-
} catch (Throwable ex) {
93-
throw AccessControllerUtil.wrapCheckedException(ex);
94-
}
87+
public static <T> T doPrivileged(PrivilegedAction<T> action, AccessControlContext context) throws Throwable {
88+
Class<?> caller = Target_jdk_internal_reflect_Reflection.getCallerClass();
89+
AccessControlContext acc = AccessControllerUtil.checkContext(context, caller);
90+
return AccessControllerUtil.executePrivileged(action, acc, caller);
9591
}
9692

9793
@Substitute
98-
private static <T> T doPrivileged(PrivilegedAction<T> action, AccessControlContext context) throws Throwable {
99-
try {
100-
return action.run();
101-
} catch (Throwable ex) {
102-
throw AccessControllerUtil.wrapCheckedException(ex);
103-
}
94+
public static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Throwable {
95+
Class<?> caller = Target_jdk_internal_reflect_Reflection.getCallerClass();
96+
return AccessControllerUtil.executePrivileged(action, null, caller);
10497
}
10598

10699
@Substitute
107-
private static <T> T doPrivileged(PrivilegedAction<T> action, AccessControlContext context, Permission... perms) throws Throwable {
108-
try {
109-
return action.run();
110-
} catch (Throwable ex) {
111-
throw AccessControllerUtil.wrapCheckedException(ex);
112-
}
100+
static <T> T doPrivileged(PrivilegedExceptionAction<T> action, AccessControlContext context) throws Throwable {
101+
Class<?> caller = Target_jdk_internal_reflect_Reflection.getCallerClass();
102+
AccessControlContext acc = AccessControllerUtil.checkContext(context, caller);
103+
return AccessControllerUtil.executePrivileged(action, acc, caller);
113104
}
114105

115106
@Substitute
116-
private static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Throwable {
117-
try {
118-
return action.run();
119-
} catch (Throwable ex) {
120-
throw AccessControllerUtil.wrapCheckedException(ex);
121-
}
107+
static AccessControlContext getStackAccessControlContext() {
108+
return StackAccessControlContextVisitor.getFromStack();
122109
}
123110

124111
@Substitute
125-
private static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action) throws Throwable {
126-
try {
127-
return action.run();
128-
} catch (Throwable ex) {
129-
throw AccessControllerUtil.wrapCheckedException(ex);
130-
}
112+
static AccessControlContext getInheritedAccessControlContext() {
113+
return SubstrateUtil.cast(Thread.currentThread(), Target_java_lang_Thread.class).inheritedAccessControlContext;
131114
}
132115

133-
@Substitute
134-
private static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action, AccessControlContext context, Permission... perms) throws Throwable {
116+
}
117+
118+
@InternalVMMethod
119+
class AccessControllerUtil {
120+
121+
static final AccessControlContext NO_CONTEXT_SINGLETON;
122+
static final ThreadLocal<Deque<AccessControlContext>> accStack = ThreadLocal.withInitial(LinkedList::new);
123+
124+
static {
135125
try {
136-
return action.run();
137-
} catch (Throwable ex) {
138-
throw AccessControllerUtil.wrapCheckedException(ex);
126+
NO_CONTEXT_SINGLETON = ReflectionUtil.lookupConstructor(AccessControlContext.class, ProtectionDomain[].class, boolean.class).newInstance(new ProtectionDomain[0], true);
127+
} catch (ReflectiveOperationException ex) {
128+
throw VMError.shouldNotReachHere(ex);
139129
}
140130
}
141131

142-
@Substitute
143-
private static <T> T doPrivileged(PrivilegedExceptionAction<T> action, AccessControlContext context) throws Throwable {
144-
try {
145-
return action.run();
146-
} catch (Throwable ex) {
147-
throw AccessControllerUtil.wrapCheckedException(ex);
132+
/* From JDK15's AccessController */
133+
static AccessControlContext checkContext(AccessControlContext context,
134+
Class<?> caller) {
135+
// check if caller is authorized to create context
136+
if (System.getSecurityManager() != null &&
137+
context != null && !SubstrateUtil.cast(context, Target_java_security_AccessControlContext.class).isAuthorized &&
138+
context != NO_CONTEXT_SINGLETON) {
139+
ProtectionDomain callerPD = caller.getProtectionDomain();
140+
if (callerPD != null && !callerPD.implies(SecurityConstants.CREATE_ACC_PERMISSION)) {
141+
return NO_CONTEXT_SINGLETON;
142+
}
148143
}
144+
return context;
149145
}
150146

151-
@Substitute
152-
private static void checkPermission(Permission perm) throws AccessControlException {
153-
}
147+
/* From JDK15's AccessController */
148+
@SuppressWarnings("unused")
149+
static <T> T executePrivileged(PrivilegedAction<T> action, AccessControlContext context, Class<?> caller) throws Throwable {
150+
if (action == null) {
151+
throw new NullPointerException("Null action");
152+
}
154153

155-
@Substitute
156-
private static AccessControlContext getContext() {
157-
return AccessControllerUtil.NO_CONTEXT_SINGLETON;
158-
}
154+
accStack.get().push(context);
159155

160-
@Substitute
161-
private static AccessControlContext createWrapper(DomainCombiner combiner, Class<?> caller, AccessControlContext parent, AccessControlContext context, Permission[] perms) {
162-
return AccessControllerUtil.NO_CONTEXT_SINGLETON;
156+
try {
157+
return action.run();
158+
} catch (Throwable ex) {
159+
throw wrapCheckedException(ex);
160+
} finally {
161+
if (context != null) {
162+
accStack.get().pop();
163+
}
164+
}
163165
}
164-
}
165166

166-
@InternalVMMethod
167-
class AccessControllerUtil {
167+
/* From JDK15's AccessController */
168+
@SuppressWarnings("unused")
169+
static <T> T executePrivileged(PrivilegedExceptionAction<T> action, AccessControlContext context, Class<?> caller) throws Throwable {
170+
if (action == null) {
171+
throw new NullPointerException("Null action");
172+
}
168173

169-
static final AccessControlContext NO_CONTEXT_SINGLETON;
174+
accStack.get().push(context);
170175

171-
static {
172176
try {
173-
NO_CONTEXT_SINGLETON = ReflectionUtil.lookupConstructor(AccessControlContext.class, ProtectionDomain[].class, boolean.class).newInstance(new ProtectionDomain[0], true);
174-
} catch (ReflectiveOperationException ex) {
175-
throw VMError.shouldNotReachHere(ex);
177+
return action.run();
178+
} catch (Throwable ex) {
179+
throw wrapCheckedException(ex);
180+
} finally {
181+
if (context != null) {
182+
accStack.get().pop();
183+
}
176184
}
177185
}
178186

@@ -186,6 +194,7 @@ static Throwable wrapCheckedException(Throwable ex) {
186194
}
187195

188196
@AutomaticFeature
197+
@SuppressWarnings({"unused"})
189198
class AccessControlContextFeature implements Feature {
190199
@Override
191200
public void duringSetup(DuringSetupAccess access) {
@@ -201,9 +210,14 @@ private static Object replaceAccessControlContext(Object obj) {
201210
}
202211

203212
@TargetClass(java.security.AccessControlContext.class)
213+
@SuppressWarnings({"unused"})
204214
final class Target_java_security_AccessControlContext {
205-
206215
@Alias protected boolean isPrivileged;
216+
@Alias protected boolean isAuthorized;
217+
218+
@Alias
219+
Target_java_security_AccessControlContext(ProtectionDomain[] context, AccessControlContext privilegedContext) {
220+
}
207221
}
208222

209223
@TargetClass(SecurityManager.class)
@@ -333,6 +347,7 @@ final class Target_javax_crypto_JceSecurity_IdentityWrapper {
333347
class JceSecurityAccessor {
334348
private static volatile SecureRandom RANDOM;
335349

350+
@SuppressWarnings({"unused"})
336351
static SecureRandom get() {
337352
SecureRandom result = RANDOM;
338353
if (result == null) {
@@ -430,6 +445,7 @@ final class Target_java_security_Policy_PolicyInfo {
430445
}
431446

432447
@TargetClass(java.security.Policy.class)
448+
@SuppressWarnings({"unused"})
433449
final class Target_java_security_Policy {
434450

435451
@Delete @TargetElement(onlyWith = JDK8OrEarlier.class) //
@@ -527,6 +543,7 @@ private void engineRefresh() {
527543

528544
@Delete("Substrate VM does not use SecurityManager, so loading a security policy file would be misleading")
529545
@TargetClass(className = "sun.security.provider.PolicyFile")
546+
@SuppressWarnings({"unused"})
530547
final class Target_sun_security_provider_PolicyFile {
531548
}
532549

@@ -572,5 +589,6 @@ final class Target_sun_security_jca_ProviderConfig_ProviderLoader {
572589
}
573590

574591
/** Dummy class to have a class with the file's name. */
592+
@SuppressWarnings({"unused"})
575593
public final class SecuritySubstitutions {
576594
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
*/
2525
package com.oracle.svm.core.jdk;
2626

27+
import java.security.AccessControlContext;
28+
import java.security.AccessController;
29+
import java.security.ProtectionDomain;
2730
import java.util.ArrayList;
2831

2932
import com.oracle.svm.core.thread.JavaContinuations;
@@ -33,7 +36,10 @@
3336
import org.graalvm.word.Pointer;
3437

3538
import com.oracle.svm.core.SubstrateOptions;
39+
import com.oracle.svm.core.SubstrateUtil;
40+
import com.oracle.svm.core.annotate.NeverInline;
3641
import com.oracle.svm.core.code.FrameInfoQueryResult;
42+
import com.oracle.svm.core.snippets.KnownIntrinsics;
3743
import com.oracle.svm.core.stack.JavaStackFrameVisitor;
3844
import com.oracle.svm.core.stack.JavaStackWalker;
3945

@@ -274,3 +280,67 @@ public boolean visitFrame(final FrameInfoQueryResult frameInfo) {
274280
return true;
275281
}
276282
}
283+
284+
/* Reimplementation of JVM_GetStackAccessControlContext from JDK15 */
285+
class StackAccessControlContextVisitor extends JavaStackFrameVisitor {
286+
final ArrayList<ProtectionDomain> localArray;
287+
boolean isPrivileged;
288+
ProtectionDomain previousProtectionDomain;
289+
AccessControlContext privilegedContext;
290+
291+
StackAccessControlContextVisitor() {
292+
localArray = new ArrayList<>();
293+
isPrivileged = false;
294+
privilegedContext = null;
295+
}
296+
297+
@Override
298+
public boolean visitFrame(final FrameInfoQueryResult frameInfo) {
299+
if (!StackTraceUtils.shouldShowFrame(frameInfo, true, false, false)) {
300+
return true;
301+
}
302+
303+
Class<?> clazz = frameInfo.getSourceClass();
304+
String method = frameInfo.getSourceMethodName();
305+
306+
ProtectionDomain protectionDomain = clazz.getProtectionDomain();
307+
if (clazz.equals(AccessController.class) && method.equals("doPrivileged")) {
308+
isPrivileged = true;
309+
privilegedContext = AccessControllerUtil.accStack.get().peek();
310+
}
311+
312+
if ((previousProtectionDomain == null || !previousProtectionDomain.equals(protectionDomain)) && (protectionDomain != null)) {
313+
localArray.add(protectionDomain);
314+
previousProtectionDomain = protectionDomain;
315+
}
316+
317+
FrameInfoQueryResult caller = frameInfo.getCaller();
318+
if (clazz.equals(Thread.class) && method.equals("<init>") &&
319+
caller != null && caller.getSourceClass() != null && !caller.getSourceClass().equals(clazz)) {
320+
return false; // Required since Thread.<init> resides in main thread.
321+
}
322+
323+
return !isPrivileged;
324+
}
325+
326+
@NeverInline("Starting a stack walk in the caller frame")
327+
public static AccessControlContext getFromStack() {
328+
StackAccessControlContextVisitor visitor = new StackAccessControlContextVisitor();
329+
JavaStackWalker.walkCurrentThread(KnownIntrinsics.readCallerStackPointer(), visitor);
330+
Target_java_security_AccessControlContext wrapper;
331+
332+
if (visitor.localArray.isEmpty()) {
333+
if (visitor.isPrivileged && visitor.privilegedContext == null) {
334+
return null;
335+
}
336+
wrapper = new Target_java_security_AccessControlContext(null, visitor.privilegedContext);
337+
wrapper.isPrivileged = visitor.isPrivileged;
338+
} else {
339+
wrapper = new Target_java_security_AccessControlContext(visitor.localArray.toArray(new ProtectionDomain[0]), visitor.privilegedContext);
340+
wrapper.isPrivileged = visitor.privilegedContext != null;
341+
}
342+
343+
wrapper.isAuthorized = true;
344+
return SubstrateUtil.cast(wrapper, AccessControlContext.class);
345+
}
346+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_reflect_Reflection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public final class Target_jdk_internal_reflect_Reflection {
3636

3737
@Substitute
3838
@NeverInline("Starting a stack walk in the caller frame")
39-
private static Class<?> getCallerClass() {
39+
static Class<?> getCallerClass() {
4040
return StackTraceUtils.getCallerClass(KnownIntrinsics.readCallerStackPointer(), true);
4141
}
4242

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import static com.oracle.svm.core.snippets.KnownIntrinsics.readCallerStackPointer;
2929

3030
import java.lang.Thread.UncaughtExceptionHandler;
31+
import java.security.AccessControlContext;
32+
import java.security.AccessController;
3133
import java.util.ArrayList;
3234
import java.util.HashMap;
3335
import java.util.List;
@@ -663,7 +665,6 @@ public static void dispatchUncaughtException(Thread thread, Throwable throwable)
663665
* with these unsupported features removed:
664666
* <ul>
665667
* <li>No security manager: using the ContextClassLoader of the parent.</li>
666-
* <li>Not implemented: inheritedAccessControlContext.</li>
667668
* <li>Not implemented: inheritableThreadLocals.</li>
668669
* </ul>
669670
*/
@@ -672,7 +673,8 @@ static void initializeNewThread(
672673
ThreadGroup groupArg,
673674
Runnable target,
674675
String name,
675-
long stackSize) {
676+
long stackSize,
677+
AccessControlContext acc) {
676678
if (name == null) {
677679
throw new NullPointerException("name cannot be null");
678680
}
@@ -698,6 +700,8 @@ static void initializeNewThread(
698700

699701
tjlt.contextClassLoader = parent.getContextClassLoader();
700702

703+
tjlt.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext();
704+
701705
/* Set thread ID */
702706
tjlt.tid = Target_java_lang_Thread.nextThreadID();
703707
}

0 commit comments

Comments
 (0)