Page MenuHomeFreeBSD

rc.d/cleanvar: purgedir function has shell expansion vulnerability
ClosedPublic

Authored by feld on Jan 5 2018, 10:29 PM.
Tags
None
Referenced Files
Unknown Object (File)
Thu, Jan 16, 4:58 AM
Unknown Object (File)
Tue, Jan 7, 2:42 AM
Unknown Object (File)
Tue, Dec 24, 10:43 AM
Unknown Object (File)
Nov 29 2024, 12:57 AM
Unknown Object (File)
Nov 17 2024, 9:52 AM
Unknown Object (File)
Oct 21 2024, 9:59 PM
Unknown Object (File)
Oct 7 2024, 2:05 PM
Unknown Object (File)
Oct 4 2024, 11:11 AM

Details

Summary

cleanvar is enabled by default on FreeBSD systems. Its purpose is to
clean out stale files from three directories:

  • /var/run
  • /var/spool/lock
  • /var/spool/uucp/.Temp/

For /var/run and /var/spool/lock a local function called purgedir is used.
This function has a vulnerability by shell expansion.

If any process creates a directory named "-P" in /var/run or
/var/spool/lock it will cause the purgedir function to start to rm -r /.
This seems to only be reproducible on boot or startup of a jail
(exec.start= "/bin/sh /etc/rc";).

Only /var/run and /var/spool/lock use the purgedir function. The
purgedir function has the following properties:

  • If zero arguments are given to purgedir, run purgedir on .
  • skip sockets named "log" and "logpriv" (intended for /var/run)
  • a hack to avoid following "." and ".."
  • if it's a directory, run the purgedir function against this directory
  • otherwise rm -f -- $file

I believe the vulnerability we are seeing is at line 32:

cd "$dir" && for file in .* *

-P is alphasorted as the first item in the directory and the CWD=/,
which means you get

CWD=/
/usr/bin/cd "-P" && for file in .* *

Which will inevitably cause it to start deleting /

These tasks are much better handled with find(1).

Test Plan

mkdir -- /var/run/-P
mkdir -- /var/spool/lock/-P

Restart system

Observe that cleanvar is not deleting your OS

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Improved find(1) syntax per BigKnife

Escape parens

Do not try to clear out the uucp Temp dir unless it exists

allanjude added a subscriber: allanjude.

This seems like a much safer approach

This revision is now accepted and ready to land.Feb 6 2018, 8:24 PM
This revision was automatically updated to reflect the committed changes.
head/etc/rc.d/cleanvar
42

This removes the .Temp file always, no? The old code only deleted what was under it. And how is this different than just rm -rf? Seems like the complicated way of doing it, unlike the other cleanups to the file which made things less obscure and easier to follow.

head/etc/rc.d/cleanvar
42

.Temp is a directory, not a file. The idea was to keep it consistent with the other cleanup commands which are now leveraging find(1). I don't know how many files may end up under /var/spool/uucp/.Temp/* but it would be a shame for boot to hang because of glob expansion taking forever or fail with "too many arguments". Does that make sense?