Skip to content

Device rules (udev)

Quasar needs a few devices on the host: /dev/uinput to create virtual controllers, the GPU render nodes, and in console mode the screen, sound and local input. Three udev rules files give the quasar group access to exactly those. They live in the repository under deploy/udev/.

Each rule adds an access entry (an ACL, set with setfacl) for the quasar group. It never changes a device’s owner or mode, so nothing that already uses these devices loses access. No broad group such as input or video is granted.

prepare-host.sh installs the same files, byte for byte. Use this page if you install them by hand, or want to know what they do.

File Device Why Quasar needs it When needed
70-quasar.rules /dev/uinput Creating virtual keyboards, mice, gamepads and touch devices for players. Rootless installs
Input devices named Quasar Virtual * Sessions open the virtual devices Quasar created. On an SELinux host they also get the container label, so a confined session can open them. Rootless installs
GPU render nodes (/dev/dri/renderD*) Hardware encoding and rendering. Rootless installs
71-quasar-console.rules Display cards (/dev/dri/card*) The console desktop drives the host’s own screen; the agent reads which monitors are connected. Console mode
Sound devices The console desktop plays its sound on the host. Console mode
i2c buses (/dev/i2c-*) Monitor control (DDC), such as switching the monitor’s input. Console mode
The host’s input devices (keyboards, mice, controllers, touchpads, buttons) The console desktop uses them, including ones plugged in later. Console mode
tty8 Console mode’s own terminal, so nothing typed reaches a login prompt. Console mode
72-quasar-seat.rules Input devices named Quasar Virtual * Moves them off the desktop’s seat. See below. Any host where someone logs into a desktop

70-quasar.rules does no harm on a rootful install; prepare-host.sh installs it in both modes.

On an SELinux host, sessions run as container_engine_t, and the policy gives that type none of the console’s devices: without more, the desktop starts with no keyboard, mouse or sound. prepare-host.sh --console also loads a small module, quasar-console-devices, that allows exactly these and nothing else: the input nodes, the sound nodes, the hidraw nodes Steam Input reads, and the udev database. SELinux stays enforcing. By hand:

Terminal window
cat > quasar-console-devices.cil <<'EOF'
(allow container_engine_t device_t (dir (getattr open read search watch)))
(allow container_engine_t event_device_t (chr_file (getattr ioctl lock map open read write append)))
(allow container_engine_t sound_device_t (chr_file (getattr ioctl lock map open read write append)))
(allow container_engine_t usb_device_t (chr_file (getattr ioctl lock map open read write append)))
(allow container_engine_t udev_var_run_t (dir (getattr open read search)))
(allow container_engine_t udev_var_run_t (file (getattr open read map)))
EOF
sudo semodule -i quasar-console-devices.cil

Running prepare-host.sh again without --console leaves the module in place and says so; remove it with sudo semodule -r quasar-console-devices.

On an SELinux host, an app that needs the nested-sandbox type (container_engine_t, Steam’s sandbox) connects to its session’s audio sidecar (PipeWire, serving a PulseAudio socket), which runs as container_t. The policy allows that connection only between containers of the same type, so without more the session is silent. prepare-host.sh loads a module, quasar-nested-audio, with exactly one rule for it, and SELinux stays enforcing. The rule is one permission between two types: any container_engine_t process on the host may connect to a container_t unix socket it can reach by path. Quasar mounts only the session’s own sidecar directory into the app, and file labels and permissions still apply; an app given another session’s socket directory could reach that session’s audio. By hand:

Terminal window
echo '(allow container_engine_t container_t (unix_stream_socket (connectto)))' > quasar-nested-audio.cil
sudo semodule -i quasar-nested-audio.cil

A host prepared before this module existed has no sound in Steam sessions until you run prepare-host.sh again; it is safe to repeat. Check with sudo semodule -l | grep quasar-nested-audio.

When someone is logged into a desktop on the host, systemd-logind gives that user access to every input device on the seat, including a player’s virtual controller. The player’s input would then also drive the host desktop. The seat rule puts Quasar’s virtual devices on a seat of their own, so the desktop user never gets them.

There is no uhid rule: Quasar does not emulate a DualSense controller.

The files use the group quasar, and setfacl from the acl package at /usr/bin/setfacl. Create the group first if it does not exist (prepare-host.sh does).

  1. Copy the files you need from a checkout of the repository:

    Terminal window
    sudo cp deploy/udev/70-quasar.rules deploy/udev/72-quasar-seat.rules /etc/udev/rules.d/
    # console mode only
    sudo cp deploy/udev/71-quasar-console.rules /etc/udev/rules.d/
  2. Apply them:

    Terminal window
    sudo udevadm control --reload && sudo udevadm trigger
  3. Console mode only: keep login prompts off tty8, the terminal console mode uses:

    Terminal window
    sudo systemctl mask getty@tty8.service autovt@tty8.service
Terminal window
getfacl /dev/uinput

The output includes group:quasar:rw-. With a session running, a desktop user should not appear on Quasar’s virtual devices:

Terminal window
for d in /sys/class/input/event*; do
grep -q '^Quasar Virtual' "$d/device/name" 2>/dev/null && getfacl -p "/dev/input/${d##*/}"
done

Each shows group:quasar:rw- and no named-user line such as user:alex:rw-.

Terminal window
sudo rm -f /etc/udev/rules.d/70-quasar.rules /etc/udev/rules.d/71-quasar-console.rules /etc/udev/rules.d/72-quasar-seat.rules
sudo udevadm control --reload && sudo udevadm trigger

Access entries already set stay until the device is recreated or the host reboots.