Skip to content

Commit 647327f

Browse files
committed
Make script.groovy.sandbox.method_blacklist_patch truly append-only
Additionally, this setting can be specified in elasticsearch.yml if desired, to pre-populate the list of methods to be added to the default blacklist. When making a change to this setting dynamically, the entire blacklist is logged as well. Conflicts: src/main/java/org/elasticsearch/script/ScriptService.java
1 parent 68f5ee2 commit 647327f

File tree

4 files changed

+25
-21
lines changed

4 files changed

+25
-21
lines changed

src/main/java/org/elasticsearch/script/ScriptService.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import java.io.IOException;
7272
import java.io.InputStreamReader;
7373
import java.util.Arrays;
74+
import java.nio.file.Files;
7475
import java.util.Locale;
7576
import java.util.Map;
7677
import java.util.Set;
@@ -227,10 +228,10 @@ public void onRefreshSettings(Settings settings) {
227228
GroovyScriptEngineService engine = (GroovyScriptEngineService) ScriptService.this.scriptEngines.get("groovy");
228229
if (engine != null) {
229230
String[] patches = settings.getAsArray(GroovyScriptEngineService.GROOVY_SCRIPT_BLACKLIST_PATCH, Strings.EMPTY_ARRAY);
230-
if (Arrays.equals(patches, engine.blacklistAdditions()) == false) {
231-
logger.info("updating [{}] from {} to {}", GroovyScriptEngineService.GROOVY_SCRIPT_BLACKLIST_PATCH,
232-
engine.blacklistAdditions(), patches);
233-
engine.blacklistAdditions(patches);
231+
boolean blacklistChanged = engine.addToBlacklist(patches);
232+
if (blacklistChanged) {
233+
logger.info("adding {} to [{}], new blacklisted methods: {}", patches,
234+
GroovyScriptEngineService.GROOVY_SCRIPT_BLACKLIST_PATCH, engine.blacklistAdditions());
234235
engine.reloadConfig();
235236
// Because the GroovyScriptEngineService knows nothing about the
236237
// cache, we need to clear it here if the setting changes

src/main/java/org/elasticsearch/script/groovy/GroovySandboxExpressionChecker.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class GroovySandboxExpressionChecker implements SecureASTCustomizer.Expre
5353
private final Set<String> packageWhitelist;
5454
private final Set<String> classWhitelist;
5555

56-
public GroovySandboxExpressionChecker(Settings settings, String[] blacklistAdditions) {
56+
public GroovySandboxExpressionChecker(Settings settings, Set<String> blacklistAdditions) {
5757
this.methodBlacklist = ImmutableSet.copyOf(settings.getAsArray(GROOVY_SANDBOX_METHOD_BLACKLIST, defaultMethodBlacklist, true));
5858
this.additionalMethodBlacklist = ImmutableSet.copyOf(blacklistAdditions);
5959
this.packageWhitelist = ImmutableSet.copyOf(settings.getAsArray(GROOVY_SANDBOX_PACKAGE_WHITELIST, defaultPackageWhitelist, true));
@@ -147,7 +147,7 @@ public boolean isAuthorized(Expression expression) {
147147
* Returns a customized ASTCustomizer that includes the whitelists and
148148
* expression checker.
149149
*/
150-
public static SecureASTCustomizer getSecureASTCustomizer(Settings settings, String[] blacklistAdditions) {
150+
public static SecureASTCustomizer getSecureASTCustomizer(Settings settings, Set<String> blacklistAdditions) {
151151
SecureASTCustomizer scz = new SecureASTCustomizer();
152152
// Closures are allowed
153153
scz.setClosuresAllowed(true);

src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.script.groovy;
2121

22+
import com.google.common.collect.ImmutableSet;
2223
import groovy.lang.Binding;
2324
import groovy.lang.GroovyClassLoader;
2425
import groovy.lang.Script;
@@ -52,7 +53,9 @@
5253
import java.io.IOException;
5354
import java.math.BigDecimal;
5455
import java.util.HashMap;
56+
import java.util.HashSet;
5557
import java.util.Map;
58+
import java.util.Set;
5659
import java.util.concurrent.atomic.AtomicLong;
5760

5861
/**
@@ -66,21 +69,32 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
6669
private final AtomicLong counter = new AtomicLong();
6770
private final boolean sandboxed;
6871
private volatile GroovyClassLoader loader;
69-
private volatile String[] blacklistAdditions = Strings.EMPTY_ARRAY;
72+
private volatile Set<String> blacklistAdditions;
7073

7174
@Inject
7275
public GroovyScriptEngineService(Settings settings) {
7376
super(settings);
7477
this.sandboxed = settings.getAsBoolean(GROOVY_SCRIPT_SANDBOX_ENABLED, true);
78+
this.blacklistAdditions = ImmutableSet.copyOf(settings.getAsArray(GROOVY_SCRIPT_BLACKLIST_PATCH, Strings.EMPTY_ARRAY));
7579
reloadConfig();
7680
}
7781

78-
public String[] blacklistAdditions() {
82+
public Set<String> blacklistAdditions() {
7983
return this.blacklistAdditions;
8084
}
8185

82-
public void blacklistAdditions(String[] additions) {
83-
this.blacklistAdditions = additions;
86+
/**
87+
* Appends the additional blacklisted methods to the current blacklist,
88+
* returns true if the black list has changed
89+
*/
90+
public boolean addToBlacklist(String... additions) {
91+
Set<String> newBlackList = new HashSet<>(blacklistAdditions);
92+
for (String addition : additions) {
93+
newBlackList.add(addition);
94+
}
95+
boolean changed = this.blacklistAdditions.equals(newBlackList) == false;
96+
this.blacklistAdditions = ImmutableSet.copyOf(newBlackList);
97+
return changed;
8498
}
8599

86100
public void reloadConfig() {

src/test/java/org/elasticsearch/script/GroovySandboxScriptTests.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,6 @@ public void testDynamicBlacklist() throws Exception {
110110
"Expression [MethodCallExpression] is not allowed: [doc[foo].value, 3, 4].isEmpty()");
111111
testFailure("[doc['foo'].value, 3, 4].size()",
112112
"Expression [MethodCallExpression] is not allowed: [doc[foo].value, 3, 4].size()");
113-
114-
// Undo the blacklist addition and make sure the scripts still work
115-
Settings emptyBlacklistSettings = ImmutableSettings.builder()
116-
.put(GroovyScriptEngineService.GROOVY_SCRIPT_BLACKLIST_PATCH, "")
117-
.build();
118-
119-
client().admin().cluster().prepareUpdateSettings().setTransientSettings(emptyBlacklistSettings).get();
120-
121-
testSuccess("[doc['foo'].value, 3, 4].isEmpty()");
122-
testSuccess("[doc['foo'].value, 3, 4].size()");
123-
124113
}
125114

126115
public void testSuccess(String script) {

0 commit comments

Comments
 (0)