Skip to content

Commit c3a59bb

Browse files
authored
Process execution checks and IT tests (#119010)
* Process creation checks and IT tests * Remove process queries; only forbid execution
1 parent c54a26d commit c3a59bb

File tree

8 files changed

+66
-15
lines changed

8 files changed

+66
-15
lines changed

libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java.net.URL;
1313
import java.net.URLStreamHandlerFactory;
14+
import java.util.List;
1415

1516
public interface EntitlementChecker {
1617

@@ -29,4 +30,10 @@ public interface EntitlementChecker {
2930
void check$java_net_URLClassLoader$(Class<?> callerClass, String name, URL[] urls, ClassLoader parent);
3031

3132
void check$java_net_URLClassLoader$(Class<?> callerClass, String name, URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory);
33+
34+
// Process creation
35+
void check$$start(Class<?> callerClass, ProcessBuilder that, ProcessBuilder.Redirect[] redirects);
36+
37+
void check$java_lang_ProcessBuilder$startPipeline(Class<?> callerClass, List<ProcessBuilder> builders);
38+
3239
}

libs/entitlement/qa/common/src/main/java/org/elasticsearch/entitlement/qa/common/RestEntitlementsCheckAction.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,58 +29,74 @@
2929
import java.util.stream.Collectors;
3030

3131
import static java.util.Map.entry;
32+
import static org.elasticsearch.entitlement.qa.common.RestEntitlementsCheckAction.CheckAction.deniedToPlugins;
33+
import static org.elasticsearch.entitlement.qa.common.RestEntitlementsCheckAction.CheckAction.forPlugins;
3234
import static org.elasticsearch.rest.RestRequest.Method.GET;
3335

3436
public class RestEntitlementsCheckAction extends BaseRestHandler {
3537
private static final Logger logger = LogManager.getLogger(RestEntitlementsCheckAction.class);
3638
private final String prefix;
3739

38-
private record CheckAction(Runnable action, boolean isServerOnly) {
39-
40-
static CheckAction serverOnly(Runnable action) {
40+
record CheckAction(Runnable action, boolean isAlwaysDeniedToPlugins) {
41+
/**
42+
* These cannot be granted to plugins, so our test plugins cannot test the "allowed" case.
43+
* Used both for always-denied entitlements as well as those granted only to the server itself.
44+
*/
45+
static CheckAction deniedToPlugins(Runnable action) {
4146
return new CheckAction(action, true);
4247
}
4348

44-
static CheckAction serverAndPlugin(Runnable action) {
49+
static CheckAction forPlugins(Runnable action) {
4550
return new CheckAction(action, false);
4651
}
4752
}
4853

4954
private static final Map<String, CheckAction> checkActions = Map.ofEntries(
50-
entry("runtime_exit", CheckAction.serverOnly(RestEntitlementsCheckAction::runtimeExit)),
51-
entry("runtime_halt", CheckAction.serverOnly(RestEntitlementsCheckAction::runtimeHalt)),
52-
entry("create_classloader", CheckAction.serverAndPlugin(RestEntitlementsCheckAction::createClassLoader))
55+
entry("runtime_exit", deniedToPlugins(RestEntitlementsCheckAction::runtimeExit)),
56+
entry("runtime_halt", deniedToPlugins(RestEntitlementsCheckAction::runtimeHalt)),
57+
entry("create_classloader", forPlugins(RestEntitlementsCheckAction::createClassLoader)),
58+
// entry("processBuilder_start", deniedToPlugins(RestEntitlementsCheckAction::processBuilder_start)),
59+
entry("processBuilder_startPipeline", deniedToPlugins(RestEntitlementsCheckAction::processBuilder_startPipeline))
5360
);
5461

5562
@SuppressForbidden(reason = "Specifically testing Runtime.exit")
5663
private static void runtimeExit() {
57-
logger.info("Calling Runtime.exit;");
5864
Runtime.getRuntime().exit(123);
5965
}
6066

6167
@SuppressForbidden(reason = "Specifically testing Runtime.halt")
6268
private static void runtimeHalt() {
63-
logger.info("Calling Runtime.halt;");
6469
Runtime.getRuntime().halt(123);
6570
}
6671

6772
private static void createClassLoader() {
68-
logger.info("Calling new URLClassLoader");
6973
try (var classLoader = new URLClassLoader("test", new URL[0], RestEntitlementsCheckAction.class.getClassLoader())) {
7074
logger.info("Created URLClassLoader [{}]", classLoader.getName());
7175
} catch (IOException e) {
7276
throw new UncheckedIOException(e);
7377
}
7478
}
7579

80+
private static void processBuilder_start() {
81+
// TODO: processBuilder().start();
82+
}
83+
84+
private static void processBuilder_startPipeline() {
85+
try {
86+
ProcessBuilder.startPipeline(List.of());
87+
} catch (IOException e) {
88+
throw new IllegalStateException(e);
89+
}
90+
}
91+
7692
public RestEntitlementsCheckAction(String prefix) {
7793
this.prefix = prefix;
7894
}
7995

8096
public static Set<String> getServerAndPluginsCheckActions() {
8197
return checkActions.entrySet()
8298
.stream()
83-
.filter(kv -> kv.getValue().isServerOnly() == false)
99+
.filter(kv -> kv.getValue().isAlwaysDeniedToPlugins() == false)
84100
.map(Map.Entry::getKey)
85101
.collect(Collectors.toSet());
86102
}
@@ -112,6 +128,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
112128
}
113129

114130
return channel -> {
131+
logger.info("Calling check action [{}]", actionName);
115132
checkAction.action().run();
116133
channel.sendResponse(new RestResponse(RestStatus.OK, Strings.format("Succesfully executed action [%s]", actionName)));
117134
};

libs/entitlement/qa/entitlement-allowed-nonmodular/src/main/java/org/elasticsearch/entitlement/qa/nonmodular/EntitlementAllowedNonModularPlugin.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.function.Supplier;
2828

2929
public class EntitlementAllowedNonModularPlugin extends Plugin implements ActionPlugin {
30-
3130
@Override
3231
public List<RestHandler> getRestHandlers(
3332
final Settings settings,

libs/entitlement/qa/entitlement-allowed/src/main/java/org/elasticsearch/entitlement/qa/EntitlementAllowedPlugin.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.function.Supplier;
2828

2929
public class EntitlementAllowedPlugin extends Plugin implements ActionPlugin {
30-
3130
@Override
3231
public List<RestHandler> getRestHandlers(
3332
final Settings settings,

libs/entitlement/qa/entitlement-denied-nonmodular/src/main/java/org/elasticsearch/entitlement/qa/nonmodular/EntitlementDeniedNonModularPlugin.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.function.Supplier;
2828

2929
public class EntitlementDeniedNonModularPlugin extends Plugin implements ActionPlugin {
30-
3130
@Override
3231
public List<RestHandler> getRestHandlers(
3332
final Settings settings,

libs/entitlement/qa/entitlement-denied/src/main/java/org/elasticsearch/entitlement/qa/EntitlementDeniedPlugin.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.function.Supplier;
2828

2929
public class EntitlementDeniedPlugin extends Plugin implements ActionPlugin {
30-
3130
@Override
3231
public List<RestHandler> getRestHandlers(
3332
final Settings settings,

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import java.net.URL;
1616
import java.net.URLStreamHandlerFactory;
17+
import java.util.List;
1718

1819
/**
1920
* Implementation of the {@link EntitlementChecker} interface, providing additional
@@ -67,4 +68,14 @@ public ElasticsearchEntitlementChecker(PolicyManager policyManager) {
6768
) {
6869
policyManager.checkCreateClassLoader(callerClass);
6970
}
71+
72+
@Override
73+
public void check$$start(Class<?> callerClass, ProcessBuilder processBuilder, ProcessBuilder.Redirect[] redirects) {
74+
policyManager.checkStartProcess(callerClass);
75+
}
76+
77+
@Override
78+
public void check$java_lang_ProcessBuilder$startPipeline(Class<?> callerClass, List<ProcessBuilder> builders) {
79+
policyManager.checkStartProcess(callerClass);
80+
}
7081
}

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,26 @@ private static Map<String, List<Entitlement>> buildScopeEntitlementsMap(Policy p
105105
return policy.scopes.stream().collect(Collectors.toUnmodifiableMap(scope -> scope.name, scope -> scope.entitlements));
106106
}
107107

108+
public void checkStartProcess(Class<?> callerClass) {
109+
neverEntitled(callerClass, "start process");
110+
}
111+
112+
private void neverEntitled(Class<?> callerClass, String operationDescription) {
113+
var requestingModule = requestingModule(callerClass);
114+
if (isTriviallyAllowed(requestingModule)) {
115+
return;
116+
}
117+
118+
throw new NotEntitledException(
119+
Strings.format(
120+
"Not entitled: caller [%s], module [%s], operation [%s]",
121+
callerClass,
122+
requestingModule.getName(),
123+
operationDescription
124+
)
125+
);
126+
}
127+
108128
public void checkExitVM(Class<?> callerClass) {
109129
checkEntitlementPresent(callerClass, ExitVMEntitlement.class);
110130
}

0 commit comments

Comments
 (0)