Bug 66861

Summary: Permission denied for regular user not in group "audio" to access /dev/snd/seq
Product: systemd Reporter: Alain Kalker <a.c.kalker>
Component: generalAssignee: systemd-bugs
Status: RESOLVED FIXED QA Contact: systemd-bugs
Severity: normal    
Priority: medium    
Version: unspecified   
Hardware: x86-64 (AMD64)   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:
Attachments: Output of `journalctl -b | grep udev` with /etc/udev/udev.conf containing "udev_log="debug"

Description Alain Kalker 2013-07-12 16:33:27 UTC
Arch Linux, systemd 204, linux 3.9.9, x86_64

I'm trying to use QSynth (a frontent for fluidsynth) as a virtual synthesizer to play MIDI output from other software.
I want to run QSynth as regular user, not as a system daemon (which brings all kinds of issues like JACK setup, use with Pulseaudio, running as "root", etc.)

Starting QSynth as regular user, I get the error:
"Qsynth1: Failed to create the MIDI driver (alsa_seq).

No MIDI input will be available."

Investigating, I found the following:

$ aconnect -o
ALSA lib seq_hw.c:457:(snd_seq_hw_open) open /dev/snd/seq failed: Permission denied
can't open sequencer

$ id
uid=1000(miki) gid=100(users) groups=100(users),10(wheel),78(kvm),91(video),150(wireshark),190(systemd-journal),1002(adbusers),1003(networkminer)

