Remove leftover securesm files

These files were leftover after integrating securesm into
libs/secure-sm. This commit removes this leftover directory.
This commit is contained in:
Jason Tedor 2018-01-31 18:49:18 -05:00
parent 1b3d529bef
commit 2570dc5997
4 changed files with 0 additions and 521 deletions

View File

@ -1,262 +0,0 @@
package org.elasticsearch;
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.Objects;
/**
* Extension of SecurityManager that works around a few design flaws in Java Security.
* <p>
* There are a few major problems that require custom {@code SecurityManager} logic to fix:
* <ul>
* <li>{@code exitVM} permission is implicitly granted to all code by the default
* Policy implementation. For a server app, this is not wanted. </li>
* <li>ThreadGroups are not enforced by default, instead only system threads are
* protected out of box by {@code modifyThread/modifyThreadGroup}. Applications
* are encouraged to override the logic here to implement a stricter policy.
* <li>System threads are not even really protected, because if the system uses
* ThreadPools, {@code modifyThread} is abused by its {@code shutdown} checks. This means
* a thread must have {@code modifyThread} to even terminate its own pool, leaving
* system threads unprotected.
* </ul>
* This class throws exception on {@code exitVM} calls, and provides a whitelist where calls
* from exit are allowed.
* <p>
* Additionally it enforces threadgroup security with the following rules:
* <ul>
* <li>{@code modifyThread} and {@code modifyThreadGroup} are required for any thread access
* checks: with these permissions, access is granted as long as the thread group is
* the same or an ancestor ({@code sourceGroup.parentOf(targetGroup) == true}).
* <li>code without these permissions can do very little, except to interrupt itself. It may
* not even create new threads.
* <li>very special cases (like test runners) that have {@link ThreadPermission} can violate
* threadgroup security rules.
* </ul>
* <p>
* If java security debugging ({@code java.security.debug}) is enabled, and this SecurityManager
* is installed, it will emit additional debugging information when threadgroup access checks fail.
*
* @see SecurityManager#checkAccess(Thread)
* @see SecurityManager#checkAccess(ThreadGroup)
* @see <a href="http://cs.oswego.edu/pipermail/concurrency-interest/2009-August/006508.html">
* http://cs.oswego.edu/pipermail/concurrency-interest/2009-August/006508.html</a>
*/
public class SecureSM extends SecurityManager {
private final String[] classesThatCanExit;
/**
* Creates a new security manager where no packages can exit nor halt the virtual machine.
*/
public SecureSM() {
this(new String[0]);
}
/**
* Creates a new security manager with the specified list of regular expressions as the those that class names will be tested against to
* check whether or not a class 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[] classesThatCanExit) {
this.classesThatCanExit = classesThatCanExit;
}
/**
* Creates a new security manager with a standard set of test packages being the only packages that can exit or halt the virtual machine.
* The packages that can exit are:
* <ul>
* <li><code>org.apache.maven.surefire.booter.</code></li>
* <li><code>com.carrotsearch.ant.tasks.junit4.</code></li>
* <li><code>org.eclipse.internal.junit.runner.</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
*/
public static SecureSM createTestSecureSM() {
return new SecureSM(TEST_RUNNER_PACKAGES);
}
static final String[] TEST_RUNNER_PACKAGES = new String[] {
// surefire test runner
"org\\.apache\\.maven\\.surefire\\.booter\\..*",
// junit4 test runner
"com\\.carrotsearch\\.ant\\.tasks\\.junit4\\.slave\\..*",
// eclipse test runner
"org\\.eclipse.jdt\\.internal\\.junit\\.runner\\..*",
// intellij test runner
"com\\.intellij\\.rt\\.execution\\.junit\\..*"
};
// java.security.debug support
private static final boolean DEBUG = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
try {
String v = System.getProperty("java.security.debug");
// simple check that they are trying to debug
return v != null && v.length() > 0;
} catch (SecurityException e) {
return false;
}
}
});
@Override
public void checkAccess(Thread t) {
try {
checkThreadAccess(t);
} catch (SecurityException e) {
if (DEBUG) {
System.out.println("access: caller thread=" + Thread.currentThread());
System.out.println("access: target thread=" + t);
debugThreadGroups(Thread.currentThread().getThreadGroup(), t.getThreadGroup());
}
throw e;
}
}
@Override
public void checkAccess(ThreadGroup g) {
try {
checkThreadGroupAccess(g);
} catch (SecurityException e) {
if (DEBUG) {
System.out.println("access: caller thread=" + Thread.currentThread());
debugThreadGroups(Thread.currentThread().getThreadGroup(), g);
}
throw e;
}
}
private void debugThreadGroups(final ThreadGroup caller, final ThreadGroup target) {
System.out.println("access: caller group=" + caller);
System.out.println("access: target group=" + target);
}
// thread permission logic
private static final Permission MODIFY_THREAD_PERMISSION = new RuntimePermission("modifyThread");
private static final Permission MODIFY_ARBITRARY_THREAD_PERMISSION = new ThreadPermission("modifyArbitraryThread");
protected void checkThreadAccess(Thread t) {
Objects.requireNonNull(t);
// first, check if we can modify threads at all.
checkPermission(MODIFY_THREAD_PERMISSION);
// check the threadgroup, if its our thread group or an ancestor, its fine.
final ThreadGroup source = Thread.currentThread().getThreadGroup();
final ThreadGroup target = t.getThreadGroup();
if (target == null) {
return; // its a dead thread, do nothing.
} else if (source.parentOf(target) == false) {
checkPermission(MODIFY_ARBITRARY_THREAD_PERMISSION);
}
}
private static final Permission MODIFY_THREADGROUP_PERMISSION = new RuntimePermission("modifyThreadGroup");
private static final Permission MODIFY_ARBITRARY_THREADGROUP_PERMISSION = new ThreadPermission("modifyArbitraryThreadGroup");
protected void checkThreadGroupAccess(ThreadGroup g) {
Objects.requireNonNull(g);
// first, check if we can modify thread groups at all.
checkPermission(MODIFY_THREADGROUP_PERMISSION);
// check the threadgroup, if its our thread group or an ancestor, its fine.
final ThreadGroup source = Thread.currentThread().getThreadGroup();
final ThreadGroup target = g;
if (source == null) {
return; // we are a dead thread, do nothing
} else if (source.parentOf(target) == false) {
checkPermission(MODIFY_ARBITRARY_THREADGROUP_PERMISSION);
}
}
// exit permission logic
@Override
public void checkExit(int status) {
innerCheckExit(status);
}
/**
* The "Uwe Schindler" algorithm.
*
* @param status the exit status
*/
protected void innerCheckExit(final int status) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
final String systemClassName = System.class.getName(),
runtimeClassName = Runtime.class.getName();
String exitMethodHit = null;
for (final StackTraceElement se : Thread.currentThread().getStackTrace()) {
final String className = se.getClassName(), methodName = se.getMethodName();
if (
("exit".equals(methodName) || "halt".equals(methodName)) &&
(systemClassName.equals(className) || runtimeClassName.equals(className))
) {
exitMethodHit = className + '#' + methodName + '(' + status + ')';
continue;
}
if (exitMethodHit != null) {
if (classesThatCanExit == null) {
break;
}
if (classCanExit(className, classesThatCanExit)) {
// this exit point is allowed, we return normally from closure:
return null;
}
// anything else in stack trace is not allowed, break and throw SecurityException below:
break;
}
}
if (exitMethodHit == null) {
// should never happen, only if JVM hides stack trace - replace by generic:
exitMethodHit = "JVM exit method";
}
throw new SecurityException(exitMethodHit + " calls are not allowed");
}
});
// we passed the stack check, delegate to super, so default policy can still deny permission:
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;
}
}

