COMMAND
kernel
SYSTEMS AFFECTED
Linux 2.2.12
PROBLEM
Solar Designer posted following. This advisory serves two
purposes: (1) let people know that they could want to upgrade to
2.2.13 when it comes out, for security reasons; (2) announce the
new location for downloading his patches, as well as the fact that
they're now available for Linux 2.2.
SD finally ported (actually, mostly re-coded) my patch to Linux
2.2, which has obviously resulted in some form of an audit of the
relevant parts of the kernel. Many of the issues have already
been discussed on the security-audit list, and some are even
fixed in 2.2.13 pre-patches. Of course, his patches for both 2.2
and 2.0 (as some of the issues turned out to affect 2.0 as well)
have either fixes or workarounds (to be improved in the future)
for all of the issues he'll be talking about, below. Note that
the issues are relatively minor, no instant root or such, but
are still bad enough to be worth fixing.
As this advisory is going to be fairly long, let's start by
providing the new URL. The new download location for future
versions of SD's patches, is:
http://www.openwall.com/linux/
The patches also no longer call themselves "Secure Linux", to stop
giving a false sense of security (I've spent quite a while to make
sure the documentation doesn't, either, as those things appear to
be quite important), and to avoid confusion with the Linux
distribution being developed under the same codename.
Well, done with that, now we can get to the security issues. To
save space, SD will put either (2.0.38) or (2.2.12), or both,
before every description, to indicate which kernel versions it
applies to. Also, a (*) will mean that 2.2.13pre7 contains a
fix, and a (+) will mean that this hasn't been on security-audit,
to let those on both lists look through this post a bit faster.
(2.2.12) (*)
Tymm Twillman has reported a problem with execve(2) halting the
system when passed some illegal addresses. After some testing,
the problem turned out to be a missing error check on the return
from strlen_user(), which was used on user-supplied arguments,
and thus could indicate a fault; execve(2), in turn, should have
converted that into a EFAULT.
(2.0.38) (2.2.12) (*)
While investigating the problem mentioned above, as well as
porting Pavel Kankovsky's fd 0-2 fix to Linux 2.2, SD noticed yet
another problem with execve(2), which has a similar impact. The
problem is that all arguments are first counted, and their
lengths measured, and only after that the results are checked
against the limit (32 pages, or 128 KB on x86). Thus, it is
possible to make execve(2) spend a significant amount of CPU
cycles in the kernel, with the big kernel lock obtained. In
terms of real time, SD was able to get 25 minutes for one
execve(2) call on Alpha (the 64-bit address space helps), and
several seconds on modern x86 boxes. The latter can still be
halted to death by repeating the call in a loop, and in a few
processes.
Fixing this required a trivial modification to the argument
counting function, and a switch to strnlen_user() for the strings
(on 2.2). The latter is an architecture-specific assembly
function. My patch only fixes it on x86 and Alpha, and 2.2.13
will do that for some more architectures (but maybe not all
supported by Linux 2.2, yet). Linux 2.0 didn't have a
strlen_user(), and thus used a simple loop in this place, which
had the same vulnerability (but not in my 2.0.38 patch, of
course). Note that RLIMIT_AS can be used as a workaround for
this problem, and you should probably be using it for other
reasons, anyway.
(2.0.38) (+)
There was an intentional lack of fault checking when accessing the
arguments, as indicated by a comment in the code. This allowed a
user to generate kernel-mode faults inside execve(2), after some
kernel resources have been allocated (and would never be freed).
Simply fixing the problem mentioned above seemed uninteresting, so
SD re-written the argument counting code to do all the necessary
checking, and to share the same checks with measuring the lengths
of individual arguments. SD even managed to make it have the
same performance that it used to; the new count() function looks
a bit like a puzzle because of that, though. Actually, this is
something that should have been done earlier; now it can only
remain in my 2.0.38 patch.
(2.0.38) (2.2.12) (*)
/proc/<pid> directories, and /proc/<pid>/fd symlinks could also be
accessed with any amount of zeroes prepended to their names. This
could be used, say, to obtain an overly long cwd. There's no
obvious security impact, but something to be fixed anyway (and
that has been done).
(2.0.38) (2.2.12) (*)
CLONE_PID could be set from the user-space, thus producing two
user processes with the same PID. Attacks include: stopping SUID
programs from sending signals to themselves (even raise(3)
wouldn't work), covering your high resource usage by the other
dummy process, making unkillable processes that can still be
running just fine (covered by dummy zombie processes with the
same PID).
(2.0.38) (2.2.12)
It is possible to request any exit_signal, not just SIGCHLD, via
clone(2). This is normally not a problem, but there's one
exception: the parent could have executed a SUID program, and
that program could have done a "setuid(geteuid())", expecting to
protect itself from signals sent by the original user. This
feature of clone(2) can be used to send an arbitrary signal to
such a program. SD put a workaround into my patches, that
restricts the allowed signal numbers to SIGCHLD, SIGUSR1, SIGUSR2,
or no signal, with SIGUSR1 and SIGUSR2 allowed specifically for
LinuxThreads to work. This also means that SUID programs which
use LinuxThreads remain unprotected. A solution to this should
be developed. SD proposed one in a comment in the patches, and
Pavel Kankovsky has offered another one. Unfortunately, both of
them have some (different) disadvantages. This problem isn't
fixed in 2.2.13pre7, and isn't likely to be any time soon.
(2.2.12) (*)
We have now reverted to the behavior of chown(2) we had in 2.0:
reset SUID/SGID bits on ownership change even if done by root.
Until now, Linux 2.2 didn't do that for root (and not even for
CAP_FSETID, like it was supposed to do), which allowed for some
races that have been discussed on the security-audit list a few
months ago.
(2.0.38) (+)
Linux 2.0's version of process_unauthorized() forgot to check the
dumpable flag, so it was possible to access memory of a SUID
process a user has started, via PID re-use. Linux 2.2 did the
right thing, and isn't vulnerable.
(2.0.37 with secure-linux-11) (+)
It was possible to bypass some restrictions of CONFIG_SECURE_PROC
via PID re-use in 2.0.36 and 2.0.37 kernels with SD patches. SD
simply didn't re-check the code closely enough when updating the
patch for 2.0.36. Thanks to Pavel Kankovsky for noticing this.
(2.0.38) (2.2.12) (+)
User-space values of the instruction and stack pointers are
available via /proc, -- for every process in the system, and to
everyone. This information should in fact be treated just as
private as the address space of the processes (such a patch will
likely get into 2.2.13pre soon). Imagine a crypto algorithm
implementation that does branches based on its key bits. Thanks
to Thomas who has reported this to me (but underestimated the
impact).
One final note: SD is still going to fix all 2.0.38 security
issues that are any serious, in his patches, for a few months
more.
SOLUTION
Well, you saw the URL above....