Skip to content

Commit

Permalink
Modifed runjava classes to support running Java 9 apps and added swit…
Browse files Browse the repository at this point in the history
…ch to display Java classloader diagnostic information

The bulk of the changes that are part of this patch are about modifying runjava and java.cc so that runjava classes
are loaded by system classloader instead of extension classloader that is deprecated in Java 8 and removed from Java 9. That
way OSv can run Java applications in Java 9 JRE which will be demostrated in the seperate patch.

Following changes are part of this commit:
 * Added number of missing permissions to the AppClassLoader that loads application classes in isolated mode only (see issue #804)
 * Added ClassDiagnostics utility class that can determine what classloader along with its parents was used to load individual class
 * Added handling of -Dosv.java.diagnostics switch to  MultiJarLoader, RunIsolatedJvmApp, RunNonIsolatedJvmApp, RunJvmAppHelper to show classloader and security information
 * Added NonIsolatingOsvSystemClassLoader intended for non-isolated mode so that applications (like Tomcat) that rely on standard Java LogManager (JUL) can properly initialize logging
 * Changed java.cc to set JVM system classpath to /java/runjava.jar and set relevant classloader (NonIsolatingOsvSystemClassLoader or IsolatingOsvSystemClassLoader) depending on the mode
 * Added java.policy to make runjava.jar have all permissions as if it was loaded by extension classloader which matters when security manager is enabled (see derby)
 * Changed modules/java/module.py to place runjava under /java/runjava.jar instead of JRE extension folder

Fixes #802
Fixes #803
Fixed #804

Signed-off-by: Waldemar Kozaczuk <[email protected]>
Message-Id: <[email protected]>
  • Loading branch information
wkozaczuk authored and nyh committed Nov 2, 2016
1 parent 3ab8dd4 commit bee9421
Show file tree
Hide file tree
Showing 15 changed files with 330 additions and 88 deletions.
21 changes: 14 additions & 7 deletions java/jvm/java.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ extern size_t jvm_heap_size;
// sets up the class path, and runs the jar or class specified in these
// parameters.

#define JVM_PATH "/usr/lib/jvm/jre/lib/amd64/server/libjvm.so"
#define JVM_PATH "/usr/lib/jvm/jre/lib/amd64/server/libjvm.so"
#define RUNJAVA_JAR_PATH "/java/runjava.jar"

#if defined(RUN_JAVA_NON_ISOLATED)
#define RUNJAVA "io/osv/nonisolated/RunNonIsolatedJvmApp" // separated by slashes, not dots
#define RUNJAVA "io/osv/nonisolated/RunNonIsolatedJvmApp" // separated by slashes, not dots
#else
#define RUNJAVA "io/osv/isolated/RunIsolatedJvmApp" // separated by slashes, not dots
#define RUNJAVA "io/osv/isolated/RunIsolatedJvmApp" // separated by slashes, not dots
#endif

JavaVMOption mkoption(const char* s)
Expand Down Expand Up @@ -113,12 +115,17 @@ static int java_main(int argc, char **argv)
JNI_GetDefaultJavaVMInitArgs(&vm_args);

std::vector<JavaVMOption> options;
options.push_back(mkoption("-Djava.class.path=/dev/null"));
#if !defined(RUN_JAVA_NON_ISOLATED)
std::cout << "java.so: Setting Java system classloader and logging manager to the isolated ones" << "\n";
options.push_back(mkoption("-Djava.system.class.loader=io.osv.isolated.OsvSystemClassLoader"));
options.push_back(mkoption("-Djava.class.path=%s", RUNJAVA_JAR_PATH));

#if defined(RUN_JAVA_NON_ISOLATED)
std::cout << "java.so: Setting Java system classloader to NonIsolatingOsvSystemClassLoader" << "\n";
options.push_back(mkoption("-Djava.system.class.loader=io.osv.nonisolated.NonIsolatingOsvSystemClassLoader"));
#else
std::cout << "java.so: Setting Java system classloader to IsolatingOsvSystemClassLoader and logging manager to IsolatingLogManager" << "\n";
options.push_back(mkoption("-Djava.system.class.loader=io.osv.isolated.IsolatingOsvSystemClassLoader"));
options.push_back(mkoption("-Djava.util.logging.manager=io.osv.jul.IsolatingLogManager"));
#endif

options.push_back(mkoption("-Dosv.version=" + osv::version()));

{
Expand Down
72 changes: 25 additions & 47 deletions java/runjava/src/main/java/io/osv/Jvm.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package io.osv;

import io.osv.util.ClassDiagnostics;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilePermission;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
Expand Down Expand Up @@ -84,31 +82,38 @@ private T runJar(String jarName, String[] args, ArrayList<String> classpath, Pro
}
}

private T runClass(String mainClass, String[] args, Iterable<String> classpath, Properties properties) throws MalformedURLException {
ClassLoader appClassLoader = createAppClassLoader(classpath, getParentClassLoader());
return run(appClassLoader, joinClassPath(classpath), mainClass, args, properties);
}

protected abstract T run(ClassLoader classLoader, final String classpath, final String mainClass,
final String[] args, final Properties properties);

protected abstract ClassLoader getParentClassLoader();

private ClassLoader createAppClassLoader(Iterable<String> classpath, ClassLoader parent) throws MalformedURLException {
List<URL> urls = toUrls(classpath);
URL[] urlArray = urls.toArray(new URL[urls.size()]);
return new AppClassLoader(urlArray, parent);
}
protected abstract T runClass(String mainClass, String[] args, Iterable<String> classpath, Properties properties) throws MalformedURLException;

private List<URL> toUrls(Iterable<String> classpath) throws MalformedURLException {
protected List<URL> toUrls(Iterable<String> classpath) throws MalformedURLException {
ArrayList<URL> urls = new ArrayList<>();
for (String path : classpath) {
urls.add(toUrl(path));
}
return urls;
}

protected String joinClassPath(Iterable<String> classpath) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (String path : classpath) {
if (!first) {
sb.append(":");
}
first = false;
sb.append(path);
}
return sb.toString();
}

protected void runMain(Class<?> klass, String[] args) throws Throwable {

if(ClassDiagnostics.showDiagnostics(args)) {
System.out.println("Classpath: " + System.getProperty("java.class.path"));
System.out.println("------ Main class information --------");
System.out.println("Classloader: " + ClassDiagnostics.showClassLoaderHierarchy(klass,false));
System.out.println("Security: " + ClassDiagnostics.showClassSecurity(klass));
}

Method main = klass.getMethod("main", String[].class);
try {
main.invoke(null, new Object[]{args});
Expand All @@ -125,19 +130,6 @@ protected Class<?> loadClass(String name) throws MainClassNotFoundException {
}
}

private String joinClassPath(Iterable<String> classpath) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (String path : classpath) {
if (!first) {
sb.append(":");
}
first = false;
sb.append(path);
}
return sb.toString();
}

private URL toUrl(String path) throws MalformedURLException {
return new URL("file:///" + path + (isDirectory(path) ? "/" : ""));
}
Expand Down Expand Up @@ -176,18 +168,4 @@ private Iterable<String> expandClassPath(String classpath) {
}
return ret;
}

