Date: Sat, 2 Oct 2004 13:18:42 +0300 From: Giorgos Keramidas <keramida@freebsd.org> To: Ryan Sommers <ryans@gamersimpact.com>, Max Laier <max@love2party.net> Cc: freebsd-hackers@freebsd.org Subject: Re: Protection from the dreaded "rm -fr /" Message-ID: <20041002101842.GA23272@gothmog.gr> In-Reply-To: <200410021123.59811.max@love2party.net> <415E6C4A.1010804@gamersimpact.com> References: <20041002081928.GA21439@gothmog.gr> <200410021123.59811.max@love2party.net> <20041002081928.GA21439@gothmog.gr> <20041002083336.GA10355@k7.mavetju> <415E6C4A.1010804@gamersimpact.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On 2004-10-02 03:52, Ryan Sommers <ryans@gamersimpact.com> wrote: > On Sat, Oct 02, 2004 at 11:19:28AM +0300, Giorgos Keramidas wrote: > >about "rm -fr /" protection, which I liked a lot: > >http://blogs.sun.com/roller/page/jbeck/20041001#rm_rf_protection > > > >His idea was remarkably simple, so I went ahead and wrote this patch > >for > >rm(1) of FreeBSD: > > As for adding this kind of oops-proofing. I'm not sure I like the idea > of completely removing the ability to use / as an argument. How about > prompting and needing 'yes' as input? This might break things because the user hasn't specified -i and will suddenly get a prompt. Unexpected prompts might never get an answer. I liked what Max Laier proposed though, about making this tunable and defaulting to off. See below for the behavior of what I've come up with: On 2004-10-02 11:23, Max Laier <max@love2party.net> wrote: > [ Sorry to be so negative ... ] > > At very least you should consider to error out silently as POSIX > requires "-f" to be silent. Other than that you should really look > into the standards and what they way about rm and friends. Agreed. Thanks for the feedback. Positive replies are not the only sort that are worth a lot :-) How does the following look instead of forcing stuff to the user? 1. Silently erroring out: chroot# export RM_PROTECT_ROOT=1 chroot# /bin/rm -fr / chroot# echo $? 1 chroot# /bin/rm -fr .././ chroot# echo $? 1 2. Warning with an error message because RM_PROTECT_ROOT is set: chroot# export RM_PROTECT_ROOT=1 chroot# /bin/rm -r / rm: recursive rm of / not allowed chroot# /bin/rm -r .././ rm: recursive rm of / not allowed 3. The current behavior as a default when RM_PROTECT_ROOT is unset: chroot# unset RM_PROTECT_ROOT chroot# /bin/rm -r / override rwxr-xr-x 0/0 for /bin/rm? ^Cchroot# chroot# chroot# chroot# /bin/rm -fr / rm: /libexec/ld-elf.so.1: Operation not permitted rm: /libexec: Directory not empty rm: /lib/libc.so.5: Operation not permitted rm: /lib/libcrypt.so.2: Operation not permitted rm: /lib: Directory not empty rm: /: Is a directory chroot# ls -l ls: not found chroot# echo * lib libexec chroot# cd lib chroot# echo * libc.so.5 libcrypt.so.2 chroot# exit Here's the updated diff: %%% Index: rm.c =================================================================== RCS file: /home/ncvs/src/bin/rm/rm.c,v retrieving revision 1.47 diff -u -r1.47 rm.c --- rm.c 6 Apr 2004 20:06:50 -0000 1.47 +++ rm.c 2 Oct 2004 10:06:59 -0000 @@ -57,7 +57,7 @@ #include <sysexits.h> #include <unistd.h> -int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok; +int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok, protect_root; uid_t uid; int check(char *, char *, struct stat *); @@ -100,6 +100,10 @@ exit(eval); } + protect_root = 0; + if (getenv("RM_PROTECT_ROOT") != NULL) + protect_root = 1; + Pflag = rflag = 0; while ((ch = getopt(argc, argv, "dfiPRrvW")) != -1) switch(ch) { @@ -157,6 +161,8 @@ void rm_tree(char **argv) { + static char *rpath = NULL; + char **argv_tmp; FTS *fts; FTSENT *p; int needstat; @@ -164,6 +170,25 @@ int rval; /* + * If enabled in the environment with RM_PROTECT_ROOT disable the + * ability to recursively remove the root directory. + */ + if (protect_root) { + if (rpath == NULL && + (rpath = malloc(PATH_MAX * sizeof(char))) == NULL) + err(1, "malloc"); + for (argv_tmp = argv; *argv_tmp != NULL; argv_tmp++) { + if (realpath(*argv_tmp, rpath) == NULL && + strcmp(rpath, "/") != 0) + continue; + if (fflag != 0) + exit (1); + else + errx(1, "recursive rm of / not allowed"); + } + } + + /* * Remove a file hierarchy. If forcing removal (-f), or interactive * (-i) or can't ask anyway (stdin_ok), don't stat the file. */ %%%
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20041002101842.GA23272>