svn commit: r214431 - head/bin/rm

Alexander Best arundel at freebsd.org
Thu Oct 28 13:14:15 UTC 2010


On Thu Oct 28 10, Ceri Davies wrote:
> On Thu, Oct 28, 2010 at 10:25:47AM +0000, Alexander Best wrote:
> > On Thu Oct 28 10, Gary Jennejohn wrote:
> > > On Thu, 28 Oct 2010 16:22:05 +1100 (EST)
> > > Bruce Evans <brde at optusnet.com.au> wrote:
> > > 
> > > > On Wed, 27 Oct 2010, Xin LI wrote:
> > > > 
> > > > > I think what really defeats -P is the fact that the file system or
> > > > > underlying data storage would not overwrite data on a file at sync().
> > > > > COW is of course one of the case, journaling MAY defeat -P but is not
> > > > > guaranteed.  FS with variable block size - I believe this really depends
> > > > > on the implementation.
> > > > >
> > > > > If I understood the code correctly, UFS, UFS+SU, UFS+SUJ, msdosfs and
> > > > > ext2fs supports rm -P as long as they are not being put on gjournal'ed
> > > > > disk, ZFS zvol, etc., and no snapshot is being used.
> > > > 
> > > > And that the underlying data storage us dumb.  Any flash drive now
> > > > tries to minimise writes.  It wouldn't take much buffering to defeat
> > > > the 0xff, 0,0xff pattern.  Wear leveling should result in different
> > > > physical blocks being written each time if the writes get to the
> > > > lowest level of storage.
> > > > 
> > > > And that block reallocation (done by ffs1 and ffs2) doesn't choose
> > > > different blocks.
> > > > 
> > > > > It seems to be hard for me to conclude all cases in short, plain English
> > > > > but I'm all for improvements to the manual page to describe that in an
> > > > > elegant and precise manner.
> > > > >
> > > > > Maybe something like:
> > > > >
> > > > > ===============
> > > > > BUGS
> > > > >
> > > > > The -P option assumes that the underlying storage overwrites file block
> > > > > when data is written on existing offset.  Several factors including the
> > > > > file system and its backing store could defeat the assumption, this
> > > > > includes, but is not limited to file systems that uses Copy-On-Write
> > > > > strategy (e.g. ZFS or UFS when snapshot is being used), or backing
> > > > > datastore that does journaling, etc.  In addition, only regular files
> > > > > are overwritten, other types of files are not.
> > > > > ===============
> > > > 
> > > > Summary: it is very hard to tell whether -P works, even when you think
> > > > you know what all the subsystems are doing.
> > > > 
> > > 
> > > All this discussion leads me to the conclusion that we should just
> > > remove the -P functionality and add a remark to the man page that that
> > > was done because it isn't guaranteed to work on all file systems.
> > > 
> > > Why give users a false sense of security?  If they're concerned about
> > > data security then they should use geli or something similar.
> > 
> > that might be the ultimate solution. also one could use security/srm instead.
> > 
> > +1 here. ;)
> > 
> > question is: should -P be removed entirely or be made a no op?
> 
> Probably best that it fail.

how about the following patch?

cheers.
alex

> 
> Ceri
> -- 
> Haffely, Gaffely, Gaffely, Gonward.



-- 
a13x
-------------- next part --------------
diff --git a/bin/rm/rm.1 b/bin/rm/rm.1
index 11bc77d..569e7db 100644
--- a/bin/rm/rm.1
+++ b/bin/rm/rm.1
@@ -84,22 +84,6 @@ directory is being recursively removed.
 This is a far less intrusive option than
 .Fl i
 yet provides almost the same level of protection against mistakes.
-.It Fl P
-Overwrite regular files before deleting them.
-Files are overwritten three times, first with the byte pattern 0xff,
-then 0x00, and then 0xff again, before they are deleted.
-Files with multiple links will not be overwritten nor deleted
-and a warning will be issued.
-If the
-.Fl f
-option is specified, files with multiple links will also be overwritten
-and deleted.
-No warning will be issued.
-.Pp
-Specifying this flag for a read only file will cause
-.Nm
-to generate an error message and exit.
-The file will not be removed or overwritten.
 .It Fl R
 Attempt to remove the file hierarchy rooted in each
 .Ar file
@@ -182,12 +166,6 @@ For example:
 .Pp
 .Dl "rm /home/user/-filename"
 .Dl "rm ./-filename"
-.Pp
-When
-.Fl P
-is specified with
-.Fl f
-the file will be overwritten and removed even if it has hard links.
 .Sh COMPATIBILITY
 The
 .Nm
@@ -203,6 +181,23 @@ Also, historical
 .Bx
 implementations prompted on the standard output,
 not the standard error output.
+.Pp
+Previous
+.Bx
+versions of
+.Nm
+featured a
+.Fl P
+option which instructed
+.Nm
+to overwrite regular files three times with the byte pattern
+0xff, then 0x00, and then 0xff again, before they were deleted.
+Support for the
+.Fl P
+flag was removed in
+.Fx 9.0 ,
+because overwriting specific blocks cannot be assured
+on certain filesystems and media.
 .Sh SEE ALSO
 .Xr chflags 1 ,
 .Xr rmdir 1 ,
@@ -226,11 +221,3 @@ A
 .Nm
 command appeared in
 .At v1 .
