From owner-freebsd-hackers@FreeBSD.ORG Sat Oct 2 10:19:46 2004 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 5D75516A4CE for ; Sat, 2 Oct 2004 10:19:46 +0000 (GMT) Received: from kane.otenet.gr (kane.otenet.gr [195.170.0.27]) by mx1.FreeBSD.org (Postfix) with ESMTP id A481D43D2D for ; Sat, 2 Oct 2004 10:19:45 +0000 (GMT) (envelope-from keramida@freebsd.org) Received: from gothmog.gr (patr530-b179.otenet.gr [212.205.244.187]) i92AJfJD023758; Sat, 2 Oct 2004 13:19:42 +0300 Received: from gothmog.gr (gothmog [127.0.0.1]) by gothmog.gr (8.13.1/8.13.1) with ESMTP id i92AJdoI023361; Sat, 2 Oct 2004 13:19:39 +0300 (EEST) (envelope-from keramida@freebsd.org) Received: (from giorgos@localhost) by gothmog.gr (8.13.1/8.13.1/Submit) id i92AIgwD023338; Sat, 2 Oct 2004 13:18:42 +0300 (EEST) (envelope-from keramida@freebsd.org) Date: Sat, 2 Oct 2004 13:18:42 +0300 From: Giorgos Keramidas To: Ryan Sommers , Max Laier Message-ID: <20041002101842.GA23272@gothmog.gr> References: <20041002081928.GA21439@gothmog.gr> <200410021123.59811.max@love2party.net> <20041002081928.GA21439@gothmog.gr> <20041002083336.GA10355@k7.mavetju> <415E6C4A.1010804@gamersimpact.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <200410021123.59811.max@love2party.net> <415E6C4A.1010804@gamersimpact.com> cc: freebsd-hackers@freebsd.org Subject: Re: Protection from the dreaded "rm -fr /" X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 02 Oct 2004 10:19:46 -0000 On 2004-10-02 03:52, Ryan Sommers 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 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 #include -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. */ %%%