Skip to content

Permissions

Why OpenLogi never runs as root, how the uaccess ACL works, and why it avoids the input group.

Permissions

Anything that can remap your mouse buttons can, by construction, synthesise keystrokes. That is not a flaw in OpenLogi — it is what remapping is. But it does mean the permission model deserves more scrutiny than a typical desktop app, so this page documents exactly what access is granted, to whom, and for how long.

OpenLogi never runs as root

The application runs entirely as your user. The single privileged action in the whole project is installing a udev rule at setup time. Nothing at runtime is elevated, and there is no setuid binary, no system-wide daemon and no polkit agent.

What the rule grants

Two distinct pieces of access, for two different reasons.

Reading and writing Logitech HID endpoints

SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", TAG+="uaccess"
KERNEL=="hidraw*", KERNELS=="*:0000046D:*", TAG+="uaccess"

/dev/hidraw* defaults to 0600 root:root, and for good reason: raw HID access to a keyboard is equivalent to a keylogger. So this access has to be narrow.

TAG+="uaccess" asks systemd-logind to attach an ACL for the user at the active physical seat. The important properties:

  • Access is granted at login and revoked at logout
  • It follows the active seat, so a remote SSH session does not inherit it
  • It is not permanent group membership, so it cannot be quietly accumulated

The second rule exists because Bluetooth HID devices have no USB idVendor attribute — the vendor id appears in the device path as uppercase hex instead.

Writing to /dev/uinput

KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", MODE="0660", GROUP="openlogi"

Remapped buttons are delivered by synthesising input events through the kernel's uinput device.

uinput deliberately does not use uaccess: it is a misc device with no seat assignment, so logind will not attach an ACL to it. The usual advice in this situation is to join the input group — and OpenLogi deliberately does not do that.

Why not input: membership in input grants read access to every /dev/input/event* node on the system. That is the ability to log every keystroke typed on the machine, in any application, including passwords and sudo prompts. It is a far broader capability than this app needs.

OpenLogi instead creates a dedicated openlogi system group that conveys exactly one capability — write access to uinput — and nothing else.

Why uinput and not the display server

Input is synthesised below the display server rather than injected into it. This is a deliberate architectural choice:

ApproachX11Wayland
XTEST / client-side injectionWorksDoes not work
uinput (kernel virtual device)WorksWorks

Wayland compositors intentionally refuse client-side input injection, because permitting it would let any application type into any other. Writing to uinput produces a virtual input device that the compositor treats like real hardware, so one code path serves both display servers.

What is not granted

  • No network access — the application contains no networking code
  • No access to other users' devices or sessions
  • No read access to /dev/input/event*
  • No persistent root, no setuid, no system daemon

Auditing it yourself

The complete rule file is about 30 lines, and every clause is commented:

cat /etc/udev/rules.d/70-openlogi.rules

To confirm what you were actually granted:

# Expect a "user:" ACL entry for your username
getfacl -p /dev/hidraw0

# Expect group "openlogi", mode 0660
ls -l /dev/uinput

# Confirm you are not in the "input" group
id -nG