Skip to content

Commit 64843f2

Browse files
Proper getStackAccessControlContext implementation
1 parent af2167a commit 64843f2

File tree

5 files changed

+164
-77
lines changed

5 files changed

+164
-77
lines changed

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

Lines changed: 81 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;
@@ -51,6 +51,7 @@
5151
import org.graalvm.word.Pointer;
5252

5353
import com.oracle.svm.core.SubstrateOptions;
54+
import com.oracle.svm.core.SubstrateUtil;
5455
import com.oracle.svm.core.annotate.Alias;
5556
import com.oracle.svm.core.annotate.AutomaticFeature;
5657
import com.oracle.svm.core.annotate.Delete;
@@ -62,6 +63,7 @@
6263
import com.oracle.svm.core.annotate.TargetElement;
6364
import com.oracle.svm.core.log.Log;
6465
import com.oracle.svm.core.option.SubstrateOptionsParser;
66+
import com.oracle.svm.core.thread.Target_java_lang_Thread;
6567
import com.oracle.svm.core.util.VMError;
6668
import com.oracle.svm.util.ReflectionUtil;
6769

@@ -80,102 +82,108 @@
8082
final class Target_java_security_AccessController {
8183

8284
@Substitute
83-
private static <T> T doPrivileged(PrivilegedAction<T> action) throws Throwable {
84-
try {
85-
return action.run();
86-
} catch (Throwable ex) {
87-
throw AccessControllerUtil.wrapCheckedException(ex);
88-
}
85+
public static <T> T doPrivileged(PrivilegedAction<T> action) throws Throwable {
86+
return AccessControllerUtil.executePrivileged(action, null, Target_jdk_internal_reflect_Reflection.getCallerClass());
8987
}
9088

9189
@Substitute
92-
private static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) throws Throwable {
93-
try {
94-
return action.run();
95-
} catch (Throwable ex) {
96-
throw AccessControllerUtil.wrapCheckedException(ex);
97-
}
90+
public static <T> T doPrivileged(PrivilegedAction<T> action, AccessControlContext context) throws Throwable {
91+
Class<?> caller = Target_jdk_internal_reflect_Reflection.getCallerClass();
92+
AccessControlContext acc = AccessControllerUtil.checkContext(context, caller);
93+
return AccessControllerUtil.executePrivileged(action, acc, caller);
9894
}
9995

10096
@Substitute
101-
private static <T> T doPrivileged(PrivilegedAction<T> action, AccessControlContext context) throws Throwable {
102-
try {
103-
return action.run();
104-
} catch (Throwable ex) {
105-
throw AccessControllerUtil.wrapCheckedException(ex);
106-
}
97+
public static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Throwable {
98+
Class<?> caller = Target_jdk_internal_reflect_Reflection.getCallerClass();
99+
return AccessControllerUtil.executePrivileged(action, null, caller);
107100
}
108101

109102
@Substitute
110-
private static <T> T doPrivileged(PrivilegedAction<T> action, AccessControlContext context, Permission... perms) throws Throwable {
111-
try {
112-
return action.run();
113-
} catch (Throwable ex) {
114-
throw AccessControllerUtil.wrapCheckedException(ex);
115-
}
103+
static <T> T doPrivileged(PrivilegedExceptionAction<T> action, AccessControlContext context) throws Throwable {
104+
Class<?> caller = Target_jdk_internal_reflect_Reflection.getCallerClass();
105+
AccessControlContext acc = AccessControllerUtil.checkContext(context, caller);
106+
return AccessControllerUtil.executePrivileged(action, acc, caller);
116107
}
117108

118109
@Substitute
119-
private static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Throwable {
120-
try {
121-
return action.run();
122-
} catch (Throwable ex) {
123-
throw AccessControllerUtil.wrapCheckedException(ex);
124-
}
110+
static AccessControlContext getStackAccessControlContext() {
111+
return StackAccessControlContextVisitor.getFromStack();
125112
}
126113

127114
@Substitute
128-
private static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action) throws Throwable {
129-
try {
130-
return action.run();
131-
} catch (Throwable ex) {
132-
throw AccessControllerUtil.wrapCheckedException(ex);
133-
}
115+
static AccessControlContext getInheritedAccessControlContext() {
116+
return SubstrateUtil.cast(Thread.currentThread(), Target_java_lang_Thread.class).inheritedAccessControlContext;
134117
}
135118

136-
@Substitute
137-
private static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action, AccessControlContext context, Permission... perms) throws Throwable {
119+
}
120+
121+
@InternalVMMethod
122+
class AccessControllerUtil {
123+
124+
static final AccessControlContext NO_CONTEXT_SINGLETON;
125+
static final ThreadLocal<Deque<AccessControlContext>> accStack = ThreadLocal.withInitial(LinkedList::new);
126+
127+
static {
138128
try {
139-
return action.run();
140-
} catch (Throwable ex) {
141-
throw AccessControllerUtil.wrapCheckedException(ex);
129+
NO_CONTEXT_SINGLETON = ReflectionUtil.lookupConstructor(AccessControlContext.class, ProtectionDomain[].class, boolean.class).newInstance(new ProtectionDomain[0], true);
130+
} catch (ReflectiveOperationException ex) {
131+
throw VMError.shouldNotReachHere(ex);
142132
}
143133
}
144134

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

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

158-
@Substitute
159-
private static AccessControlContext getContext() {
160-
return AccessControllerUtil.NO_CONTEXT_SINGLETON;
161-
}
157+
accStack.get().push(context);
162158

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

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

172-
static final AccessControlContext NO_CONTEXT_SINGLETON;
177+
accStack.get().push(context);
173178

174-
static {
175179
try {
176-
NO_CONTEXT_SINGLETON = ReflectionUtil.lookupConstructor(AccessControlContext.class, ProtectionDomain[].class, boolean.class).newInstance(new ProtectionDomain[0], true);
177-
} catch (ReflectiveOperationException ex) {
178-
throw VMError.shouldNotReachHere(ex);
180+
return action.run();
181+
} catch (Throwable ex) {
182+
throw wrapCheckedException(ex);
183+
} finally {
184+
if (context != null) {
185+
accStack.get().pop();
186+
}
179187
}
180188
}
181189

@@ -204,9 +212,14 @@ private static Object replaceAccessControlContext(Object obj) {
204212
}
205213

206214
@TargetClass(java.security.AccessControlContext.class)
215+
@SuppressWarnings({"unused"})
207216
final class Target_java_security_AccessControlContext {
208-
209217
@Alias protected boolean isPrivileged;
218+
@Alias protected boolean isAuthorized;
219+
220+
@Alias
221+
Target_java_security_AccessControlContext(ProtectionDomain[] context, AccessControlContext privilegedContext) {
222+
}
210223
}
211224

212225
@TargetClass(SecurityManager.class)

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;
@@ -636,7 +638,6 @@ public static void dispatchUncaughtException(Thread thread, Throwable throwable)
636638
* with these unsupported features removed:
637639
* <ul>
638640
* <li>No security manager: using the ContextClassLoader of the parent.</li>
639-
* <li>Not implemented: inheritedAccessControlContext.</li>
640641
* <li>Not implemented: inheritableThreadLocals.</li>
641642
* </ul>
642643
*/
@@ -645,7 +646,8 @@ static void initializeNewThread(
645646
ThreadGroup groupArg,
646647
Runnable target,
647648
String name,
648-
long stackSize) {
649+
long stackSize,
650+
AccessControlContext acc) {
649651
if (name == null) {
650652
throw new NullPointerException("name cannot be null");
651653
}
@@ -671,6 +673,8 @@ static void initializeNewThread(
671673

672674
tjlt.contextClassLoader = parent.getContextClassLoader();
673675

676+
tjlt.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext();
677+
674678
/* Set thread ID */
675679
tjlt.tid = Target_java_lang_Thread.nextThreadID();
676680
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public final class Target_java_lang_Thread {
125125
* inherit a (more or less random) access control context.
126126
*/
127127
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
128-
private AccessControlContext inheritedAccessControlContext;
128+
public AccessControlContext inheritedAccessControlContext;
129129

130130
@Alias @TargetElement(onlyWith = NotLoomJDK.class) //
131131
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = ThreadStatusRecomputation.class) //
@@ -250,7 +250,7 @@ private void init(ThreadGroup groupArg, Runnable targetArg, String nameArg, long
250250
this.unsafeParkEvent = new AtomicReference<>();
251251
this.sleepParkEvent = new AtomicReference<>();
252252
/* Initialize the rest of the Thread object. */
253-
JavaThreads.initializeNewThread(this, groupArg, targetArg, nameArg, stackSizeArg);
253+
JavaThreads.initializeNewThread(this, groupArg, targetArg, nameArg, stackSizeArg, null);
254254
}
255255

256256
@Alias
@@ -272,8 +272,8 @@ private Target_java_lang_Thread(
272272
/* Injected Target_java_lang_Thread instance field initialization. */
273273
this.unsafeParkEvent = new AtomicReference<>();
274274
this.sleepParkEvent = new AtomicReference<>();
275-
/* Initialize the rest of the Thread object, ignoring `acc` and `inheritThreadLocals`. */
276-
JavaThreads.initializeNewThread(this, g, target, name, stackSize);
275+
/* Initialize the rest of the Thread object, ignoring `inheritThreadLocals`. */
276+
JavaThreads.initializeNewThread(this, g, target, name, stackSize, acc);
277277
}
278278

279279
@Substitute
@@ -294,8 +294,8 @@ private Target_java_lang_Thread(
294294

295295
checkCharacteristics(characteristics);
296296

297-
/* Initialize the rest of the Thread object, ignoring `acc` and `characteristics`. */
298-
JavaThreads.initializeNewThread(this, g, target, name, stackSize);
297+
/* Initialize the rest of the Thread object, ignoring `characteristics`. */
298+
JavaThreads.initializeNewThread(this, g, target, name, stackSize, acc);
299299
}
300300

301301
/**

0 commit comments

Comments
 (0)