Solving the console permission problem [LONG]
WARNING: long and boring technical post below
The console permission problem is something that everybody who has a sound card
is used to: which permissions should be set on /dev/dsp and the other audio
devices so that they can be used as a normal user? The current solutions are:
1) -rw-rw-rw- root/audio
This is the easiest one, but allows anyone that is logging in from a
remote location to read from the mic or make embarassing or annoying
2) Adding people to group audio
This is also bad, since it's like above but restricted to a few people.
3) Adding people to group audio on login
Idem, since after getting audio group perms it's easy to create and
hide a setgid file.
4) Making programs setgid audio
Same problem as above
5) Making programs setgid audio and making them check if on console or local X
It would be too great of a change for some programs, and since sound
programs are not prepared to be setgid, it might be possible to get a
shell and then the same problems appear
6) Changing the uid of the audio files on login and changing them back to 0 on
The best idea, but works only with xdm (and the one I use here)
7) Using a sound server
OK... But how the sound server knows I'm on the console (not a problem
with esd)? And which one (there are three, and one of them is a device
hog)? And should we have to modify all the programs to use it (it would
be too hard for some programs; esddsp helps here)? Also, this won't
work with other devices, and has a "lowest common denominator" problem.
This problem is not limited to the audio I/O devices. Other things that are
also part of the "console" (in a broad sense of "everything that interacts
directly with the user") are the joysticks (/dev/js*), floopy drive (/dev/fd*),
CD drive (/dev/hda* or /dev/sc*) and maybe others (of course only some of the
/dev/hda* or /dev/sc* are CD drives...) like CD writers.
Solution 6 is the best so far, but extending it to the VTs creates a problem:
what if more than one person is logged on it at the same time? (Don't laugh,
people at the labs on my university do that all the time). And it is also a
problem on multiheaded systems with two sets of input devices (but I won't
present a solution to this non-existant case).
The solution I devised is to have a special program change the perms on the
devices when something needs it and change them back when they are not in use.
Here's a (hopefully legible and not boring) outline of it:
- sound program starts
- calls consoleperms_acquire ("audio"); from libconsoleperms
- consoleperms_acquire forks and execs
"consoleperms-helper acquire audio"
- consoleperms-helper checks a file in /var/run with a list of the
subsystems and all pids using them
- no program from other user is using it, change the perms
(consoleperms-helper is setuid root)
- when the program finishes, it calls
consoleperms_release ("audio"); ->
"consoleperms-helper release audio"
So basically we have four components:
1. The sound (or joystick, or whatever)-using program is linked to a new
library and special calls are made in the begginning and the end of the
program. This is a very small and non-invasive change
2. The library, libconsoleperms, provides the wrapper functions to call the
int consoleperms_acquire (const char *);
int consoleperms_release (const char *);
Both acquire or release one "resource" (so if you want both sound and
joystick you have to make two calls). They return 1 on success and 0 on
failure (but the program will probably ignore the return code and give the
"can't open /dev/dsp" error).
The changes to a program code would be normally only three lines (one
include for consoleperms.h and two calls)
3. The setuid consoleperms-helper program
consoleperms-helper acquire <resource>
consoleperms-helper release <resource>
It first checks $DISPLAY for X; if found and local, tries to connect to
check if the .Xauthority has the right key. If no $DISPLAY, it checks if the
program is running on a VT.
Then, it checks if the resource is not being used (or already being used by
the same user) in some random file in /var/run. If so, it adds its _parent_
pid (ppid) to the file and sets the perms on the device (harmless if already
acquired). On release, it removes the pid and sets the perms to uid 0 if it
was the last pid on that resource. Note that only the uid of the device is
changed (so the perms still need to be sane by default)
The list of resources would be in some random file in /etc. One possible
list would be audio, joystick, floppy, cdrom, cdwriter.
4. The wrapper program
To help the programs that are not yet converted to the library, a program
called consoleperms-wrapper could be used.
consoleperms-wrapper res1 res2 ... -- program args
It would simply call the library acquire function, run the program, wait for
it, and then call the library release function.
This would allow things like wrapping a whole X session
("exec consoleperms-wrapper audio -- enlightenment" instead of
"exec enlightenment" in ~/.xsession, for example). It should be used only if
the user requests it, to avoid problems.
I could do a sample implementation of this mess -- but only when I discover the
low-level X calls needed for validating a user (I'm not a X programmer...).
Also, being setuid is a bit more complex than a normal program.
Why adding this to Debian? Because it would make sound work "out of the box"
(well, almost) while maintaining a strong security model.
Cesar Eduardo Barros