9

It's well known fact that extra space in env.variable can lead to deletion of / directory in bash script.

#!/bin/bash
...
rm -rf /$MYPATH

if $MYPATH contains values like " dir" or "dir /" it will lead to "rm -rf / dir" or "rm -rf dir /". And will result into "rm -rf /"

Are there any best practices to prevent this situation?

igorp1024
  • 228
  • 3
  • 8

10 Answers10

12
alias rm='rm --preserve-root'

IIRC --preserve-root is the default in newer versions of coreutils.

janneb
  • 3,761
  • 18
  • 22
  • 4
    In Bash, unless you do `shopt -s expand_aliases` aliases aren't expanded inside scripts. Also, aliasing `rm` is a bad idea - what if you're depending on the aliased behavior and the alias isn't there? Some versions of `rm` may not have `--preserve-root`. – Dennis Williamson Nov 09 '10 at 15:37
7

Always quote your arguments. Even when you know they are sane, it almost never hurts to quote them in scripts.

rm -rf "/$FOO" will not delete / if $FOO has a leading space, instead you'll just not delete anything. This does require the quotes to be present on the line with rm -rf, of course, not something like:

TODEL="/$FOO"
rm -rf $TODEL

If you do that, you'll be back in a whole load of trouble.

Also, I tend to think a good ol':

if [ -d "/$FOO" ] ; then
    ...
fi

(Or -e if it's just a file) is always a good idea before deleting anything.

mark
  • 2,325
  • 14
  • 10
2

First things first: have backups. :-)

But while I hack up those potentially dangerous scripts, I always first echo the dangerous lines, so I can see what would happen.

You can also add a file named -i to important directories, so in some situations rm would prompt while trying to remove those. Of course, if you do the deletion via some other method, such as Perl script or even with different rm parameters, that would not help.

It's also possible to set immutable flag to important files and dirs with chattr +i, but be careful with that one. That can bite you if you actually should remove files from some directory or modify the files ...

Janne Pikkarainen
  • 31,454
  • 4
  • 56
  • 78
2

One way to avoid the issue would be to use an OS that prevents such a command to succeed by design as it is arguably non POSIX compliant. It was initiated by Solaris 10 (2005), followed by BSD then Gnu rm in 2006.

jlliagre
  • 8,691
  • 16
  • 36
1

Sanity check your code first. Seriously, anything anyone will tell you will just be something equivalent to the check you should have done inside your code to check the value of $MYPATH. If the script is running interactively, you could remove the -f.

James L
  • 5,915
  • 1
  • 19
  • 24
1

You can trim the MYPATH variable before executing the rm command. Just use echo:

MYPATH=`echo $MYPATH`
Khaled
  • 35,688
  • 8
  • 69
  • 98
  • be aware that this will also convert any whitespace inside $MYPATH to single spaces, possibly corrupting it... (it applies the shell's word-splitting to the value, and then reconstructs it by appending the words, with spaces in between...) – r00t Dec 20 '10 at 19:05
1

After an embarrassing incident many years ago on an Ultrix box, where I did as root a userdel -r sccs (or Ultrix equivalent, it's been a long time) without checking what the sccs user's home directory was beforehand, and the sccs user's $HOME turned out to be /, and the file system went away, I've avoided putting rm -rf $ANYTHING in scripts. You can check the variable until you're blue in the face, but I tend instead to print out a message like "if you're happy with the idea, you should now run sudo rm -rf $ANYTHING".

MadHatter
  • 78,442
  • 20
  • 178
  • 229
1

You could pass MYPATH through sed and check that what you put in is that same as what you get out

MYPATH1=`echo "$MYPATH" | sed -e 's|[ \t]\/[ \t]| |' -e 's|^/[ \t]| |' -e 's|[ \t]/$| |' `
if [ "$MYPATH" != "$MYPATH1" ]
then
    dosomething 
fi
user9517
  • 114,104
  • 20
  • 206
  • 289
0

rm /*

In my case, I ran rm /* without -rf option on a Debian 10 server.
A bit less critical, but not too far .

System is still alive but many things are broken.

  • Mostly all commands are unavailable in my command line
  • I can not open a new SSH session
  • But, astonishing: my services are still running (docker, ssh, ...)

If I restart the server, I won't be able to login.
It would run in recovery mode.
panic mode

I've made all my tests on an equivalent case on a local VM to check my operations.

The point is that all symbolic links and files on / path are deleted.
Fortunately, all directories looks untouched. (that what has saved the situation )

Detailed road back to operational

Here are my detailed steps to get back to my machine with a runnable status.

  • Start server with an Ubuntu ISO to get a terminal from a bootable CD.

    Debian should work also.

  • Boot on CD.
    Do not install it, just use try mode.
    grub try ubuntu

    In my case, I'm using french keyboard ⌨ and I went through many keyboard issues.
    So, I decided to install openssh temporary server to run all following steps via SSH connection . For this, you can

    • open terminal (Ctrl+Alt+F3 / password: ubuntu)
      and type sudo apt-get install -y openssh-server
    • Customize password, with passwd command
    • Then, I was able to connect to ssh ubuntu@my-ip
      Get IP by typing ip a
    • and then, with sudo -s, I was back again in root mode in an efficient way
  • Mount harddrive on /debian path.

    mkdir /debian
    mount /dev/sda1 /debian
    
  • Here is the tricky part: you have to compare your /debian subdirs with a equivalent system.
    On basic Debian 10.11 setup, here is default structure : default debian structure.
    In my case, I started with following

    • main directories : bin, lib, lib32, lib64, libx32 and sbin
    • vmlinux and initrd.img files

    For this,

    • go to /debian dir with cd /debian
    • then, use syntax ln -s ./usr/bin ./bin.
      Relative path are required.

    Have a look on script section below, it can help

    From this, first reboot try. (hardware reboot, with CD removal).
    But, fortunately, it starts again in normal mode

I've declined this on 3 test VM before running it in production. I've tested Debian 11, Debian 10.11 & Ubuntu If your on a virtual system, you may run a snapshot on broken server before running these steps, in order to get back if things go worst.

I'm running tests for a few hours now, but it looks 100% operational and back to previous settings.
You can breath again

Script

For fast deployment of these steps, you can use my script on linux-rm-all-recovering.sh.

wget https://media.gtnapp.com/it/linux-rm-all-recovering.sh
bash linux-rm-all-recovering.sh
Damien C
  • 133
  • 1
  • 10
0

You're doing a really funny thing here by taking what looks like a relative path and turning it into an absolute one. Treating the given path as the given path is a good start towards accomplishing what you want, but take other commenters' advice and definitely quote everything.

jgoldschrafe
  • 4,385
  • 17
  • 18