Security 使用LuaJIT编写脚本并有选择地对FFI进行沙箱化

Security 使用LuaJIT编写脚本并有选择地对FFI进行沙箱化,security,lua,sandbox,ffi,luajit,Security,Lua,Sandbox,Ffi,Luajit,在尝试并见证了将Lua和LuaJIT集成到游戏引擎中的难以置信的轻松之后,我确信这就是我想要使用的脚本语言。我想把它用于我的人工智能、单位描述、地图触发器等等。(真的尽可能多)。这个问题不仅适用于gamedev,我可以想象创建一个可编写脚本的编辑器或窗口管理器,它可以加载外部脚本(例如:带有python和包控件的升华文本) 但现在我有一个难题:我真的很欣赏LuaJIT FFI提供的绑定到我的引擎的易用性,但我不想提供FFI的免费统治权来映射作者。通过FFI进行lua-to-c呼叫的惊人速度(在紧

在尝试并见证了将Lua和LuaJIT集成到游戏引擎中的难以置信的轻松之后,我确信这就是我想要使用的脚本语言。我想把它用于我的人工智能、单位描述、地图触发器等等。(真的尽可能多)。这个问题不仅适用于gamedev,我可以想象创建一个可编写脚本的编辑器或窗口管理器,它可以加载外部脚本(例如:带有python和包控件的升华文本)

但现在我有一个难题:我真的很欣赏LuaJIT FFI提供的绑定到我的引擎的易用性,但我不想提供FFI的免费统治权来映射作者。通过FFI进行lua-to-c呼叫的惊人速度(在紧张状态下)也是我真正想要的

所以,理想情况下,我会编写自己的包装器Lua文件,用FFI绑定到我的引擎,并导出一个很好的模块供地图作者和修改者使用。我的替代方案是编写一个普通的lua模块,这是可能的,但要复杂得多,速度也慢得多

我不能在编译luajit时禁用FFI,因为我显然想自己使用它,但我不知道如何在每个脚本或每个模块的基础上限制FFI。显然,FFI需要在我加载模块的lua_状态下处于活动状态(之后我无法开始加载用户修改的脚本)。那我该怎么办?有可能吗

编辑:在我看来,理想的工作流程应该是:

  • 开放lua状态
  • 加载所有模块(luaL_openlibs()),FFI也会预加载
  • 加载使用FFI的my.lua模块(这是引擎绑定,它们是受信任的文件,因此可以使用FFI)
  • 禁用选择本机模块和功能:操作系统、ffi。。。(这是缺少的步骤)
  • 执行用户提供的脚本(这些脚本不受信任,我不希望它们访问FFI)
  • 可选:寻找重新加载lua模块以实现快速编辑周期的方法,这将涉及重新启用FFI和其他模块。(也不知道该怎么做

  • 注意:我知道这仍然不是一个完美的(甚至不是一个好的沙箱),正如Mike Pall在他的一些邮件中指出的那样,但我仍然不想让地图作者访问FFI。

    也许我不理解这个问题,但是如果你使用的是无法访问FFI的地方,问题是什么

    例如:

    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("%s\n", "world")
    ]]
    
    f = loadstring(my_user_script)
    
    print("=== without sandbox ===")
    print(pcall(f))
    
    print("=== with sandbox ===")
    setfenv(f,{say_hello = say_hello})
    print(pcall(f))
    
    这应该输出:

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

    请注意,您还需要小心不要将FFI cdata泄漏到沙箱中。有。

    但是我想用FFI编写我的引擎绑定,所以我不能完全禁用它。我更新了我的答案,以便更好地说明这个问题。不确定是我还是你遗漏了什么。我在上面添加了一个代码示例,它有帮助吗?再次编辑,使其比您可以让用户访问使用FFI的引擎功能更清晰。在这里,
    say_hello
    函数在沙箱中确实起作用。@Aktau您是说执行“setfenv”之后的
    print(pcall(f))
    setfenv'更改传入函数的环境——它不会更改调用站点的环境。@Aktau注意,正确地沙盒不安全的代码是很棘手的。例如,即使您在新环境中不允许使用“ffi”、“os”等,您也要确保他们无法使用类似于
    要求使用“ffi”
    的内容将其取回,因为“ffi”在
    包中。预加载