/bin/rm: fix removing symlinks with uchg/uappnd set
authorJohn Marino <draco@marino.st>
Thu, 15 Nov 2012 23:31:35 +0000 (00:31 +0100)
committerJohn Marino <draco@marino.st>
Thu, 15 Nov 2012 23:44:56 +0000 (00:44 +0100)
One error case described in FreeBSD PR bin/111226:
  /bin/rm when running as super user and failing to unlink a
  UF_APPEND|UF_IMMUTABLE protected symbolic link will reset the
  UF_APPEND and UF_IMMUTABLE flags on the symbolic link's target (if
  that target exists) - an object that /bin/rm should not touch! (Quote
  from SUSv3: "The rm utility removes symbolic links themselves, not
  the files they refer to, as a consequence of the dependence on the
  unlink() functionality").

There was a failure case for /usr/bin/find as well, but swildner
recently synchronized find with FreeBSD and fixed that one.

Taken-from: FreeBSD SVN 193087 (30 MAY 2009)

bin/rm/rm.c

index 47529b5..25d7d9f 100644 (file)
@@ -33,7 +33,6 @@
  * @(#) Copyright (c) 1990, 1993, 1994 The Regents of the University of California.  All rights reserved.
  * @(#)rm.c    8.5 (Berkeley) 4/18/94
  * $FreeBSD: src/bin/rm/rm.c,v 1.29.2.5 2002/07/12 07:25:48 tjr Exp $
- * $DragonFly: src/bin/rm/rm.c,v 1.19 2006/11/12 00:51:47 swildner Exp $
  */
 
 #include <sys/stat.h>
@@ -239,7 +238,7 @@ rm_tree(char **argv)
                        else if (!uid &&
                                 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
                                 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
-                                chflags(p->fts_accpath,
+                                lchflags(p->fts_accpath,
                                         p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
                                goto err;
                        continue;
@@ -263,7 +262,7 @@ rm_tree(char **argv)
                if (!uid &&
                    (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
                    !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
-                       rval = chflags(p->fts_accpath,
+                       rval = lchflags(p->fts_accpath,
                                       p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
 
                if (rval == 0) {
@@ -369,7 +368,7 @@ rm_file(char **argv)
                if (!uid &&
                    (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
                    !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE)))
-                       rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
+                       rval = lchflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
                if (rval == 0) {
                        if (S_ISWHT(sb.st_mode))
                                rval = undelete(f);