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).