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
198
199
200
201
202
# 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']

  # The pass function acts as a Ruby => Lua converter.
  # It simply passes back it's first argument.
  # Arguments are converted from Ruby to Lua by rufus-lua.
  @pass_function = @state.eval "return function(obj) return obj end"

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

Class Method Details

.check_rufus_stack(state, message) ⇒ Object



219
220
221
222
223
224
# File 'lib/immunio/vm.rb', line 219

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



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/immunio/vm.rb', line 233

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.



205
206
207
208
209
# File 'lib/immunio/vm.rb', line 205

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

#create_object(object) ⇒ Object



211
212
213
214
215
216
217
# File 'lib/immunio/vm.rb', line 211

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

  lua_call do
    @pass_function.call(object)
  end
end

#lua_callObject

Wrap calls to Lua VM.



227
228
229
230
231
# File 'lib/immunio/vm.rb', line 227

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.



251
252
253
254
255
# File 'lib/immunio/vm.rb', line 251

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