Secure Linux -- kernel patch for Linux 2.0.33 ... 2.0.36
==========
Overview
==========
This patch is a collection of security improvements for the Linux kernel,
all configurable via the new 'Security options' configuration section.
Non-executable user stack area
--------------------------------
Most buffer overflow exploits are based on overwriting a function's return
address on the stack to point to some arbitrary code, which is also put
onto the stack. If the stack area is non-executable, buffer overflow
vulnerabilities become harder to exploit.
Another way to exploit a buffer overflow is to point the return address to
a function in libc, usually system(). This patch also changes the default
address that shared libraries are mmap()ed at to make it always contain a
zero byte. This makes it impossible to specify any more data (parameters
to the function, or more copies of the return address when filling with a
pattern) in an exploit that has to do with ASCIIZ strings (this is the case
for most buffer overflow vulnerabilities).
However, note that this patch is by no means a complete solution, it just
adds an extra layer of security. Many buffer overflow vulnerabilities will
still remain exploitable a more complicated way. The reason for using such
a patch is to protect against some of the buffer overflow vulnerabilities
that are yet unknown.
Also, note that some buffer overflows can be used for denial of service
attacks (usually in non-respawning daemons and network clients). A patch
like this cannot do anything against that. So I suggest to use the patch,
but fix vulnerabilities anyway as soon as they become known.
Restricted links in /tmp
--------------------------
I've also added a link-in-/tmp security fix, originally by Andrew Tridgell.
I changed it to prevent from using hard links too, by not allowing non-root
users to create hard links to files they don't own. This seems to be the
desired behavior anyway, since otherwise users couldn't remove such links
they just created in a +t directory. I also added exploit attempt logging.
Restricted pipes in /tmp
--------------------------
In addition to restricting links, you might also want to restrict pipes
to make data spoofing attacks (like the GCC virus) harder. Enabling this
option disallows writing to pipes not owned by the user in +t directories,
unless the pipe is owned by root.
Restricted /proc
------------------
This was originally a patch by route that only changed the permissions on
some directories in /proc, so you had to be root to access them. Then there
were some more very similar patches by other people. I found them all quite
unusable for my purposes, on a system where I wanted several admins to be
able to see all the processes, etc, without having to su root each time. So
I had to create my own patch that I include here.
This option restricts the permissions on /proc so that non-root users can
see their own processes only, and nothing about active network connections,
unless they're in a special group. This group's id is specified via the
gid= mount option, and is 0 by default. (Note: if you're using identd, you
will need to edit the inetd.conf line to run identd as this special group.)
Also, this disables dmesg(8) for non-root users. You might want to use this
on an ISP shell server where privacy is an issue.
When using this part of the patch, most programs (ps, top, who) work as
desired -- they only show the processes of this user (unless root or in
the special group), and don't complain they can't access others. However,
there's a known problem with some versions of w(1), which only show this
user when they can't get the command line of others. The workaround is to
use who(1) instead, or install a version of w(1) that doesn't have the
problem (old Slackware 3.1's works just fine: shows other users too, but
without their commands).
================
How to install
================
Apply the patch. In kernel configuration, go to the new 'Security options'
section. Read help for the suboptions, and configure them. If desired, edit
/etc/fstab to specify the group id for /proc. Build the kernel and reboot.
You may also want to add the following line to your /etc/syslog.conf to
log [security] alerts separately:
kern.alert /var/log/alert
Additionally, you may do something like this (assuming the log file will
be empty most of the time):
> /var/log/alert
chown root.staff /var/log/alert
chmod 640 /var/log/alert
echo "more /var/log/alert" >> ~your_usual_non-root_account/.bash_profile
chattr +a /var/log/alert
[ The last command doesn't do much unless you raise your securelevel, for
example, with securelevel.c supplied with this patch. ]
Ensure that the non-executable stack part of the patch is working correctly,
use stacktest.c for that -- running './stacktest -e' should segfault, and a
message about possible buffer overflow exploit attempt should get logged to
/var/log/alert (with syslogd configuration described above). If you enabled
the GCC trampolines autodetection, try running './stacktest -t', it should
succeed. If you have trampoline call emulation enabled, you can also try
'./stacktest -b', the exploit attempt should fail even after a trampoline
call in the same process.
Also, check the address libc is mmap()ed at: its most significant byte
should be zero instead of 0x40 like it was before. Use a command like this:
strace /bin/ls 2>&1 | grep mmap\[^\|\]\*\|PROT_EXEC | sed s/\[^=\]\*=//
[ Note: strace doesn't zero pad 32 bit values it prints, so output like
0x119000 means the most significant byte is zero (this value got only 6
digits, while full 32 bit numbers are 8 hexadecimal digits long). If the
patch wasn't applied, the value would be 0x40009000. ]
If you enabled the link-in-/tmp fix, you can also try to create a symlink
in /tmp (as a non-root user) pointing to a file that user has no read
access to, then switch to some other user that has the read access (for
example, root) and try to read the file via the link (like, cat /tmp/link).
This should fail, and a message should get logged (if enabled). Everything
is similar for write access, and for symlinks to files that don't exist.
Now, you can try to create a hard link as a non-root user to a file that
user doesn't own. This should also fail.
========
F.A.Q.
========
Q: Will you be updating the patch for the new kernel version 2.0.x?
A: Yes, I am going to update the patch for all "stable" kernels. See:
http://www.false.com/security/linux/
Q: What about 2.1.x?
A: Currently I have no plans of porting the patch to Linux 2.1.
Q: Will GCC-compiled programs that use trampolines work with the non-exec
stack part of the patch?
A: Yes, read help for the 'Autodetect GCC trampolines' configuration option.
Q: How do you differ a trampoline call from an exploit attempt?
A: Since most buffer overflow exploits overwrite the return address, the
instruction to pass control to the stack has to be a RET. With trampoline
calls the instruction is a CALL. However, in some cases such trampoline
autodetection can be fooled by RET'ing to a CALL instruction and making
this CALL pass control onto the stack (in reality, this also requires a
register to be set to the address). Again, read help for the 'Autodetect
GCC trampolines' configuration option.
Q: What about glibc and non-executable stack?
A: You have to enable trampoline autodetection when using glibc 2.0.x, or
the system won't even boot. You will likely also want to enable trampoline
call emulation since some privileged processes will have to be running with
executable stack if you don't. Let's hope glibc gets fixed not to use
trampolines some day.
Q: What is chstk.c for?
A: The patch adds an extra flag to ELF and a.out headers, which controls
whether the program will be allowed to execute code on the stack or not,
and chstk.c is what you should use to manage the flag. You might find it
useful if you choose to disable the GCC trampolines autodetection. BTW,
setting the flag also restores the original address shared libraries are
mmap()ed at, just in case some program depends on that.
Q: What if an attacker uses chstk.c on a buffer overflow exploit?
A: Nothing changes. It's the vulnerable program being exploited that needs
executable stack, not the exploit. The attacker would need write access
to this program's binary to use chstk.c successfully.
Q: Do I have to reboot with an unpatched kernel to try out a new overflow
exploit to see if I'm vulnerable?
A: No, you can use chstk.c on the vulnerable program to temporarily allow
it to execute code on the stack. Just don't forget to reset the flag back
when you're done.
Q: Why did you modify signal handler return code?
A: Originally the kernel put some code onto the stack to return from signal
handlers. Now signal handler returns are done via the GPF handler instead
(an invalid magic return address is put on the stack).
Q: What to do if a program needs to follow a symlink in a +t directory for
its normal operation (without introducing a security hole)?
A: Usually such a link needs to be created only once, so create it as root.
Such links are followed even when the patch is enabled.
Q: What will happen if someone does:
ln -s /etc/passwd ~/link
ln -s ~/link /tmp/link
and the vulnerable program runs as root and writes to /tmp/link?
A: The patch is not looking at the target of the symlink in /tmp, it only
checks if the symlink itself is owned by the user that vulnerable program
is running as, and doesn't follow the link if not (like in this example).
Q: Is there some performance impact of using the patch?
A: Well, normally the only thing affected is singal handler returns. I didn't
want to modify the sigreturn syscall, so there is some extra code to setup
its stack frame. I don't think this has a noticable effect on the performance:
saved context checks and other signal handling stuff are taking much more
time. Executing code on the stack was not fast anyway. Also, programs using
GCC trampolines will run slower if trampoline calls are emulated. However,
I don't know of any program that uses trampolines where the performance is
critical (would be a stupid thing to do so anyway).
Signed,
Solar Designer