Skip to content

Commit bee9421

Browse files
wkozaczuknyh
authored andcommitted
Modifed runjava classes to support running Java 9 apps and added switch 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]>
1 parent 3ab8dd4 commit bee9421

File tree

15 files changed

+330
-88
lines changed

15 files changed

+330
-88
lines changed

java/jvm/java.cc

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ extern size_t jvm_heap_size;
2929
// sets up the class path, and runs the jar or class specified in these
3030
// parameters.
3131

32-
#define JVM_PATH "/usr/lib/jvm/jre/lib/amd64/server/libjvm.so"
32+
#define JVM_PATH "/usr/lib/jvm/jre/lib/amd64/server/libjvm.so"
33+
#define RUNJAVA_JAR_PATH "/java/runjava.jar"
34+
3335
#if defined(RUN_JAVA_NON_ISOLATED)
34-
#define RUNJAVA "io/osv/nonisolated/RunNonIsolatedJvmApp" // separated by slashes, not dots
36+
#define RUNJAVA "io/osv/nonisolated/RunNonIsolatedJvmApp" // separated by slashes, not dots
3537
#else
36-
#define RUNJAVA "io/osv/isolated/RunIsolatedJvmApp" // separated by slashes, not dots
38+
#define RUNJAVA "io/osv/isolated/RunIsolatedJvmApp" // separated by slashes, not dots
3739
#endif
3840

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

115117
std::vector<JavaVMOption> options;
116-
options.push_back(mkoption("-Djava.class.path=/dev/null"));
117-
#if !defined(RUN_JAVA_NON_ISOLATED)
118-
std::cout << "java.so: Setting Java system classloader and logging manager to the isolated ones" << "\n";
119-
options.push_back(mkoption("-Djava.system.class.loader=io.osv.isolated.OsvSystemClassLoader"));
118+
options.push_back(mkoption("-Djava.class.path=%s", RUNJAVA_JAR_PATH));
119+
120+
#if defined(RUN_JAVA_NON_ISOLATED)
121+
std::cout << "java.so: Setting Java system classloader to NonIsolatingOsvSystemClassLoader" << "\n";
122+
options.push_back(mkoption("-Djava.system.class.loader=io.osv.nonisolated.NonIsolatingOsvSystemClassLoader"));
123+
#else
124+
std::cout << "java.so: Setting Java system classloader to IsolatingOsvSystemClassLoader and logging manager to IsolatingLogManager" << "\n";
125+
options.push_back(mkoption("-Djava.system.class.loader=io.osv.isolated.IsolatingOsvSystemClassLoader"));
120126
options.push_back(mkoption("-Djava.util.logging.manager=io.osv.jul.IsolatingLogManager"));
121127
#endif
128+
122129
options.push_back(mkoption("-Dosv.version=" + osv::version()));
123130

124131
{

java/runjava/src/main/java/io/osv/Jvm.java

Lines changed: 25 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package io.osv;
22

3+
import io.osv.util.ClassDiagnostics;
4+
35
import java.io.File;
46
import java.io.FileNotFoundException;
5-
import java.io.FilePermission;
67
import java.lang.reflect.InvocationTargetException;
78
import java.lang.reflect.Method;
89
import java.net.MalformedURLException;
910
import java.net.URL;
10-
import java.net.URLClassLoader;
11-
import java.security.CodeSource;
12-
import java.security.PermissionCollection;
1311
import java.util.ArrayList;
1412
import java.util.List;
1513
import java.util.Properties;
@@ -84,31 +82,38 @@ private T runJar(String jarName, String[] args, ArrayList<String> classpath, Pro
8482
}
8583
}
8684

87-
private T runClass(String mainClass, String[] args, Iterable<String> classpath, Properties properties) throws MalformedURLException {
88-
ClassLoader appClassLoader = createAppClassLoader(classpath, getParentClassLoader());
89-
return run(appClassLoader, joinClassPath(classpath), mainClass, args, properties);
90-
}
91-
92-
protected abstract T run(ClassLoader classLoader, final String classpath, final String mainClass,
93-
final String[] args, final Properties properties);
94-
95-
protected abstract ClassLoader getParentClassLoader();
96-
97-
private ClassLoader createAppClassLoader(Iterable<String> classpath, ClassLoader parent) throws MalformedURLException {
98-
List<URL> urls = toUrls(classpath);
99-
URL[] urlArray = urls.toArray(new URL[urls.size()]);
100-
return new AppClassLoader(urlArray, parent);
101-
}
85+
protected abstract T runClass(String mainClass, String[] args, Iterable<String> classpath, Properties properties) throws MalformedURLException;
10286

