Backport of the input-device name fix (PR #8129 by @acrogenesis, merged to
quattro as 9285b19d) onto the v4-0-1 release branch.
Hyprland input-device and monitor names come from USB descriptors and hyprctl
output, so they are attacker-influenceable, yet the toggle and monitor commands
interpolated them straight into hyprctl eval and into generated Lua that
Hyprland re-executes on every reload. XF86TouchpadToggle is bound with
locked = true, so a malicious USB name reached Lua execution from the lock
screen as the logged-in user, and a persisted disable made it run on every
start. Publicly reported by Jorrit Jongma / Chainfire.
The disable is no longer executable Lua anywhere. The device name is stored as
plain-text data in a *-disabled-name sidecar and read back by a packaged module,
default/hypr/disabled-input-device.lua, on every reload; the live hyprctl eval
Lua-quotes the name and rejects control characters outright. The reload loader
excludes the two legacy filenames, so a leftover generated *-disabled.lua on a
not-yet-migrated install can never be sourced as code again, and a migration
recovers the device name from it and deletes it, sanitizing installs that ran
the vulnerable version. All four monitor scripts validate an output name against
a plain-connector-name pattern before writing it as Lua, closing the same latent
pattern in the siblings, and paths.lua treats a set-but-empty XDG_STATE_HOME as
unset to match the bash side.
Clean cherry-pick: all fourteen files are byte-identical to quattro, so merging
v4-0-1 into quattro resolves without a conflict. This branch ships no leftover
*-disabled.lua template of its own -- the tracked "disabled" files are the same
two quattro has -- so the migration is the only path that has to sanitize
anything here.
test/shell passes: 192 files, including the three this adds. The toggle suite's
public-PoC case passes here, as do the monitor scripts' accept/reject cases and
the XDG path cases. test/cli passes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DEMYa9UWtroz93DhMTtcV
40 lines
1.3 KiB
Lua
40 lines
1.3 KiB
Lua
-- Require every *.lua file in a directory in sorted order.
|
|
-- Used for Omarchy extension-style folders such as default/hypr/apps,
|
|
-- default/hypr/bindings, and ~/.local/state/omarchy/toggles/hypr.
|
|
-- Pass a module prefix for normal package.path modules, e.g.
|
|
-- require_all.files(paths.omarchy_path .. "/default/hypr/apps", "default.hypr.apps")
|
|
-- Pass nil as the prefix when the directory itself has been added to package.path.
|
|
-- Pass options.exclude as a set of base names (without ".lua") to skip; a legacy
|
|
-- file that must never be loaded as code stays on disk for a migration to remove.
|
|
|
|
local M = {}
|
|
|
|
local function shell_quote(path)
|
|
return "'" .. path:gsub("'", "'\\''") .. "'"
|
|
end
|
|
|
|
function M.files(dir, module_prefix, options)
|
|
local exclude = options and options.exclude or {}
|
|
local handle = io.popen("find " .. shell_quote(dir) .. " -maxdepth 1 -type f -name '*.lua' -printf '%f\\n' 2>/dev/null | sort")
|
|
if handle then
|
|
for filename in handle:lines() do
|
|
local name = filename:gsub("%.lua$", "")
|
|
if not exclude[name] then
|
|
local module = name
|
|
if module_prefix then
|
|
module = module_prefix .. "." .. module
|
|
end
|
|
|
|
if options and options.reload then
|
|
package.loaded[module] = nil
|
|
end
|
|
|
|
require(module)
|
|
end
|
|
end
|
|
handle:close()
|
|
end
|
|
end
|
|
|
|
return M
|