Scripting with LuaJIT and selectively sandboxing the FFI

After trying and witnessing the incredible ease with which I could integrate Lua and LuaJIT into my game engine, I'm convinced that that's the scripting language I want to use. I would like to use it for my AI, unit descriptions, map triggers, et cetera. (as much as possible really). This question is not just applicable to gamedev, I can imagine creating a scriptable editor or window manager which can load external scripts (case in point: sublime text with python and package control)

But now I have a conundrum: I really appreciate the ease of use that the LuaJIT FFI offers to bind to my engine, but I don't want to provide free reign of the FFI to map authors for example. The incredible speed of lua-to-c calls via the FFI (when JITted) is also something I really want.

So ideally, I would write my own wrapper Lua files that bind to my engine with the FFI and export a nice module for map authors and modders to use. My alternative to this is to write a vanilla lua module, which is possible but much more cumbersome and slower.

I can't disable the FFI when compiling luajit because obviously I want to use it myself, but I don't see how to restrict the FFI on a per-script or per-module basis. Obviously the FFI needs to be active in the lua_State where I load my modules (after which I cant start loading the user-modified scripts). So what do I do? Is it even possible?

EDIT : In my mind, the ideal workflow would be:

  • open lua state
  • load all modules (luaL_openlibs()), the FFI is also preloaded
  • load my .lua modules, which use the FFI (this is the engine binding, they are trusted files so they can use the FFI)
  • disable select native modules and functions: os, ffi, ... (this is the missing step)
  • execute user-provided scripts (these are untrusted, I don't want them to access the FFI)
  • optional : look for a way to reload lua modules for a fast edit cycle, this would involve re-enabling the FFI and other modules. ( not sure how to do this either )
  • NOTE : I'm aware that this would still not be a perfect (or even good sandbox), as Mike Pall already pointed out in some of his mails, but I still don't want to give map authors access to the FFI.


    Maybe I do not understand the issue, but if you use a normal Lua sandbox in which the FFI is not accessible, what is the problem?

    For instance:

    ffi = require "ffi"
    
    ffi.cdef([[int printf(const char *fmt, ...);]])
    
    function say_hello()
      ffi.C.printf("%s", "hello, ");
    end
    
    my_user_script = [[
    say_hello()
    ffi.C.printf("%sn", "world")
    ]]
    
    f = loadstring(my_user_script)
    
    print("=== without sandbox ===")
    print(pcall(f))
    
    print("=== with sandbox ===")
    setfenv(f,{say_hello = say_hello})
    print(pcall(f))
    

    This should output:

    === without sandbox ===
    hello, world
    true
    === with sandbox ===
    hello, false    [string "say_hello()..."]:2: attempt to index global 'ffi' (a nil value)
    

    Note that you also need to be careful not to leak FFI cdata into the sandbox. There is a paragraph about this in the LuaJIT documentation.

    链接地址: http://www.djcxy.com/p/95460.html

    上一篇: 调用(S,0,0)将不起作用(试图调用字符串值)?

    下一篇: 使用LuaJIT编写脚本并选择性地对FFI进行沙箱处理