103-
private List<URL> toUrls(Iterable<String> classpath) throws MalformedURLException {
87+
protected List<URL> toUrls(Iterable<String> classpath) throws MalformedURLException {
10488
ArrayList<URL> urls = new ArrayList<>();
10589
for (String path : classpath) {
10690
urls.add(toUrl(path));
10791
}
10892
return urls;
10993
}
11094

95+
protected String joinClassPath(Iterable<String> classpath) {
96+
StringBuilder sb = new StringBuilder();
97+
boolean first = true;
98+
for (String path : classpath) {
99+
if (!first) {
100+
sb.append(":");
101+
}
102+
first = false;
103+
sb.append(path);
104+
}
105+
return sb.toString();
106+
}
107+
111108
protected void runMain(Class<?> klass, String[] args) throws Throwable {
109+
110+
if(ClassDiagnostics.showDiagnostics(args)) {
111+
System.out.println("Classpath: " + System.getProperty("java.class.path"));
112+
System.out.println("------ Main class information --------");
113+
System.out.println("Classloader: " + ClassDiagnostics.showClassLoaderHierarchy(klass,false));
114+
System.out.println("Security: " + ClassDiagnostics.showClassSecurity(klass));
115+
}
116+
112117
Method main = klass.getMethod("main", String[].class);
113118
try {
114119
main.invoke(null, new Object[]{args});
@@ -125,19 +130,6 @@ protected Class<?> loadClass(String name) throws MainClassNotFoundException {
125130
}
126131
}
127132

128-
private String joinClassPath(Iterable<String> classpath) {
129-
StringBuilder sb = new StringBuilder();
130-
boolean first = true;
131-
for (String path : classpath) {
132-
if (!first) {
133-
sb.append(":");
134-
}
135-
first = false;
136-
sb.append(path);
137-
}
138-
return sb.toString();
139-
}
140-
141133
private URL toUrl(String path) throws MalformedURLException {
142134
return new URL("file:///" + path + (isDirectory(path) ? "/" : ""));
143135
}
@@ -176,18 +168,4 @@ private Iterable<String> expandClassPath(String classpath) {
176168
}
177169
return ret;
178170
}
179-
180-
private static class AppClassLoader extends URLClassLoader {
181-
public AppClassLoader(URL[] urlArray, ClassLoader parent) {
182-
super(urlArray, parent);
183-
}
184-
185-
@Override
186-
protected PermissionCollection getPermissions(CodeSource codesource) {
187-
PermissionCollection permissions = super.getPermissions(codesource);
188-
permissions.add(new FilePermission("/usr/lib/jvm/jre/lib/ext/runjava.jar", "read"));
189-
permissions.add(new RuntimePermission("exitVM"));
190-
return permissions;
191-
}
192-
}
193171
}

java/runjava/src/main/java/io/osv/RunJvmAppHelper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.osv;
22

