Bug#840685: TOCTOU race condition in initscript on chown'ing JVM_TMP temporary directory (was: Re: Bug#840685: tomcat8: DSA-3670 incomplete)

Salvatore Bonaccorso carnil at debian.org
Fri Oct 14 19:40:42 UTC 2016


Hi Paul,

Markus followed already up, I just want to give some additional
comments on the below:

On Fri, Oct 14, 2016 at 07:07:52PM +1100, paul.szabo at sydney.edu.au wrote:
> Dear Salvatore,
> 
> > ... if the attacher created a symlink between the rm and the mkdir
> > then mkdir will still fail with -p on a symlink.  (Or do I miss
> > something?). ...
> 
> Yes, you missed a simple test:
> 
> $ mkdir mydir
> $ ln -s mydir mylink
> $ ls -ld my*
> drwx------ 2 psz amstaff 4096 Oct 14 18:46 mydir
> lrwxrwxrwx 1 psz amstaff    5 Oct 14 18:46 mylink -> mydir
> $ mkdir -p mylink || echo failed
> $ mkdir -p mylink; echo $?
> 0
> $ mkdir mylink || echo failed
> mkdir: cannot create directory `mylink': File exists
> failed
> $ mkdir mylink; echo $?
> mkdir: cannot create directory `mylink': File exists
> 1
> $ ls -ld my*
> drwx------ 2 psz amstaff 4096 Oct 14 18:46 mydir
> lrwxrwxrwx 1 psz amstaff    5 Oct 14 18:46 mylink -> mydir
> $ 
> 
> showing that "mkdir -p" does not fail (but plain mkdir does).

You are doing all the tests with the same user. But yes mkdir -p will
succeed for the root user still in some cases. Let's recapitulate your
described attack. The attacker has shell-access on the tomcat8 running
host or by other mean can run code on the server by an unprivileged
user and used inotify to detect when $JVM_TMP will be removed.

Let's say the tomcat8 service is started.

JVM_TMP=/tmp/tomcat8-tomcat8-tmp

# rm -rf "$JVM_TMP".

With inotify the evil user detects, that /tmp/tomcat8-tomcat8-tmp got
removed and has several options for proceeding. Either create a
directory, or directly a malicious symlink. 

evil at jessie:~$ ln -s /etc/passwd /tmp/tomcat8-tomcat8-tmp
evil at jessie:~$ ls -l /tmp/tomcat8-tomcat8-tmp 
lrwxrwxrwx 1 evil evil 11 Oct 14 20:20 /tmp/tomcat8-tomcat8-tmp -> /etc/passwd
evil at jessie:~$

raced before root will issue the mkdir -p call:

root at jessie# mkdir -p /tmp/tomcat8-tomcat8-tmp 
mkdir: cannot create directory ‘/tmp/tomcat8-tomcat8-tmp’: File exists
root at jessie# echo $?
1
root at jessie#

if the evil user instead created a directory, then yes you are right
for that part:

evil at jessie$ mkdir -p /tmp/tomcat8-tomcat8-tmp
evil at jessie$ ls -ld /tmp/tomcat8-tomcat8-tmp
drwxr-xr-x 2 evil evil 4096 Oct 14 20:25 /tmp/tomcat8-tomcat8-tmp
evil at jessie$

followed by the root user

root at jessie# mkdir -p /tmp/tomcat8-tomcat8-tmp
root at jessie# echo $?
0
root at jessie#

If now the evil user wins again the race, and removes the directory in
time and replaces it with the symlink to a desired file to overwrite,
before the chown call of the root user:

evil at jessie$ rmdir /tmp/tomcat8-tomcat8-tmp
evil at jessie$ ln -s /etc/passwd /tmp/tomcat8-tomcat8-tmp
evil at jessie$ ls -l /tmp/tomcat8-tomcat8-tmp
lrwxrwxrwx 1 evil evil 11 Oct 14 20:28 /tmp/tomcat8-tomcat8-tmp -> /etc/passwd
evil at jessie$

root at jessie# chown tomcat8 /tmp/tomcat8-tomcat8-tmp
chown: cannot dereference ‘/tmp/tomcat8-tomcat8-tmp’: Permission denied
root at jessie# echo $?
1
root at jessie# ls -l /etc/passwd
-rw-r--r-- 1 root root 1631 Oct 14 20:07 /etc/passwd
root at jessie#

The same if the evil user created a symlink to a existing directory:

evil at jessie$ ln -sf /etc /tmp/tomcat8-tomcat8-tmp
evil at jessie$ ls -l /tmp/tomcat8-tomcat8-tmp
lrwxrwxrwx 1 evil evil 4 Oct 14 21:01 /tmp/tomcat8-tomcat8-tmp -> /etc
evil at jessie$

root at jessie# mkdir -p /tmp/tomcat8-tomcat8-tmp
mkdir: cannot create directory ‘/tmp/tomcat8-tomcat8-tmp’: File exists
root at jessie#

root at jessie# chown tomcat8 /tmp/tomcat8-tomcat8-tmp 
chown: cannot dereference ‘/tmp/tomcat8-tomcat8-tmp’: Permission denied
root at jessie#

because of the kernel hardening.

> > On the practicality for Debian systems though this is mitigated by the
> > Kernel hardenings which are enabled by default:
> > 
> > fs.protected_hardlinks=1
> > fs.protected_symlink=1
> > 
> > which will prevent that the target of the symlink in /tmp will be
> > changed on the chown call.
> 
> Another missing test (besides: who is changing anything?):
> 
> # grep . /proc/sys/fs/prot*
> /proc/sys/fs/protected_hardlinks:1
> /proc/sys/fs/protected_symlinks:1
> # cd ~psz
> # ls -ld my*
> drwx------ 2 psz amstaff 4096 Oct 14 18:46 mydir
> lrwxrwxrwx 1 psz amstaff    5 Oct 14 18:46 mylink -> mydir
> # chown mike mylink
> # ls -ld my*
> drwx------ 2 mike amstaff 4096 Oct 14 18:46 mydir
> lrwxrwxrwx 1 psz  amstaff    5 Oct 14 18:46 mylink -> mydir
> # 

You are operating here outside of /tmp (sticky world-writable
directory) which the above issue for the init scripts relies on,
right?  fs.protected_(hardlinks|symlinks) is exactly a hardening for
those issues:

https://www.kernel.org/doc/Documentation/sysctl/fs.txt
https://sources.debian.net/src/linux/3.16.36-1%2Bdeb8u1/Documentation/sysctl/fs.txt/#L205

In the release notes such issues are not treated as security-issues
anymore since:

https://www.debian.org/releases/stable/amd64/release-notes/ch-whats-new.en.html#security


> > So while I think it should be fixed, this would not warrant a DSA,
> > since mitigated by default in Debian.
> 
> No mitigation: fix and DSA, please!

See my explanation above. I'm not saying the issue should not be
fixed, if that was the impression from our replies, then this can be
rectified; but it does not seem warrant a DSA (so can be fixed via a
regular update via a point release). Maybe still I'm missing
something, so if you have a PoC could you please share your PoC it
with apo at debian.org and team at security.debian.org? 

Regards,
Salvatore



More information about the pkg-java-maintainers mailing list