8214583: AccessController.getContext may return wrong value after JDK-8212605

Reviewed-by: mchung, redestad
This commit is contained in:
Dean Long 2018-12-18 16:36:26 -08:00
parent ad47b4c4cc
commit 57dc039131
6 changed files with 167 additions and 4 deletions
src
hotspot/share
include
prims
java.base/share
classes/java/security
native/libjava
test/jdk
java/security/AccessController
javax/security/auth/Subject

@ -625,6 +625,15 @@ JVM_GetMethodParameters(JNIEnv *env, jobject method);
JNIEXPORT jobject JNICALL
JVM_GetInheritedAccessControlContext(JNIEnv *env, jclass cls);
/*
* Ensure that code doing a stackwalk and using javaVFrame::locals() to
* get the value will see a materialized value and not a scalar-replaced
* null value.
*/
#define JVM_EnsureMaterializedForStackWalk(env, value) \
do {} while(0) // Nothing to do. The fact that the value escaped
// through a native method is enough.
JNIEXPORT jobject JNICALL
JVM_GetStackAccessControlContext(JNIEnv *env, jclass cls);

@ -61,6 +61,7 @@
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jfieldIDWorkaround.hpp"
@ -1245,8 +1246,12 @@ JVM_ENTRY(jobject, JVM_GetStackAccessControlContext(JNIEnv *env, jclass cls))
javaVFrame *priv = vfst.asJavaVFrame(); // executePrivileged
StackValueCollection* locals = priv->locals();
privileged_context = locals->obj_at(1);
Handle caller = locals->obj_at(2);
StackValue* ctx_sv = locals->at(1); // AccessControlContext context
StackValue* clr_sv = locals->at(2); // Class<?> caller
assert(!ctx_sv->obj_is_scalar_replaced(), "found scalar-replaced object");
assert(!clr_sv->obj_is_scalar_replaced(), "found scalar-replaced object");
privileged_context = ctx_sv->get_obj();
Handle caller = clr_sv->get_obj();
Klass *caller_klass = java_lang_Class::as_Klass(caller());
protection_domain = caller_klass->protection_domain();

@ -709,6 +709,13 @@ public final class AccessController {
return context;
}
/**
* The value needs to be physically located in the frame, so that it
* can be found by a stack walk.
*/
@Hidden
private static native void ensureMaterializedForStackWalk(Object o);
/**
* Sanity check that the caller context is indeed privileged.
*
@ -734,6 +741,11 @@ public final class AccessController {
AccessControlContext context,
Class<?> caller)
{
// Ensure context has a physical value in the frame
if (context != null) {
ensureMaterializedForStackWalk(context);
}
assert isPrivileged(); // sanity check invariant
T result = action.run();
assert isPrivileged(); // sanity check invariant
@ -742,7 +754,6 @@ public final class AccessController {
// retrieved by getStackAccessControlContext().
Reference.reachabilityFence(context);
Reference.reachabilityFence(caller);
Reference.reachabilityFence(action);
return result;
}
@ -761,6 +772,11 @@ public final class AccessController {
Class<?> caller)
throws Exception
{
// Ensure context has a physical value in the frame
if (context != null) {
ensureMaterializedForStackWalk(context);
}
assert isPrivileged(); // sanity check invariant
T result = action.run();
assert isPrivileged(); // sanity check invariant
@ -769,7 +785,6 @@ public final class AccessController {
// retrieved by getStackAccessControlContext().
Reference.reachabilityFence(context);
Reference.reachabilityFence(caller);
Reference.reachabilityFence(action);
return result;
}

@ -59,3 +59,12 @@ Java_java_security_AccessController_getInheritedAccessControlContext(
{
return JVM_GetInheritedAccessControlContext(env, this);
}
JNIEXPORT void JNICALL
Java_java_security_AccessController_ensureMaterializedForStackWalk(
JNIEnv *env,
jclass cls,
jobject value)
{
JVM_EnsureMaterializedForStackWalk(env, value);
}

@ -0,0 +1,68 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8214583
* @summary Check that getContext works after JIT compiler escape analysis.
*/
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.DomainCombiner;
import java.security.ProtectionDomain;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.net.URL;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class DoPriv {
static void go(final DomainCombiner dc0, final AccessControlContext co, final int index) throws Exception {
final AccessControlContext ci = new AccessControlContext(co, dc0);
AccessController.doPrivileged((PrivilegedExceptionAction<Integer>)() -> {
AccessControlContext c1 = AccessController.getContext();
DomainCombiner dc = c1.getDomainCombiner();
if (dc != dc0 || dc == null) {
throw new AssertionError("iteration " + index + " " + dc + " != " + dc0);
}
return 0;
}, ci);
}
public static void main(String[] args) throws Exception {
final DomainCombiner dc0 = new DomainCombiner() {
public ProtectionDomain[] combine(ProtectionDomain[] currentDomains,
ProtectionDomain[] assignedDomains) {
return null;
}
};
final AccessControlContext co = AccessController.getContext();
for (int i = 0; i < 500_000; ++i) {
go(dc0, co, i);
}
}
}

@ -0,0 +1,57 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8214583
* @summary Check that getSubject works after JIT compiler escape analysis.
*/
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.security.auth.Subject;
public class DoAs {
public static void main(String[] args) throws Exception {
final Set<String> outer = new HashSet<>(Arrays.asList("Outer"));
final Subject subject = new Subject(true, Collections.EMPTY_SET, outer, Collections.EMPTY_SET);
for (int i = 0; i < 100_000; ++i) {
final int index = i;
Subject.doAs(subject, (PrivilegedExceptionAction<Integer>)() -> {
AccessControlContext c1 = AccessController.getContext();
Subject s = Subject.getSubject(c1);
if (s != subject) {
throw new AssertionError("outer Oops! " + "iteration " + index + " " + s + " != " + subject);
}
return 0;
});
}
}
}