Linux automatic user ACL management
You may have not noticed, because it just works in Linux. Every time user logs in, Access Control Lists on a few important devices nodes are set for him. And every time his session becomes inactive, ACL are revoked. It looks like this:
# getfacl /dev/video0 getfacl: Removing leading '/' from absolute path names # file: dev/video0 # owner: root # group: video user::rw- user:zdzichu:rw- group::rw- mask::rw- other::---
Works like this:
Audio device access for user “zdzichu” is only granted when this user has an active session. If no one is logged in, or user “tomek” has an active session, then “zdzichu” access is revoked.
And works internally like this...
Which devices are affected?
In theory, the devices belonging to the seat used by user. In addition to peripherals, access to a few subsystems is granted. Best practice is to classify your device — some classes have the privilege of being ACL-managed. The logic lies in 70-uaccess.rules
in udev
configuration. Devices of the following classes are made accessible: ID_GPHOTO2, ID_HPLIP, ID_CDROM, ID_FFADO, ID_SMARTCARD_READER, ID_PDA, ID_REMOTE_CONTROL, ID_INPUT_JOYSTICK, ID_MEDIA_PLAYER
. Names are self-explanatory.
In future, this classification will let administator decide which classes are granted to local user.
Some subsystems are treated specially, access is allowed without further classification. Those subsystems are: sound, video4linux, dvb, drm.
We need to go deeper
Classification from previous paragraph is really an abstraction layer. The ACL granting is handled at the lowest level in file /usr/lib/udev/rules.d/73-seat-late.rules
by this line:
TAG=="uaccess", ENV{MAJOR}!="", RUN+="/usr/lib/systemd/systemd-uaccess $env{DEVNAME} $env{ID_SEAT}"
The systemd-uaccess
helper is run for each device with uaccess
tag (tagging itself happens in 70-uaccess.rules
). On my system, there are a few devices affected:
# udevadm info --export-db | grep -cE "TAG.*uaccess" 9
Example: USB-to-RS232 converter
There is no proper class for this gizmo. We can either invent one and send the patch to upstream, or short-circuit logic by tagging device directly. For simplicity, let’s take the second route, keeping in mind it’s discouraged :)
After plugging in our device, use udevadm info
to see what udev
knows about it and what makes it special. It may be a serial number, specific values of vendor id or product id, type, model or any other property. For my device, I will differentiate on model. Create a simple rule:
From now on, every time this converter is plugged in, an active user will gain access to# cat /etc/udev/rules.d/92-usbserial-for-user.rules SUBSYSTEM=="tty", ENV{ID_MODEL}=="USB_Serial_Converter", TAG+="uaccess"
/dev/ttyUSB0
thanks to ACLs.
This leaves us with important question:
Who is an active user?
This information is managed by logind
. CLI interaction is provided by loginctl
:
# loginctl SESSION UID USER SEAT 36 502 tomek seat0 2 500 zdzichu seat0 # loginctl show-session -p Active 36 Active=no # loginctl show-session -p Active 2 Active=yes
Thus, ACLs for currently active user “zdzichu” are applied. Start of new session is signalled by pam_systemd
module, which should be included in PAM stack. logind
by itself watches for active VT console. In other implementations, like for example kmscon, explicit calls on console switch are needed. Calls to logind
, of course.
(This section probably needs to be expanded)
Daemons
What to do if you have daemon requiring access to device nodes? Should it start its own session and keep it active? The answer is no. Daemons should be added to the appropriate group. For example, CCTV daemon should be in group video
, which has access to /dev/video*
.
Group ownership of device nodes is of course managed by udev
:
# grep video /usr/lib/udev/rules.d/* /usr/lib/udev/rules.d/50-udev-default.rules:# video4linux /usr/lib/udev/rules.d/50-udev-default.rules:SUBSYSTEM=="video4linux", GROUP="video"
Yes, that’s an UNIX way.
By the way, you don’t want users permanently added to groups like audio
or video
. Such user would be able to ssh into the machine while you are using it and spy on you using webcam, microphone etc. Access to such critical peripherals should only be granted for active user.
What could possibly go wrong?
Everything. There’s a lot of moving parts. Hopefully, most of them are very simple. And with this document, you’ll know what parts to check.
One quite complicated aspect is finding the link between current graphical session and Xorg socket in /tmp
. This could go wrong, and will go wrong if you have per-user /tmp dirs¹. In this case current user will have no sound, no accelerated GUI etc.
Standard installations require pam_systemd
to be included in PAM stack. pam_systemd(8) man page contains example snippet.
¹ — this could be fixed by looking for X socket in abstract namespace first. Nobody needed it done, yet.
Look into the past
Information here applies to the last couple of Fedora releases.
Some time ago, ACL modifications were done by udev
working with ConsoleKit database. The rules were different. Devices had to be TAGed with TAG+="udev-acl"
or variables like ENV{ACL_MANAGE}="1"
were used. This no longer applies.
And PA gives more than what's supported in ALSA (Bluetooth audio comes to mind).
And http://0pointer.de/blog/projects/when-pa-and-when-not.html