39
39
* a thread must have {@code modifyThread} to even terminate its own pool, leaving
40
40
* system threads unprotected.
41
41
* </ul>
42
- * This class throws exception on {@code exitVM} calls, and provides a testing mode
43
- * where calls from test runners are allowed.
42
+ * This class throws exception on {@code exitVM} calls, and provides a whitelist where calls
43
+ * from exit are allowed.
44
44
* <p>
45
45
* Additionally it enforces threadgroup security with the following rules:
46
46
* <ul>
62
62
* http://cs.oswego.edu/pipermail/concurrency-interest/2009-August/006508.html</a>
63
63
*/
64
64
public class SecureSM extends SecurityManager {
65
- private final boolean allowTestExit ;
66
-
65
+
66
+ private final String [] packagesThatCanExit ;
67
+
67
68
/**
68
- * Create a new SecurityManager .
69
+ * Creates a new security manager where no packages can exit nor halt the virtual machine .
69
70
*/
70
71
public SecureSM () {
71
- this (false );
72
+ this (new String [ 0 ] );
72
73
}
73
-
74
- /**
75
- * Expert: for testing only.
76
- * @param allowTestExit {@code true} if test-runners should be allowed to exit the VM.
74
+
75
+ /**
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.
78
+ *
79
+ * @param packagesThatCanExit the list of packages that can exit or halt the virtual machine
77
80
*/
78
- public SecureSM (boolean allowTestExit ) {
79
- this .allowTestExit = allowTestExit ;
81
+ public SecureSM (final String [] packagesThatCanExit ) {
82
+ this .packagesThatCanExit = packagesThatCanExit ;
80
83
}
81
-
84
+
85
+ /**
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
88
+ * <li><code>org.apache.maven.surefire.booter.</code></li>
89
+ * <li><code>com.carrotsearch.ant.tasks.junit4.</code></li>
90
+ * <li><code>org.eclipse.internal.junit.runner.</code></li>
91
+ * <li><code>com.intellij.rt.execution.junit.</code></li>
92
+ *
93
+ * @return an instance of SecureSM where test packages can halt or exit the virtual machine
94
+ */
95
+ public static SecureSM createTestSecureSM () {
96
+ return new SecureSM (TEST_RUNNER_PACKAGES );
97
+ }
98
+
99
+ private static final String [] TEST_RUNNER_PACKAGES = new String [] {
100
+ // surefire test runner
101
+ "org.apache.maven.surefire.booter." ,
102
+ // junit4 test runner
103
+ "com.carrotsearch.ant.tasks.junit4." ,
104
+ // eclipse test runner
105
+ "org.eclipse.jdt.internal.junit.runner." ,
106
+ // intellij test runner
107
+ "com.intellij.rt.execution.junit."
108
+ };
109
+
82
110
// java.security.debug support
83
111
private static final boolean DEBUG = AccessController .doPrivileged (new PrivilegedAction <Boolean >() {
84
112
@ Override
@@ -170,28 +198,13 @@ protected void checkThreadGroupAccess(ThreadGroup g) {
170
198
// exit permission logic
171
199
@ Override
172
200
public void checkExit (int status ) {
173
- if (allowTestExit ) {
174
- checkTestExit (status );
175
- } else {
176
- throw new SecurityException ("exit(" + status + ") not allowed by system policy" );
177
- }
201
+ innerCheckExit (status );
178
202
}
179
-
180
- static final String TEST_RUNNER_PACKAGES [] = {
181
- // surefire test runner
182
- "org.apache.maven.surefire.booter." ,
183
- // junit4 test runner
184
- "com.carrotsearch.ant.tasks.junit4." ,
185
- // eclipse test runner
186
- "org.eclipse.jdt.internal.junit.runner." ,
187
- // intellij test runner
188
- "com.intellij.rt.execution.junit."
189
- };
190
203
191
204
/**
192
205
* The "Uwe Schindler" algorithm.
193
206
*/
194
- protected void checkTestExit (final int status ) {
207
+ protected void innerCheckExit (final int status ) {
195
208
AccessController .doPrivileged (new PrivilegedAction <Void >() {
196
209
@ Override
197
210
public Void run () {
@@ -209,8 +222,11 @@ public Void run() {
209
222
}
210
223
211
224
if (exitMethodHit != null ) {
212
- for (String testPackage : TEST_RUNNER_PACKAGES ) {
213
- if (className .startsWith (testPackage )) {
225
+ if (packagesThatCanExit == null ) {
226
+ break ;
227
+ }
228
+ for (String packageThatCanExit : packagesThatCanExit ) {
229
+ if (className .startsWith (packageThatCanExit )) {
214
230
// this exit point is allowed, we return normally from closure:
215
231
return null ;
216
232
}
@@ -224,11 +240,12 @@ public Void run() {
224
240
// should never happen, only if JVM hides stack trace - replace by generic:
225
241
exitMethodHit = "JVM exit method" ;
226
242
}
227
- throw new SecurityException (exitMethodHit + " calls are not allowed because they terminate the test runner's JVM. " );
243
+ throw new SecurityException (exitMethodHit + " calls are not allowed" );
228
244
}
229
245
});
230
246
231
247
// we passed the stack check, delegate to super, so default policy can still deny permission:
232
248
super .checkExit (status );
233
249
}
250
+
234
251
}
0 commit comments