diff --git a/core/src/main/java/org/jruby/Ruby.java b/core/src/main/java/org/jruby/Ruby.java index 9dd148c1cc5..e2830667fa6 100644 --- a/core/src/main/java/org/jruby/Ruby.java +++ b/core/src/main/java/org/jruby/Ruby.java @@ -507,13 +507,21 @@ private Ruby(RubyInstanceConfig config) { initExceptions(context); // Thread library utilities - mutexClass = Mutex.setup(context, threadClass, objectClass); - conditionVariableClass = ConditionVariable.setup(context, threadClass, objectClass); - queueClass = Queue.setup(context, threadClass, objectClass); - closedQueueError = Queue.setupError(context, queueClass, stopIteration, objectClass); - sizedQueueClass = SizedQueue.setup(context, threadClass, queueClass, objectClass); - - fiberClass = new ThreadFiberLibrary().createFiberClass(context, objectClass); + if (profile.allowClass("Thread")) { + mutexClass = Mutex.setup(context, threadClass, objectClass); + conditionVariableClass = ConditionVariable.setup(context, threadClass, objectClass); + queueClass = Queue.setup(context, threadClass, objectClass); + closedQueueError = Queue.setupError(context, queueClass, stopIteration, objectClass); + sizedQueueClass = SizedQueue.setup(context, threadClass, queueClass, objectClass); + fiberClass = new ThreadFiberLibrary().createFiberClass(context, objectClass); + } else { + mutexClass = null; + conditionVariableClass = null; + queueClass = null; + closedQueueError = null; + sizedQueueClass = null; + fiberClass = null; + } dataClass = RubyData.createDataClass(context, objectClass); @@ -1676,12 +1684,12 @@ private void initExceptions(ThreadContext context) { ifAllowed("KeyError", (ruby) -> keyError = RubyKeyError.define(context, indexError)); ifAllowed("DomainError", (ruby) -> mathDomainError = RubyDomainError.define(context, argumentError, mathModule)); - setRegexpTimeoutError(regexpClass.defineClassUnder(context, "TimeoutError", getRegexpError(), RubyRegexpError::new)); + ifAllowed("Regex", (ruby) -> setRegexpTimeoutError(regexpClass.defineClassUnder(context, "TimeoutError", getRegexpError(), RubyRegexpError::new))); RubyClass runtimeError = this.runtimeError; - ObjectAllocator runtimeErrorAllocator = runtimeError.getAllocator(); - if (Options.FIBER_SCHEDULER.load()) { + if (profile.allowClass("Thread") && Options.FIBER_SCHEDULER.load()) { + ObjectAllocator runtimeErrorAllocator = runtimeError.getAllocator(); bufferLockedError = ioBufferClass.defineClassUnder(context, "LockedError", runtimeError, runtimeErrorAllocator); bufferAllocationError = ioBufferClass.defineClassUnder(context, "AllocationError", runtimeError, runtimeErrorAllocator); bufferAccessError = ioBufferClass.defineClassUnder(context, "AccessError", runtimeError, runtimeErrorAllocator); @@ -1775,7 +1783,9 @@ private void initJavaSupport(ThreadContext context) { private void initRubyKernel() { // load Ruby parts of core - loadService.loadFromClassLoader(getClassLoader(), "jruby/kernel.rb", false); + if (profile.allowLoad("jruby/kernel")) { + loadService.loadFromClassLoader(getClassLoader(), "jruby/kernel.rb", false); + } } private void initRubyPreludes() { @@ -1783,7 +1793,9 @@ private void initRubyPreludes() { if (RubyInstanceConfig.DEBUG_PARSER) return; // load Ruby parts of core - loadService.loadFromClassLoader(getClassLoader(), "jruby/preludes.rb", false); + if (profile.allowLoad("jruby/preludes")) { + loadService.loadFromClassLoader(getClassLoader(), "jruby/preludes.rb", false); + } } public IRManager getIRManager() { diff --git a/core/src/main/java/org/jruby/RubyGlobal.java b/core/src/main/java/org/jruby/RubyGlobal.java index 2e58c1c9810..6ef275d5b7e 100644 --- a/core/src/main/java/org/jruby/RubyGlobal.java +++ b/core/src/main/java/org/jruby/RubyGlobal.java @@ -199,7 +199,9 @@ public static RubyHash createGlobalsAndENV(ThreadContext context, GlobalVariable runtime.defineVariable(new LastlineGlobalVariable(runtime, "$_"), FRAME); runtime.defineVariable(new LastExitStatusVariable(runtime, "$?"), THREAD); - runtime.defineVariable(new ErrorInfoGlobalVariable(runtime, "$!", context.nil), THREAD); + if (runtime.getProfile().allowClass("Thread")) { + runtime.defineVariable(new ErrorInfoGlobalVariable(runtime, "$!", context.nil), THREAD); + } runtime.defineVariable(new NonEffectiveGlobalVariable(runtime, "$=", context.fals), GLOBAL); if(instanceConfig.getInputFieldSeparator() == null) { diff --git a/core/src/test/java/org/jruby/javasupport/JavaEmbedUtilsTest.java b/core/src/test/java/org/jruby/javasupport/JavaEmbedUtilsTest.java index ce4bf4c39d6..116159378a0 100644 --- a/core/src/test/java/org/jruby/javasupport/JavaEmbedUtilsTest.java +++ b/core/src/test/java/org/jruby/javasupport/JavaEmbedUtilsTest.java @@ -13,9 +13,15 @@ import static org.jruby.api.Create.newEmptyArray; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.jruby.Profile; +import org.jruby.RubyFixnum; +import org.jruby.RubyString; +import org.jruby.exceptions.NameError; +import org.jruby.exceptions.SyntaxError; import org.jruby.java.proxies.ConcreteJavaProxy; import org.jruby.java.proxies.JavaProxy; import org.jruby.runtime.ThreadContext; @@ -64,6 +70,55 @@ public void testAddClassloaderToLoadPathOnTCCL() throws Exception { assertEquals(result, "uri:" + url); } + class CustomProfile implements Profile { + private List classAllow = List.of("String", "Fixnum", "Integer", "Numeric", "Hash", "Array", + "Thread", "ThreadGroup", "RubyError", "StopIteration", "LoadError", "ArgumentError", "Encoding", + "EncodingError", "StandardError", "Exception", "NameError", "SyntaxError", "ScriptError"); + private List loadAllow = List.of("jruby/java.rb", "jruby/java/core_ext.rb", "jruby/java/java_ext.rb", + "jruby/java/core_ext/object.rb"); + + @Override + public boolean allowBuiltin(String name) { + return false; + } + + @Override + public boolean allowClass(String name) { + return classAllow.contains(name); + } + + @Override + public boolean allowModule(String name) { + return false; + } + + @Override + public boolean allowLoad(String name) { + return loadAllow.contains(name); + } + + @Override + public boolean allowRequire(String name) { + return false; + } + } + + @Test + public void testRestrictedProfile() throws Exception { + RubyInstanceConfig config = new RubyInstanceConfig(); + config.setDisableGems(true); + config.setProfile(new CustomProfile()); + + Ruby runtime = Ruby.newInstance(config); + assertEquals(20L, ((RubyFixnum) runtime.evalScriptlet("def double(a); a * 2; end; double(10)")).getValue()); + assertThrows(NameError.class, () -> runtime.evalScriptlet("File.open('test.tmp')")); + assertThrows(NameError.class, () -> runtime.evalScriptlet("UDPSocket.new")); + assertEquals("cute_cats",((RubyString)runtime.evalScriptlet("\"cute_cats\"")).getValue()); + assertEquals("cute_cat",((RubyString)runtime.evalScriptlet("\"cute_cats\".delete('s')")).getValue()); + assertThrows(SyntaxError.class, () -> runtime.evalScriptlet("puts 'you shouldn't see this'")); + //assertThrows(NameError.class, () -> runtime.evalScriptlet("IO.sysopen('test.tmp')")); + } + @Test public void testAddClassloaderToLoadPathOnNoneTCCL() throws Exception { RubyInstanceConfig config = new RubyInstanceConfig();