undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
454
test/jdk/java/lang/reflect/AccessControl/AccessControlTest.java
Normal file
454
test/jdk/java/lang/reflect/AccessControl/AccessControlTest.java
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
import util.ClassSupplier;
|
||||
import util.MemberFactory;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.mapping;
|
||||
import static java.util.stream.Collectors.toCollection;
|
||||
import static util.MemberFactory.*;
|
||||
import static util.MemberFactory.Group.*;
|
||||
import static util.ClassSupplier.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary An exhaustive test of reflective access controls
|
||||
* @bug 6378384
|
||||
* @build a.PublicSuper a.Package b.PublicSub b.Package
|
||||
* util.MemberFactory util.ClassSupplier
|
||||
* @run main AccessControlTest
|
||||
*/
|
||||
public class AccessControlTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean ok = true;
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_A)
|
||||
.member (PACKAGE_CLASS_IN_PKG_A).target(PACKAGE_CLASS_IN_PKG_A)
|
||||
.allowed(ALL)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_A)
|
||||
.member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_A)
|
||||
.member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_A)
|
||||
.member (PACKAGE_CLASS_IN_PKG_B).target(PACKAGE_CLASS_IN_PKG_B)
|
||||
.denied (ALL)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_A)
|
||||
.member (PUBLIC_SUBCLASS_IN_PKG_B).target(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.allowed(PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.member (PACKAGE_CLASS_IN_PKG_A).target(PACKAGE_CLASS_IN_PKG_A)
|
||||
.allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.allowed(ALL)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.allowed(ALL)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.member (PACKAGE_CLASS_IN_PKG_B).target(PACKAGE_CLASS_IN_PKG_B)
|
||||
.denied (ALL)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.member (PUBLIC_SUBCLASS_IN_PKG_B).target(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.allowed(PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_B)
|
||||
.member (PACKAGE_CLASS_IN_PKG_A).target(PACKAGE_CLASS_IN_PKG_A)
|
||||
.denied (ALL)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_B)
|
||||
.member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.allowed(PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_B)
|
||||
.member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.allowed(PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_B)
|
||||
.member (PACKAGE_CLASS_IN_PKG_B).target(PACKAGE_CLASS_IN_PKG_B)
|
||||
.allowed(ALL)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PACKAGE_CLASS_IN_PKG_B)
|
||||
.member (PUBLIC_SUBCLASS_IN_PKG_B).target(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.member (PACKAGE_CLASS_IN_PKG_A).target(PACKAGE_CLASS_IN_PKG_A)
|
||||
.denied (ALL)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUPERCLASS_IN_PKG_A)
|
||||
.allowed(PUBLIC_MEMBERS, PROTECTED_STATIC_F_M)
|
||||
.denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_INSTANCE_F_M,
|
||||
PROTECTED_C)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.allowed(PUBLIC_MEMBERS, PROTECTED_INSTANCE_F_M, PROTECTED_STATIC_F_M)
|
||||
.denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_C)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.member (PACKAGE_CLASS_IN_PKG_B).target(PACKAGE_CLASS_IN_PKG_B)
|
||||
.allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
|
||||
.denied (PRIVATE_MEMBERS)
|
||||
.perform();
|
||||
|
||||
ok &= new Test()
|
||||
.current(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.member (PUBLIC_SUBCLASS_IN_PKG_B).target(PUBLIC_SUBCLASS_IN_PKG_B)
|
||||
.allowed(ALL)
|
||||
.perform();
|
||||
|
||||
if (ok) {
|
||||
System.out.println("\nAll cases passed.");
|
||||
} else {
|
||||
throw new RuntimeException("Some cases failed - see log.");
|
||||
}
|
||||
}
|
||||
|
||||
// use this for generating an exhaustive set of test cases on stdout
|
||||
public static class Generate {
|
||||
public static void main(String[] args) {
|
||||
for (ClassSupplier current : ClassSupplier.values()) {
|
||||
for (ClassSupplier member : ClassSupplier.values()) {
|
||||
for (ClassSupplier target : ClassSupplier.values()) {
|
||||
if (member.get().isAssignableFrom(target.get())) {
|
||||
new Test()
|
||||
.current(current).member(member).target(target)
|
||||
.allowed(ALL)
|
||||
.perform(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Test {
|
||||
|
||||
ClassSupplier currentClassSupplier, memberClassSupplier, targetClassSupplier;
|
||||
EnumSet<MemberFactory> expectAllowedMembers = EnumSet.noneOf(MemberFactory.class);
|
||||
EnumSet<MemberFactory> expectDeniedMembers = EnumSet.noneOf(MemberFactory.class);
|
||||
|
||||
Test current(ClassSupplier current) {
|
||||
currentClassSupplier = current;
|
||||
return this;
|
||||
}
|
||||
|
||||
Test member(ClassSupplier member) {
|
||||
memberClassSupplier = member;
|
||||
return this;
|
||||
}
|
||||
|
||||
Test target(ClassSupplier target) {
|
||||
targetClassSupplier = target;
|
||||
return this;
|
||||
}
|
||||
|
||||
Test allowed(MemberFactory... allowed) {
|
||||
expectAllowedMembers = MemberFactory.asSet(allowed);
|
||||
return this;
|
||||
}
|
||||
|
||||
Test allowed(MemberFactory.Group... allowedGroups) {
|
||||
expectAllowedMembers = MemberFactory.groupsToMembers(
|
||||
MemberFactory.Group.asSet(allowedGroups));
|
||||
return this;
|
||||
}
|
||||
|
||||
Test denied(MemberFactory... denied) {
|
||||
expectDeniedMembers = MemberFactory.asSet(denied);
|
||||
return this;
|
||||
}
|
||||
|
||||
Test denied(MemberFactory.Group... deniedGroups) {
|
||||
expectDeniedMembers = MemberFactory.groupsToMembers(
|
||||
MemberFactory.Group.asSet(deniedGroups));
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean perform() {
|
||||
return perform(false);
|
||||
}
|
||||
|
||||
boolean perform(boolean generateCases) {
|
||||
|
||||
// some validation 1st
|
||||
EnumSet<MemberFactory> intersection = EnumSet.copyOf(expectAllowedMembers);
|
||||
intersection.retainAll(expectDeniedMembers);
|
||||
if (!intersection.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expected allowed and denied MemberFactories have non-empty intersection: " +
|
||||
intersection);
|
||||
}
|
||||
|
||||
EnumSet<MemberFactory> missing = EnumSet.allOf(MemberFactory.class);
|
||||
missing.removeAll(expectAllowedMembers);
|
||||
missing.removeAll(expectDeniedMembers);
|
||||
if (!missing.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Union of expected allowed and denied MemberFactories is missing elements: " +
|
||||
missing);
|
||||
}
|
||||
|
||||
// retrieve method that will perform reflective access
|
||||
Method checkAccessMethod;
|
||||
try {
|
||||
checkAccessMethod = currentClassSupplier.get().getDeclaredMethod(
|
||||
"checkAccess", AccessibleObject.class, Object.class);
|
||||
// in case of inaccessible currentClass
|
||||
checkAccessMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// construct a target object (for instance field/method)
|
||||
Object target;
|
||||
Constructor<?> targetConstructor =
|
||||
(Constructor<?>) PUBLIC_CONSTRUCTOR.apply(targetClassSupplier.get());
|
||||
// in case of inaccessible targetClass
|
||||
targetConstructor.setAccessible(true);
|
||||
try {
|
||||
target = targetConstructor.newInstance(
|
||||
new Object[targetConstructor.getParameterCount()]);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Class<?> memberClass = memberClassSupplier.get();
|
||||
|
||||
Map<Boolean, EnumSet<MemberFactory>> actualMembers = Stream.concat(
|
||||
|
||||
expectAllowedMembers.stream().map(member -> new Trial(member, true)),
|
||||
expectDeniedMembers.stream().map(member -> new Trial(member, false))
|
||||
|
||||
).map(trial -> {
|
||||
|
||||
// obtain AccessibleObject to be used to perform reflective access
|
||||
AccessibleObject accessibleObject = trial.member.apply(memberClass);
|
||||
|
||||
// only need target 'obj' for instance fields and methods
|
||||
Object obj =
|
||||
(accessibleObject instanceof Field &&
|
||||
!Modifier.isStatic(((Field) accessibleObject).getModifiers())
|
||||
||
|
||||
accessibleObject instanceof Method &&
|
||||
!Modifier.isStatic(((Method) accessibleObject).getModifiers())
|
||||
)
|
||||
? target : null;
|
||||
|
||||
// invoke checkAccess method and let it perform the reflective access
|
||||
try {
|
||||
checkAccessMethod.invoke(null, accessibleObject, obj);
|
||||
trial.actualAllowed = true;
|
||||
} catch (IllegalAccessException e) {
|
||||
// should not happen as checkAccessMethod.isAccessible()
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof IllegalAccessException) {
|
||||
trial.actualAllowed = false;
|
||||
} else {
|
||||
// any other Exception is a fault in test or infrastructure - fail fast
|
||||
throw new RuntimeException(e.getTargetException());
|
||||
}
|
||||
}
|
||||
|
||||
if (!generateCases) {
|
||||
System.out.printf(
|
||||
"%-26s accessing %26s's %-25s %-43s - expected %s, actual %s: %s\n",
|
||||
currentClassSupplier, memberClassSupplier, trial.member.name(),
|
||||
(obj == null ? "" : "with instance of " + targetClassSupplier),
|
||||
(trial.expectAllowed ? "allowed" : "denied "),
|
||||
(trial.actualAllowed ? "allowed" : "denied "),
|
||||
(trial.expectAllowed == trial.actualAllowed ? "OK" : "FAILURE")
|
||||
);
|
||||
}
|
||||
|
||||
return trial;
|
||||
|
||||
}).collect(
|
||||
groupingBy(
|
||||
Trial::isActualAllowed,
|
||||
mapping(
|
||||
Trial::getMember,
|
||||
toCollection(() -> EnumSet.noneOf(MemberFactory.class))))
|
||||
);
|
||||
|
||||
EnumSet<MemberFactory> actualAllowedMembers =
|
||||
Optional.ofNullable(actualMembers.get(true))
|
||||
.orElse(EnumSet.noneOf(MemberFactory.class));
|
||||
EnumSet<MemberFactory> actualDeniedMembers =
|
||||
Optional.ofNullable(actualMembers.get(false))
|
||||
.orElse(EnumSet.noneOf(MemberFactory.class));
|
||||
|
||||
if (generateCases) {
|
||||
System.out.printf(
|
||||
" ok &= new Test()\n" +
|
||||
" .current(%s)\n" +
|
||||
" .member (%s).target(%s)\n",
|
||||
currentClassSupplier,
|
||||
memberClassSupplier, targetClassSupplier
|
||||
);
|
||||
|
||||
if (!actualAllowedMembers.isEmpty()) {
|
||||
EnumSet<? extends Enum> actualAllowed =
|
||||
MemberFactory.membersToGroupsOrNull(actualAllowedMembers);
|
||||
if (actualAllowed == null)
|
||||
actualAllowed = actualAllowedMembers;
|
||||
System.out.print(
|
||||
chunkBy(3, actualAllowed.stream().map(Enum::name))
|
||||
.map(chunk -> chunk.collect(joining(", ")))
|
||||
.collect(joining(",\n" +
|
||||
" ",
|
||||
" .allowed(",
|
||||
")\n"))
|
||||
);
|
||||
}
|
||||
|
||||
if (!actualDeniedMembers.isEmpty()) {
|
||||
EnumSet<? extends Enum> actualDenied =
|
||||
MemberFactory.membersToGroupsOrNull(actualDeniedMembers);
|
||||
if (actualDenied == null)
|
||||
actualDenied = actualAllowedMembers;
|
||||
System.out.print(
|
||||
chunkBy(3, actualDenied.stream().map(Enum::name))
|
||||
.map(chunk -> chunk.collect(joining(", ")))
|
||||
.collect(joining(",\n" +
|
||||
" ",
|
||||
" .denied (",
|
||||
")\n"))
|
||||
);
|
||||
}
|
||||
|
||||
System.out.print(
|
||||
" .perform();\n"
|
||||
);
|
||||
}
|
||||
|
||||
return expectAllowedMembers.equals(actualAllowedMembers) &&
|
||||
expectDeniedMembers.equals(actualDeniedMembers);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> Stream<Stream<T>> chunkBy(int chunkSize, Stream<T> stream) {
|
||||
Iterator<T> elements = stream.iterator();
|
||||
Stream.Builder<Stream<T>> b1 = Stream.builder();
|
||||
while (elements.hasNext()) {
|
||||
Stream.Builder<T> b2 = Stream.builder();
|
||||
for (int i = 0; i < chunkSize && elements.hasNext(); i++) {
|
||||
b2.accept(elements.next());
|
||||
}
|
||||
b1.accept(b2.build());
|
||||
}
|
||||
return b1.build();
|
||||
}
|
||||
|
||||
private static class Trial {
|
||||
final MemberFactory member;
|
||||
final boolean expectAllowed;
|
||||
boolean actualAllowed;
|
||||
|
||||
Trial(MemberFactory member, boolean expectAllowed) {
|
||||
this.member = member;
|
||||
this.expectAllowed = expectAllowed;
|
||||
}
|
||||
|
||||
MemberFactory getMember() {
|
||||
return member;
|
||||
}
|
||||
|
||||
boolean isActualAllowed() {
|
||||
return actualAllowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue