diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 59cb4bfb..6fb6ddc0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -98,11 +98,11 @@ variables: # See the documentation here: # # https://wayland.freedesktop.org/libinput/doc/latest/building.html # ############################################################################### - FEDORA_PACKAGES: 'git-core gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx_rtd_theme python3-pytest-xdist libwacom-devel cairo-devel gtk4-devel glib2-devel mtdev-devel diffutils wayland-protocols-devel black clang clang-tools-extra jq rpmdevtools valgrind systemd-udev qemu-img qemu-system-x86-core qemu-system-aarch64-core jq python3-click python3-rich virtme-ng lua-devel' - DEBIAN_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev curl lua5.4-dev' - UBUNTU_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev lua5.4-dev' - ARCH_PACKAGES: 'git gcc pkgconfig meson check libsystemd libevdev python-pytest-xdist libwacom gtk4 mtdev diffutils lua' - ALPINE_PACKAGES: 'git gcc build-base pkgconfig meson check-dev eudev-dev libevdev-dev libwacom-dev cairo-dev gtk4.0-dev mtdev-dev bash lua5.4-dev' + FEDORA_PACKAGES: 'git-core gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx_rtd_theme python3-pytest-xdist libwacom-devel cairo-devel gtk4-devel glib2-devel mtdev-devel diffutils wayland-protocols-devel black clang clang-tools-extra jq rpmdevtools valgrind systemd-udev qemu-img qemu-system-x86-core qemu-system-aarch64-core jq python3-click python3-rich virtme-ng luajit-devel' + DEBIAN_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev curl libluajit-5.1-dev' + UBUNTU_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev libluajit-5.1-dev' + ARCH_PACKAGES: 'git gcc pkgconfig meson check libsystemd libevdev python-pytest-xdist libwacom gtk4 mtdev diffutils luajit' + ALPINE_PACKAGES: 'git gcc build-base pkgconfig meson check-dev eudev-dev libevdev-dev libwacom-dev cairo-dev gtk4.0-dev mtdev-dev bash luajit-dev' FREEBSD_PACKAGES: 'git pkgconf meson libepoll-shim libudev-devd libevdev libwacom gtk3 libmtdev bash wayland' ############################ end of package lists ############################# @@ -110,12 +110,12 @@ variables: # changing these will force rebuilding the associated image # Note: these tags have no meaning and are not tied to a particular # libinput version - FEDORA_TAG: '2025-05-20.0' - DEBIAN_TAG: '2025-05-20.0' - UBUNTU_TAG: '2025-05-20.0' - ARCH_TAG: '2025-05-20.0' - ALPINE_TAG: '2025-05-20.0' - FREEBSD_TAG: '2025-05-20.0' + FEDORA_TAG: '2025-08-01.0' + DEBIAN_TAG: '2025-08-01.0' + UBUNTU_TAG: '2025-08-01.0' + ARCH_TAG: '2025-08-01.0' + ALPINE_TAG: '2025-08-01.0' + FREEBSD_TAG: '2025-08-01.0' FDO_UPSTREAM_REPO: libinput/libinput diff --git a/.gitlab-ci/config.yml b/.gitlab-ci/config.yml index bcdf0d6f..fc275397 100644 --- a/.gitlab-ci/config.yml +++ b/.gitlab-ci/config.yml @@ -3,7 +3,7 @@ # # We're happy to rebuild all containers when one changes. -.default_tag: &default_tag '2025-05-20.0' +.default_tag: &default_tag '2025-08-01.0' distributions: - name: fedora @@ -50,7 +50,7 @@ distributions: - python3-click - python3-rich - virtme-ng - - lua-devel + - luajit-devel - name: debian tag: *default_tag versions: @@ -76,7 +76,7 @@ distributions: - libglib2.0-dev - libmtdev-dev - curl # for the coverity job - - lua5.4-dev + - libluajit-5.1-dev - name: ubuntu tag: *default_tag versions: @@ -101,7 +101,7 @@ distributions: - libgtk-3-dev - libglib2.0-dev - libmtdev-dev - - lua5.4-dev + - libluajit-5.1-dev - name: arch tag: *default_tag versions: @@ -119,7 +119,7 @@ distributions: - gtk4 - mtdev - diffutils - - lua + - luajit build: extra_variables: - "MESON_ARGS: '-Ddocumentation=false'" # python-recommonmark is no longer in the repos @@ -140,7 +140,7 @@ distributions: - gtk4.0-dev - mtdev-dev - bash - - lua5.4-dev + - luajit-dev build: extra_variables: - "MESON_ARGS: '-Ddocumentation=false' # alpine does not have python-recommonmark" diff --git a/doc/user/lua-plugins.rst b/doc/user/lua-plugins.rst index 6e581c49..b95fbdb8 100644 --- a/doc/user/lua-plugins.rst +++ b/doc/user/lua-plugins.rst @@ -9,7 +9,7 @@ of devices. For example, a plugin may add or remove axes and/or buttons on a device and/or modify the event stream seen by this device before it is passed to libinput. -Plugins are implemented in `Lua `_ (version 5.4 or later) +Plugins are implemented in `Lua `_ (version 5.1) and are typically loaded from ``/usr/lib{64}/libinput/plugins`` and ``/etc/libinput/plugins``. Plugins are loaded in alphabetical order and where multiple plugins share the same file name, the one in the highest precedence @@ -20,7 +20,7 @@ Plugins are run sequentially in ascending sort-order (i.e. ``00-foo.lua`` runs before ``10-bar.lua``) and each plugin sees the state left by any previous plugins. -See the `Lua Reference manual `_ for +See the `Lua Reference manual `_ for details on the Lua language. .. note:: Plugins are **not** loaded by default, it is up to the compositor diff --git a/meson.build b/meson.build index 057da9fa..0172d1d4 100644 --- a/meson.build +++ b/meson.build @@ -168,8 +168,7 @@ dep_libevdev = dependency('libevdev', version: '>= 1.10.0') dep_lm = cc.find_library('m', required : false) dep_rt = cc.find_library('rt', required : false) -dep_lua = dependency('lua-5.4', 'lua5.4', 'lua', - version : '>= 5.4', +dep_lua = dependency(get_option('lua-interpreter'), required : get_option('lua-plugins')) have_lua = dep_lua.found() config_h.set10('HAVE_LUA', have_lua) @@ -184,6 +183,11 @@ summary({ section : 'Plugins', bool_yn : true) +if have_lua + summary({'Lua Interpreter' : get_option('lua-interpreter')}, + section : 'Plugins') +endif + # Include directories includes_include = include_directories('include') includes_src = include_directories('src') diff --git a/meson_options.txt b/meson_options.txt index 784ab58d..a3ffb3e1 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -46,3 +46,7 @@ option('lua-plugins', type: 'feature', value: 'auto', description: 'Enable support for Lua plugins') +option('lua-interpreter', + type: 'string', + value: 'luajit', + description: 'The Lua interpreter to use (pkgconfig name)') diff --git a/src/libinput-plugin-lua.c b/src/libinput-plugin-lua.c index 00130165..233e25f1 100644 --- a/src/libinput-plugin-lua.c +++ b/src/libinput-plugin-lua.c @@ -284,7 +284,18 @@ libinput_lua_pcall(struct libinput_lua_plugin *plugin, int narg, int nres) { lua_State *L = plugin->L; - int rc = lua_pcall(L, narg, nres, 0); + lua_pushvalue(L, -(narg + 1)); /* Copy the function */ + lua_pushvalue(L, plugin->sandbox_table_idx); + /* Now set the sandbox environment for the function we're about to call */ + int rc = lua_setfenv(L, -2) == 1 ? LUA_OK : LUA_ERRRUN; + if (rc == LUA_OK) { + /* Replace original function with sandboxed one */ + lua_replace(L, -(narg + 2)); + /* Now call the function */ + rc = lua_pcall(L, narg, nres, 0); + } else { + lua_pushstring(L, "Failed to set up sandbox"); + } if (rc != LUA_OK) { auto libinput_plugin = plugin->parent; const char *errormsg = lua_tostring(L, -1); @@ -1114,20 +1125,6 @@ libinput_lua_plugin_run(struct libinput_plugin *libinput_plugin) { struct libinput_lua_plugin *plugin = libinput_plugin_get_user_data(libinput_plugin); - struct lua_State *L = plugin->L; - - /* Main entry point into the plugin, so we need to push our sandbox - * as _ENV. This only needs to be done here because all other entry - * points into the Lua script are callbacks that are set up during - * this run (and thus share the _ENV) - */ - lua_pushvalue(L, plugin->sandbox_table_idx); - const char *upval = lua_setupvalue(L, -2, 1); - if (!upval || !streq(upval, "_ENV")) { - plugin_log_bug_libinput(libinput_plugin, "Failed to set up sandbox\n"); - libinput_plugin_unregister(libinput_plugin); - return; - } if (libinput_lua_pcall(plugin, 0, 0) && !plugin->register_called) { plugin_log_bug(libinput_plugin, @@ -1214,7 +1211,7 @@ libinput_lua_plugin_init_lua(struct libinput *libinput, if (!L) return NULL; - /* This will be our _ENV later, see libinput_lua_pcall */ + /* This will be our our global env later, see libinput_lua_pcall() */ lua_newtable(L); int sandbox_table_idx = lua_gettop(L); plugin->sandbox_table_idx = sandbox_table_idx; @@ -1227,32 +1224,36 @@ libinput_lua_plugin_init_lua(struct libinput *libinput, * all have their own individual sandbox. */ - luaL_requiref(L, LUA_GNAME, luaopen_base, 0); + luaopen_base(L); static const char *allowed_funcs[] = { - "assert", "error", "ipairs", "next", "pcall", "pairs", "pairs", - "print", "warn", "tonumber", "tostring", "type", "xpcall", + "assert", "error", "ipairs", "next", "pcall", "pairs", + "print", "tonumber", "tostring", "type", "unpack", "xpcall", }; ARRAY_FOR_EACH(allowed_funcs, func) { - lua_getfield(L, -1, *func); + lua_getglobal(L, *func); lua_setfield(L, sandbox_table_idx, *func); } /* Math is fine as a whole */ - luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 0); + luaopen_math(L); + lua_getglobal(L, "math"); lua_setfield(L, sandbox_table_idx, "math"); /* Table is fine as a whole */ - luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 0); + luaopen_table(L); + lua_getglobal(L, "table"); lua_setfield(L, sandbox_table_idx, "table"); - /* Table is fine as a whole */ - luaL_requiref(L, LUA_STRLIBNAME, luaopen_table, 0); + /* String is fine as a whole */ + luaopen_string(L); + lua_getglobal(L, "string"); lua_setfield(L, sandbox_table_idx, "string"); /* Override metatable to prevent access to unregistered globals */ - lua_pushvalue(L, sandbox_table_idx); lua_newtable(L); - lua_setfield(L, -2, "__index"); + lua_pushstring(L, "__index"); + lua_pushnil(L); + lua_settable(L, -3); lua_setmetatable(L, sandbox_table_idx); /* Our objects */ @@ -1260,7 +1261,8 @@ libinput_lua_plugin_init_lua(struct libinput *libinput, evdevdevice_init(L); /* Our globals */ - luaL_newlib(L, log_funcs); + lua_newtable(L); + luaL_register(L, "log", log_funcs); lua_setfield(L, sandbox_table_idx, "log"); libinput_lua_init_evdev_global(L, sandbox_table_idx);