3+
import io.osv.util.ClassDiagnostics;
4+
35
/*
46
* Copyright (C) 2016 Waldemar Kozaczuk
57
* Copyright (C) 2013-2016 Cloudius Systems, Ltd.
@@ -27,6 +29,13 @@ static public void runSync(JvmFactory jvmFactory, String[] args) {
2729
return;
2830
}
2931

32+
if(ClassDiagnostics.showDiagnostics(args)) {
33+
System.out.println("Arguments:");
34+
for(String arg:args) {
35+
System.out.println("\t[" + arg + "]");
36+
}
37+
}
38+
3039
try {
3140
jvmFactory.getJvm().runSync(args);
3241
} catch (IllegalArgumentException ex) {

java/runjava/src/main/java/io/osv/isolated/IsolatedJvm.java

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,19 @@
66
import net.sf.cglib.proxy.Dispatcher;
77
import net.sf.cglib.proxy.Enhancer;
88

9+
import java.io.FilePermission;
910
import java.lang.reflect.Field;
11+
import java.lang.reflect.ReflectPermission;
12+
import java.net.MalformedURLException;
13+
import java.net.URL;
14+
import java.net.URLClassLoader;
15+
import java.security.CodeSource;
16+
import java.security.PermissionCollection;
17+
import java.util.List;
1018
import java.util.Properties;
19+
import java.util.PropertyPermission;
1120
import java.util.logging.LogManager;
21+
import java.util.logging.LoggingPermission;
1222

1323
/*
1424
* Copyright (C) 2016 Waldemar Kozaczuk
@@ -88,8 +98,8 @@ public Context getContext() {
8898
return currentContext.get();
8999
}
90100

91-
protected Context run(ClassLoader classLoader, final String classpath, final String mainClass,
92-
final String[] args, final Properties properties) {
101+
private Context run(ClassLoader classLoader, final String classpath, final String mainClass,
102+
final String[] args, final Properties properties) {
93103
Properties contextProperties = new Properties();
94104
contextProperties.putAll(commonSystemProperties);
95105
contextProperties.putAll(properties);
@@ -126,7 +136,18 @@ public void uncaughtException(Thread t, Throwable e) {
126136
return context;
127137
}
128138

129-
protected ClassLoader getParentClassLoader() {
139+
protected Context runClass(String mainClass, String[] args, Iterable<String> classpath, Properties properties) throws MalformedURLException {
140+
ClassLoader appClassLoader = createAppClassLoader(classpath, getParentClassLoader());
141+
return run(appClassLoader, joinClassPath(classpath), mainClass, args, properties);
142+
}
143+
144+
private ClassLoader createAppClassLoader(Iterable<String> classpath, ClassLoader parent) throws MalformedURLException {
145+
List<URL> urls = toUrls(classpath);
146+
URL[] urlArray = urls.toArray(new URL[urls.size()]);
147+
return new AppClassLoader(urlArray, parent);
148+
}
149+
150+
private ClassLoader getParentClassLoader() {
130151
return parentClassLoaderForIsolates;
131152
}
132153

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

146-
private OsvSystemClassLoader getOsvClassLoader() {
167+
private IsolatingOsvSystemClassLoader getOsvClassLoader() {
147168
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
148-
if (!(systemClassLoader instanceof OsvSystemClassLoader)) {
169+
if (!(systemClassLoader instanceof IsolatingOsvSystemClassLoader)) {
149170
throw new AssertionError("System class loader should be an instance of "
150-
+ OsvSystemClassLoader.class.getName() + " but is "
171+
+ IsolatingOsvSystemClassLoader.class.getName() + " but is "
151172
+ systemClassLoader.getClass().getName());
152173
}
153174

154-
return (OsvSystemClassLoader) systemClassLoader;
175+
return (IsolatingOsvSystemClassLoader) systemClassLoader;
155176
}
156177

157178
public Object receive() throws InterruptedException {
158179
return getContext().takeMessage();
159180
}
181+
182+
183+
private static class AppClassLoader extends URLClassLoader {
184+
AppClassLoader(URL[] urlArray, ClassLoader parent) {
185+
super(urlArray, parent);
186+
}
187+
188+
@Override
189+
protected PermissionCollection getPermissions(CodeSource codesource) {
190+
PermissionCollection permissions = super.getPermissions(codesource);
191+
permissions.add(new FilePermission("/java/runjava.jar", "read"));
192+
permissions.add(new RuntimePermission("exitVM"));
193+
permissions.add(new RuntimePermission("shutdownHooks"));
194+
permissions.add(new RuntimePermission("setContextClassLoader"));
195+
permissions.add(new ReflectPermission("suppressAccessChecks"));
196+
permissions.add(new LoggingPermission("control",null));
197+
permissions.add(new PropertyPermission("java.util.logging.config.*", "read"));
198+
return permissions;
199+
}
200+
}
160201
}

java/runjava/src/main/java/io/osv/isolated/OsvSystemClassLoader.java renamed to java/runjava/src/main/java/io/osv/isolated/IsolatingOsvSystemClassLoader.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import java.net.URL;
1515
import java.util.Enumeration;
1616

17-
public class OsvSystemClassLoader extends ClassLoader {
17+
public class IsolatingOsvSystemClassLoader extends ClassLoader {
1818
private final ClassLoader defaultSystemClassLoader;
1919

2020
static {
@@ -31,7 +31,7 @@ public class OsvSystemClassLoader extends ClassLoader {
3131
private final Method findLibrary;
3232
private final Method findResources;
3333

34-
public OsvSystemClassLoader(ClassLoader defaultSystemClassLoader) throws NoSuchMethodException {
34+
public IsolatingOsvSystemClassLoader(ClassLoader defaultSystemClassLoader) throws NoSuchMethodException {
3535
super(defaultSystemClassLoader);
3636
this.defaultSystemClassLoader = defaultSystemClassLoader;
3737

java/runjava/src/main/java/io/osv/isolated/MultiJarLoader.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
package io.osv.isolated;
22

3+
import io.osv.util.ClassDiagnostics;
4+
35
import java.io.BufferedReader;
46
import java.io.File;
57
import java.io.FileReader;
68
import java.io.IOException;
9+
import java.util.ArrayList;
10+
import java.util.Arrays;
11+
import java.util.List;
12+
13+
import static io.osv.util.ClassDiagnostics.JAVA_DIAGNOSTICS_PROPERTY_NAME;
714

815
/**
916
* MultiJarLoader load multiple jars with their main and command line when using
@@ -21,18 +28,19 @@ public class MultiJarLoader {
2128
* - mains /usr/mgmt/myfile.txt
2229
*/
2330
public static void main(String[] args) {
31+
final boolean showDiagnostics = ClassDiagnostics.showDiagnostics(args);
2432
for (int i = 0; i < args.length; i++) {
2533
if (args[i].equals("-mains")) {
2634
if (i + 1 >= args.length) {
2735
System.err.println("No file specified for load from file");
2836
}
29-
runFromFile(args[i + 1]);
37+
runFromFile(args[i + 1],showDiagnostics);
3038
return;
3139
}
3240
}
3341
System.err
3442
.println("No load file was specified, using default /usr/mgmt/javamains, use -mains to overide");
35-
runFromFile("/usr/mgmt/javamains");
43+
runFromFile("/usr/mgmt/javamains",showDiagnostics);
3644
}
3745

