8210496: Improve filtering for classes with security sensitive fields

Reviewed-by: plevart, mchung
This commit is contained in:
Alan Bateman 2018-09-19 08:49:07 +01:00
parent a17816f881
commit 9c70e26c14
8 changed files with 138 additions and 66 deletions

View file

@ -54,6 +54,7 @@ import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -643,6 +644,10 @@ public class MethodHandles {
/** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
private final int allowedModes;
static {
Reflection.registerFieldsToFilter(Lookup.class, Set.of("lookupClass", "allowedModes"));
}
/** A single-bit mask representing {@code public} access,
* which may contribute to the result of {@link #lookupModes lookupModes}.
* The value, {@code 0x01}, happens to be the same as the value of the

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -26,6 +26,7 @@
package jdk.internal.reflect;
import java.lang.reflect.*;
import java.util.Set;
/** Provides reflective access to the constant pools of classes.
Currently this is needed to provide reflective access to annotations
@ -104,7 +105,7 @@ public class ConstantPool {
//
static {
Reflection.registerFieldsToFilter(ConstantPool.class, new String[] { "constantPoolOop" });
Reflection.registerFieldsToFilter(ConstantPool.class, Set.of("constantPoolOop"));
}
// HotSpot-internal constant pool object (set by the VM, name known to the VM)

View file

@ -25,13 +25,12 @@
package jdk.internal.reflect;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.loader.ClassLoaders;
import jdk.internal.misc.VM;
/** Common utility routines used by both java.lang and
@ -43,18 +42,23 @@ public class Reflection {
view, where they are sensitive or they may contain VM-internal objects.
These Maps are updated very rarely. Rather than synchronize on
each access, we use copy-on-write */
private static volatile Map<Class<?>,String[]> fieldFilterMap;
private static volatile Map<Class<?>,String[]> methodFilterMap;
private static volatile Map<Class<?>, Set<String>> fieldFilterMap;
private static volatile Map<Class<?>, Set<String>> methodFilterMap;
private static final String WILDCARD = "*";
public static final Set<String> ALL_MEMBERS = Set.of(WILDCARD);
static {
Map<Class<?>,String[]> map = new HashMap<Class<?>,String[]>();
map.put(Reflection.class,
new String[] {"fieldFilterMap", "methodFilterMap"});
map.put(System.class, new String[] {"security"});
map.put(Class.class, new String[] {"classLoader"});
fieldFilterMap = map;
methodFilterMap = new HashMap<>();
fieldFilterMap = Map.of(
Reflection.class, ALL_MEMBERS,
AccessibleObject.class, ALL_MEMBERS,
Class.class, Set.of("classLoader"),
ClassLoader.class, ALL_MEMBERS,
Constructor.class, ALL_MEMBERS,
Field.class, ALL_MEMBERS,
Method.class, ALL_MEMBERS,
System.class, Set.of("security")
);
methodFilterMap = Map.of();
}
/** Returns the class of the caller of the method calling this method,
@ -236,31 +240,31 @@ public class Reflection {
// fieldNames must contain only interned Strings
public static synchronized void registerFieldsToFilter(Class<?> containingClass,
String ... fieldNames) {
Set<String> fieldNames) {
fieldFilterMap =
registerFilter(fieldFilterMap, containingClass, fieldNames);
}
// methodNames must contain only interned Strings
public static synchronized void registerMethodsToFilter(Class<?> containingClass,
String ... methodNames) {
Set<String> methodNames) {
methodFilterMap =
registerFilter(methodFilterMap, containingClass, methodNames);
}
private static Map<Class<?>,String[]> registerFilter(Map<Class<?>,String[]> map,
Class<?> containingClass, String ... names) {
private static Map<Class<?>, Set<String>> registerFilter(Map<Class<?>, Set<String>> map,
Class<?> containingClass,
Set<String> names) {
if (map.get(containingClass) != null) {
throw new IllegalArgumentException
("Filter already registered: " + containingClass);
}
map = new HashMap<Class<?>,String[]>(map);
map.put(containingClass, names);
map = new HashMap<>(map);
map.put(containingClass, Set.copyOf(names));
return map;
}
public static Field[] filterFields(Class<?> containingClass,
Field[] fields) {
public static Field[] filterFields(Class<?> containingClass, Field[] fields) {
if (fieldFilterMap == null) {
// Bootstrapping
return fields;
@ -276,35 +280,24 @@ public class Reflection {
return (Method[])filter(methods, methodFilterMap.get(containingClass));
}
private static Member[] filter(Member[] members, String[] filteredNames) {
private static Member[] filter(Member[] members, Set<String> filteredNames) {
if ((filteredNames == null) || (members.length == 0)) {
return members;
}
Class<?> memberType = members[0].getClass();
if (filteredNames.contains(WILDCARD)) {
return (Member[]) Array.newInstance(memberType, 0);
}
int numNewMembers = 0;
for (Member member : members) {
boolean shouldSkip = false;
for (String filteredName : filteredNames) {
if (member.getName() == filteredName) {
shouldSkip = true;
break;
}
}
if (!shouldSkip) {
if (!filteredNames.contains(member.getName())) {
++numNewMembers;
}
}
Member[] newMembers =
(Member[])Array.newInstance(members[0].getClass(), numNewMembers);
Member[] newMembers = (Member[])Array.newInstance(memberType, numNewMembers);
int destIdx = 0;
for (Member member : members) {
boolean shouldSkip = false;
for (String filteredName : filteredNames) {
if (member.getName() == filteredName) {
shouldSkip = true;
break;
}
}
if (!shouldSkip) {
if (!filteredNames.contains(member.getName())) {
newMembers[destIdx++] = member;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -28,6 +28,8 @@ package jdk.internal.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.util.Set;
import jdk.internal.misc.Unsafe;
/** Base class for jdk.internal.misc.Unsafe-based FieldAccessors for static
@ -40,7 +42,7 @@ import jdk.internal.misc.Unsafe;
abstract class UnsafeStaticFieldAccessorImpl extends UnsafeFieldAccessorImpl {
static {
Reflection.registerFieldsToFilter(UnsafeStaticFieldAccessorImpl.class,
new String[] { "base" });
Set.of("base"));
}
protected final Object base; // base