Re: cdrecord local root exploit
On Mon, 27 Sep 2004, Dr Andrew C Aitchison wrote:
> I belive at one time the kernel wasn't trusted to stop a malicious
> user from generating a SCSI request which was received by a different
> device than the one the kernel was told was the target.
Even if it were, there's a more subtle security hole lurking here -- most
recordable optical drives allow firmware updates via the bus. Aside from
filtering specific commands to specific devices (error-prone and difficult
to maintain, especially as the commands in question are frequently
undocumented), there's nothing the kernel can do to prevent the uploading
of malicious firmware that, among other things, could proxy SCSI commands
to other devices on the bus. This probably isn't an issue on a
single-initiator bus like IDE, but it's certainly possible in the
multiple-initiator world of SCSI.
In addition, there are many opportunities for denial-of-service,
particularly with older devices that don't do a very good job of sharing
the SCSI bus in the first place (e.g., devices that don't support
disconnect/reconnect), and devices that allow SCSI controller
configuration via mode pages (e.g., disabling D/R). Of course, it's
probably a bad idea to put the first class of devices on the same bus with
critical devices in the first place, but I digress.
With that said, the safest way to run cdrecord seems like the following:
- create a user (e.g., cdrecord) and a group (e.g., cdrecord-user)
- give the cdrecord user (_not_ the group) permission to access any
resources necessary to run cdrecord
- chown cdrecord:cdrecord-user cdrecord
- chmod 4550 cdrecord
This is simply the principle of least privilege. Cdrecord shouldn't need
to be root -- it only needs certain permissions to get its job done.
Cdrecord users don't need to be able to send arbitrary SCSI commands --
cdrecord itself does.
The notion that a program must be root if an ordinary user doesn't have
the necessary permissions by default is a dangerous one. Sometimes UNIX
makes this unavoidable (root-based security checks, e.g., privileged port
access), but, curiously, I see it more in the Windows world, where lots of
software wants to run as either a local Administrator or LocalSystem
(i.e., as a part of the TCB) instead of as an ordinary user with whatever
additional privileges are required, even though more granular security is
available (e.g., why does the Windows Time service need to run as a part
of the TCB? It needs to be able to set the system's clock, but NT has a
separate privilege [SeSystemTime] for this, presumably for a reason).
If one were to re-implement cdrecord with security in mind, it may make
sense to separate it into two executables:
- a front-end program, running as the user, which does command-line
processing, file access, and other tasks not directly related to device
control
- a "device access" program, running as cdrecord, which contains the
minimum amount of code necessary to control the optical drives. The
front-end would send it generic requests (e.g., write, finalize) which
would then be translated into the appropriate SCSI commands.
This way, only the smaller (and, presumably, easier to audit) "device
access" program would have to be trusted with raw SCSI access.
Since the "device access" portion of cdrecord is probably the largest and
most error-prone portion of the code (I assume this from my own experience
writing SCSI software, not from inspecting the cdrecord sources), it is
questionable whether this would be worth the trouble. However, if
implemented as a generic, portable "burner daemon" with a simplified API
that could be useful to multiple front-end programs (e.g., X11 front ends,
music players, backup software), it could be worthwhile.
-jtm