3846
/**
@@ -41,8 +49,8 @@ public static void main(String[] args) {
4149
*
4250
* @param fileName the file name to read from
4351
*/
44-
private static void runFromFile(String fileName) {
45-
FileReader fr = null;
52+
private static void runFromFile(String fileName,boolean showDiagnostics) {
53+
FileReader fr;
4654
try {
4755
File f = new File(fileName);
4856
fr = new FileReader(f);
@@ -51,14 +59,14 @@ private static void runFromFile(String fileName) {
5159
+ " with exception " + e);
5260
return;
5361
}
54-
BufferedReader reader = new BufferedReader(fr);
55-
String line;
56-
try {
62+
63+
try(final BufferedReader reader = new BufferedReader(fr)) {
64+
String line;
5765
while ((line = reader.readLine()) != null) {
58-
String trimedLine = line.trim();
59-
if (isExec(trimedLine)) {
60-
RunOnThread thrd = new RunOnThread(trimedLine);
61-
thrd.start();
66+
String trimmedLine = line.trim();
67+
if (isExec(trimmedLine)) {
68+
final RunOnThread thread = new RunOnThread(trimmedLine,showDiagnostics);
69+
thread.start();
6270
}
6371
}
6472
} catch (IOException e) {
@@ -102,15 +110,24 @@ private static boolean isExec(String line) {
102110
*/
103111
private static class RunOnThread extends Thread {
104112
private String args;
113+
private boolean showDiagnostics;
105114

106-
public RunOnThread(String args) {
115+
RunOnThread(String args,boolean showDiagnostics) {
107116
this.args = args;
117+
this.showDiagnostics = showDiagnostics;
108118
}
109119

110120
@Override
111121
public void run() {
112122
try {
113-
IsolatedJvm.getInstance().runSync(args.split("\\s+"));
123+
final List<String> argumentsList = new ArrayList<>();
124+
if(showDiagnostics) {
125+
argumentsList.add("-D" + JAVA_DIAGNOSTICS_PROPERTY_NAME);
126+
}
127+
argumentsList.addAll(Arrays.asList(args.split("\\s+")));
128+
129+
final String[] argumentsArray = argumentsList.toArray(new String[] {});
130+
IsolatedJvm.getInstance().runSync(argumentsArray);
114131
} catch (Throwable e) {
115132
System.err.println("Exception was caught while running " + args
116133
+ " exception: " + e);

0 commit comments

Comments
 (0)