aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Christopher Vogt <oss.nsp@cvogt.org>2016-09-15 13:03:07 +0100
committerGitHub <noreply@github.com>2016-09-15 13:03:07 +0100
commit551c473845fa49a545ed39f00b7cf9efd98dce65 (patch)
tree02fa34ec031ffb920f9f3760953c18beb5cbf990
parent32abe161b5454e2c9e9265bb5b95e8fad3c09bb3 (diff)
parentf905891a4deabdc474cac7b46c2f5f135fe8e1b7 (diff)
downloadcbt-551c473845fa49a545ed39f00b7cf9efd98dce65.tar.gz
cbt-551c473845fa49a545ed39f00b7cf9efd98dce65.tar.bz2
cbt-551c473845fa49a545ed39f00b7cf9efd98dce65.zip
Merge pull request #229 from cvogt/chris3
fix System.exit and jar checksum checks
-rw-r--r--nailgun_launcher/NailgunLauncher.java15
-rw-r--r--nailgun_launcher/ProxySecurityManager.java102
-rw-r--r--nailgun_launcher/Stage0Lib.java13
-rw-r--r--nailgun_launcher/TrapSecurityManager.java24
-rw-r--r--stage1/Stage1Lib.scala12
-rw-r--r--test/simple/build/build.scala4
6 files changed, 154 insertions, 16 deletions
diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java
index 904a646..5a70312 100644
--- a/nailgun_launcher/NailgunLauncher.java
+++ b/nailgun_launcher/NailgunLauncher.java
@@ -20,7 +20,15 @@ public class NailgunLauncher{
new ConcurrentHashMap<Object,ClassLoader>()
);
- public final static SecurityManager defaultSecurityManager = System.getSecurityManager();
+ public final static SecurityManager initialSecurityManager
+ = System.getSecurityManager();
+
+ public final static ThreadLocal<Boolean> trapExitCode =
+ new ThreadLocal<Boolean>() {
+ @Override protected Boolean initialValue() {
+ return false;
+ }
+ };
public static String TARGET = System.getenv("TARGET");
private static String NAILGUN = "nailgun_launcher/";
@@ -54,6 +62,7 @@ public class NailgunLauncher{
return;
}
+ System.setSecurityManager( new TrapSecurityManager() );
installProxySettings();
String[] diff = args[0].split("\\.");
long start = _start - (Long.parseLong(diff[0]) * 1000L) - Long.parseLong(diff[1]);
@@ -119,7 +128,7 @@ public class NailgunLauncher{
compatibilitySourceFiles.add(f);
}
}
- changed = compile(changed, start, "", compatibilityTarget, earlyDeps, compatibilitySourceFiles, defaultSecurityManager);
+ changed = compile(changed, start, "", compatibilityTarget, earlyDeps, compatibilitySourceFiles);
if( classLoaderCache.contains( compatibilityTarget ) ){
compatibilityClassLoader = classLoaderCache.get( compatibilityTarget );
@@ -145,7 +154,7 @@ public class NailgunLauncher{
stage1SourceFiles.add(f);
}
}
- changed = compile(changed, start, stage1Classpath, stage1Target, earlyDeps, stage1SourceFiles, defaultSecurityManager);
+ changed = compile(changed, start, stage1Classpath, stage1Target, earlyDeps, stage1SourceFiles);
ClassLoader stage1classLoader;
if( !changed && classLoaderCache.contains( stage1Classpath ) ){
diff --git a/nailgun_launcher/ProxySecurityManager.java b/nailgun_launcher/ProxySecurityManager.java
new file mode 100644
index 0000000..1a6e49c
--- /dev/null
+++ b/nailgun_launcher/ProxySecurityManager.java
@@ -0,0 +1,102 @@
+package cbt;
+
+import java.security.*;
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+
+/*
+SecurityManager proxy that forwards all calls to the provided target if != null.
+Useful to replace a previously installed SecurityManager, overriding some methods
+but forwarding the rest.
+*/
+public class ProxySecurityManager extends SecurityManager{
+ private SecurityManager target;
+ public ProxySecurityManager(SecurityManager target){
+ this.target = target;
+ }
+ public Object getSecurityContext() {
+ if(target != null)
+ return target.getSecurityContext();
+ else return super.getSecurityContext();
+ }
+ public void checkPermission(Permission perm) {
+ if(target != null) target.checkPermission(perm);
+ }
+ public void checkPermission(Permission perm, Object context) {
+ if(target != null) target.checkPermission(perm, context);
+ }
+ public void checkCreateClassLoader() {
+ if(target != null) target.checkCreateClassLoader();
+ }
+ public void checkAccess(Thread t) {
+ if(target != null) target.checkAccess(t);
+ }
+ public void checkAccess(ThreadGroup g) {
+ if(target != null) target.checkAccess(g);
+ }
+ public void checkExit(int status) {
+ if(target != null) target.checkExit(status);
+ }
+ public void checkExec(String cmd) {
+ if(target != null) target.checkExec(cmd);
+ }
+ public void checkLink(String lib) {
+ if(target != null) target.checkLink(lib);
+ }
+ public void checkRead(FileDescriptor fd) {
+ if(target != null) target.checkRead(fd);
+ }
+ public void checkRead(String file) {
+ if(target != null) target.checkRead(file);
+ }
+ public void checkRead(String file, Object context) {
+ if(target != null) target.checkRead(file, context);
+ }
+ public void checkWrite(FileDescriptor fd) {
+ if(target != null) target.checkWrite(fd);
+ }
+ public void checkWrite(String file) {
+ if(target != null) target.checkWrite(file);
+ }
+ public void checkDelete(String file) {
+ if(target != null) target.checkDelete(file);
+ }
+ public void checkConnect(String host, int port) {
+ if(target != null) target.checkConnect(host, port);
+ }
+ public void checkConnect(String host, int port, Object context) {
+ if(target != null) target.checkConnect(host, port, context);
+ }
+ public void checkListen(int port) {
+ if(target != null) target.checkListen(port);
+ }
+ public void checkAccept(String host, int port) {
+ if(target != null) target.checkAccept(host, port);
+ }
+ public void checkMulticast(InetAddress maddr) {
+ if(target != null) target.checkMulticast(maddr);
+ }
+ public void checkPropertiesAccess() {
+ if(target != null) target.checkPropertiesAccess();
+ }
+ public void checkPropertyAccess(String key) {
+ if(target != null) target.checkPropertyAccess(key);
+ }
+ public void checkPrintJobAccess() {
+ if(target != null) target.checkPrintJobAccess();
+ }
+ public void checkPackageAccess(String pkg) {
+ if(target != null) target.checkPackageAccess(pkg);
+ }
+ public void checkPackageDefinition(String pkg) {
+ if(target != null) target.checkPackageDefinition(pkg);
+ }
+ public void checkSetFactory() {
+ if(target != null) target.checkSetFactory();
+ }
+ public ThreadGroup getThreadGroup() {
+ if(target != null)
+ return target.getThreadGroup();
+ else return super.getThreadGroup();
+ }
+}
diff --git a/nailgun_launcher/Stage0Lib.java b/nailgun_launcher/Stage0Lib.java
index ebf9d09..bc6679e 100644
--- a/nailgun_launcher/Stage0Lib.java
+++ b/nailgun_launcher/Stage0Lib.java
@@ -19,9 +19,10 @@ public class Stage0Lib{
}
}
- public static int runMain(String cls, String[] args, ClassLoader cl, SecurityManager defaultSecurityManager) throws Throwable{
+ public static int runMain(String cls, String[] args, ClassLoader cl) throws Throwable{
+ Boolean trapExitCodeBefore = NailgunLauncher.trapExitCode.get();
try{
- System.setSecurityManager( new TrapSecurityManager() );
+ NailgunLauncher.trapExitCode.set(true);
cl.loadClass(cls)
.getMethod("main", String[].class)
.invoke( null, (Object) args);
@@ -33,7 +34,7 @@ public class Stage0Lib{
}
throw exception;
} finally {
- System.setSecurityManager(defaultSecurityManager);
+ NailgunLauncher.trapExitCode.set(trapExitCodeBefore);
}
}
@@ -54,7 +55,7 @@ public class Stage0Lib{
public static Boolean compile(
Boolean changed, Long start, String classpath, String target,
- EarlyDependencies earlyDeps, List<File> sourceFiles, SecurityManager defaultSecurityManager
+ EarlyDependencies earlyDeps, List<File> sourceFiles
) throws Throwable{
File statusFile = new File( new File(target) + ".last-success" );
Long lastSuccessfullCompile = statusFile.lastModified();
@@ -89,7 +90,7 @@ public class Stage0Lib{
PrintStream oldOut = System.out;
try{
System.setOut(System.err);
- int exitCode = runMain( "com.typesafe.zinc.Main", zincArgs.toArray(new String[zincArgs.size()]), earlyDeps.zinc, defaultSecurityManager );
+ int exitCode = runMain( "com.typesafe.zinc.Main", zincArgs.toArray(new String[zincArgs.size()]), earlyDeps.zinc );
if( exitCode == 0 ){
write( statusFile, "" );
Files.setLastModifiedTime( statusFile.toPath(), FileTime.fromMillis(start) );
@@ -177,7 +178,7 @@ public class Stage0Lib{
public static String sha1(byte[] bytes) throws Throwable {
final MessageDigest sha1 = MessageDigest.getInstance("SHA1");
sha1.update(bytes, 0, bytes.length);
- return (new HexBinaryAdapter()).marshal(sha1.digest());
+ return (new HexBinaryAdapter()).marshal(sha1.digest()).toUpperCase();
}
public static String join(String separator, String[] parts){
diff --git a/nailgun_launcher/TrapSecurityManager.java b/nailgun_launcher/TrapSecurityManager.java
index ed00582..fada878 100644
--- a/nailgun_launcher/TrapSecurityManager.java
+++ b/nailgun_launcher/TrapSecurityManager.java
@@ -1,19 +1,39 @@
package cbt;
import java.security.*;
-public class TrapSecurityManager extends SecurityManager{
+/*
+When enabled, this SecurityManager turns System.exit(...) calls into exceptions that can be caught and handled.
+Installing a SecurityManager is a global side-effect and thus needs extra care in a persistent
+background process like CBT's. The current approach is install it once during JVM-startup.
+When disabled this delegates to the SecurityManager installed before if any, which
+would be Nailgun's if running on Nailgun. If we do not delegate to Nailgun, it seems we
+could in some cases kill the server process
+*/
+public class TrapSecurityManager extends ProxySecurityManager{
+ public TrapSecurityManager(){
+ super(NailgunLauncher.initialSecurityManager);
+ }
+
public void checkPermission( Permission permission ){
/*
NOTE: is it actually ok, to just make these empty?
Calling .super leads to ClassNotFound exteption for a lambda.
Calling to the previous SecurityManager leads to a stack overflow
*/
+ if(!NailgunLauncher.trapExitCode.get()){
+ super.checkPermission(permission);
+ }
}
public void checkPermission( Permission permission, Object context ){
/* Does this methods need to be overidden? */
+ if(!NailgunLauncher.trapExitCode.get()){
+ super.checkPermission(permission, context);
+ }
}
@Override
public void checkExit( int status ){
+ if(NailgunLauncher.trapExitCode.get()){
+ throw new TrappedExitCode(status);
+ }
super.checkExit(status);
- throw new TrappedExitCode(status);
}
}
diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala
index 9e500a3..a1688c1 100644
--- a/stage1/Stage1Lib.scala
+++ b/stage1/Stage1Lib.scala
@@ -45,8 +45,8 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
val hex = new java.math.BigInteger(1, array).toString(16)
("0" * (padTo-hex.size)) ++ hex
}
- def md5( bytes: Array[Byte] ): String = array2hex(32, MessageDigest.getInstance("MD5").digest(bytes))
- def sha1( bytes: Array[Byte] ): String = array2hex(40, MessageDigest.getInstance("SHA-1").digest(bytes))
+ def md5( bytes: Array[Byte] ): String = array2hex(32, MessageDigest.getInstance("MD5").digest(bytes)).toUpperCase
+ def sha1( bytes: Array[Byte] ): String = array2hex(40, MessageDigest.getInstance("SHA-1").digest(bytes)).toUpperCase
def red(string: String) = scala.Console.RED++string++scala.Console.RESET
def blue(string: String) = scala.Console.BLUE++string++scala.Console.RESET
@@ -76,7 +76,7 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
}
sha1.foreach{
hash =>
- val expected = hash
+ val expected = hash.toUpperCase
val actual = this.sha1(Files.readAllBytes(incomplete))
assert( expected == actual, s"$expected == $actual" )
logger.resolver( green("verified") ++ " checksum for " ++ target.string)
@@ -251,14 +251,16 @@ ${files.sorted.mkString(" \\\n")}
}
def trapExitCode( code: => ExitCode ): ExitCode = {
+ val trapExitCodeBefore = NailgunLauncher.trapExitCode.get
try{
- System.setSecurityManager( new TrapSecurityManager )
+ NailgunLauncher.trapExitCode.set(true)
code
} catch {
case CatchTrappedExitCode(exitCode) =>
+ logger.stage1(s"caught exit code $exitCode")
exitCode
} finally {
- System.setSecurityManager(NailgunLauncher.defaultSecurityManager)
+ NailgunLauncher.trapExitCode.set(trapExitCodeBefore)
}
}
diff --git a/test/simple/build/build.scala b/test/simple/build/build.scala
index 66ee392..b75d262 100644
--- a/test/simple/build/build.scala
+++ b/test/simple/build/build.scala
@@ -25,6 +25,10 @@ class Build(val context: cbt.Context) extends BaseBuild{
// currently fails, let's see if because of a bug
// io.spray:spray-http:1.3.3
) ++
+ Resolver( new java.net.URL("http://maven.spikemark.net/roundeights") ).bind(
+ // Check that lower case checksums work
+ ScalaDependency("com.roundeights","hasher","1.2.0")
+ ) ++
Resolver(
mavenCentral,
bintray("tpolecat"),