8210274: Source Launcher should work with a security manager
Reviewed-by: mchung, alanb
This commit is contained in:
parent
e6c0c9dde7
commit
cad60d14a6
@ -50,6 +50,9 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.InvalidPathException;
|
import java.nio.file.InvalidPathException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.security.CodeSigner;
|
||||||
|
import java.security.CodeSource;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -182,7 +185,7 @@ public class Main {
|
|||||||
public void run(String[] runtimeArgs, String[] args) throws Fault, InvocationTargetException {
|
public void run(String[] runtimeArgs, String[] args) throws Fault, InvocationTargetException {
|
||||||
Path file = getFile(args);
|
Path file = getFile(args);
|
||||||
|
|
||||||
Context context = new Context();
|
Context context = new Context(file.toAbsolutePath());
|
||||||
String mainClassName = compile(file, getJavacOpts(runtimeArgs), context);
|
String mainClassName = compile(file, getJavacOpts(runtimeArgs), context);
|
||||||
|
|
||||||
String[] appArgs = Arrays.copyOfRange(args, 1, args.length);
|
String[] appArgs = Arrays.copyOfRange(args, 1, args.length);
|
||||||
@ -193,7 +196,7 @@ public class Main {
|
|||||||
* Returns the path for the filename found in the first of an array of arguments.
|
* Returns the path for the filename found in the first of an array of arguments.
|
||||||
*
|
*
|
||||||
* @param args the array
|
* @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
|
* @throws Fault if there is a problem determining the path, or if the file does not exist
|
||||||
*/
|
*/
|
||||||
private Path getFile(String[] args) throws Fault {
|
private Path getFile(String[] args) throws Fault {
|
||||||
@ -478,14 +481,19 @@ public class Main {
|
|||||||
* a class loader.
|
* a class loader.
|
||||||
*/
|
*/
|
||||||
private static class Context {
|
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) {
|
JavaFileManager getFileManager(StandardJavaFileManager delegate) {
|
||||||
return new MemoryFileManager(inMemoryClasses, delegate);
|
return new MemoryFileManager(inMemoryClasses, delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassLoader getClassLoader(ClassLoader parent) {
|
ClassLoader getClassLoader(ClassLoader parent) {
|
||||||
return new MemoryClassLoader(inMemoryClasses, parent);
|
return new MemoryClassLoader(inMemoryClasses, parent, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,9 +554,22 @@ public class Main {
|
|||||||
*/
|
*/
|
||||||
private final Map<String, byte[]> sourceFileClasses;
|
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);
|
super(parent);
|
||||||
this.sourceFileClasses = sourceFileClasses;
|
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 @@ public class Main {
|
|||||||
if (bytes == null) {
|
if (bytes == null) {
|
||||||
throw new ClassNotFoundException(name);
|
throw new ClassNotFoundException(name);
|
||||||
}
|
}
|
||||||
return defineClass(name, bytes, 0, bytes.length);
|
return defineClass(name, bytes, 0, bytes.length, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -192,6 +192,64 @@ public class SourceLauncherTest extends TestRunner {
|
|||||||
checkEqual("stdout", log.trim(), "Hello World! [1, 2, 3]");
|
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 {
|
void testSuccess(Path file, String expect) throws IOException {
|
||||||
Result r = run(file, Collections.emptyList(), List.of("1", "2", "3"));
|
Result r = run(file, Collections.emptyList(), List.of("1", "2", "3"));
|
||||||
checkEqual("stdout", r.stdOut, expect);
|
checkEqual("stdout", r.stdOut, expect);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user