diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8f0ee9a9..30fca07d 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 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' + 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' 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-11-04.0' - DEBIAN_TAG: '2025-11-04.0' - UBUNTU_TAG: '2025-11-04.0' - ARCH_TAG: '2025-11-04.0' - ALPINE_TAG: '2025-11-04.0' - FREEBSD_TAG: '2025-11-04.0' + FEDORA_TAG: '2025-11-17.0' + DEBIAN_TAG: '2025-11-17.0' + UBUNTU_TAG: '2025-11-17.0' + ARCH_TAG: '2025-11-17.0' + ALPINE_TAG: '2025-11-17.0' + FREEBSD_TAG: '2025-11-17.0' FDO_UPSTREAM_REPO: libinput/libinput diff --git a/.gitlab-ci/config.yml b/.gitlab-ci/config.yml index 7401f19e..7edc2104 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-11-04.0' +.default_tag: &default_tag '2025-11-17.0' distributions: - name: fedora @@ -50,7 +50,7 @@ distributions: - python3-click - python3-rich - virtme-ng - - luajit-devel + - lua-devel - name: debian tag: *default_tag versions: @@ -76,7 +76,7 @@ distributions: - libglib2.0-dev - libmtdev-dev - curl # for the coverity job - - libluajit-5.1-dev + - lua5.4-dev - name: ubuntu tag: *default_tag versions: @@ -101,7 +101,7 @@ distributions: - libgtk-3-dev - libglib2.0-dev - libmtdev-dev - - libluajit-5.1-dev + - lua5.4-dev - name: arch tag: *default_tag versions: @@ -119,7 +119,7 @@ distributions: - gtk4 - mtdev - diffutils - - luajit + - lua 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 - - luajit-dev + - lua5.4-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 c2683266..d507b058 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.1) +Plugins are implemented in `Lua `_ (version 5.4) and are typically loaded from the following paths: - ``/etc/libinput/plugins/*.lua``, and @@ -29,7 +29,7 @@ before ``10-bar.lua``) and each plugin sees the state left by any previous plugins. For example if ``00-foo.lua`` changes all left button events to right button events, ``10-bar.lua`` only ever sees right button events. -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 bb253c42..5d484790 100644 --- a/meson.build +++ b/meson.build @@ -168,7 +168,8 @@ 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(get_option('lua-interpreter'), +dep_lua = dependency('lua-5.4', 'lua5.4', 'lua', + version : '>= 5.4', required : get_option('lua-plugins')) have_lua = dep_lua.found() if have_lua @@ -193,11 +194,6 @@ 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 de0b1c41..20d7e05e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -50,7 +50,3 @@ 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 c11998f3..c7581236 100644 --- a/src/libinput-plugin-lua.c +++ b/src/libinput-plugin-lua.c @@ -296,18 +296,7 @@ libinput_lua_pcall(struct libinput_lua_plugin *plugin, int narg, int nres) { lua_State *L = plugin->L; - 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"); - } + int rc = lua_pcall(L, narg, nres, 0); if (rc != LUA_OK) { auto libinput_plugin = plugin->parent; const char *errormsg = lua_tostring(L, -1); @@ -1120,6 +1109,22 @@ 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; + + assert(lua_isfunction(L, -1)); + + /* 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, @@ -1206,7 +1211,7 @@ libinput_lua_plugin_init_lua(struct libinput *libinput, if (!L) return NULL; - /* This will be our our global env later, see libinput_lua_pcall() */ + /* This will be our _ENV later, see libinput_lua_pcall */ lua_newtable(L); int sandbox_table_idx = lua_gettop(L); plugin->sandbox_table_idx = sandbox_table_idx; @@ -1219,36 +1224,34 @@ libinput_lua_plugin_init_lua(struct libinput *libinput, * all have their own individual sandbox. */ - luaopen_base(L); + luaL_requiref(L, LUA_GNAME, luaopen_base, 0); static const char *allowed_funcs[] = { "assert", "error", "ipairs", "next", "pcall", "pairs", "print", "select", "tonumber", "tostring", "type", "xpcall", "_VERSION", }; ARRAY_FOR_EACH(allowed_funcs, func) { - lua_getglobal(L, *func); + lua_getfield(L, -1, *func); lua_setfield(L, sandbox_table_idx, *func); } + lua_pop(L, 1); /* Math is fine as a whole */ - luaopen_math(L); - lua_getglobal(L, "math"); + luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 0); lua_setfield(L, sandbox_table_idx, "math"); /* Table is fine as a whole */ - luaopen_table(L); - lua_getglobal(L, "table"); + luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 0); lua_setfield(L, sandbox_table_idx, "table"); /* String is fine as a whole */ - luaopen_string(L); - lua_getglobal(L, "string"); + luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 0); 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_pushstring(L, "__index"); lua_pushnil(L); - lua_settable(L, -3); + lua_setfield(L, -2, "__index"); lua_setmetatable(L, sandbox_table_idx); /* Our objects */