Skip to content

Commit e6bd34e

Browse files
committed
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
1 parent 09057f2 commit e6bd34e

File tree

2 files changed

+40
-19
lines changed

2 files changed

+40
-19
lines changed

securesm/src/main/java/org/elasticsearch/SecureSM.java

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
*/
6464
public class SecureSM extends SecurityManager {
6565

66-
private final String[] packagesThatCanExit;
66+
private final String[] classesThatCanExit;
6767

6868
/**
6969
* Creates a new security manager where no packages can exit nor halt the virtual machine.
@@ -73,38 +73,40 @@ public SecureSM() {
7373
}
7474

7575
/**
76-
* Creates a new security manager with the specified list of packages being the only packages
77-
* that can exit or halt the virtual machine.
76+
* Creates a new security manager with the specified list of regular expressions as the those that class names will be tested against to
77+
* check whether or not a class can exit or halt the virtual machine.
7878
*
79-
* @param packagesThatCanExit the list of packages that can exit or halt the virtual machine
79+
* @param classesThatCanExit the list of classes that can exit or halt the virtual machine
8080
*/
81-
public SecureSM(final String[] packagesThatCanExit) {
82-
this.packagesThatCanExit = packagesThatCanExit;
81+
public SecureSM(final String[] classesThatCanExit) {
82+
this.classesThatCanExit = classesThatCanExit;
8383
}
8484

8585
/**
86-
* Creates a new security manager with a standard set of test packages being the only packages
87-
* that can exit or halt the virtual machine. The packages that can exit are
86+
* Creates a new security manager with a standard set of test packages being the only packages that can exit or halt the virtual machine.
87+
* The packages that can exit are:
88+
* <ul>
8889
* <li><code>org.apache.maven.surefire.booter.</code></li>
8990
* <li><code>com.carrotsearch.ant.tasks.junit4.</code></li>
9091
* <li><code>org.eclipse.internal.junit.runner.</code></li>
9192
* <li><code>com.intellij.rt.execution.junit.</code></li>
93+
* </ul>
9294
*
9395
* @return an instance of SecureSM where test packages can halt or exit the virtual machine
9496
*/
9597
public static SecureSM createTestSecureSM() {
9698
return new SecureSM(TEST_RUNNER_PACKAGES);
9799
}
98100

99-
private static final String[] TEST_RUNNER_PACKAGES = new String[] {
101+
static final String[] TEST_RUNNER_PACKAGES = new String[] {
100102
// surefire test runner
101-
"org.apache.maven.surefire.booter.",
103+
"org\\.apache\\.maven\\.surefire\\.booter\\..*",
102104
// junit4 test runner
103-
"com.carrotsearch.ant.tasks.junit4.",
105+
"com\\.carrotsearch\\.ant\\.tasks\\.junit4\\.slave\\..*",
104106
// eclipse test runner
105-
"org.eclipse.jdt.internal.junit.runner.",
107+
"org\\.eclipse.jdt\\.internal\\.junit\\.runner\\..*",
106108
// intellij test runner
107-
"com.intellij.rt.execution.junit."
109+
"com\\.intellij\\.rt\\.execution\\.junit\\..*"
108110
};
109111

110112
// java.security.debug support
@@ -203,6 +205,8 @@ public void checkExit(int status) {
203205

204206
/**
205207
* The "Uwe Schindler" algorithm.
208+
*
209+
* @param status the exit status
206210
*/
207211
protected void innerCheckExit(final int status) {
208212
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@@ -222,14 +226,12 @@ public Void run() {
222226
}
223227

224228
if (exitMethodHit != null) {
225-
if (packagesThatCanExit == null) {
229+
if (classesThatCanExit == null) {
226230
break;
227231
}
228-
for (String packageThatCanExit : packagesThatCanExit) {
229-
if (className.startsWith(packageThatCanExit)) {
230-
// this exit point is allowed, we return normally from closure:
231-
return null;
232-
}
232+
if (classCanExit(className, classesThatCanExit)) {
233+
// this exit point is allowed, we return normally from closure:
234+
return null;
233235
}
234236
// anything else in stack trace is not allowed, break and throw SecurityException below:
235237
break;
@@ -248,4 +250,13 @@ public Void run() {
248250
super.checkExit(status);
249251
}
250252

253+
static boolean classCanExit(final String className, final String[] classesThatCanExit) {
254+
for (final String classThatCanExit : classesThatCanExit) {
255+
if (className.matches(classThatCanExit)) {
256+
return true;
257+
}
258+
}
259+
return false;
260+
}
261+
251262
}

securesm/src/test/java/org/elasticsearch/TestSecureSM.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ public void testTryToExit() {
5555
fail("did not hit expected exception");
5656
} catch (SecurityException expected) {}
5757
}
58+
59+
@Test
60+
public void testClassCanExit() {
61+
assertTrue(SecureSM.classCanExit("org.apache.maven.surefire.booter.CommandReader", SecureSM.TEST_RUNNER_PACKAGES));
62+
assertTrue(SecureSM.classCanExit("com.carrotsearch.ant.tasks.junit4.slave.JvmExit", SecureSM.TEST_RUNNER_PACKAGES));
63+
assertTrue(SecureSM.classCanExit("org.eclipse.jdt.internal.junit.runner.RemoteTestRunner", SecureSM.TEST_RUNNER_PACKAGES));
64+
assertTrue(SecureSM.classCanExit("com.intellij.rt.execution.junit.JUnitStarter", SecureSM.TEST_RUNNER_PACKAGES));
65+
assertTrue(SecureSM.classCanExit("org.elasticsearch.Foo", new String[]{"org.elasticsearch.Foo"}));
66+
assertFalse(SecureSM.classCanExit("org.elasticsearch.Foo", new String[]{"org.elasticsearch.Bar"}));
67+
}
5868

5969
@Test
6070
public void testCreateThread() throws Exception {

0 commit comments

Comments
 (0)