OpenJDK / amber / amber
changeset 52685:789cc1561621
8210274: Source Launcher should work with a security manager
Reviewed-by: mchung, alanb
author | jjg |
---|---|
date | Wed, 26 Sep 2018 11:41:08 -0700 |
parents | 2ee7e1b7ba66 |
children | bdf62f266de4 |
files | src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java test/langtools/tools/javac/launcher/SourceLauncherTest.java |
diffstat | 2 files changed, 85 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java Sat Aug 25 20:16:43 2018 +0530 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java Wed Sep 26 11:41:08 2018 -0700 @@ -50,6 +50,9 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.CodeSigner; +import java.security.CodeSource; +import java.security.ProtectionDomain; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -182,7 +185,7 @@ public void run(String[] runtimeArgs, String[] args) throws Fault, InvocationTargetException { Path file = getFile(args); - Context context = new Context(); + Context context = new Context(file.toAbsolutePath()); String mainClassName = compile(file, getJavacOpts(runtimeArgs), context); String[] appArgs = Arrays.copyOfRange(args, 1, args.length); @@ -193,7 +196,7 @@ * Returns the path for the filename found in the first of an array of arguments. * * @param args the array - * @return the path + * @return the path, as given in the array of args * @throws Fault if there is a problem determining the path, or if the file does not exist */ private Path getFile(String[] args) throws Fault { @@ -478,14 +481,19 @@ * a class loader. */ private static class Context { - private Map<String, byte[]> inMemoryClasses = new HashMap<>(); + private final Path file; + private final Map<String, byte[]> inMemoryClasses = new HashMap<>(); + + Context(Path file) { + this.file = file; + } JavaFileManager getFileManager(StandardJavaFileManager delegate) { return new MemoryFileManager(inMemoryClasses, delegate); } ClassLoader getClassLoader(ClassLoader parent) { - return new MemoryClassLoader(inMemoryClasses, parent); + return new MemoryClassLoader(inMemoryClasses, parent, file); } } @@ -546,9 +554,22 @@ */ private final Map<String, byte[]> sourceFileClasses; - MemoryClassLoader(Map<String, byte[]> sourceFileClasses, ClassLoader parent) { + /** + * A minimal protection domain, specifying a code source of the source file itself, + * used for classes found in the source file and defined by this loader. + */ + private final ProtectionDomain domain; + + MemoryClassLoader(Map<String, byte[]> sourceFileClasses, ClassLoader parent, Path file) { super(parent); this.sourceFileClasses = sourceFileClasses; + CodeSource codeSource; + try { + codeSource = new CodeSource(file.toUri().toURL(), (CodeSigner[]) null); + } catch (MalformedURLException e) { + codeSource = null; + } + domain = new ProtectionDomain(codeSource, null, this, null); } /** @@ -632,7 +653,7 @@ if (bytes == null) { throw new ClassNotFoundException(name); } - return defineClass(name, bytes, 0, bytes.length); + return defineClass(name, bytes, 0, bytes.length, domain); } @Override
--- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java Sat Aug 25 20:16:43 2018 +0530 +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java Wed Sep 26 11:41:08 2018 -0700 @@ -192,6 +192,64 @@ checkEqual("stdout", log.trim(), "Hello World! [1, 2, 3]"); } + @Test + public void testCodeSource(Path base) throws IOException { + tb.writeJavaFiles(base, + "import java.net.URL;\n" + + "class ShowCodeSource {\n" + + " public static void main(String... args) {\n" + + " URL u = ShowCodeSource.class.getProtectionDomain().getCodeSource().getLocation();\n" + + " System.out.println(u);\n" + + " }\n" + + "}"); + + Path file = base.resolve("ShowCodeSource.java"); + String log = new JavaTask(tb) + .className(file.toString()) + .run(Task.Expect.SUCCESS) + .getOutput(Task.OutputKind.STDOUT); + checkEqual("stdout", log.trim(), file.toAbsolutePath().toUri().toURL().toString()); + } + + @Test + public void testPermissions(Path base) throws IOException { + Path policyFile = base.resolve("test.policy"); + Path sourceFile = base.resolve("TestPermissions.java"); + + tb.writeFile(policyFile, + "grant codeBase \"jrt:/jdk.compiler\" {\n" + + " permission java.security.AllPermission;\n" + + "};\n" + + "grant codeBase \"" + sourceFile.toUri().toURL() + "\" {\n" + + " permission java.util.PropertyPermission \"user.dir\", \"read\";\n" + + "};\n"); + + tb.writeJavaFiles(base, + "import java.net.URL;\n" + + "class TestPermissions {\n" + + " public static void main(String... args) {\n" + + " System.out.println(\"user.dir=\" + System.getProperty(\"user.dir\"));\n" + + " try {\n" + + " System.setProperty(\"user.dir\", \"\");\n" + + " System.out.println(\"no exception\");\n" + + " System.exit(1);\n" + + " } catch (SecurityException e) {\n" + + " System.out.println(\"exception: \" + e);\n" + + " }\n" + + " }\n" + + "}"); + + String log = new JavaTask(tb) + .vmOptions("-Djava.security.manager", "-Djava.security.policy=" + policyFile) + .className(sourceFile.toString()) + .run(Task.Expect.SUCCESS) + .getOutput(Task.OutputKind.STDOUT); + checkEqual("stdout", log.trim().replace(tb.lineSeparator, "\n"), + "user.dir=" + System.getProperty("user.dir") + "\n" + + "exception: java.security.AccessControlException: " + + "access denied (\"java.util.PropertyPermission\" \"user.dir\" \"write\")"); + } + void testSuccess(Path file, String expect) throws IOException { Result r = run(file, Collections.emptyList(), List.of("1", "2", "3")); checkEqual("stdout", r.stdOut, expect);