View File

@ -1,62 +0,0 @@
package org.elasticsearch;
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.security.BasicPermission;
/**
* Permission to modify threads or thread groups normally not accessible
* to the current thread.
* <p>
* {@link SecureSM} enforces ThreadGroup security: threads with
* {@code RuntimePermission("modifyThread")} or {@code RuntimePermission("modifyThreadGroup")}
* are only allowed to modify their current thread group or an ancestor of that group.
* <p>
* In some cases (e.g. test runners), code needs to manipulate arbitrary threads,
* so this Permission provides for that: the targets {@code modifyArbitraryThread} and
* {@code modifyArbitraryThreadGroup} allow a thread blanket access to any group.
*
* @see ThreadGroup
* @see SecureSM
*/
public final class ThreadPermission extends BasicPermission {
private static final long serialVersionUID = -3467631034676832244L;
/**
* Creates a new ThreadPermission object.
*
* @param name target name
*/
public ThreadPermission(String name) {
super(name);
}
/**
* Creates a new ThreadPermission object.
* This constructor exists for use by the {@code Policy} object to instantiate new Permission objects.
*
* @param name target name
* @param actions ignored
*/
public ThreadPermission(String name, String actions) {
super(name, actions);
}
}

View File

@ -1,147 +0,0 @@
package org.elasticsearch;
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import junit.framework.TestCase;
import org.junit.Test;
import java.security.Permission;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.util.concurrent.atomic.AtomicBoolean;
/** Simple tests for SecureSM */
public class TestSecureSM extends TestCase {
static {
// install a mock security policy:
// AllPermission to source code
// ThreadPermission not granted anywhere else
final ProtectionDomain sourceCode = SecureSM.class.getProtectionDomain();
Policy.setPolicy(new Policy() {
@Override
public boolean implies(ProtectionDomain domain, Permission permission) {
if (domain == sourceCode) {
return true;
} else if (permission instanceof ThreadPermission) {
return false;
}
return true;
}
});
System.setSecurityManager(SecureSM.createTestSecureSM());
}
@Test
public void testTryToExit() {
try {
System.exit(1);
fail("did not hit expected exception");
} 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
public void testCreateThread() throws Exception {
Thread t = new Thread();
t.start();
t.join();
// no exception
}
@Test
public void testCreateThreadGroup() throws Exception {
Thread t = new Thread(new ThreadGroup("childgroup"), "child");
t.start();
t.join();
// no exception
}
@Test
public void testModifyChild() throws Exception {
final AtomicBoolean interrupted = new AtomicBoolean(false);
Thread t = new Thread(new ThreadGroup("childgroup"), "child") {
@Override
public void run() {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException expected) {
interrupted.set(true);
}
}
};
t.start();
t.interrupt();
t.join();
// no exception
assertTrue(interrupted.get());
}
@Test
public void testNoModifySibling() throws Exception {
final AtomicBoolean interrupted1 = new AtomicBoolean(false);
final AtomicBoolean interrupted2 = new AtomicBoolean(false);
final Thread t1 = new Thread(new ThreadGroup("childgroup"), "child") {
@Override
public void run() {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException expected) {
interrupted1.set(true);
}
}
};
t1.start();
Thread t2 = new Thread(new ThreadGroup("anothergroup"), "another child") {
@Override
public void run() {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException expected) {
interrupted2.set(true);
try {
t1.interrupt(); // try to bogusly interrupt our sibling
fail("did not hit expected exception");
} catch (SecurityException expected2) {}
}
}
};
t2.start();
t2.interrupt();
t2.join();
// sibling attempted to but was not able to muck with its other sibling
assertTrue(interrupted2.get());
assertFalse(interrupted1.get());
// but we are the parent and can terminate
t1.interrupt();
t1.join();
assertTrue(interrupted1.get());
}
}

