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

在尝试并亲眼目睹了将Lua和LuaJIT整合到我的游戏引擎中的难以置信的简易性之后,我确信这就是我想要使用的脚本语言。 我想将它用于我的AI,单元描述,地图触发器等等。 (尽可能多)。 这个问题不仅适用于gamedev,我可以想象创建一个脚本编辑器或窗口管理器,它可以加载外部脚本(例如:使用python和包控件的崇高文本)

但是现在我有一个难题:我非常欣赏LuaJIT FFI提供的易用性,以便与我的引擎绑定,但我不想提供FFI的免费统计信息来映射作者 。 通过FFI进行lua-to-c调用的令人难以置信的速度(当JITted时)也是我真正想要的。

因此,理想情况下,我会编写我自己的包装Lua文件,该文件通过FFI绑定到我的引擎,并为地图作者和模块使用导出一个很好的模块。 我的替代方案是编写一个香草lua模块,这是可能的,但更麻烦,更慢。

编译luajit时我无法禁用FFI,因为显然我想自己使用它,但我没有看到如何在每个脚本或每个模块的基础上限制FFI。 很显然,FFI需要在加载我的模块的lua_State中处于活动状态(之后我无法启动加载用户修改的脚本)。 那么我该怎么做? 它甚至有可能吗?

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

  • 打开卢阿州
  • 加载所有模块(luaL_openlibs()),FFI也被预加载
  • 加载我的.lua模块,它使用FFI(这是引擎绑定,它们是可信的文件,因此它们可以使用FFI)
  • 禁用选择本地模块和功能:os,ffi,...(这是缺少的步骤)
  • 执行用户提供的脚本(这些不受信任,我不希望他们访问FFI)
  • 可选 :寻找一种方法来重新加载lua模块以实现快速编辑周期,这将涉及重新启用FFI和其他模块。 ( 不知道如何做到这一点
  • 注意 :我知道这还不是一个完美的(或者甚至是不错的沙箱),正如Mike Pall在他的一些邮件中已经指出的那样,但我仍然不想让地图作者访问FFI。


    也许我不明白这个问题,但是如果你使用一个不能访问FFI的普通Lua沙盒,那么问题是什么?

    例如:

    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))
    

    这应该输出:

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

    请注意,您还需要注意不要将FFI cdata泄漏到沙箱中。 在LuaJIT文档中有关于此的段落。

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

    上一篇: Scripting with LuaJIT and selectively sandboxing the FFI

    下一篇: Embedding javascript into an application (like Lua)