mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8210496: Improve filtering for classes with security sensitive fields
Reviewed-by: plevart, mchung
This commit is contained in:
parent
a17816f881
commit
9c70e26c14
8 changed files with 138 additions and 66 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue