Tighten which classes can exit
Today a SecureSM security manager allows defining a list of packages that can exit the VM. However, today there are no restrictions on defining a package inside another JAR. This commit strengthens the ability to prevent exit by allowing construction of SecureSM to be done with a list of regular expressions (instead of a list of prefix names) that classes will be tested against. With this, a security manager can be installed that permits only exiting from an exact list of classes. Relates #5
This commit is contained in:
parent
09057f24b5
commit
e6bd34e22c
|
@ -63,7 +63,7 @@ import java.util.Objects;
|
||||||
*/
|
*/
|
||||||
public class SecureSM extends SecurityManager {
|
public class SecureSM extends SecurityManager {
|
||||||
|
|
||||||
private final String[] packagesThatCanExit;
|
private final String[] classesThatCanExit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new security manager where no packages can exit nor halt the virtual machine.
|
* Creates a new security manager where no packages can exit nor halt the virtual machine.
|
||||||
|
@ -73,22 +73,24 @@ public class SecureSM extends SecurityManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new security manager with the specified list of packages being the only packages
|
* Creates a new security manager with the specified list of regular expressions as the those that class names will be tested against to
|
||||||
* that can exit or halt the virtual machine.
|
* check whether or not a class can exit or halt the virtual machine.
|
||||||
*
|
*
|
||||||
* @param packagesThatCanExit the list of packages that can exit or halt the virtual machine
|
* @param classesThatCanExit the list of classes that can exit or halt the virtual machine
|
||||||
*/
|
*/
|
||||||
public SecureSM(final String[] packagesThatCanExit) {
|
public SecureSM(final String[] classesThatCanExit) {
|
||||||
this.packagesThatCanExit = packagesThatCanExit;
|
this.classesThatCanExit = classesThatCanExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new security manager with a standard set of test packages being the only packages
|
* Creates a new security manager with a standard set of test packages being the only packages that can exit or halt the virtual machine.
|
||||||
* that can exit or halt the virtual machine. The packages that can exit are
|
* The packages that can exit are:
|
||||||
|
* <ul>
|
||||||
* <li><code>org.apache.maven.surefire.booter.</code></li>
|
* <li><code>org.apache.maven.surefire.booter.</code></li>
|
||||||
* <li><code>com.carrotsearch.ant.tasks.junit4.</code></li>
|
* <li><code>com.carrotsearch.ant.tasks.junit4.</code></li>
|
||||||
* <li><code>org.eclipse.internal.junit.runner.</code></li>
|
* <li><code>org.eclipse.internal.junit.runner.</code></li>
|
||||||
* <li><code>com.intellij.rt.execution.junit.</code></li>
|
* <li><code>com.intellij.rt.execution.junit.</code></li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @return an instance of SecureSM where test packages can halt or exit the virtual machine
|
* @return an instance of SecureSM where test packages can halt or exit the virtual machine
|
||||||
*/
|
*/
|
||||||
|
@ -96,15 +98,15 @@ public class SecureSM extends SecurityManager {
|
||||||
return new SecureSM(TEST_RUNNER_PACKAGES);
|
return new SecureSM(TEST_RUNNER_PACKAGES);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String[] TEST_RUNNER_PACKAGES = new String[] {
|
static final String[] TEST_RUNNER_PACKAGES = new String[] {
|
||||||
// surefire test runner
|
// surefire test runner
|
||||||
"org.apache.maven.surefire.booter.",
|
"org\\.apache\\.maven\\.surefire\\.booter\\..*",
|
||||||
// junit4 test runner
|
// junit4 test runner
|
||||||
"com.carrotsearch.ant.tasks.junit4.",
|
"com\\.carrotsearch\\.ant\\.tasks\\.junit4\\.slave\\..*",
|
||||||
// eclipse test runner
|
// eclipse test runner
|
||||||
"org.eclipse.jdt.internal.junit.runner.",
|
"org\\.eclipse.jdt\\.internal\\.junit\\.runner\\..*",
|
||||||
// intellij test runner
|
// intellij test runner
|
||||||
"com.intellij.rt.execution.junit."
|
"com\\.intellij\\.rt\\.execution\\.junit\\..*"
|
||||||
};
|
};
|
||||||
|
|
||||||
// java.security.debug support
|
// java.security.debug support
|
||||||
|
@ -203,6 +205,8 @@ public class SecureSM extends SecurityManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "Uwe Schindler" algorithm.
|
* The "Uwe Schindler" algorithm.
|
||||||
|
*
|
||||||
|
* @param status the exit status
|
||||||
*/
|
*/
|
||||||
protected void innerCheckExit(final int status) {
|
protected void innerCheckExit(final int status) {
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||||
|
@ -222,14 +226,12 @@ public class SecureSM extends SecurityManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exitMethodHit != null) {
|
if (exitMethodHit != null) {
|
||||||
if (packagesThatCanExit == null) {
|
if (classesThatCanExit == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (String packageThatCanExit : packagesThatCanExit) {
|
if (classCanExit(className, classesThatCanExit)) {
|
||||||
if (className.startsWith(packageThatCanExit)) {
|
// this exit point is allowed, we return normally from closure:
|
||||||
// this exit point is allowed, we return normally from closure:
|
return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// anything else in stack trace is not allowed, break and throw SecurityException below:
|
// anything else in stack trace is not allowed, break and throw SecurityException below:
|
||||||
break;
|
break;
|
||||||
|
@ -248,4 +250,13 @@ public class SecureSM extends SecurityManager {
|
||||||
super.checkExit(status);
|
super.checkExit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean classCanExit(final String className, final String[] classesThatCanExit) {
|
||||||
|
for (final String classThatCanExit : classesThatCanExit) {
|
||||||
|
if (className.matches(classThatCanExit)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,16 @@ public class TestSecureSM extends TestCase {
|
||||||
fail("did not hit expected exception");
|
fail("did not hit expected exception");
|
||||||
} catch (SecurityException expected) {}
|
} catch (SecurityException expected) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClassCanExit() {
|
||||||
|
assertTrue(SecureSM.classCanExit("org.apache.maven.surefire.booter.CommandReader", SecureSM.TEST_RUNNER_PACKAGES));
|
||||||
|
assertTrue(SecureSM.classCanExit("com.carrotsearch.ant.tasks.junit4.slave.JvmExit", SecureSM.TEST_RUNNER_PACKAGES));
|
||||||
|
assertTrue(SecureSM.classCanExit("org.eclipse.jdt.internal.junit.runner.RemoteTestRunner", SecureSM.TEST_RUNNER_PACKAGES));
|
||||||
|
assertTrue(SecureSM.classCanExit("com.intellij.rt.execution.junit.JUnitStarter", SecureSM.TEST_RUNNER_PACKAGES));
|
||||||
|
assertTrue(SecureSM.classCanExit("org.elasticsearch.Foo", new String[]{"org.elasticsearch.Foo"}));
|
||||||
|
assertFalse(SecureSM.classCanExit("org.elasticsearch.Foo", new String[]{"org.elasticsearch.Bar"}));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateThread() throws Exception {
|
public void testCreateThread() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue