Skip to content

Commit a4c1501

Browse files
Proper getStackAccessControlContext implementation
1 parent 4794b8c commit a4c1501

File tree

5 files changed

+150
-76
lines changed

5 files changed

+150
-76
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;
@@ -61,6 +62,7 @@
6162
import com.oracle.svm.core.annotate.TargetElement;
6263
import com.oracle.svm.core.log.Log;
6364
import com.oracle.svm.core.option.SubstrateOptionsParser;
65+
import com.oracle.svm.core.thread.Target_java_lang_Thread;
6466
import com.oracle.svm.core.util.VMError;
6567
import com.oracle.svm.util.ReflectionUtil;
6668

@@ -79,102 +81,108 @@
7981
final class Target_java_security_AccessController {
8082

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

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

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

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

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

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

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

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

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

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

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

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

171-
static final AccessControlContext NO_CONTEXT_SINGLETON;
176+
accStack.get().push(context);
172177

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

@@ -203,9 +211,14 @@ private static Object replaceAccessControlContext(Object obj) {
203211
}
204212

205213
@TargetClass(java.security.AccessControlContext.class)
214+
@SuppressWarnings({"unused"})
206215
final class Target_java_security_AccessControlContext {
207-
208216
@Alias protected boolean isPrivileged;
217+
@Alias protected boolean isAuthorized;
218+
219+
@Alias
220+
Target_java_security_AccessControlContext(ProtectionDomain[] context, AccessControlContext privilegedContext) {
221+
}
209222
}
210223

211224
@TargetClass(SecurityManager.class)

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,20 @@
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

32+
import com.oracle.svm.core.annotate.NeverInline;
2933
import org.graalvm.nativeimage.IsolateThread;
3034
import org.graalvm.util.DirectAnnotationAccess;
3135
import org.graalvm.word.Pointer;
3236

3337
import com.oracle.svm.core.SubstrateOptions;
38+
import com.oracle.svm.core.SubstrateUtil;
3439
import com.oracle.svm.core.code.FrameInfoQueryResult;
40+
import com.oracle.svm.core.snippets.KnownIntrinsics;
3541
import com.oracle.svm.core.stack.JavaStackFrameVisitor;
3642
import com.oracle.svm.core.stack.JavaStackWalker;
3743

@@ -263,3 +269,54 @@ public boolean visitFrame(final FrameInfoQueryResult frameInfo) {
263269
return true;
264270
}
265271
}
272+
273+
/* Reimplementation of JVM_GetStackAccessControlContext from JDK15 */
274+
class StackAccessControlContextVisitor extends JavaStackFrameVisitor {
275+
final ArrayList<ProtectionDomain> localArray;
276+
boolean isPrivileged;
277+
ProtectionDomain previousProtectionDomain;
278+
AccessControlContext privilegedContext;
279+
280+
StackAccessControlContextVisitor() {
281+
localArray = new ArrayList<>();
282+
isPrivileged = false;
283+
}
284+
285+
@Override
286+
public boolean visitFrame(final FrameInfoQueryResult frameInfo) {
287+
Class<?> clazz = frameInfo.getSourceClass();
288+
ProtectionDomain protectionDomain = clazz.getProtectionDomain();
289+
if (clazz.equals(AccessController.class) && frameInfo.getSourceMethodName().equals("doPrivileged")) {
290+
isPrivileged = true;
291+
privilegedContext = AccessControllerUtil.accStack.get().peek();
292+
}
293+
294+
if ((previousProtectionDomain == null || !previousProtectionDomain.equals(protectionDomain)) && (protectionDomain != null)) {
295+
localArray.add(protectionDomain);
296+
previousProtectionDomain = protectionDomain;
297+
}
298+
299+
return !isPrivileged;
300+
}
301+
302+
@NeverInline("Starting a stack walk in the caller frame")
303+
public static AccessControlContext getFromStack() {
304+
StackAccessControlContextVisitor visitor = new StackAccessControlContextVisitor();
305+
JavaStackWalker.walkCurrentThread(KnownIntrinsics.readCallerStackPointer(), visitor);
306+
Target_java_security_AccessControlContext wrapper;
307+
308+
if (visitor.localArray.isEmpty()) {
309+
if (visitor.isPrivileged && visitor.privilegedContext == null) {
310+
return null;
311+
}
312+
wrapper = new Target_java_security_AccessControlContext(new ProtectionDomain[0], visitor.privilegedContext);
313+
wrapper.isPrivileged = visitor.isPrivileged;
314+
} else {
315+
wrapper = new Target_java_security_AccessControlContext(visitor.localArray.toArray(new ProtectionDomain[0]), visitor.privilegedContext);
316+
wrapper.isPrivileged = visitor.privilegedContext != null;
317+
}
318+
319+
wrapper.isAuthorized = true;
320+
return SubstrateUtil.cast(wrapper, AccessControlContext.class);
321+
}
322+
}

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;
@@ -634,7 +636,6 @@ public static void dispatchUncaughtException(Thread thread, Throwable throwable)
634636
* with these unsupported features removed:
635637
* <ul>
636638
* <li>No security manager: using the ContextClassLoader of the parent.</li>
637-
* <li>Not implemented: inheritedAccessControlContext.</li>
638639
* <li>Not implemented: inheritableThreadLocals.</li>
639640
* </ul>
640641
*/
@@ -643,7 +644,8 @@ static void initializeNewThread(
643644
ThreadGroup groupArg,
644645
Runnable target,
645646
String name,
646-
long stackSize) {
647+
long stackSize,
648+
AccessControlContext acc) {
647649
if (name == null) {
648650
throw new NullPointerException("name cannot be null");
649651
}
@@ -664,6 +666,8 @@ static void initializeNewThread(
664666
/* Stash the specified stack size in case the VM cares */
665667
tjlt.stackSize = stackSize;
666668

669+
tjlt.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext();
670+
667671
/* Set thread ID */
668672
tjlt.tid = Target_java_lang_Thread.nextThreadID();
669673
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050

5151
@TargetClass(Thread.class)
5252
@SuppressWarnings({"unused"})
53-
final class Target_java_lang_Thread {
53+
public final class Target_java_lang_Thread {
5454

5555
/** Every thread has a boolean for noting whether this thread is interrupted. */
5656
@Inject @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)//
@@ -114,7 +114,7 @@ final class Target_java_lang_Thread {
114114
* inherit a (more or less random) access control context.
115115
*/
116116
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
117-
private AccessControlContext inheritedAccessControlContext;
117+
public AccessControlContext inheritedAccessControlContext;
118118

119119
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = ThreadStatusRecomputation.class) //
120120
volatile int threadStatus;
@@ -182,7 +182,7 @@ private void init(ThreadGroup groupArg, Runnable targetArg, String nameArg, long
182182
this.unsafeParkEvent = new AtomicReference<>();
183183
this.sleepParkEvent = new AtomicReference<>();
184184
/* Initialize the rest of the Thread object. */
185-
JavaThreads.initializeNewThread(this, groupArg, targetArg, nameArg, stackSizeArg);
185+
JavaThreads.initializeNewThread(this, groupArg, targetArg, nameArg, stackSizeArg, null);
186186
}
187187

188188
@Substitute
@@ -200,8 +200,8 @@ private Target_java_lang_Thread(
200200
/* Injected Target_java_lang_Thread instance field initialization. */
201201
this.unsafeParkEvent = new AtomicReference<>();
202202
this.sleepParkEvent = new AtomicReference<>();
203-
/* Initialize the rest of the Thread object, ignoring `acc` and `inheritThreadLocals`. */
204-
JavaThreads.initializeNewThread(this, g, target, name, stackSize);
203+
/* Initialize the rest of the Thread object, ignoring `inheritThreadLocals`. */
204+
JavaThreads.initializeNewThread(this, g, target, name, stackSize, acc);
205205
}
206206

207207
@Substitute

0 commit comments

Comments
 (0)