private static class AppClassLoader extends URLClassLoader {
public AppClassLoader(URL[] urlArray, ClassLoader parent) {
super(urlArray, parent);
}

@Override
protected PermissionCollection getPermissions(CodeSource codesource) {
PermissionCollection permissions = super.getPermissions(codesource);
permissions.add(new FilePermission("/usr/lib/jvm/jre/lib/ext/runjava.jar", "read"));
permissions.add(new RuntimePermission("exitVM"));
return permissions;
}
}
}
9 changes: 9 additions & 0 deletions java/runjava/src/main/java/io/osv/RunJvmAppHelper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.osv;

import io.osv.util.ClassDiagnostics;

/*
* Copyright (C) 2016 Waldemar Kozaczuk
* Copyright (C) 2013-2016 Cloudius Systems, Ltd.
Expand Down Expand Up @@ -27,6 +29,13 @@ static public void runSync(JvmFactory jvmFactory, String[] args) {
return;
}

if(ClassDiagnostics.showDiagnostics(args)) {
System.out.println("Arguments:");
for(String arg:args) {
System.out.println("\t[" + arg + "]");
}
}

try {
jvmFactory.getJvm().runSync(args);
} catch (IllegalArgumentException ex) {
Expand Down
55 changes: 48 additions & 7 deletions java/runjava/src/main/java/io/osv/isolated/IsolatedJvm.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@
import net.sf.cglib.proxy.Dispatcher;
import net.sf.cglib.proxy.Enhancer;

import java.io.FilePermission;
import java.lang.reflect.Field;
import java.lang.reflect.ReflectPermission;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.util.List;
import java.util.Properties;
import java.util.PropertyPermission;
import java.util.logging.LogManager;
import java.util.logging.LoggingPermission;

/*
* Copyright (C) 2016 Waldemar Kozaczuk
Expand Down Expand Up @@ -88,8 +98,8 @@ public Context getContext() {
return currentContext.get();
}

protected Context run(ClassLoader classLoader, final String classpath, final String mainClass,
final String[] args, final Properties properties) {
private Context run(ClassLoader classLoader, final String classpath, final String mainClass,
final String[] args, final Properties properties) {
Properties contextProperties = new Properties();
contextProperties.putAll(commonSystemProperties);
contextProperties.putAll(properties);
Expand Down Expand Up @@ -126,7 +136,18 @@ public void uncaughtException(Thread t, Throwable e) {
return context;
}

protected ClassLoader getParentClassLoader() {
protected Context runClass(String mainClass, String[] args, Iterable<String> classpath, Properties properties) throws MalformedURLException {
ClassLoader appClassLoader = createAppClassLoader(classpath, getParentClassLoader());
return run(appClassLoader, joinClassPath(classpath), mainClass, args, properties);
}

private ClassLoader createAppClassLoader(Iterable<String> classpath, ClassLoader parent) throws MalformedURLException {
List<URL> urls = toUrls(classpath);
URL[] urlArray = urls.toArray(new URL[urls.size()]);
return new AppClassLoader(urlArray, parent);
}

private ClassLoader getParentClassLoader() {
return parentClassLoaderForIsolates;
}

Expand All @@ -143,18 +164,38 @@ public void runSync(String... args) throws Throwable {
}
}

private OsvSystemClassLoader getOsvClassLoader() {
private IsolatingOsvSystemClassLoader getOsvClassLoader() {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
if (!(systemClassLoader instanceof OsvSystemClassLoader)) {
if (!(systemClassLoader instanceof IsolatingOsvSystemClassLoader)) {
throw new AssertionError("System class loader should be an instance of "
+ OsvSystemClassLoader.class.getName() + " but is "
+ IsolatingOsvSystemClassLoader.class.getName() + " but is "
+ systemClassLoader.getClass().getName());
}

return (OsvSystemClassLoader) systemClassLoader;
return (IsolatingOsvSystemClassLoader) systemClassLoader;
}

public Object receive() throws InterruptedException {
return getContext().takeMessage();
}


private static class AppClassLoader extends URLClassLoader {
AppClassLoader(URL[] urlArray, ClassLoader parent) {
super(urlArray, parent);
}

@Override
protected PermissionCollection getPermissions(CodeSource codesource) {
PermissionCollection permissions = super.getPermissions(codesource);
permissions.add(new FilePermission("/java/runjava.jar", "read"));
permissions.add(new RuntimePermission("exitVM"));
permissions.add(new RuntimePermission("shutdownHooks"));
permissions.add(new RuntimePermission("setContextClassLoader"));
permissions.add(new ReflectPermission("suppressAccessChecks"));
permissions.add(new LoggingPermission("control",null));
permissions.add(new PropertyPermission("java.util.logging.config.*", "read"));
return permissions;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import java.net.URL;
import java.util.Enumeration;

public class OsvSystemClassLoader extends ClassLoader {
public class IsolatingOsvSystemClassLoader extends ClassLoader {
private final ClassLoader defaultSystemClassLoader;

static {
Expand All @@ -31,7 +31,7 @@ public class OsvSystemClassLoader extends ClassLoader {
private final Method findLibrary;
private final Method findResources;

public OsvSystemClassLoader(ClassLoader defaultSystemClassLoader) throws NoSuchMethodException {
public IsolatingOsvSystemClassLoader(ClassLoader defaultSystemClassLoader) throws NoSuchMethodException {
super(defaultSystemClassLoader);
this.defaultSystemClassLoader = defaultSystemClassLoader;

Expand Down
43 changes: 30 additions & 13 deletions java/runjava/src/main/java/io/osv/isolated/MultiJarLoader.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package io.osv.isolated;

import io.osv.util.ClassDiagnostics;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static io.osv.util.ClassDiagnostics.JAVA_DIAGNOSTICS_PROPERTY_NAME;

/**
* MultiJarLoader load multiple jars with their main and command line when using
Expand All @@ -21,18 +28,19 @@ public class MultiJarLoader {
* - mains /usr/mgmt/myfile.txt
*/
public static void main(String[] args) {
final boolean showDiagnostics = ClassDiagnostics.showDiagnostics(args);
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-mains")) {
if (i + 1 >= args.length) {
System.err.println("No file specified for load from file");
}
runFromFile(args[i + 1]);
runFromFile(args[i + 1],showDiagnostics);
return;
}
}
System.err
.println("No load file was specified, using default /usr/mgmt/javamains, use -mains to overide");
runFromFile("/usr/mgmt/javamains");
runFromFile("/usr/mgmt/javamains",showDiagnostics);
}

