Skip to content

Commit

Permalink
Remove bootstrap.system_call_filter setting (#72848)
Browse files Browse the repository at this point in the history
This commit removes the bootstrap.system_call_filter setting, as
starting in Elasticsearch 8.0.0 we are going to require that system call
filters be installed and that this is not user configurable. Note that
while we force bootstrap to attempt to install system call filters, we
only enforce that they are installed via a bootstrap check in production
environments. We can consider changing this behavior, but leave that for
future consideration and thus a potential follow-up change.
  • Loading branch information
jasontedor authored May 7, 2021
1 parent 694229f commit 8b4b2f9
Show file tree
Hide file tree
Showing 10 changed files with 47 additions and 70 deletions.
9 changes: 5 additions & 4 deletions docs/reference/migration/migrate_8_0/settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,17 @@ Discontinue use of the removed settings. Specifying these settings in
====

[[system-call-filter-setting]]
.System call filter setting deprecated
.System call filter setting removed
[%collapsible]
====
*Details* +
Elasticsearch uses system call filters to remove its ability to fork another
process. This is useful to mitigate remote code exploits. These system call
filters are enabled by default, and controlled via the setting
filters are enabled by default, and were previously controlled via the setting
`bootstrap.system_call_filter`. Starting in Elasticsearch 8.0, system call
filters will be required. As such, the setting `bootstrap.system_call_filter` is
deprecated and will be removed in Elasticsearch 8.0.
filters will be required. As such, the setting `bootstrap.system_call_filter`
was deprecated in Elasticsearch 7.13.0, and is removed as of Elasticsearch
8.0.0.
*Impact* +
Discontinue use of the removed setting. Specifying this setting in Elasticsearch
Expand Down
19 changes: 15 additions & 4 deletions server/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,28 @@ public void run() {
});
}