-.Sh BUGS
-The
-.Fl P
-option assumes that the underlying file system updates existing blocks
-in-place and does not store new data in a new location.
-This is true for UFS but not for ZFS, which is using a Copy-On-Write strategy.
-In addition, only regular files are overwritten, other types of files
-are not.
diff --git a/bin/rm/rm.c b/bin/rm/rm.c
index 653833a..1aff60f 100644
--- a/bin/rm/rm.c
+++ b/bin/rm/rm.c
@@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$");
 #include <sysexits.h>
 #include <unistd.h>
 
-int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
+int dflag, eval, fflag, iflag, vflag, Wflag, stdin_ok;
 int rflag, Iflag;
 uid_t uid;
 volatile sig_atomic_t info;
@@ -67,7 +67,6 @@ int	check2(char **);
 void	checkdot(char **);
 void	checkslash(char **);
 void	rm_file(char **);
-int	rm_overwrite(char *, struct stat *);
 void	rm_tree(char **);
 static void siginfo(int __unused);
 void	usage(void);
@@ -105,8 +104,8 @@ main(int argc, char *argv[])
 		exit(eval);
 	}
 
-	Pflag = rflag = 0;
-	while ((ch = getopt(argc, argv, "dfiIPRrvW")) != -1)
+	rflag = 0;
+	while ((ch = getopt(argc, argv, "dfiIRrvW")) != -1)
 		switch(ch) {
 		case 'd':
 			dflag = 1;
@@ -122,9 +121,6 @@ main(int argc, char *argv[])
 		case 'I':
 			Iflag = 1;
 			break;
-		case 'P':
-			Pflag = 1;
-			break;
 		case 'R':
 		case 'r':			/* Compatibility. */
 			rflag = 1;
@@ -302,9 +298,6 @@ rm_tree(char **argv)
 					continue;
 				/* FALLTHROUGH */
 			default:
-				if (Pflag)
-					if (!rm_overwrite(p->fts_accpath, NULL))
-						continue;
 				rval = unlink(p->fts_accpath);
 				if (rval == 0 || (fflag && errno == ENOENT)) {
 					if (rval == 0 && vflag)
@@ -374,12 +367,8 @@ rm_file(char **argv)
 				rval = undelete(f);
 			else if (S_ISDIR(sb.st_mode))
 				rval = rmdir(f);
-			else {
-				if (Pflag)
-					if (!rm_overwrite(f, &sb))
-						continue;
+			else
 				rval = unlink(f);
-			}
 		}
 		if (rval && (!fflag || errno != ENOENT)) {
 			warn("%s", f);
@@ -394,77 +383,6 @@ rm_file(char **argv)
 	}
 }
 
-/*
- * rm_overwrite --
- *	Overwrite the file 3 times with varying bit patterns.
- *
- * XXX
- * This is a cheap way to *really* delete files.  Note that only regular
- * files are deleted, directories (and therefore names) will remain.
- * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
- * System V file system).  In a logging or COW file system, you'll have to
- * have kernel support.
- */
-int
-rm_overwrite(char *file, struct stat *sbp)
-{
-	struct stat sb;
-	struct statfs fsb;
-	off_t len;
-	int bsize, fd, wlen;
-	char *buf = NULL;
-
-	fd = -1;
-	if (sbp == NULL) {
-		if (lstat(file, &sb))
-			goto err;
-		sbp = &sb;
-	}
-	if (!S_ISREG(sbp->st_mode))
-		return (1);
-	if (sbp->st_nlink > 1 && !fflag) {
-		warnx("%s (inode %u): not overwritten due to multiple links",
-		    file, sbp->st_ino);
-		return (0);
-	}
-	if ((fd = open(file, O_WRONLY, 0)) == -1)
-		goto err;
-	if (fstatfs(fd, &fsb) == -1)
-		goto err;
-	bsize = MAX(fsb.f_iosize, 1024);
-	if ((buf = malloc(bsize)) == NULL)
-		err(1, "%s: malloc", file);
-
-#define	PASS(byte) {							\
-	memset(buf, byte, bsize);					\
-	for (len = sbp->st_size; len > 0; len -= wlen) {		\
-		wlen = len < bsize ? len : bsize;			\
-		if (write(fd, buf, wlen) != wlen)			\
-			goto err;					\
-	}								\
-}
-	PASS(0xff);
-	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
-		goto err;
-	PASS(0x00);
-	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
-		goto err;
-	PASS(0xff);
-	if (!fsync(fd) && !close(fd)) {
-		free(buf);
-		return (1);
-	}
-
-err:	eval = 1;
-	if (buf)
-		free(buf);
-	if (fd != -1)
-		close(fd);
-	warn("%s", file);
-	return (0);
-}
-
-
 int
 check(char *path, char *name, struct stat *sp)
 {
@@ -489,10 +407,6 @@ check(char *path, char *name, struct stat *sp)
 		strmode(sp->st_mode, modep);
 		if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
 			err(1, "fflagstostr");
-		if (Pflag)
-			errx(1,
-			    "%s: -P was specified, but file is not writable",
-			    path);
 		(void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
 		    modep + 1, modep[9] == ' ' ? "" : " ",
 		    user_from_uid(sp->st_uid, 0),
@@ -610,7 +524,7 @@ usage(void)
 {
 
 	(void)fprintf(stderr, "%s\n%s\n",
-	    "usage: rm [-f | -i] [-dIPRrvW] file ...",
+	    "usage: rm [-f | -i] [-dIRrvW] file ...",
 	    "       unlink file");
 	exit(EX_USAGE);
 }


More information about the svn-src-all mailing list