Merge remote-tracking branch 'origin/master' into gradle-master

This commit is contained in:
Dawid Weiss 2019-12-18 15:10:04 +01:00
commit 206d62b9d5
6 changed files with 121 additions and 4 deletions

View File

@ -19,6 +19,12 @@ package org.apache.solr.handler.dataimport;
import static org.apache.solr.handler.dataimport.DataImportHandlerException.wrapAndThrow;
import static org.apache.solr.handler.dataimport.DataImportHandlerException.SEVERE;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.Map;
import javax.script.Invocable;
@ -46,7 +52,16 @@ public class ScriptTransformer extends Transformer {
private String functionName;
@Override
public Object transformRow(Map<String, Object> row, Context context) {
public Object transformRow(Map<String,Object> row, Context context) {
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return transformRowUnsafe(row, context);
}
}, SCRIPT_SANDBOX);
}
public Object transformRowUnsafe(Map<String, Object> row, Context context) {
try {
if (engine == null)
initEngine(context);
@ -84,7 +99,17 @@ public class ScriptTransformer extends Transformer {
+ scriptEngine.getClass().getName());
}
try {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws ScriptException {
scriptEngine.eval(scriptText);
return null;
}
}, SCRIPT_SANDBOX);
} catch (PrivilegedActionException e) {
throw (ScriptException) e.getException();
}
} catch (ScriptException e) {
wrapAndThrow(SEVERE, e, "'eval' failed with language: " + scriptLang
+ " and script: \n" + scriptText);
@ -99,4 +124,8 @@ public class ScriptTransformer extends Transformer {
return functionName;
}
// sandbox for script code: zero permissions
private static final AccessControlContext SCRIPT_SANDBOX =
new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, null) });
}

View File

@ -56,6 +56,28 @@ public class TestScriptTransformer extends AbstractDataImportHandlerTestCase {
}
}
@Test
public void testEvil() {
assumeTrue("This test only works with security manager", System.getSecurityManager() != null);
String script = "function f1(row) {"
+ "var os = Packages.java.lang.System.getProperty('os.name');"
+ "row.put('name', os);"
+ "return row;\n"
+ "}";
Context context = getContext("f1", script);
Map<String, Object> map = new HashMap<>();
map.put("name", "Scott");
EntityProcessorWrapper sep = new EntityProcessorWrapper(new SqlEntityProcessor(), null, null);
sep.init(context);
DataImportHandlerException expected = expectThrows(DataImportHandlerException.class, () -> {
sep.applyTransformer(map);
});
assumeFalse("This JVM does not have JavaScript installed. Test Skipped.",
expected.getMessage().startsWith("Cannot load Script Engine for language"));
assertTrue(expected.getCause().toString(), SecurityException.class.isAssignableFrom(expected.getCause().getClass()));
}
private Context getContext(String funcName, String script) {
List<Map<String, String>> fields = new ArrayList<>();
Map<String, String> entity = new HashMap<>();

View File

@ -41,6 +41,12 @@ import java.io.InputStream;
import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.ArrayList;
@ -269,7 +275,7 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
}
for (ScriptFile scriptFile : scriptFiles) {
ScriptEngine engine = null;
final ScriptEngine engine;
if (null != engineName) {
engine = scriptEngineManager.getEngineByName(engineName);
if (engine == null) {
@ -314,7 +320,17 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
Reader scriptSrc = scriptFile.openReader(resourceLoader);
try {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws ScriptException {
engine.eval(scriptSrc);
return null;
}
}, SCRIPT_SANDBOX);
} catch (PrivilegedActionException e) {
throw (ScriptException) e.getException();
}
} catch (ScriptException e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Unable to evaluate script: " +
@ -424,6 +440,15 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
* cast to a java Boolean.
*/
private boolean invokeFunction(String name, Object... cmd) {
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return invokeFunctionUnsafe(name, cmd);
}
}, SCRIPT_SANDBOX);
}
private boolean invokeFunctionUnsafe(String name, Object... cmd) {
for (EngineInfo engine : engines) {
try {
@ -496,4 +521,8 @@ public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcesso
(input, StandardCharsets.UTF_8);
}
}
// sandbox for script code: zero permissions
private static final AccessControlContext SCRIPT_SANDBOX =
new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, null) });
}

View File

@ -0,0 +1,21 @@
var sys = Packages.java.lang.System;
function processAdd(cmd) {
sys.getProperty("os.name");
}
function processDelete(cmd) {
}
function processMergeIndexes(cmd) {
}
function processCommit(cmd) {
}
function processRollback(cmd) {
}
function finish() {
}

View File

@ -117,4 +117,10 @@
</processor>
</updateRequestProcessorChain>
<updateRequestProcessorChain name="evil">
<processor class="solr.StatelessScriptUpdateProcessorFactory">
<str name="script">evil.js</str>
</processor>
</updateRequestProcessorChain>
</config>

View File

@ -259,4 +259,14 @@ public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTe
}
public void testScriptSandbox() throws Exception {
assumeTrue("This test only works with security manager", System.getSecurityManager() != null);
expectThrows(SecurityException.class, () -> {
processAdd("evil",
doc(f("id", "5"),
f("name", " foo "),
f("subject", "BAR")));
});
}
}