/** initialize native resources */
public static void initializeNatives(Path tmpFile, boolean mlockAll, boolean systemCallFilter, boolean ctrlHandler) {
/**
* Initialize native resources.
*
* @param tmpFile the temp directory
* @param mlockAll whether or not to lock memory
* @param systemCallFilter whether or not to install system call filters
* @param ctrlHandler whether or not to install the ctrl-c handler (applies to Windows only)
*/
static void initializeNatives(final Path tmpFile, final boolean mlockAll, final boolean systemCallFilter, final boolean ctrlHandler) {
final Logger logger = LogManager.getLogger(Bootstrap.class);

// check if the user is running as root, and bail
if (Natives.definitelyRunningAsRoot()) {
throw new RuntimeException("can not run elasticsearch as root");
}

// enable system call filter
if (systemCallFilter) {
/*
* Try to install system call filters; if they fail to install; a bootstrap check will fail startup in production mode.
*
* TODO: should we fail hard here if system call filters fail to install, or remain lenient in non-production environments?
*/
Natives.tryInstallSystemCallFilter(tmpFile);
}

Expand Down Expand Up @@ -165,7 +176,7 @@ private void setup(boolean addShutdownHook, Environment environment) throws Boot
initializeNatives(
environment.tmpFile(),
BootstrapSettings.MEMORY_LOCK_SETTING.get(settings),
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(settings),
true, // always install system call filters, not user-configurable since 8.0.0
BootstrapSettings.CTRLHANDLER_SETTING.get(settings));

// initialize probes before the security manager is installed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,15 +523,14 @@ String getUseSerialGC() {
}

/**
* Bootstrap check that if system call filters are enabled, then system call filters must have installed successfully.
* Bootstrap check that system call filters must have installed successfully.
*/
static class SystemCallFilterCheck implements BootstrapCheck {

@Override
public BootstrapCheckResult check(BootstrapContext context) {
if (BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(context.settings()) && isSystemCallFilterInstalled() == false) {
final String message = "system call filters failed to install; " +
"check the logs and fix your configuration or disable system call filters at your own risk";
if (isSystemCallFilterInstalled() == false) {
final String message = "system call filters failed to install; check the logs and fix your configuration";
return BootstrapCheckResult.failure(message);
} else {
return BootstrapCheckResult.success();
Expand Down Expand Up @@ -590,10 +589,10 @@ String onError() {
String message(BootstrapContext context) {
return String.format(
Locale.ROOT,
"OnError [%s] requires forking but is prevented by system call filters ([%s=true]);" +
"OnError [%s] requires forking but is prevented by system call filters;" +
" upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError",
onError(),
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.getKey());
onError()
);
}

}
Expand All @@ -614,10 +613,10 @@ String onOutOfMemoryError() {
String message(BootstrapContext context) {
return String.format(
Locale.ROOT,
"OnOutOfMemoryError [%s] requires forking but is prevented by system call filters ([%s=true]);" +
"OnOutOfMemoryError [%s] requires forking but is prevented by system call filters;" +
" upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError",
onOutOfMemoryError(),
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.getKey());
onOutOfMemoryError()
);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,6 @@ public void apply(Settings value, Settings current, Settings previous) {
PluginsService.MANDATORY_SETTING,
BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING,
BootstrapSettings.MEMORY_LOCK_SETTING,
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING,
BootstrapSettings.CTRLHANDLER_SETTING,
KeyStoreWrapper.SEED_SETTING,
IndexingMemoryController.INDEX_BUFFER_SIZE_SETTING,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,37 +417,31 @@ String getUseSerialGC() {

public void testSystemCallFilterCheck() throws NodeValidationException {
final AtomicBoolean isSystemCallFilterInstalled = new AtomicBoolean();
BootstrapContext context = randomBoolean() ? createTestContext(Settings.builder().put("bootstrap.system_call_filter", true)
.build(), null) : emptyContext;
final BootstrapContext context;
if (randomBoolean()) {
context = createTestContext(Settings.builder().put("bootstrap.system_call_filter", true).build(), null);
} else {
context = emptyContext;
}

final BootstrapChecks.SystemCallFilterCheck systemCallFilterEnabledCheck = new BootstrapChecks.SystemCallFilterCheck() {

@Override
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
}

};

final NodeValidationException e = expectThrows(
NodeValidationException.class,
() -> BootstrapChecks.check(context, true, Collections.singletonList(systemCallFilterEnabledCheck)));
assertThat(
e.getMessage(),
containsString("system call filters failed to install; " +
"check the logs and fix your configuration or disable system call filters at your own risk"));
containsString("system call filters failed to install; check the logs and fix your configuration"));

isSystemCallFilterInstalled.set(true);
BootstrapChecks.check(context, true, Collections.singletonList(systemCallFilterEnabledCheck));
BootstrapContext context_1 = createTestContext(Settings.builder().put("bootstrap.system_call_filter", false).build(), null);
final BootstrapChecks.SystemCallFilterCheck systemCallFilterNotEnabledCheck = new BootstrapChecks.SystemCallFilterCheck() {
@Override
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
}
};
isSystemCallFilterInstalled.set(false);
BootstrapChecks.check(context_1, true, Collections.singletonList(systemCallFilterNotEnabledCheck));
isSystemCallFilterInstalled.set(true);
BootstrapChecks.check(context_1, true, Collections.singletonList(systemCallFilterNotEnabledCheck));
}

public void testMightForkCheck() throws NodeValidationException {
Expand Down Expand Up @@ -482,6 +476,7 @@ public void testOnErrorCheck() throws NodeValidationException {
final AtomicBoolean isSystemCallFilterInstalled = new AtomicBoolean();
final AtomicReference<String> onError = new AtomicReference<>();
final BootstrapChecks.MightForkCheck check = new BootstrapChecks.OnErrorCheck() {

@Override
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
Expand All @@ -491,6 +486,7 @@ boolean isSystemCallFilterInstalled() {
String onError() {
return onError.get();
}

};

final String command = randomAlphaOfLength(16);
Expand All @@ -502,14 +498,15 @@ String onError() {
e -> assertThat(
e.getMessage(),
containsString(
"OnError [" + command + "] requires forking but is prevented by system call filters " +
"([bootstrap.system_call_filter=true]); upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError")));
"OnError [" + command + "] requires forking but is prevented by system call filters;" +
" upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError")));
}

public void testOnOutOfMemoryErrorCheck() throws NodeValidationException {
final AtomicBoolean isSystemCallFilterInstalled = new AtomicBoolean();
final AtomicReference<String> onOutOfMemoryError = new AtomicReference<>();
final BootstrapChecks.MightForkCheck check = new BootstrapChecks.OnOutOfMemoryErrorCheck() {

@Override
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
Expand All @@ -519,6 +516,7 @@ boolean isSystemCallFilterInstalled() {
String onOutOfMemoryError() {
return onOutOfMemoryError.get();
}

};

final String command = randomAlphaOfLength(16);
Expand All @@ -531,7 +529,7 @@ String onOutOfMemoryError() {
e.getMessage(),
containsString(
"OnOutOfMemoryError [" + command + "]"
+ " requires forking but is prevented by system call filters ([bootstrap.system_call_filter=true]);"
+ " requires forking but is prevented by system call filters;"
+ " upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError")));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public class BootstrapSettingsTests extends ESTestCase {
public void testDefaultSettings() {
assertTrue(BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING.get(Settings.EMPTY));
assertFalse(BootstrapSettings.MEMORY_LOCK_SETTING.get(Settings.EMPTY));
assertTrue(BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(Settings.EMPTY));
assertTrue(BootstrapSettings.CTRLHANDLER_SETTING.get(Settings.EMPTY));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public class BootstrapForTesting {
// just like bootstrap, initialize natives, then SM
final boolean memoryLock =
BootstrapSettings.MEMORY_LOCK_SETTING.get(Settings.EMPTY); // use the default bootstrap.memory_lock setting
// some tests need the ability to disable system call filters (so they can fork other processes as part of test execution)
final boolean systemCallFilter = Booleans.parseBoolean(System.getProperty("tests.system_call_filter", "true"));
Bootstrap.initializeNatives(javaTmpDir, memoryLock, systemCallFilter, true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ private DeprecationChecks() {
static List<Function<ClusterState, DeprecationIssue>> CLUSTER_SETTINGS_CHECKS =
Collections.emptyList();

static List<BiFunction<Settings, PluginsAndModules, DeprecationIssue>> NODE_SETTINGS_CHECKS =
List.of(NodeDeprecationChecks::checkBootstrapSystemCallFilterSetting);
static List<BiFunction<Settings, PluginsAndModules, DeprecationIssue>> NODE_SETTINGS_CHECKS = List.of();

static List<Function<IndexMetadata, DeprecationIssue>> INDEX_SETTINGS_CHECKS =
List.of(IndexDeprecationChecks::oldIndicesCheck, IndexDeprecationChecks::translogRetentionSettingCheck);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
package org.elasticsearch.xpack.deprecation;

import org.elasticsearch.action.admin.cluster.node.info.PluginsAndModules;
import org.elasticsearch.bootstrap.BootstrapSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
Expand All @@ -18,14 +17,6 @@

public class NodeDeprecationChecks {

static DeprecationIssue checkBootstrapSystemCallFilterSetting(final Settings settings, final PluginsAndModules pluginsAndModules) {
return checkRemovedSetting(
settings,
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING,
"https://www.elastic.co/guide/en/elasticsearch/reference/7.13/breaking-changes-7.13.html#deprecate-system-call-filter-setting"
);
}

private static DeprecationIssue checkDeprecatedSetting(
final Settings settings,
final PluginsAndModules pluginsAndModules,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,17 @@

package org.elasticsearch.xpack.deprecation;

import org.elasticsearch.action.admin.cluster.node.info.PluginsAndModules;
import org.elasticsearch.bootstrap.BootstrapSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;

import java.util.List;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;

public class NodeDeprecationChecksTests extends ESTestCase {

public void testCheckBootstrapSystemCallFilterSetting() {
final boolean boostrapSystemCallFilter = randomBoolean();
final Settings settings =
Settings.builder().put(BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.getKey(), boostrapSystemCallFilter).build();
final PluginsAndModules pluginsAndModules = new PluginsAndModules(List.of(), List.of());
final List<DeprecationIssue> issues =
DeprecationChecks.filterChecks(DeprecationChecks.NODE_SETTINGS_CHECKS, c -> c.apply(settings, pluginsAndModules));
final DeprecationIssue expected = new DeprecationIssue(
DeprecationIssue.Level.CRITICAL,
"setting [bootstrap.system_call_filter] is deprecated and will be removed in the next major version",
"https://www.elastic.co/guide/en/elasticsearch/reference/7.13/breaking-changes-7.13.html#deprecate-system-call-filter-setting",
"the setting [bootstrap.system_call_filter] is currently set to [" + boostrapSystemCallFilter + "], remove this setting");
assertThat(issues, hasItem(expected));
assertSettingDeprecationsAndWarnings(new Setting<?>[]{BootstrapSettings.SYSTEM_CALL_FILTER_SETTING});
}

public void testRemovedSettingNotSet() {
final Settings settings = Settings.EMPTY;
final Setting<?> removedSetting = Setting.simpleString("node.removed_setting");
Expand Down

0 comments on commit 8b4b2f9

Please sign in to comment.