Skip to content

Commit

Permalink
[GR-14125] Do not give any permissions to TruffleRubyScriptEngine by …
Browse files Browse the repository at this point in the history
…default

PullRequest: truffleruby/3388
  • Loading branch information
eregon committed Jul 29, 2022
2 parents 4a02764 + 25b11d4 commit e44f6d6
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 65 deletions.
2 changes: 0 additions & 2 deletions src/main/java/org/truffleruby/core/string/CoreStrings.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public class CoreStrings {
public final CoreString STACK_LEVEL_TOO_DEEP;
public final CoreString TIME_INTERVAL_MUST_BE_POS;
public final CoreString TOO_FEW_ARGUMENTS;
public final CoreString TZ;
public final CoreString UNKNOWN;
public final CoreString UTC;
public final CoreString WRONG_ARGS_ZERO_PLUS_ONE;
Expand All @@ -52,7 +51,6 @@ public CoreStrings(RubyLanguage language) {
STACK_LEVEL_TOO_DEEP = new CoreString(language, "stack level too deep");
TIME_INTERVAL_MUST_BE_POS = new CoreString(language, "time interval must be positive");
TOO_FEW_ARGUMENTS = new CoreString(language, "too few arguments");
TZ = new CoreString(language, "TZ");
UNKNOWN = new CoreString(language, "(unknown)");
UTC = new CoreString(language, "UTC");
WRONG_ARGS_ZERO_PLUS_ONE = new CoreString(language, "wrong number of arguments (0 for 1+)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class FrozenStrings {
public static final ImmutableRubyString SELF = createFrozenStaticBinaryString("self");
public static final ImmutableRubyString SUPER = createFrozenStaticBinaryString("super");
public static final ImmutableRubyString TRUE = createFrozenStaticBinaryString("true");
public static final ImmutableRubyString TZ = createFrozenStaticBinaryString("TZ");

private static ImmutableRubyString createFrozenStaticBinaryString(String string) {
// defined?(...) returns frozen strings with a binary encoding
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/org/truffleruby/core/time/GetTimeZoneNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import java.util.regex.Pattern;

import com.oracle.truffle.api.CompilerDirectives;
import org.truffleruby.RubyLanguage;
import org.truffleruby.core.string.FrozenStrings;
import org.truffleruby.language.RubyBaseNode;
import org.truffleruby.language.RubyGuards;
import org.truffleruby.language.control.RaiseException;
Expand Down Expand Up @@ -63,13 +63,17 @@ public static void invalidateTZ() {

@Specialization(assumptions = "TZ_UNCHANGED.getAssumption()")
protected TimeZoneAndName getTimeZone(
@Cached("getTZ(getLanguage())") Object tzValue,
@Cached("getTZ()") Object tzValue,
@Cached("getTimeZone(tzValue)") TimeZoneAndName zone) {
return zone;
}

protected Object getTZ(RubyLanguage language) {
return lookupEnvNode.call(coreLibrary().getENV(), "[]", language.coreStrings.TZ.createInstance(getContext()));
protected Object getTZ() {
if (getContext().getEnv().isNativeAccessAllowed()) {
return lookupEnvNode.call(coreLibrary().getENV(), "[]", FrozenStrings.TZ);
} else {
return nil;
}
}

@TruffleBoundary
Expand All @@ -82,18 +86,14 @@ protected TimeZoneAndName getTimeZone(Object tz) {

if (tz == nil) {
// $TZ is not set, use the system timezone
return new TimeZoneAndName(getSystemTimeZone());
return new TimeZoneAndName(getContext().getEnv().getTimeZone());
} else if (libString.isRubyString(tz)) {
return parse(tzString);
} else {
throw CompilerDirectives.shouldNotReachHere();
}
}

private static ZoneId getSystemTimeZone() {
return ZoneId.systemDefault();
}

private static final Map<String, String> LONG_TZNAME = Helpers.map(
"MET",
"CET", // JRUBY-2759
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public class TruffleRubyScriptEngine extends AbstractScriptEngine

private final Context polyglot;

TruffleRubyScriptEngine(TruffleRubyScriptEngineFactory factory) {
TruffleRubyScriptEngine(TruffleRubyScriptEngineFactory factory, boolean allowAllAccess) {
this.factory = factory;
polyglot = Context.newBuilder().allowAllAccess(true).build();
this.polyglot = Context.newBuilder("ruby").allowAllAccess(allowAllAccess).build();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,11 @@ public String getProgram(String... statements) {

@Override
public ScriptEngine getScriptEngine() {
return new TruffleRubyScriptEngine(this);
return getScriptEngine(false);
}

public ScriptEngine getScriptEngine(boolean allowAllAccess) {
return new TruffleRubyScriptEngine(this, allowAllAccess);
}

private String query(String expression) {
Expand Down
121 changes: 72 additions & 49 deletions src/test/java/org/truffleruby/JSR223InteropTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,45 @@
package org.truffleruby;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.List;

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.junit.After;
import org.junit.Test;
import org.truffleruby.fixtures.FluidForce;
import org.truffleruby.services.scriptengine.TruffleRubyScriptEngine;
import org.truffleruby.services.scriptengine.TruffleRubyScriptEngineFactory;
import org.truffleruby.shared.TruffleRuby;

public class JSR223InteropTest {

private ScriptEngine scriptEngine = null;

@After
public void after() {
if (scriptEngine != null) {
close(scriptEngine);
scriptEngine = null;
}
}

private static void close(ScriptEngine scriptEngine) {
try {
((AutoCloseable) scriptEngine).close();
} catch (Exception e) {
throw new Error(e);
}
}

@Test
public void testVersion() {
assertEquals(TruffleRuby.getEngineVersion(), new TruffleRubyScriptEngineFactory().getEngineVersion());
Expand All @@ -36,91 +57,93 @@ public void testVersion() {
@Test
public void testCreateEngine() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
try (TruffleRubyScriptEngine scriptEngine = (TruffleRubyScriptEngine) m
.getEngineByName(TruffleRuby.LANGUAGE_ID)) {
assertEquals(14, scriptEngine.eval("14"));
scriptEngine = m.getEngineByName("ruby");
assertEquals(42, scriptEngine.eval("6 * 7"));
}

@Test
public void testNoPermissionsByDefault() {
final ScriptEngineManager m = new ScriptEngineManager();
scriptEngine = m.getEngineByName("ruby");
try {
scriptEngine.eval("Process.pid");
fail("should have thrown");
} catch (ScriptException scriptException) {
assertEquals("org.graalvm.polyglot.PolyglotException: native access is not allowed (SecurityError)",
scriptException.getMessage());
}
}

@Test
public void testAllAccess() throws ScriptException {
scriptEngine = new TruffleRubyScriptEngineFactory().getScriptEngine(true);
assertTrue(scriptEngine.eval("Process.pid") instanceof Integer);
}

@Test
public void testParameters() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
try (TruffleRubyScriptEngine scriptEngine = (TruffleRubyScriptEngine) m
.getEngineByName(TruffleRuby.LANGUAGE_ID)) {
final Bindings bindings = scriptEngine.createBindings();
bindings.put("a", 14);
bindings.put("b", 2);
assertEquals(16, scriptEngine.eval("a + b", bindings));
}
scriptEngine = m.getEngineByName("ruby");
final Bindings bindings = scriptEngine.createBindings();
bindings.put("a", 14);
bindings.put("b", 2);
assertEquals(16, scriptEngine.eval("a + b", bindings));
}

@Test
public void testCallingMethods() throws ScriptException, NoSuchMethodException {
final ScriptEngineManager m = new ScriptEngineManager();
try (TruffleRubyScriptEngine scriptEngine = (TruffleRubyScriptEngine) m
.getEngineByName(TruffleRuby.LANGUAGE_ID)) {
assertEquals(
0.909,
(double) ((Invocable) scriptEngine).invokeMethod(scriptEngine.eval("Math"), "sin", 2),
0.01);
}
scriptEngine = m.getEngineByName("ruby");
assertEquals(
0.909,
(double) ((Invocable) scriptEngine).invokeMethod(scriptEngine.eval("Math"), "sin", 2),
0.01);
}

@Test
public void testCreatingObjects() throws ScriptException, NoSuchMethodException {
final ScriptEngineManager m = new ScriptEngineManager();
try (TruffleRubyScriptEngine scriptEngine = (TruffleRubyScriptEngine) m
.getEngineByName(TruffleRuby.LANGUAGE_ID)) {
final Object time = ((Invocable) scriptEngine).invokeMethod(scriptEngine.eval("Time"), "new", 2021, 3, 18);
final Object year = ((Invocable) scriptEngine).invokeMethod(time, "year");
assertEquals(2021, year);
}
scriptEngine = m.getEngineByName("ruby");
final Object time = ((Invocable) scriptEngine).invokeMethod(scriptEngine.eval("Time"), "new", 2021, 3, 18);
final Object year = ((Invocable) scriptEngine).invokeMethod(time, "year");
assertEquals(2021, year);
}

@SuppressWarnings("unchecked")
@Test
public void testAccessingArrays() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
try (TruffleRubyScriptEngine scriptEngine = (TruffleRubyScriptEngine) m
.getEngineByName(TruffleRuby.LANGUAGE_ID)) {
assertEquals(4, ((List<Object>) scriptEngine.eval("[3, 4, 5]")).get(1));
}
scriptEngine = m.getEngineByName("ruby");
assertEquals(4, ((List<Object>) scriptEngine.eval("[3, 4, 5]")).get(1));
}

@SuppressWarnings("unchecked")
@Test
public void testAccessingHashes() throws ScriptException, NoSuchMethodException {
final ScriptEngineManager m = new ScriptEngineManager();
try (TruffleRubyScriptEngine scriptEngine = (TruffleRubyScriptEngine) m
.getEngineByName(TruffleRuby.LANGUAGE_ID)) {
assertEquals(
4,
(int) ((Invocable) scriptEngine).invokeMethod(
scriptEngine.eval("{'a' => 3, 'b' => 4, 'c' => 5}"),
"fetch",
'b'));
}
scriptEngine = m.getEngineByName("ruby");
assertEquals(
4,
(int) ((Invocable) scriptEngine).invokeMethod(
scriptEngine.eval("{'a' => 3, 'b' => 4, 'c' => 5}"),
"fetch",
'b'));
}

@Test
public void testImplementInterface() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
try (TruffleRubyScriptEngine scriptEngine = (TruffleRubyScriptEngine) m
.getEngineByName(TruffleRuby.LANGUAGE_ID)) {
final FluidForce fluidForce = ((Invocable) scriptEngine)
.getInterface(scriptEngine.eval(FluidForce.RUBY_SOURCE), FluidForce.class);
assertEquals(5587.008375144088, fluidForce.getFluidForce(2.0, 3.0, 6.0), 0.01);
}
scriptEngine = m.getEngineByName("ruby");
final FluidForce fluidForce = ((Invocable) scriptEngine)
.getInterface(scriptEngine.eval(FluidForce.RUBY_SOURCE), FluidForce.class);
assertEquals(5587.008375144088, fluidForce.getFluidForce(2.0, 3.0, 6.0), 0.01);
}

@Test
public void testParseOnceRunMany() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
try (TruffleRubyScriptEngine scriptEngine = (TruffleRubyScriptEngine) m
.getEngineByName(TruffleRuby.LANGUAGE_ID)) {
final CompiledScript compiled = ((Compilable) scriptEngine).compile("14");
assertEquals(14, compiled.eval());
}
scriptEngine = m.getEngineByName("ruby");
final CompiledScript compiled = ((Compilable) scriptEngine).compile("14");
assertEquals(14, compiled.eval());
}

}
3 changes: 1 addition & 2 deletions src/test/java/org/truffleruby/PolyglotInteropTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ public void testPassingBlocks() {

@Test
public void testCreatingObjects() {
// Native access needed for ENV['TZ']
try (Context polyglot = Context.newBuilder().allowNativeAccess(true).build()) {
try (Context polyglot = Context.create()) {
assertEquals(
2021,
polyglot.eval("ruby", "Time").newInstance(2021, 3, 18).getMember("year").execute().asInt());
Expand Down

0 comments on commit e44f6d6

Please sign in to comment.