Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@
* <p>
* A bit like Mockito but way more painful.
*/
class DummyImplementations {

static class DummyLocaleServiceProvider extends LocaleServiceProvider {
public class DummyImplementations {

public static class DummyLocaleServiceProvider extends LocaleServiceProvider {
@Override
public Locale[] getAvailableLocales() {
throw unexpected();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {

private static final Map<String, CheckAction> checkActions = Stream.concat(
Stream.<Entry<String, CheckAction>>of(
entry("static_reflection", deniedToPlugins(RestEntitlementsCheckAction::staticMethodNeverEntitledViaReflection)),
entry("nonstatic_reflection", deniedToPlugins(RestEntitlementsCheckAction::nonstaticMethodNeverEntitledViaReflection)),
entry("constructor_reflection", deniedToPlugins(RestEntitlementsCheckAction::constructorNeverEntitledViaReflection)),
entry("runtime_exit", deniedToPlugins(RestEntitlementsCheckAction::runtimeExit)),
entry("runtime_halt", deniedToPlugins(RestEntitlementsCheckAction::runtimeHalt)),
entry("system_exit", deniedToPlugins(RestEntitlementsCheckAction::systemExit)),
Expand Down Expand Up @@ -338,6 +341,11 @@ private static void systemExit() {
System.exit(123);
}

private static void staticMethodNeverEntitledViaReflection() throws Exception {
Method systemExit = System.class.getMethod("exit", int.class);
systemExit.invoke(null, 123);
}

private static void createClassLoader() throws IOException {
try (var classLoader = new URLClassLoader("test", new URL[0], RestEntitlementsCheckAction.class.getClassLoader())) {
logger.info("Created URLClassLoader [{}]", classLoader.getName());
Expand All @@ -348,6 +356,11 @@ private static void processBuilder_start() throws IOException {
new ProcessBuilder("").start();
}

private static void nonstaticMethodNeverEntitledViaReflection() throws Exception {
Method processBuilderStart = ProcessBuilder.class.getMethod("start");
processBuilderStart.invoke(new ProcessBuilder(""));
}

private static void processBuilder_startPipeline() throws IOException {
ProcessBuilder.startPipeline(List.of());
}
Expand Down Expand Up @@ -386,6 +399,10 @@ private static void setHttpsConnectionProperties() {
new DummyLocaleServiceProvider();
}

private static void constructorNeverEntitledViaReflection() throws Exception {
DummyLocaleServiceProvider.class.getConstructor().newInstance();
}

private static void breakIteratorProvider$() {
new DummyBreakIteratorProvider();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ protected void before() throws Throwable {
.systemProperty("es.entitlements.enabled", "true")
.systemProperty("es.entitlements.testdir", () -> testDir.getRoot().getAbsolutePath())
.setting("xpack.security.enabled", "false")
.setting("logger.org.elasticsearch.entitlement", "TRACE")
.build();
ruleChain = RuleChain.outerRule(testDir).around(tempDirSetup).around(cluster);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
import org.elasticsearch.logging.Logger;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
import java.util.Map;
import java.util.function.Function;

Expand Down Expand Up @@ -144,19 +146,33 @@ private static String findAgentJar() {
* @throws IllegalStateException if the entitlements system can't prevent an unauthorized action of our choosing
*/
private static void selfTest() {
ensureCannotStartProcess();
ensureCanCreateTempFile();
ensureCannotStartProcess(false);
ensureCannotStartProcess(true);
ensureCanCreateTempFile(false);
ensureCanCreateTempFile(true);
}

private static void ensureCannotStartProcess() {
private static void ensureCannotStartProcess(boolean useReflection) {
try {
// The command doesn't matter; it doesn't even need to exist
new ProcessBuilder("").start();
ProcessBuilder builder = new ProcessBuilder("");
if (useReflection) {
try {
var start = ProcessBuilder.class.getMethod("start");
start.invoke(builder);
} catch (InvocationTargetException e) {
throw e.getCause();
}
} else {
builder.start();
}
} catch (NotEntitledException e) {
logger.debug("Success: Entitlement protection correctly prevented process creation");
return;
} catch (IOException e) {
throw new IllegalStateException("Failed entitlement protection self-test", e);
} catch (Throwable e) {
throw new IllegalStateException("Error during entitlement protection self-test", e);
}
throw new IllegalStateException("Entitlement protection self-test was incorrectly permitted");
}
Expand All @@ -165,9 +181,15 @@ private static void ensureCannotStartProcess() {
* Originally {@code Security.selfTest}.
*/
@SuppressForbidden(reason = "accesses jvm default tempdir as a self-test")
private static void ensureCanCreateTempFile() {
private static void ensureCanCreateTempFile(boolean useReflection) {
try {
Path p = Files.createTempFile(null, null);
Path p;
if (useReflection) {
p = (Path) Files.class.getMethod("createTempFile", String.class, String.class, FileAttribute[].class)
.invoke(null, null, null, new FileAttribute<?>[0]);
} else {
p = Files.createTempFile(null, null);
}
p.toFile().deleteOnExit();

// Make an effort to clean up the file immediately; also, deleteOnExit leaves the file if the JVM exits abnormally.
Expand Down