1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.FilePermission; 25 import java.io.IOException; 26 import java.lang.reflect.Field; 27 import java.lang.reflect.ReflectPermission; 28 import java.net.URI; 29 import java.nio.file.FileSystem; 30 import java.nio.file.FileSystems; 31 import java.nio.file.Files; 32 import java.nio.file.Path; 33 import java.security.CodeSource; 34 import java.security.Permission; 35 import java.security.PermissionCollection; 36 import java.security.Permissions; 37 import java.security.Policy; 38 import java.security.ProtectionDomain; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.Collections; 42 import java.util.Enumeration; 43 import java.util.Iterator; 44 import java.util.List; 45 import java.util.PropertyPermission; 46 import java.util.concurrent.atomic.AtomicBoolean; 47 import java.util.concurrent.atomic.AtomicLong; 48 import java.util.stream.Stream; 49 50 /** 51 * @test 52 * @bug 8065552 53 * @summary test that all fields returned by getDeclaredFields() can be 54 * set accessible if the right permission is granted; this test 55 * loads all the classes in the BCL, get their declared fields, 56 * and call setAccessible(false) followed by setAccessible(true); 57 * @run main/othervm FieldSetAccessibleTest UNSECURE 58 * @run main/othervm FieldSetAccessibleTest SECURE 59 * 60 * @author danielfuchs 61 */ 62 public class FieldSetAccessibleTest { 63 64 static final List<String> skipped = new ArrayList<>(); 65 static final List<String> cantread = new ArrayList<>(); 66 static final List<String> failed = new ArrayList<>(); 67 static final AtomicLong classCount = new AtomicLong(); 68 static final AtomicLong fieldCount = new AtomicLong(); 69 static long startIndex = 0; 70 static long maxSize = Long.MAX_VALUE; 71 static long maxIndex = Long.MAX_VALUE; 72 static final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); 73 74 75 // Test that all fields for any given class can be made accessibles 76 static void testSetFieldsAccessible(Class<?> c) { 77 for (Field f : c.getDeclaredFields()) { 78 fieldCount.incrementAndGet(); 79 f.setAccessible(false); 80 f.setAccessible(true); 81 } 82 } 83 84 // Performs a series of test on the given class. 85 // At this time, we only call testSetFieldsAccessible(c) 86 public static boolean test(Class<?> c) { 87 //System.out.println(c.getName()); 88 classCount.incrementAndGet(); 89 90 // Call getDeclaredFields() and try to set their accessible flag. 91 testSetFieldsAccessible(c); 92 93 // add more tests here... 94 95 return c == Class.class; 96 } 97 98 // Prints a summary at the end of the test. 99 static void printSummary(long secs, long millis, long nanos) { 100 System.out.println("Tested " + fieldCount.get() + " fields of " 101 + classCount.get() + " classes in " 102 + secs + "s " + millis + "ms " + nanos + "ns"); 103 } 104 105 106 /** 107 * @param args the command line arguments: 108 * 109 * SECURE|UNSECURE [startIndex (default=0)] [maxSize (default=Long.MAX_VALUE)] 110 * 111 * @throws java.lang.Exception if the test fails 112 */ 113 public static void main(String[] args) throws Exception { 114 if (args == null || args.length == 0) { 115 args = new String[] {"SECURE", "0"}; 116 } else if (args.length > 3) { 117 throw new RuntimeException("Expected at most one argument. Found " 118 + Arrays.asList(args)); 119 } 120 try { 121 if (args.length > 1) { 122 startIndex = Long.parseLong(args[1]); 123 if (startIndex < 0) { 124 throw new IllegalArgumentException("startIndex args[1]: " 125 + startIndex); 126 } 127 } 128 if (args.length > 2) { 129 maxSize = Long.parseLong(args[2]); 130 if (maxSize <= 0) { 131 maxSize = Long.MAX_VALUE; 132 } 133 maxIndex = (Long.MAX_VALUE - startIndex) < maxSize 134 ? Long.MAX_VALUE : startIndex + maxSize; 135 } 136 TestCase.valueOf(args[0]).run(); 137 } catch (OutOfMemoryError oome) { 138 System.err.println(classCount.get()); 139 throw oome; 140 } 141 } 142 143 public static void run(TestCase test) { 144 System.out.println("Testing " + test); 145 test(listAllClassNames()); 146 System.out.println("Passed " + test); 147 } 148 149 static Iterable<String> listAllClassNames() { 150 return new ClassNameJrtStreamBuilder(); 151 } 152 153 static void test(Iterable<String> iterable) { 154 final long start = System.nanoTime(); 155 boolean classFound = false; 156 int index = 0; 157 for (String s: iterable) { 158 if (index == maxIndex) break; 159 try { 160 if (index < startIndex) continue; 161 if (test(s)) { 162 classFound = true; 163 } 164 } finally { 165 index++; 166 } 167 } 168 long elapsed = System.nanoTime() - start; 169 long secs = elapsed / 1000_000_000; 170 long millis = (elapsed % 1000_000_000) / 1000_000; 171 long nanos = elapsed % 1000_000; 172 System.out.println("Unreadable path elements: " + cantread); 173 System.out.println("Skipped path elements: " + skipped); 174 System.out.println("Failed path elements: " + failed); 175 printSummary(secs, millis, nanos); 176 177 if (!failed.isEmpty()) { 178 throw new RuntimeException("Test failed for the following classes: " + failed); 179 } 180 if (!classFound && startIndex == 0 && index < maxIndex) { 181 // this is just to verify that we have indeed parsed rt.jar 182 // (or the java.base module) 183 throw new RuntimeException("Test failed: Class.class not found..."); 184 } 185 if (classCount.get() == 0 && startIndex == 0) { 186 throw new RuntimeException("Test failed: no class found?"); 187 } 188 } 189 190 static boolean test(String s) { 191 try { 192 if (s.startsWith("WrapperGenerator")) { 193 System.out.println("Skipping "+ s); 194 return false; 195 } 196 final Class<?> c = Class.forName( 197 s.replace('/', '.').substring(0, s.length() - 6), 198 false, 199 systemClassLoader); 200 return test(c); 201 } catch (Exception t) { 202 t.printStackTrace(System.err); 203 failed.add(s); 204 } catch (NoClassDefFoundError e) { 205 e.printStackTrace(System.err); 206 failed.add(s); 207 } 208 return false; 209 } 210 211 static class ClassNameJrtStreamBuilder implements Iterable<String>{ 212 213 final FileSystem jrt; 214 final List<Path> roots = new ArrayList<>(); 215 ClassNameJrtStreamBuilder() { 216 jrt = FileSystems.getFileSystem(URI.create("jrt:/")); 217 for (Path root : jrt.getRootDirectories()) { 218 roots.add(root); 219 } 220 } 221 222 Stream<String> build() { 223 return roots.stream().flatMap(this::toStream) 224 .filter(x -> x.getNameCount() > 2) 225 .map( x-> x.subpath(2, x.getNameCount())) 226 .map( x -> x.toString()) 227 .filter(s -> s.endsWith(".class")); 228 } 229 230 @Override 231 public Iterator<String> iterator() { 232 return build().iterator(); 233 } 234 235 private Stream<Path> toStream(Path root) { 236 try { 237 return Files.walk(root); 238 } catch(IOException x) { 239 x.printStackTrace(System.err); 240 skipped.add(root.toString()); 241 } 242 return Collections.<Path>emptyList().stream(); 243 } 244 245 } 246 247 // Test with or without a security manager 248 public static enum TestCase { 249 UNSECURE, SECURE; 250 public void run() throws Exception { 251 System.out.println("Running test case: " + name()); 252 Configure.setUp(this); 253 FieldSetAccessibleTest.run(this); 254 } 255 } 256 257 // A helper class to configure the security manager for the test, 258 // and bypass it when needed. 259 static class Configure { 260 static Policy policy = null; 261 static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() { 262 @Override 263 protected AtomicBoolean initialValue() { 264 return new AtomicBoolean(false); 265 } 266 }; 267 static void setUp(TestCase test) { 268 switch (test) { 269 case SECURE: 270 if (policy == null && System.getSecurityManager() != null) { 271 throw new IllegalStateException("SecurityManager already set"); 272 } else if (policy == null) { 273 policy = new SimplePolicy(TestCase.SECURE, allowAll); 274 Policy.setPolicy(policy); 275 System.setSecurityManager(new SecurityManager()); 276 } 277 if (System.getSecurityManager() == null) { 278 throw new IllegalStateException("No SecurityManager."); 279 } 280 if (policy == null) { 281 throw new IllegalStateException("policy not configured"); 282 } 283 break; 284 case UNSECURE: 285 if (System.getSecurityManager() != null) { 286 throw new IllegalStateException("SecurityManager already set"); 287 } 288 break; 289 default: 290 throw new InternalError("No such testcase: " + test); 291 } 292 } 293 static void doPrivileged(Runnable run) { 294 allowAll.get().set(true); 295 try { 296 run.run(); 297 } finally { 298 allowAll.get().set(false); 299 } 300 } 301 } 302 303 // A Helper class to build a set of permissions. 304 final static class PermissionsBuilder { 305 final Permissions perms; 306 public PermissionsBuilder() { 307 this(new Permissions()); 308 } 309 public PermissionsBuilder(Permissions perms) { 310 this.perms = perms; 311 } 312 public PermissionsBuilder add(Permission p) { 313 perms.add(p); 314 return this; 315 } 316 public PermissionsBuilder addAll(PermissionCollection col) { 317 if (col != null) { 318 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) { 319 perms.add(e.nextElement()); 320 } 321 } 322 return this; 323 } 324 public Permissions toPermissions() { 325 final PermissionsBuilder builder = new PermissionsBuilder(); 326 builder.addAll(perms); 327 return builder.perms; 328 } 329 } 330 331 // Policy for the test... 332 public static class SimplePolicy extends Policy { 333 334 final Permissions permissions; 335 final Permissions allPermissions; 336 final ThreadLocal<AtomicBoolean> allowAll; 337 public SimplePolicy(TestCase test, ThreadLocal<AtomicBoolean> allowAll) { 338 this.allowAll = allowAll; 339 340 // Permission needed by the tested code exercised in the test 341 permissions = new Permissions(); 342 permissions.add(new RuntimePermission("fileSystemProvider")); 343 permissions.add(new RuntimePermission("createClassLoader")); 344 permissions.add(new RuntimePermission("closeClassLoader")); 345 permissions.add(new RuntimePermission("getClassLoader")); 346 permissions.add(new RuntimePermission("accessDeclaredMembers")); 347 permissions.add(new ReflectPermission("suppressAccessChecks")); 348 permissions.add(new PropertyPermission("*", "read")); 349 permissions.add(new FilePermission("<<ALL FILES>>", "read")); 350 351 // these are used for configuring the test itself... 352 allPermissions = new Permissions(); 353 allPermissions.add(new java.security.AllPermission()); 354 } 355 356 @Override 357 public boolean implies(ProtectionDomain domain, Permission permission) { 358 if (allowAll.get().get()) return allPermissions.implies(permission); 359 if (permissions.implies(permission)) return true; 360 if (permission instanceof java.lang.RuntimePermission) { 361 if (permission.getName().startsWith("accessClassInPackage.")) { 362 // add these along to the set of permission we have, when we 363 // discover that we need them. 364 permissions.add(permission); 365 return true; 366 } 367 } 368 return false; 369 } 370 371 @Override 372 public PermissionCollection getPermissions(CodeSource codesource) { 373 return new PermissionsBuilder().addAll(allowAll.get().get() 374 ? allPermissions : permissions).toPermissions(); 375 } 376 377 @Override 378 public PermissionCollection getPermissions(ProtectionDomain domain) { 379 return new PermissionsBuilder().addAll(allowAll.get().get() 380 ? allPermissions : permissions).toPermissions(); 381 } 382 } 383 384 }