(i.e. I'm *not* a member of the audio group, following the advice of documentation in many places to let systemd handle access to devices.)

$ loginctl seat-status seat0
seat0
	Sessions: *2 1
	 Devices:
		  ├─/sys/devices/LNXSYSTM:00/LNXPWRBN:00/input/input1
		  │ input:input1 "Power Button"
		  ├─/sys/device...XSYSTM:00/LNXSYBUS:00/PNP0C0C:00/input/input0
		  │ input:input0 "Power Button"
		  ├─/sys/devices/pci0000:00/0000:00:04.0/usb2
		  │ usb:usb2
		  │ ├─/sys/device.../0000:00:04.0/usb2/2-1/2-1:1.0/input/input3
		  │ │ input:input3 "  USB Keyboard"
		  │ ├─/sys/device.../0000:00:04.0/usb2/2-1/2-1:1.1/input/input4
		  │ │ input:input4 "  USB Keyboard"
		  │ └─/sys/device.../0000:00:04.0/usb2/2-2/2-2:1.0/input/input5
		  │   input:input5 "Logitech USB Mouse"
		  ├─/sys/devices/pci0000:00/0000:00:04.1/usb1
		  │ usb:usb1
		  ├─/sys/device...0000:00/0000:00:0a.0/0000:01:06.0/sound/card0
		  │ sound:card0 "CMI8738"
		  ├─/sys/device...0e.0/ata1/host0/target0:0:0/0:0:0:0/block/sr0
		  │ block:sr0
		  ├─/sys/devices/platform/HDHomeRun.0/dvb/dvb0.demux0
		  │ dvb:dvb0.demux0
		  ├─/sys/devices/platform/HDHomeRun.0/dvb/dvb0.dvr0
		  │ dvb:dvb0.dvr0
		  ├─/sys/devices/platform/HDHomeRun.0/dvb/dvb0.frontend0
		  │ dvb:dvb0.frontend0
		  ├─/sys/devices/platform/HDHomeRun.1/dvb/dvb1.demux0
		  │ dvb:dvb1.demux0
		  ├─/sys/devices/platform/HDHomeRun.1/dvb/dvb1.dvr0
		  │ dvb:dvb1.dvr0
		  ├─/sys/devices/platform/HDHomeRun.1/dvb/dvb1.frontend0
		  │ dvb:dvb1.frontend0
		  ├─/sys/devices/platform/pcspkr/input/input2
		  │ input:input2 "PC Speaker"
		  ├─/sys/devices/platform/vesafb.0/graphics/fb0
		  │ [MASTER] graphics:fb0 "VESA VGA"
		  └─/sys/devices/virtual/misc/kvm
		    misc:kvm

$ getfacl /dev/snd/pcmC0D0p /dev/snd/midiC0D0 /dev/snd/seq
getfacl: Removing leading '/' from absolute path names
# file: dev/snd/pcmC0D0p
# owner: root
# group: audio
user::rw-
user:miki:rw-
group::rw-
mask::rw-
other::---

# file: dev/snd/midiC0D0
# owner: root
# group: audio
user::rw-
user:miki:rw-
group::rw-
mask::rw-
other::---

# file: dev/snd/seq
# owner: root
# group: audio
user::rw-
group::rw-
other::---

(i.e. I have access to sound playback and "raw" (hardware) MIDI devices, but not to the sequencer device, needed for virtual MIDI.

I believe an uaccess rule could be added to 71-seat.rules to enable access to the sequencer, correct?
Comment 1 Kay Sievers 2013-07-12 17:10:27 UTC
It's covered by:
  SUBSYSTEM=="sound", TAG+="uaccess"

Try to load the kernel module first, only after that udev applies the user's
ACLs.
Comment 2 Alain Kalker 2013-07-12 17:38:57 UTC
Thanks for the tip and quick reply!

I don't think that udev picking up the device at module load time is the problem, the device does get set to group "audio" by udev (see a looong way below).
I realize that I may have worded the bug subject wrong: it's possibly not a problem with uaccess but with adding the device to a seat. Sorry for that ;-)

In 71-seat.rules, sound devices are handled specially:
71-seat.rules:10:TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat"
71-seat.rules:11:SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat"

i.e. anything that does _not_ have KERNEL=="card*" is filtered out for some reason, and doesn't get the "seat" tag.

The trouble is, /dev/snd/seq is a virtual device (alas, without an entry in /sys/devices/virtual/sound , is this an ALSA bug?), and is handled yet elsewhere in:

50-udev-default.rules:33:SUBSYSTEM=="sound", GROUP="audio", \
50-udev-default.rules:34:  OPTIONS+="static_node=snd/seq", OPTIONS+="static_node=snd/timer"

i.e. it most probably doesn't have KERNEL=="card*", so does not get "seat" tag.

How do I get /dev/snd/seq added to a seat, given that it has this strange "static_node=" option?
Comment 3 Alain Kalker 2013-07-12 17:48:03 UTC
The more I think of it, probably ALSA bug: /sys/devices/virtual/timer exists, /sys/devices/virtual/seq doesn't...
Comment 4 Alain Kalker 2013-07-12 17:49:00 UTC
erhhm that should be /sys/devices/virtual/*sound*/{timer,seq} , duh.
Comment 5 Alain Kalker 2013-07-12 18:02:09 UTC
Perhaps this (old) post is relevant, since it mentions /dev/snd/seq specifically: http://lists.freedesktop.org/archives/systemd-devel/2012-December/007750.html

I can't figure out from the context how exactly it is (was) handled there.
Comment 6 Alain Kalker 2013-07-12 18:59:31 UTC
Created attachment 82372 [details]
Output of `journalctl -b | grep udev` with /etc/udev/udev.conf containing "udev_log="debug"

Not of much use, I'm afraid. The log entries generated by libudev are scattered over multiple processes, so I filtered it on 'udev'.

I'll try to hack together an ad-hoc `udevadm monitor` service next, to get some more detailed output.
Comment 7 Alain Kalker 2013-07-12 19:05:33 UTC
One interesting thing found:

$ getfacl /dev/snd/{seq,timer}
getfacl: Removing leading '/' from absolute path names
# file: dev/snd/seq
# owner: root
# group: audio
user::rw-
group::rw-
other::---

# file: dev/snd/timer
# owner: root
# group: audio
user::rw-
user:miki:rw-
group::rw-
mask::rw-
other::---

Yup, that supports my suspicion: the 'timer' device has an entry in /sys, and so it gets the right ACL set. 'seq' has no entry in /sys, and doesn't get right ACL set. Bummer.
Comment 8 Kay Sievers 2013-07-12 19:49:20 UTC
As mentioned, if you do:
  modprobe snd_seq
the seq device should show up in /sys.

$ ls -l /sys/class/sound/{seq,timer}
/sys/class/sound/seq -> ../../devices/virtual/sound/seq
sys/class/sound/timer -> ../../devices/virtual/sound/timer
Comment 9 Zbigniew Jedrzejewski-Szmek 2013-07-12 19:52:10 UTC
(In reply to comment #8)
> As mentioned, if you do:
>   modprobe snd_seq
> the seq device should show up in /sys.
But that's hardly a solution?
Comment 10 Alain Kalker 2013-07-12 20:57:29 UTC
Ahh!, I was assuming that

$ lsmod | grep seq
snd_seq_device          5180  2 snd_rawmidi,snd_opl3_lib
snd                    58893  8 snd_hwdep,snd_timer,snd_pcm,snd_rawmidi,snd_mpu401_uart,snd_seq_device,snd_cmipci,snd_opl3_lib

and the /dev/snd/seq device node existing was all I needed. Never ever realized that I needed to *manually* modprobe snd_seq for it to actually start working.
The distro I was using before Arch had this setup out-of-the-box.

# modprobe snd_seq
$ getfacl /dev/snd/seq
getfacl: Removing leading '/' from absolute path names
# file: dev/snd/seq
# owner: root
# group: audio
user::rw-
user:miki:rw-
group::rw-
mask::rw-
other::---

Case closed, I think, and sorry for wasting your time...
Comment 11 Alain Kalker 2013-07-12 21:11:08 UTC
To add just one more thing:

I don't know if it is due to the "static_node" stuff or if the kernel really does create /dev/snd/seq even before the snd_seq kernel module is loaded, anyway, it would be nice if the error message that started all this had been something like

"/dev/snd/seq: No such file or directory"

instead of:

"/dev/snd/seq: Permission denied"

The former would have me go looking for missing kernel modules, hardware problems etc. immediately, the latter sent me down this twisting path...

Just my 2 cents.
Comment 12 Kay Sievers 2013-07-16 23:45:35 UTC
(In reply to comment #11)
> I don't know if it is due to the "static_node" stuff or if the kernel really
> does create /dev/snd/seq even before the snd_seq kernel module is loaded,

Right, it's udev, not the kernel. And things work as expected. It's just
unfortunate, that it does not work for ordinary users who log in. All other
use cases for on-demand module-loading are covered, needed, and will work
fine.

> instead of:
> 
> "/dev/snd/seq: Permission denied"

Hmm, that's pretty actionable, isn't it?

It tells you that you don't have the permission to open the node. Just
throwing a 'sudo' in front, which gets the permissions, would have made everything work.

Btw, future versions of systemd will also handle logged-in users ACLs:
  http://cgit.freedesktop.org/systemd/systemd/commit/?id=6b78df0a6ec75f25705a0f78ef895b95ab75a7ea

Thanks!
Comment 13 Alain Kalker 2013-07-17 13:59:27 UTC
(In reply to comment #12)
> (In reply to comment #11)
> > I don't know if it is due to the "static_node" stuff or if the kernel really
> > does create /dev/snd/seq even before the snd_seq kernel module is loaded,
> 
> Right, it's udev, not the kernel. And things work as expected. It's just
> unfortunate, that it does not work for ordinary users who log in. All other
> use cases for on-demand module-loading are covered, needed, and will work
> fine.

No, they do not. At least on Arch Linux, which tries to provide packages as 'vanilla' i.e. unpatched, unmodified as possible, no dynamic module loading happens for /dev/snd/seq .

> > instead of:
> > 
> > "/dev/snd/seq: Permission denied"
> 
> Hmm, that's pretty actionable, isn't it?
> 
> It tells you that you don't have the permission to open the node. Just
> throwing a 'sudo' in front, which gets the permissions, would have made
> everything work.

Please *don't* advise users to try to solve problems whose cause they don't know by simply throwing 'sudo' at them. It sounds like "If you hit it and it doesn't budge, just use a bigger hammer."

In this particular case (/dev/snd/seq file exists, snd_seq kernel module not loaded, what happens is this:

$ sudo aconnect -l
[sudo] password for miki: 
aconnect - ALSA sequencer connection manager
Copyright (C) 1999-2000 Takashi Iwai
Usage:
 * Connection/disconnection between two ports
   aconnect [-options] sender receiver
[snip usage text]

The user's confusion will now be complete, s/he might think that sudo 'ate' the -l option, that aconnect doesn't like being run with root privileges, etc.

Only running aconnect under strace with root privileges reveals a tiny bit of extra information, but you'd need a trained eye to spot it:

$ sudo strace -e trace=file -f aconnect -l
execve("/usr/bin/aconnect", ["aconnect", "-l"], [/* 15 vars */]) = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libasound.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
stat("/usr/share/alsa/alsa.conf", {st_mode=S_IFREG|0644, st_size=9184, ...}) = 0
open("/usr/share/alsa/alsa.conf", O_RDONLY) = 3
access("/usr/share/alsa/alsa.conf.d/", R_OK) = 0
stat("/usr/share/alsa/alsa.conf.d/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
openat(AT_FDCWD, "/usr/share/alsa/alsa.conf.d/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
open("/usr/share/alsa/alsa.conf.d//50-pulseaudio.conf", O_RDONLY) = 3
access("/etc/asound.conf", R_OK)        = 0
stat("/etc/asound.conf", {st_mode=S_IFREG|0644, st_size=260, ...}) = 0
open("/etc/asound.conf", O_RDONLY)      = 3
access("/root/.asoundrc", R_OK)         = -1 ENOENT (No such file or directory)
open("/dev/snd/seq", O_RDWR|O_CLOEXEC)  = 3
------------------------------------------^ (>=0, success!)
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/alsa-utils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US.utf8/LC_MESSAGES/alsa-utils.mo", O_RDONLY) = -1 
[snip lots of unimportant output]
+++ exited with 1 +++

If unlucky, at this point someone could now decide to compile alsa-lib/alsa-utils from source with debug symbols and fire up gdb...

Just to try and make a point: the different errors (let's call them ENOENT, EPERM and ENODEV for short) do make a lot of difference in a user's perception of the problem:
- "No such device": The (virtual) device doesn't exist, let's try and fix that.
- "No such file or directory": The (virtual) device may or may not exist, first check for the device some other way (dmesg, journald), then try and fix the device file.
- "Permission denied": whoops, the device does exist, but I'm not allowed to access it.

> 
> Btw, future versions of systemd will also handle logged-in users ACLs:
>  
> http://cgit.freedesktop.org/systemd/systemd/commit/
> ?id=6b78df0a6ec75f25705a0f78ef895b95ab75a7ea
> 
> Thanks!

You're welcome :-)
Comment 14 Alain Kalker 2013-07-17 15:15:17 UTC
Please ignore my comment above, I misspelled `aconnect -o`.
The module does autoload when using it with sudo.

I'm looking forward to the next version of systemd with your patch included.

Thanks again.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.