/**
Expand All @@ -41,8 +49,8 @@ public static void main(String[] args) {
*
* @param fileName the file name to read from
*/
private static void runFromFile(String fileName) {
FileReader fr = null;
private static void runFromFile(String fileName,boolean showDiagnostics) {
FileReader fr;
try {
File f = new File(fileName);
fr = new FileReader(f);
Expand All @@ -51,14 +59,14 @@ private static void runFromFile(String fileName) {
+ " with exception " + e);
return;
}
BufferedReader reader = new BufferedReader(fr);
String line;
try {

try(final BufferedReader reader = new BufferedReader(fr)) {
String line;
while ((line = reader.readLine()) != null) {
String trimedLine = line.trim();
if (isExec(trimedLine)) {
RunOnThread thrd = new RunOnThread(trimedLine);
thrd.start();
String trimmedLine = line.trim();
if (isExec(trimmedLine)) {
final RunOnThread thread = new RunOnThread(trimmedLine,showDiagnostics);
thread.start();
}
}
} catch (IOException e) {
Expand Down Expand Up @@ -102,15 +110,24 @@ private static boolean isExec(String line) {
*/
private static class RunOnThread extends Thread {
private String args;
private boolean showDiagnostics;

public RunOnThread(String args) {
RunOnThread(String args,boolean showDiagnostics) {
this.args = args;
this.showDiagnostics = showDiagnostics;
}

@Override
public void run() {
try {
IsolatedJvm.getInstance().runSync(args.split("\\s+"));
final List<String> argumentsList = new ArrayList<>();
if(showDiagnostics) {
argumentsList.add("-D" + JAVA_DIAGNOSTICS_PROPERTY_NAME);
}
argumentsList.addAll(Arrays.asList(args.split("\\s+")));

final String[] argumentsArray = argumentsList.toArray(new String[] {});
IsolatedJvm.getInstance().runSync(argumentsArray);
} catch (Throwable e) {
System.err.println("Exception was caught while running " + args
+ " exception: " + e);
Expand Down
Loading

0 comments on commit bee9421

Please sign in to comment.