Writing

Software, technology, sysadmin war stories, and more. Feed
Sunday, October 21, 2018

A hidden complication for Linux desktop audio

"Next year is the year of Linux on the desktop."

That line has been the case for many years. I assume it will continue for many more: always *just* out of reach.

But this isn't about that, and this isn't even about what I use. I run Linux on the desktop, and have for long enough that some people might think I'm doing it to prove a point or to just keep that timer ticking.

No, this is about what happens when (presumably) desktop-focused things show up in what you expect to be a "somewhat Unixy" environment, and when you're operating in the wrong mindset.

A couple of days ago, I was out in the world, doing my current thing of mercenary Linux troubleshooting work. People have problems, and I try to help them out. They happen to be with computers, but really, I'm there for the people.

Anyway, most of these situations involve systems and network stuff, but I'm happy to sniff around other problems just to see if I can be of any assistance. This time, it was something a little more unusual: "audio isn't working on this box". They run a program, and nothing comes out of the speakers.

To set the stage, this is a fairly boring, if large, machine, running one of the "long term support" builds of Ubuntu. It has speakers connected. They are turned on. The volume is at a decent level. But... the sound isn't working. It apparently had been, but now it wasn't.

I decided to ssh in from my own machine to check it out. Nothing seemed obviously wrong. There was sound hardware being found at boot time (in dmesg), and all of that stuff. I figured, okay, it's time to just try playing something, and see what happens. I loaded sox on there, since it's easier than dragging in all of mplayer, and copied whatever random wav file I had hanging around from other projects. I was already in a root shell, so I just did "play whatever.wav" and sure enough, a bunch of Morse code came out of the speakers.

At this point it was clear that the hardware worked, the kernel was happy, and userspace was able to talk to it, and I headed back to the office with the machine to see what else was going on. There, I logged in at the console as myself, and tried running play again. It worked. Knowing what I did from my own Slackware machine at home, I figured, "okay, that's because console logins put you in a bunch of groups like audio", and figured that's why. (Check out CONSOLE_GROUPS in /etc/login.defs if you haven't seen this before.) To prove it, I sshed BACK to the box from itself, figuring that a network login would lack those groups and then it would fail to play audio in that context.

I was wrong. It played just fine. Clearly, my assumptions were wrong. A quick sniff through some of the system calls made by the tools (play, alsamixer, and so on) showed they were twiddling files in /dev/snd. It was at this point that I noticed something unusual but didn't pay nearly enough attention to it.

~$ ls -la /dev/snd/controlC0 
crw-rw----+ 1 root audio 116, 2 Oct 14 21:58 /dev/snd/controlC0

See that "+" at the end of the permissions? I figured that "something extra" was up, but it had been a long time and wasn't sure exactly what to do about it to find out.

Meanwhile, the original trouble report stood: the machine's usual user, over in their usual login session from another machine, still couldn't play audio. "play" would RUN, but nothing came out of the speakers. alsamixer just gave some weird complaint like it couldn't find some file and would die on the spot.

Somewhere in here, I tripped over some random comment on the web about ConsoleKit (something I had ignored completely previously, because I don't believe in Linux "desktop environments"), and realized what the "+" meant. It was trying to tell me that this file had funky permissions going on. ACLs. Stuff I hadn't played with since the '90s when I tried to get people to use Samba on Linux instead of Windows. Crazy stuff like that.

Now it was starting to make sense. I ran getfacl on the device node. It showed me as a "user:" since I was still logged in on the console. Unlike on my Slackware boxes, it wouldn't matter how I logged in, since my group memberships weren't the operative thing now. It was the device node itself having its permissions changed on the fly whenever I happened to be logged in on the console.

To prove this, I got the machine's usual user to also log in on the console, at which point they gained a "user:" entry in the access control list. Playback from the remote session now worked.

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

The timeline started fitting together. Normally they would have a login on the console through the X window manager in addition to the remote login. The X login would usually be there behind a screen saver just hanging out, but it was enough to get the ACLs in place to let audio "just work". However, the machine had been rebooted to install some kernel patches or somesuch, and that cleared the console login, and that meant no audio-granting ACL entries.

The longer-term fix was to put their account in the "audio" group and then get a fresh set of processes running which picked up those permissions.

When it comes to spooky action at a distance, I guess filesystem ACLs just got added to my list of things to check.

...

Finally, if you read through this and thought "you're so dumb, everyone knows this about Linux audio", then obviously you are THE ONE and this post was not for you.