Class: Immunio::LuaVM

Inherits:
Object
  • Object
show all
Defined in:
lib/immunio/vm.rb

Constant Summary collapse

@@monitor =

One Monitor for the class, which means while we can have more than one VM, we can’t allow more than one to be called at a time. Unfortunate necessity because we can’t tell which VM every rufus-lua method is called on.

Monitor.new

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, secret, dev_mode = false, debug_mode = false) ⇒ LuaVM

Returns a new instance of LuaVM.



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/immunio/vm.rb', line 165

def initialize(key, secret, dev_mode = false, debug_mode = false)
  @state = Rufus::Lua::State.new

  # Bootstrap the VM ...

  # Define load path for `require`.
  lua_hooks = File.expand_path("#{Immunio::DIR}/../lua-hooks")
  @state['package.path'] = lua_hooks + "/lib/?.lua;" + lua_hooks + "/lib/lexers/?.lua"
  # Set the config key
  @state['IMMUNIO_KEY'] = key
  # Set the secret key
  @state['IMMUNIO_SECRET'] = secret
  # Pass dev mode option
  @state['DEV_MODE'] = dev_mode
  # Pass debug mode option
  @state['DEBUG_MODE'] = debug_mode
  # Pass platform to the vm.
  # From: http://stackoverflow.com/questions/170956/how-can-i-find-which-operating-system-my-ruby-program-is-running-on
  if (/cygwin|mswin|mingw|bccwin|wince|emx|windows/ =~ RUBY_PLATFORM) != nil then
    @state['LUA_PLATFORM'] = 'windows'
  elsif (/darwin/ =~ RUBY_PLATFORM) != nil
    @state['LUA_PLATFORM'] = 'darwin'
  else
    @state['LUA_PLATFORM'] = 'unix'
  end
  # Boot it. Yeaaaaah!
  @state.eval "require 'boot'"

  @error_handler = @state["debug.traceback"]
  @call_function = @state['sandboxed_call']

  self.class.check_rufus_stack @state, "Stack not empty after bootstrap"
end

Class Method Details

.check_rufus_stack(state, message) ⇒ Object



214
215
216
217
218
219
# File 'lib/immunio/vm.rb', line 214

def self.check_rufus_stack(state, message)
  top = state.send(:stack_top)
  if top != 0
    raise VMError, "#{message} (#{top})"
  end
end

Instance Method Details

#call(code, vars = nil) ⇒ Object



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/immunio/vm.rb', line 228

def call(code, vars = nil)
  lua_call do
    # Setup the error handler
    @error_handler.load_onto_stack
    @call_function.error_handler = @call_function.send :stack_top

    # For the VM heavy thread test, we need to cause out-of-order execution
    # in methods modifying the Lua stack. Here we tell Ruby to swap out
    # threads if we are in the thread test.
    Thread.pass if $IMMUNIO_IN_THREAD_TEST

    ret = @call_function.call code, vars
    @state.send :stack_pop # Pop the error handler
    Array === ret ? ret.first : ret
  end
end

#create_function(code, name = nil) ⇒ Object

Create a function wrapping some Lua code or base64-encoded bytecode.



200
201
202
203
204
# File 'lib/immunio/vm.rb', line 200

def create_function(code, name=nil)
  lua_call do
    @state.load code, name
  end
end

#create_object(object) ⇒ Object



206
207
208
209
210
211
212
# File 'lib/immunio/vm.rb', line 206

def create_object(object)
  return object if object.is_a?(Rufus::Lua::Ref)

  lua_call do
    @state.eval "return #{Rufus::Lua.to_lua_s(object)}"
  end
end

#lua_callObject

Wrap calls to Lua VM.



222
223
224
225
226
# File 'lib/immunio/vm.rb', line 222

def lua_call
  @@monitor.synchronize { yield }
rescue Rufus::Lua::LuaError => e
  raise VMError, e.message, e.backtrace
end

#unsafe_call_by_name(name, *args) ⇒ Object

Call a Lua function by name, outside of the sandbox.



246
247
248
249
250
# File 'lib/immunio/vm.rb', line 246

def unsafe_call_by_name(name, *args)
  lua_call do
    @state[name].call(*args)
  end
end