COMMAND
LPRng
SYSTEMS AFFECTED
LPRng 3.6.1..15 (at least)
PROBLEM
Patrick Powell posted following. Well, even in spite of all of
efforts, care, and paranoia, he finally dropped the hammer on his
foot. Luckily it appears that he spotted this loophole before
somebody on the LPRng mailing list did.
Versions of LPRng-3.6.1-LPRng-3.6.15 installed the 'lpd' program
'SETUID root' by default. The lpd executable should be OWNED by
root, but not SETUID root.
If lpd is SETUID root and executable by users, it is possible for
users to append lpd trace and logging messages to existing files
owned by the user/group the lpd process runs as.
The problem was discovered when Lars Kellogg-Stedman asked why
the 'lpd -L logfile' option required logfile to exist. This
caused Patrick to look at the code that lpd used to open the log
file and he realized that:
- if the lpd server is not running
- AND if lpd is installed SETUID root
- AND if non-root users can execute lpd
- AND lpd is started using 'lpd -L /path'
- AND the /path file exists
- AND the /path file has permissions allowing the user/group
- the lpd runs as to open the file
THEN: lpd will append error and trace messages to /path
LPRng-3.6.1 - LPRng-3.6.15 installed LPD setuid ROOT. This
appears to be, as they say, a dumb move.
The reason for the SETUID root installation appears to be a typeo
introduced in the LPRng-3.6.1 Makefile when Patrick was fixing up
the install code to install the lpr, lpc, lprm and lpq programs
optionally SETUID root or as normal processes. It appears that
he installed the 'lpd' program the same way. This was in spite
of hos notes that "lpd should not be installed setuid ROOT".
When the Linux SETUID problem was announced on June 8 he looked at
LPRng and made sure that it did not have similar problems. He did
an analysis of LPRng and discovered the SETUID install during
testing. He removed the SETUID install on the grounds that one
less possible compromise was a good idea. This was done in the
LPRng-3.6.16 released.
The LPD process is usually started up at system initialization
time. But there is a simple attack that kills off a surprisingly
large number of servers.
a) You start a large number of processes, each of which allocates
and modifies a large amounts of memory. See the getrlimit(2)
and limits(1) for the limits usually imposed on processes. You
can exhaust the swap area using this method on most systems.
b) You now start sending requests to the server, i.e.- lpd. If
the lpd process has not allocated enough memory to hold the
pending requests information, then it will do a malloc().
This malloc() will fail due to brk(2) failing with: [ENOMEM]
Insufficient space existed in the swap area to support the
expansion, and this is a fatal error for the lpd process.
Finally, lets look at the files we can modify. The last set of
conditions mean that the only files that lpd can modify are the
ones owner daemon/group daemon, and that have write permissions
for user daemon/group daemon. This, unfortunately, includes the
files in spool queues.
So, if the user could find a way to stop the running lpd server,
then they could append trace information into these files.
SOLUTION
Remove SETUID permissions from 'lpd'
chown root /usr/sbin/lpd
chmod 555 /usr/sbin/lpd
or
chmod 500 /usr/sbin/lpd
The current release (LPRng 3.6.20) installs it non-setuid.