Ubuntu – Is quoting filenames enough security for running `xargs sudo rm -rf`

bashcommand linermscriptsSecurity

I wrote a script that deletes all except the last two files in a folder:

#!/bin/bash
ls -1 --quoting-style=shell-always /path/to/some/folder \
    | head -n -2 \
    | xargs printf -- "'/path/to/some/folder/%s'\n" \
    | xargs sudo rm -rf

This script will be executed as a cron job every day.

The reasoning is as follows:

  1. Obtain a list of all files using ls -1 (so that I get one file per line);

  2. Remove the last two from the list using head -n -2;

  3. Since ls prints relative paths, use the xargs printf thing to prepend the folder path and make it an absolute path;

  4. Send them to sudo rm -rf using xargs.

Everyone has access to this folder, so anyone can create and delete any files in this folder.

The problem is: sudo rm -rf is scary. xargs sudo rm -rf is incredibly scary.

I want to be sure that no one can damage other folders/systems by creating clever files to be deleted (either accidentally or on purpose). I don't know, something clever like:

file with / spaces.txt

which could result in a super scary sudo rm -rf /.

EDIT: My mistake, file names cannot contain /, so this specific problem wouldn't happen, but the question about whether or not there are other risks still stands.

This is why I am using --quoting-style=shell-always, this should prevent any tricks with files with spaces. But now I am wondering if someone could be extra clever with spaces and quotes in the filename, perhaps.

Is my script safe?


Note: I need sudo because I am acessing the folder remotely (from a mapped network drive using mount), and I couldn't get it to work without sudo.

Best Answer

In Linux, any character is a valid filename constituting character except:

  • \0 (ASCII NUL): as used for string termination in C
  • / (forward slash): as used for path separation

So, your approach will definitely not work in many cases as you can imagine e.g. does it handle a newline (\n) in filename? (Hint: No).

Few notes:

  • Don't parse ls; use dedicated tools (there is at least one for most use cases)
  • When dealing with filenames, try to leverage the NUL separated output provided by almost all GNU tools that work with such data
  • Take care when piping, make sure both programs can understand NUL separations
  • Whenever you're invoking xargs, see if you can get away with find ... -exec; in most cases, you will be fine with just find alone

I think these will get you going for now. steeldriver already provided the NUL separated idea in the comment (printf -- '%s\0' /path/to/some/folder/* | head -zn -2 | xargs -0 rm), use this as a starting point.