View File

@ -1,50 +0,0 @@
package org.elasticsearch;
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.security.AllPermission;
import org.junit.Test;
import junit.framework.TestCase;
/** Simple tests for ThreadPermission */
public class TestThreadPermission extends TestCase {
@Test
public void testEquals() {
assertEquals(new ThreadPermission("modifyArbitraryThread"), new ThreadPermission("modifyArbitraryThread"));
assertFalse(new ThreadPermission("modifyArbitraryThread").equals(new AllPermission()));
assertFalse(new ThreadPermission("modifyArbitraryThread").equals(new ThreadPermission("modifyArbitraryThreadGroup")));
}
@Test
public void testImplies() {
assertTrue(new ThreadPermission("modifyArbitraryThread").implies(new ThreadPermission("modifyArbitraryThread")));
assertTrue(new ThreadPermission("modifyArbitraryThreadGroup").implies(new ThreadPermission("modifyArbitraryThreadGroup")));
assertFalse(new ThreadPermission("modifyArbitraryThread").implies(new ThreadPermission("modifyArbitraryThreadGroup")));
assertFalse(new ThreadPermission("modifyArbitraryThreadGroup").implies(new ThreadPermission("modifyArbitraryThread")));
assertFalse(new ThreadPermission("modifyArbitraryThread").implies(new AllPermission()));
assertFalse(new ThreadPermission("modifyArbitraryThreadGroup").implies(new AllPermission()));
assertTrue(new ThreadPermission("*").implies(new ThreadPermission("modifyArbitraryThread")));
assertTrue(new ThreadPermission("*").implies(new ThreadPermission("modifyArbitraryThreadGroup")));
assertFalse(new ThreadPermission("*").implies(new AllPermission()));
}
}