D. Allen [CGL]) (10/09/90)
So you like to use this: find . -type f -print | xargs rm -f Interesting things happen here under some versions of xargs if you have files with odd names that look like command lines, such as: echo hi >"foo ; rm -rf /" Since some versions of xargs (or programs of similar function, such as "apply") use a shell to execute the indicated command, the shell parses the file name, splits on the ";", and executes the following part of the file name as another command, with potentially exciting results: rm -f foo ; rm -rf / Even versions that don't use a shell to run the command often split on blanks, causing file names to match things you don't intend: touch foo bar echo hi >"foo bar" echo "foo bar" | xargs rm The above example removes files "foo" and "bar" on Ultrix 3.1C. File "foo bar" (which might have been the result of a "find") is not touched. So be VERY CAREFUL using xargs and friends! -- -IAN! (Ian! D. Allen) idallen@watcgl.uwaterloo.ca idallen@watcgl.waterloo.edu [129.97.128.64] Computer Graphics Lab/University of Waterloo/Ontario/Canada
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/09/90)
Yeah. xargs should have a -0 option for taking null-separated filenames for its input. find should have a -print0 option for producing similar output. I wrote a somewhat improved PD ``apply'' clone out of boredom. It can execute commands itself, pass them to sh, or print them for sh batching. At least it's reasonably secure; you can feel safe with apply ... "$@". Copy enclosed. Kids, don't use this awful coding style at home. ---Dan #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Makefile apply.c getopt.h apply.1 # Wrapped by brnstnd@kramden on Sun Sep 9 05:33:06 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(415 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' XCC=cc XCCOPTS=-O4 -s -DVFORK X XNROFF=nroff XNROFFOPTS=-man X Xall: apply apply.man X Xshar: apply.shar X Xapply: apply.o Makefile X $(CC) $(CCOPTS) -o apply apply.o X Xapply.o: apply.c getopt.h Makefile X $(CC) $(CCOPTS) -c apply.c X Xapply.man: apply.1 Makefile X $(NROFF) $(NROFFOPTS) < apply.1 > apply.man X Xapply.shar: apply.c getopt.h apply.1 Makefile X shar Makefile apply.c getopt.h apply.1 > apply.shar X chmod 400 apply.shar END_OF_FILE if test 415 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'apply.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'apply.c'\" else echo shar: Extracting \"'apply.c'\" \(6256 characters\) sed "s/^X//" >'apply.c' <<'END_OF_FILE' X#include <sys/types.h> /* for wait and fork */ X#include <sys/wait.h> /* for wait */ X#include <stdio.h> /* for EOF, fprintf, puts */ X#include <malloc.h> /* for malloc and free */ X#include <strings.h> /* for strlen and strcpy */ X#include "getopt.h" /*XXX: should be <getopt.h> */ X/* XXX: What about system(), exit(), perror()? */ X/* XXX: Shouldn't do repeated malloc-free. Figure out the largest block */ X/* size needed, allocate it once, and use it repeatedly. */ X/* XXX: Maybe option to quote arguments under flagsystem? */ X/* XXX: Or just allow spaces within arguments inside command? */ X/* XXX: The number of separate command parsers in here is ridiculous. */ X Xstatic char applyusage[] = "Usage: apply [ -ac ] [ -n ] cmd arg ...\n"; Xstatic char applytoomany[] = "apply: warning: extra arguments\n"; Xstatic char applyforkfail[] = "apply: fatal: cannot fork"; Xstatic char applyexecfail[] = "apply: fatal: cannot exec"; Xstatic char applymalloc[] = "apply: fatal: cannot malloc\n"; X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X register char *s; X register char *t; X register char **a; X register int i; X register int j; X register char *cmd; X register int flagsystem = 0; X register int narg = 1; X register int nch = 0; X register int nesc = 0; X register char escape = '%'; X register int opt; X X while ((opt = getopt(argc,argv,"0123456789a:s")) != EOF) X switch(opt) X { X case '?': (void) fprintf(stderr,applyusage); X (void) exit(1); X case 'a': escape = *optarg; break; /* can't be null */ X case 's': flagsystem = 2; break; X#define OSN(i,j) case i: narg = j; break; X OSN('0',0) OSN('1',1) OSN('2',2) OSN('3',3) OSN('4',4) X OSN('5',5) OSN('6',6) OSN('7',7) OSN('8',8) OSN('9',9) X } X argv += optind, argc -= optind; X X if (!*argv) X { X (void) fprintf(stderr,applyusage); X (void) exit(1); X } X X /* Note that we accept %0, and do the same with it as with -0. */ X s = *argv; X while (*s) X if (*(s++) != escape) X nch++; X else X { X if (!*s) X { flagsystem = (!flagsystem ? 1 : flagsystem); break; } X switch(*(s++)) X { X#define TSN(i,j) case i: narg=(nesc++?(narg>j?narg:j):j); break; X TSN('0',0) TSN('1',1) TSN('2',2) TSN('3',3) TSN('4',4) X TSN('5',5) TSN('6',6) TSN('7',7) TSN('8',8) TSN('9',9) X default: nch++; break; X } X } X X /* Now the number of real characters is nch. */ X /* The number of escape characters is nesc. */ X /* If flagsystem is 1, we should use sh. */ X /* And we should snarf narg args per cmd, plus waste one if !narg. */ X X if (!nesc) X { X t = cmd = malloc((unsigned) (nch + 1)); X s = *argv; X while (*s) X if (*s != escape) X *(t++) = *(s++); X else X { X if (!*++s) X break; X switch(*s) X { X case 'e': *(t++) = escape; s++; break; X default: *(t++) = *(s++); break; X } X } X *t = '\0'; X } X else X cmd = *argv; X X argc--; argv++; X /* XXX: Should something be done to prevent zombies? */ X X if (narg && (argc % narg)) X (void) fprintf(stderr,applytoomany); X while (argc >= narg + !narg) X { X if (!nesc) X { X if (flagsystem) X { X i = nch + narg + !narg; X for (j = 0;j < narg;j++) X i += strlen(argv[j]); X t = s = malloc((unsigned) i); X if (!t) X { X (void) fprintf(stderr,applymalloc); X (void) exit(1); X } X (void) strcpy(t,cmd); t += strlen(cmd); *(t++) = ' '; X for (j = 0;j < narg;j++) X { X (void) strcpy(t,argv[j]); t += strlen(argv[j]); *(t++) = ' '; X } X *t = '\0'; X /* slow? whaddya mean, slow? three passes is nothing! */ X if (flagsystem == 2) X (void) puts(s); X else X (void) system(s); X (void) free(s); X } X else X { X s = argv[narg]; X argv[narg] = (char *) 0; X argv[-1] = cmd; /* This always works. Trust me. */ X /* We haven't done anything with stdio, so no need to flush. */ X#ifdef VFORK X switch(vfork()) X#else X switch(fork()) X#endif X { X case -1: perror(applyforkfail); X (void) exit(1); X case 0: (void) execvp(cmd,argv - 1); X perror(applyexecfail); X (void) exit(0); X default: (void) wait((int *) 0); X } X argv[narg] = s; X } X } X else /* nesc > 0 */ X { X i = nch + 1; X s = cmd; X while (*s) X if (*(s++) == escape) X { X if (!*s) X break; X switch(*s) X { X case '0': s++; break; X#define SSN(k,j) case k: i += strlen(argv[j]); s++; break; X /* omit 0 */ SSN('1',0); SSN('2',1); SSN('3',2); SSN('4',3); X SSN('5',4); SSN('6',5); SSN('7',6); SSN('8',7); SSN('9',8); X default: i += 1; s++; break; X } X } X X t = malloc((unsigned) i); X if (!t) X { X (void) fprintf(stderr,applymalloc); X (void) exit(1); X } X s = cmd; X while (*s) X if (*s != escape) X *(t++) = *(s++); X else X { X if (!*++s) X break; X switch(*s) X { X case '0': s++; break; X#define ISN(i,j) case i:(void)strcpy(t,argv[j]);t+=strlen(argv[j]);s++;break; X /* omit 0 */ ISN('1',0); ISN('2',1); ISN('3',2); ISN('4',3); X ISN('5',4); ISN('6',5); ISN('7',6); ISN('8',7); ISN('9',8); X default: *(t++) = *(s++); break; X } X } X *(t++) = '\0'; X t -= i; X switch(flagsystem) X { X case 0: i = 1; X for (s = t;*s;s++) X i += (*s == ' '); X a = (char **) malloc((unsigned) (sizeof(char *) * i)); X if (!a) X { X (void) fprintf(stderr,applymalloc); X (void) exit(1); X } X for (s = a[i = 0] = t;*s;s++) X if (*s == ' ') X a[a[i] == s ? i : ++i] = s + 1; X a[a[i] == s ? i : ++i] = (char *) 0; X#ifdef VFORK X switch(vfork()) X#else X switch(fork()) X#endif X { X case -1: perror(applyforkfail); X (void) exit(1); X case 0: (void) execvp(*a,a); X perror(applyexecfail); X (void) exit(0); X default: (void) wait((int *) 0); X } X (void) free((char *) a); X break; X case 1: (void) system(t); break; X case 2: (void) puts(t); break; X } X (void) free(t); X } X argv += narg + !narg; argc -= narg + !narg; X } X X (void) exit(0); X} END_OF_FILE if test 6256 -ne `wc -c <'apply.c'`; then echo shar: \"'apply.c'\" unpacked with wrong size! fi # end of 'apply.c' fi if test -f 'getopt.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getopt.h'\" else echo shar: Extracting \"'getopt.h'\" \(61 characters\) sed "s/^X//" >'getopt.h' <<'END_OF_FILE' Xextern int optind; Xextern char *optarg; Xextern int getopt(); END_OF_FILE if test 61 -ne `wc -c <'getopt.h'`; then echo shar: \"'getopt.h'\" unpacked with wrong size! fi # end of 'getopt.h' fi if test -f 'apply.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'apply.1'\" else echo shar: Extracting \"'apply.1'\" \(2909 characters\) sed "s/^X//" >'apply.1' <<'END_OF_FILE' X.TH apply 1 X.SH NAME Xapply \- apply a command to a set of arguments X.SH SYNOPSIS X.B apply X[ X.B \-a X.I escape-char X] [ X.B \-s X] [ X.I \-n X] X.I command X[ X.I arg ... X] X.SH DESCRIPTION X.B apply Xapplies X.I command Xto each X.I arg Xin sequence. X.PP X.B apply Xnormally runs X.I command Xwith one argument at a time. XUnder X.I \-2, Xit will pass two arguments at once to X.I command. XSimilarly for all of X.I \-1 Xthrough X.I \-9. XUnder X.I \-0, X.B apply Xwill run X.I command Xwithout arguments, once for each X.I arg. X.PP X.B apply Xlooks for escape characters, Xdefault %, Xin X.I command. XIf X.I %n Xappears for any X.I n Xfrom 0 through 9, X.B apply Xwill place arguments Xinside X.I command Xrather than after it: Xthe first argument replacing X.I %1, Xetc. XIt will also ignore any X.I -n Xoption, Xinstead taking as many arguments per X.I command Xas the highest-numbered X.I %n. XIn this case X.B apply Xwill split X.I command Xon spaces, Xalong with each X.I arg; Xthis is the only effect of X.I %0, Xwhich is deleted before X.I command Xis executed. X.PP X%% is passed through as a single %. X%e is also passed through as a single %. X% followed by any other character is passed through Xas that character, though this behavior may not be true Xin future versions. XThe escape character may be changed with X.B \-a. X.PP XNormally X.I command Xis executed directly Xfrom X.B apply. XIf X.I command Xends with a single %, Xit is passed through Xto X.B sh(1) Xvia X.B system(3). XThis lets X.I command Xuse output redirection and other shell features. X.PP XUnder X.B \-s, X.B apply Xprints each X.I command Xrather than executing it. XThis can be saved or piped through X.B sh(1). XIt is useful for debugging Xuses of X.B apply. X.PP X.B apply Xwill ignore any extra arguments Xand print a warning message. X.SH EXAMPLES XCompare the examples in X.B xargs(1). X.IP X.B apply echo \(** X.LP XSimilar to X.B ls(1). X.IP X\fBapply "mv $1/%1 $2/%1" `ls`\fR X.LP XMove all files from directory X.B $1 Xto directory X.B $2. X.IP X\fBapply \-s "mv $1/%1 $2/%1" \(** | sh \-v\fR X.LP XMove all files from directory X.B $1 Xto directory X.B $2, Xprinting each command before it is executed. X.IP X.B apply \-2 diff $\(** X.LP XShow differences between successive pairs of files, Xpassed to the shell as arguments. X.IP X\fBapply \-0 who 1 2 3 4 5\fR X.LP XRun X.B who(1) Xfive times. X.IP X.B apply \-2 %2 \(** X.LP XShow every other file. X.IP X.B apply \-2 %2 x \(** X.LP XShow the other every other file. X.SH RESTRICTIONS X.B apply Xwill keep going blindly if X.I command Xisn't executable. XOf course, this behavior is necessary Xin commands like X.IP X.B Xapply '%1 foo' rm touch 'chmod 755' X.LP XSometimes it is much faster to use X.I sh, Xas when X.I command Xis a shell builtin whose normal version is slow. X.B apply Xdoes not know to invoke X.I sh Xin this case. X(This can happen when, for example, X.I command Xis dynamically linked Xwhile X.I sh Xis not, on a system supporting dynamic linking.) X.SH BUGS XNone known. X.SH "SEE ALSO" X.B repeat(1), sh(1), xargs(1) END_OF_FILE if test 2909 -ne `wc -c <'apply.1'`; then echo shar: \"'apply.1'\" unpacked with wrong size! fi # end of 'apply.1' fi echo shar: End of shell archive. exit 0
sahayman@iuvax.cs.indiana.edu (Steve Hayman) (10/09/90)
>Yeah. xargs should have a -0 option for taking null-separated filenames >for its input. find should have a -print0 option for producing similar >output. So long as you have to modify "find" anyway to solve this problem, why not just add "-xargs" option to "find", that would be like the "-exec" option only using as many file names as possible at once. find .... -xargs rm {} \; Seems simpler than modifying two programs. Steve -- Steve Hayman Workstation Manager Computer Science Department Indiana U. sahayman@iuvax.cs.indiana.edu (812) 855-6984 NeXT Mail: sahayman@spurge.bloomington.in.us
lml@cbnews.att.com (L. Mark Larsen) (10/10/90)
In article <63404@iuvax.cs.indiana.edu>, sahayman@iuvax.cs.indiana.edu (Steve Hayman) writes:
# >Yeah. xargs should have a -0 option for taking null-separated filenames
# >for its input. find should have a -print0 option for producing similar
# >output.
#
# So long as you have to modify "find" anyway to solve this problem, why
# not just add "-xargs" option to "find", that would be like the "-exec"
# option only using as many file names as possible at once.
#
# find .... -xargs rm {} \;
#
# Seems simpler than modifying two programs.
#
Actually, this is what was done when find was rewritten for SVR4 (among
other things). The way to use it is to terminate the command with "+"
instead of ";" (e.g., find ... -exec rm {} +)
I never much cared for xargs since it limits you to an argument list of
only 470 bytes. Since all of the System V UNIX's I know of support argument
lists of at least 5120 bytes (12288 in UTS), this has always seemed like
too small of an upper-limit to me - though it's still better than one exec
per file...
L. Mark Larsen
lml@atlas.att.com
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (10/10/90)
In article <63404@iuvax.cs.indiana.edu> sahayman@iuvax.cs.indiana.edu (Steve Hayman) writes:
: >Yeah. xargs should have a -0 option for taking null-separated filenames
: >for its input. find should have a -print0 option for producing similar
: >output.
:
: So long as you have to modify "find" anyway to solve this problem, why
: not just add "-xargs" option to "find", that would be like the "-exec"
: option only using as many file names as possible at once.
:
: find .... -xargs rm {} \;
:
: Seems simpler than modifying two programs.
What makes you think xargs is the only program that would like to use -print0
output? Think toolbox, man! (That's how Randal would say it.)
find ... -print0 | perl -e '$/ = "\0"; while (<>) {chop; unlink;}'
That doesn't suffer any of the security holes of xargs.
Larry Wall
lwall@jpl-devvax.jpl.nasa.gov
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/10/90)
In article <63404@iuvax.cs.indiana.edu> sahayman@iuvax.cs.indiana.edu (Steve Hayman) writes: > >Yeah. xargs should have a -0 option for taking null-separated filenames > >for its input. find should have a -print0 option for producing similar > >output. > So long as you have to modify "find" anyway to solve this problem, why > not just add "-xargs" option to "find", that would be like the "-exec" > option only using as many file names as possible at once. > find .... -xargs rm {} \; > Seems simpler than modifying two programs. On the general grounds of ``modularity'' I'll claim that the separate commands are more useful. I imagine commands other than xargs being able to take that 0-terminated list and do something with it. Modularity aside, it's much, much simpler to add -0 to xargs (a few lines added) and -print0 to find (just change a \n to \0) than to add all of the argument handling of xargs into find. ---Dan
lvc@cbnews.att.com (Lawrence V. Cipriani) (10/10/90)
In article <9365:Oct910:43:4590@kramden.acf.nyu.edu>, brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: > Yeah. xargs should have a -0 option for taking null-separated filenames > for its input. find should have a -print0 option for producing similar > output. It does, sort of: find . -print | xargs -i your_command '{}' but, since the -i option executes your_command once per file it will be very slow. -- Larry Cipriani, att!cbvox!lvc or lvc@cbvox.att.com
peter@ficc.ferranti.com (Peter da Silva) (10/10/90)
In article <1990Oct9.172621.13484@cbnews.att.com> lml@cbnews.att.com (L. Mark Larsen) writes: > I never much cared for xargs since it limits you to an argument list of > only 470 bytes. Surely this is an implementation detail. After all, xargs is almost as much of a no-brainer command as echo. If you don't like it fix it... it's just an efficiency consideration anyway. -- Peter da Silva. `-_-' +1 713 274 5180. 'U` peter@ferranti.com
chip@tct.uucp (Chip Salzenberg) (10/13/90)
According to lml@cbnews.att.com (L. Mark Larsen): >I never much cared for xargs since it limits you to an argument list of >only 470 bytes. For the most common use of xargs -- "find ... | xargs command" -- the script below, called "many", does a good job. Since it doesn't spawn a subshell, it isn't prone to metacharacter-caused security problems. And you can configure the max arg size to whatever you like. Enjoy. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: many # Wrapped by chip@tct on Fri Oct 12 19:36:53 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'many' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'many'\" else echo shar: Extracting \"'many'\" \(2681 characters\) sed "s/^X//" >'many' <<'END_OF_FILE' Xeval 'exec /bin/perl -S $0 ${1+"$@"}' X if 0; X X# $Id: many,v 1.1 90/10/11 13:51:17 chip Exp $ X# X# Execute the given command with many arguments, one per line. X# This is like xargs, but it's safer, more flexible and free of X# the stupid 470-byte argument limit. X# X Xrequire 'signal.ph'; Xrequire 'errno.ph'; X X$NCARGS = 5120; ## I've never seen it less than this X X($ME = $0) =~ s#^.*/##; X X$opt_chdir = 0; X$opt_trace = 0; X$opt_argfile = undef; Xwhile (@ARGV) { X $_ = $ARGV[0]; X last unless s/^-//; X shift; X last if $_ eq "-"; X while ($_ ne "") { X if (s/^d//) { $opt_chdir = 1; } X elsif (s/^t//) { $opt_trace = 1; } X elsif (s/^f//) { $opt_argfile = length($_) ? $_ : shift; } X else { &USAGE; } X } X} X Xsub USAGE { X print STDERR <<EOF; X Xusage: $ME [-d][-t][-f argfile] command X XCollect arguments, one per line, up to maximum argument length, Xexecuting the given command with those arguments as many times Xas required until arguments are exhausted. X XOptions: X -d Change to files' directory before spawning command. X -t Trace mode: print directories and commands before acting. X -f file Get arguments from specified file instead of standard input. X XEOF X exit 1; X} X X&USAGE unless @ARGV; X@cmd = @ARGV; X$cmd_len = 0; Xgrep($cmd_len += length($_) + 1, @cmd); X Xif (defined($opt_argfile)) { X die "$ME: can't open $opt_argfile: $!\n" X unless open(ARG, "< $opt_argfile"); X} Xelse { X open(ARG, "<&STDIN"); X close(STDIN); X open(STDIN, "/dev/null") || die "$ME: can't open /dev/null: $!\n"; X} X X@args = (); X$args_len = 0; Xwhile (<ARG>) { X chop($a = $_) if /\n$/; X $a_len = length($a) + 1; X $doit = ($cmd_len + $args_len + $a_len > $NCARGS); X if ($opt_chdir) { X if ($a =~ m#^(.*)/+([^/]+/*)$#) { X $a_dir = $1; X $a = $2; X } X else { X $a_dir = "."; X } X $spawn_dir = $a_dir unless defined($spawn_dir); X $doit = 1 if $spawn_dir ne $a_dir; X } X if ($doit) { X &SPAWN(@cmd, @args); X @args = (); X $args_len = 0; X if ($opt_chdir) { X $spawn_dir = $a_dir; X } X } X if ($cmd_len + $a_len > $NCARGS) { X print STDERR "$ME: line $.: argument too long\n"; X next; X } X push(@args, $a); X $args_len += $a_len; X} X X&SPAWN(@cmd, @args) if @args; X Xexit; X Xsub SPAWN { X local(@av) = @_; X X $parent_pid = $$; X die "$ME: can't fork" unless defined($pid = fork); X if ($pid == 0) { X $failed = 0; X if ($opt_chdir) { X print STDERR "++ chdir $spawn_dir\n" if $opt_trace; X unless (chdir $spawn_dir) { X print STDERR "$ME: $spawn_dir: $!\n"; X $failed = 1; X } X } X unless ($failed) { X print STDERR join(" ", "+", @cmd, @args), "\n" X if $opt_trace; X exec @cmd, @args; X print STDERR "$ME: $cmd[0]: $!\n"; X } X kill &SIGTERM, $parent_pid; X exit 1; X } X 0 while wait == -1 && $! == &EINTR; X 1; X} END_OF_FILE if test 2681 -ne `wc -c <'many'`; then echo shar: \"'many'\" unpacked with wrong size! fi chmod +x 'many' # end of 'many' fi echo shar: End of shell archive. exit 0 -- Chip Salzenberg at Teltronics/TCT <chip@tct.uucp>, <uunet!pdn!tct!chip> "I've been cranky ever since my comp.unix.wizards was removed by that evil Chip Salzenberg." -- John F. Haugh II
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/16/90)
In article <271653D6.1CE8@tct.uucp> chip@tct.uucp (Chip Salzenberg) writes: > According to lml@cbnews.att.com (L. Mark Larsen): > >I never much cared for xargs since it limits you to an argument list of > >only 470 bytes. > For the most common use of xargs -- "find ... | xargs command" -- the > script below, called "many", does a good job. Since it doesn't spawn > a subshell, it isn't prone to metacharacter-caused security problems. But it's still susceptible to filenames with carriage returns, and will be until find has a -print0 option. Please, please, please don't claim that your xargs is by any means secure when a standard command like find / -name '#*' -atime +7 -print | xargs rm lets a malicious user remove every file on the system. Maybe it's unreasonable of me to want others to live up to my standard of security, but in my eyes no \n-parsing xargs qualifies as ``a good job.'' Sorry. ---Dan
tif@doorstop.austin.ibm.com (Paul Chamberlain) (10/16/90)
In article <4062:Oct1518:22:1290@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: > find / -name '#*' -atime +7 -print | xargs rm >lets a malicious user remove every file on the system. If I understand, to do this a user would have to create a file with a '/' in its name. Is this possible on some systems? The most malicious thing I can do with the above command is remove a file that doesn't start with '#' that's in a writable directory. Twice (I think), you have asserted grave danger with find and xargs. I still don't see it. Paul Chamberlain | I do NOT represent IBM. tif@doorstop, sc30661 at ausvm6 512/838-7008 | ...!cs.utexas.edu!ibmaus!auschs!doorstop.austin.ibm.com!tif
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/17/90)
In article <3876@awdprime.UUCP> tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: > In article <4062:Oct1518:22:1290@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: > > find / -name '#*' -atime +7 -print | xargs rm > >lets a malicious user remove every file on the system. > If I understand, to do this a user would have to create a file > with a '/' in its name. Incorrect. find prints full pathnames, not just filenames. > The most malicious thing I can do with the above command is > remove a file that doesn't start with '#' that's in a > writable directory. Incorrect. If that command is run daily from cron, as it is on many systems, then any user can remove any file on the system. ---Dan
tim@ggumby.cs.caltech.edu (Timothy L. Kay) (10/17/90)
tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: >In article brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >> find / -name '#*' -atime +7 -print | xargs rm >>lets a malicious user remove every file on the system. >If I understand, to do this a user would have to create a file >with a '/' in its name. Is this possible on some systems? >The most malicious thing I can do with the above command is >remove a file that doesn't start with '#' that's in a >writable directory. Let me see. If I create a directory named directory\n and create a file in there called vmunix, then find will spit out a file .../directory\n/vmunix\n which xargs will see as .../directory and /vmunix Tim
pfalstad@stone.Princeton.EDU (Paul John Falstad) (10/17/90)
In article <13569:Oct1617:00:0590@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >In article <3876@awdprime.UUCP> tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: >> In article <4062:Oct1518:22:1290@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >> > find / -name '#*' -atime +7 -print | xargs rm >> The most malicious thing I can do with the above command is >> remove a file that doesn't start with '#' that's in a >> writable directory. >Incorrect. If that command is run daily from cron, as it is on many >systems, then any user can remove any file on the system. Oh, I see. You could do something like this: $ echo >'# vmunix' And then cron would delete /vmunix. That's assuming cron starts up xargs with / as its current directory. And to delete other files (not necessarily in /), you could do: $ mkdir '# ' $ cd '# ' $ mkdir u; mkdir u/subbarao $ mkdir u/subbarao/.plan' ' $ date >u/subbarao/.plan' /#foo' If you do a find . -name '#*' -print | xargs echo in this directory, you get: ./# ./# /u/subbarao/.plan /#foo ./# vmunix Very nasty. Wonder if it works on my system... -- Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD "And she's always on about men following her. I don't know what she thinks they're going to do to her. Vomit on her, Basil, says."-Flowery Twats
peter@ficc.ferranti.com (Peter da Silva) (10/18/90)
In article <13569:Oct1617:00:0590@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: > find / -name '#*' -atime +7 -print | xargs rm > Incorrect. If that command is run daily from cron, as it is on many > systems, then any user can remove any file on the system. OK, enlighten me. Why is this command run daily on cron on many systems? And if it is, what systems are they so I can avoid them? -- Peter da Silva. `-_-' +1 713 274 5180. 'U` peter@ferranti.com
subbarao@phoenix.Princeton.EDU (Kartik Subbarao) (10/18/90)
In article <3369@idunno.Princeton.EDU> pfalstad@stone.Princeton.EDU (Paul John Falstad) writes: >In article <13569:Oct1617:00:0590@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >>In article <3876@awdprime.UUCP> tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: >>> In article <4062:Oct1518:22:1290@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >>> > find / -name '#*' -atime +7 -print | xargs rm >>> The most malicious thing I can do with the above command is >>> remove a file that doesn't start with '#' that's in a >>> writable directory. >>Incorrect. If that command is run daily from cron, as it is on many >>systems, then any user can remove any file on the system. > >Oh, I see. You could do something like this: >And then cron would delete /vmunix. That's assuming cron starts up xargs >with / as its current directory. >And to delete other files (not necessarily in /), you could do: > >$ mkdir '# >' >$ cd '# >' >$ mkdir u; mkdir u/subbarao >$ mkdir u/subbarao/.plan' >' >$ date >u/subbarao/.plan' >/#foo' > Yow! nah, we'd never wan't to do that, now would we? Then I'd have no goal in life?! :-) >If you do a find . -name '#*' -print | xargs echo in this directory, you get: > >./# ./# /u/subbarao/.plan /#foo ./# vmunix > >Very nasty. Wonder if it works on my system... No, good thing it doesn't. Especially after I'd want to put a pipe as my .plan to execute a command ;-). Gee, it's also a good thing there are no shell escapes in rm. I can just see the thread now: "Beware : Re: how to prevent shell escapes from rm". And then Dan would give his wonderful pty solution (not that pty isn't wonderful!), Larry Wall and Randall Schwartz would probably find a nice one line perl hack, some other sysadmin would complain about the openness of the discussion, another would cry "security through obscurity", and the wizards would go back and forth about this. comp.unix.* can be so funny at times :-) >Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD >"And she's always on about men following her. I don't know what she >thinks they're going to do to her. Vomit on her, Basil, says."-Flowery Twats Good thing Paul only removed my .plan, so I can say: (I need a new .signature -- any suggestions?) subbarao@{phoenix or gauguin}.Princeton.EDU -|Internet kartik@silvertone.Princeton.EDU (NeXT mail) -| SUBBARAO@PUCC.BITNET - Bitnet
tif@doorstop.austin.ibm.com (Paul Chamberlain) (10/19/90)
In article <tim.656101080@ggumby> tim@ggumby.cs.caltech.edu (Timothy L. Kay) writes: >tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: >>In article brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >>> find / -name '#*' -atime +7 -print | xargs rm >>>lets a malicious user remove every file on the system. >> >>The most malicious thing I can do with the above command is >>remove a file that doesn't start with '#' that's in a >>writable directory. > >Let me see. If I create a directory [and file] named > .../directory\n/vmunix Okay, I've had this explained to me and I admit that this could be a problem. But I think it is contrived because the "find" command to pass this filename to xargs either doesn't check the name or allows "vmunix" to match it. I suppose I could create the above and then convince the administrator to do "find /u/tif -print | xargs chown tif". But, then again, wouldn't "ln /etc/passwd /u/tif/my_file" be easier. In any case, I've yet to see how "a malicious user [could] remove every file on the system." Paul Chamberlain | I do NOT represent IBM. tif@doorstop, sc30661 at ausvm6 512/838-7008 | ...!cs.utexas.edu!ibmaus!auschs!doorstop.austin.ibm.com!tif
dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) (10/20/90)
In article <3940@awdprime.UUCP> tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: >In article <tim.656101080@ggumby> tim@ggumby.cs.caltech.edu (Timothy L. Kay) writes: >>tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: >>>In article brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >>>> find / -name '#*' -atime +7 -print | xargs rm >>>>lets a malicious user remove every file on the system. >>> > >In any case, I've yet to see how "a malicious user [could] >remove every file on the system." > If xargs is implemented using system (as it is on this machine), an old file named #<newline>-rf * will remove every file on the machine if the rm -rf * happens to be the start of the buffer passed to system. -- Dave Eisen Home: (415) 323-9757 dkeisen@Gang-of-Four.Stanford.EDU Office: (415) 967-5644 1447 N. Shoreline Blvd. Mountain View, CA 94043
res@cbnews.att.com (Robert E. Stampfli) (10/20/90)
> In any case, I've yet to see how "a malicious user [could] > remove every file on the system." No user, malicious or not, can remove "every file on the system." In fact, I contend it is impossible to remove the last instance of an executable that contains the unlink() system call. -- Rob Stampfli / att.com!stampfli (uucp@work) / kd8wk@w8cqk (packet radio) 614-864-9377 / osu-cis.cis.ohio-state.edu!kd8wk!res (uucp@home)
wcs) (10/21/90)
In article <SGH6K6D@xds13.ferranti.com>, peter@ficc.ferranti.com (Peter da Silva) writes: > > find / -name '#*' -atime +7 -print | xargs rm > OK, enlighten me. Why is this command run daily on cron on many systems? And > if it is, what systems are they so I can avoid them? Many systems, especially universities, have a convention that filenames beginning with '#' are "marked for death". Instead of a "real" rm command, most users use a file deletion command that renames foo as #foo, which can be recovered by an undelete command, if the user is lucky after having been stupid, and the ls command may also be hacked not to show them. Other places use similar conventions. But even if you DO avoid systems like this, LOTS of places do find /tmp /usr/tmp -atime +7 -mtime +7 -print |xargs rm to clean old stuff out of /tmp, which IS morally acceptable behaviour :-) And it can be hosed just as easily; mkdir /tmp/foo' ' cd "/tmp/foo?" ; echo gotcha > vmunix -- Thanks; Bill # Bill Stewart 908-949-0705 erebus.att.com!wcs AT&T Bell Labs 4M-312 Holmdel NJ Government is like an elephant on drugs: It's very confused, makes lots of noise, can't do anything well, stomps on anyone in its way, and it sure eats a lot.
davidsen@sixhub.UUCP (Wm E. Davidsen Jr) (10/21/90)
It *appears* that xenix quotes its arguments in xargs, since I did a small and cautious test and it worked all right. How about testing your version of xargs and posting the results here? I will do Sun, Ultrix and (if I get the files reloaded) V.4. -- bill davidsen - davidsen@sixhub.uucp (uunet!crdgw1!sixhub!davidsen) sysop *IX BBS and Public Access UNIX moderator of comp.binaries.ibm.pc and 80386 mailing list "Stupidity, like virtue, is its own reward" -me
rouben@math9.math.umbc.edu (Rouben Rostamian) (10/21/90)
In article <2113@sixhub.UUCP> davidsen@sixhub.UUCP (bill davidsen) writes: > It *appears* that xenix quotes its arguments in xargs, since I did a >small and cautious test and it worked all right. How about testing your >version of xargs and posting the results here? I will do Sun, Ultrix and >(if I get the files reloaded) V.4. Why "small and cautious"? To test whether xargs quotes its arguments, in an empty directory do: touch "This is a test" find . -print | xargs rm If the file "This is a test" goes away, then xargs is quoting its arguments. Otherwise, xargs is feeding the file name as four separate arguments to rm and you will get complains from rm for not finding the files. I ran this test on Ultrix V4.0 and on a Stardent 3000 (a hybrid SysV/bsd beast.) In neither test the file was removed. So no quoting from xargs in these cases. -- Rouben Rostamian Telephone: (301) 455-2458 Department of Mathematics and Statistics e-mail: University of Maryland Baltimore County bitnet: rostamian@umbc Baltimore, MD 21228, U.S.A. internet: rostamian@umbc3.umbc.edu
pfalstad@fish.Princeton.EDU (Paul John Falstad) (10/21/90)
>In article <2113@sixhub.UUCP> davidsen@sixhub.UUCP (bill davidsen) writes: >> It *appears* that xenix quotes its arguments in xargs, since I did a >>small and cautious test and it worked all right. How about testing your Though as Dan said earlier, even if xargs quotes its arguments, you can still get in trouble, since find and xargs use a newline as a delimiter for filenames, and filenames can have newlines in them. -- Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD And Dinsdale said, "You've been a naughty boy, Clement," and splits me nostrils open, and saws me leg off, and pulls me liver out. And I said, "My name's not Clement." And then he loses his temper. And he nails me head to the floor.
les@chinet.chi.il.us (Leslie Mikesell) (10/22/90)
In article <3484@idunno.Princeton.EDU> pfalstad@fish.Princeton.EDU (Paul John Falstad) writes: >Though as Dan said earlier, even if xargs quotes its arguments, you can >still get in trouble, since find and xargs use a newline as a delimiter for >filenames, and filenames can have newlines in them. Actually the problem of allowing characters that are valid in filenames to have special meanings on the command line runs rampant throughout unix. Even if you eliminate part of the problem by using a '\0' delimiter to syncronize find and xargs, you can still get into trouble with a file named "-r" appearing at the front of an argument list that might also mention directories. Les Mikesell les@chinet.chi.il.us
ag@cbmvax.commodore.com (Keith Gabryelski) (10/22/90)
In article <1990Oct21.223729.10521@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell) writes: >[...] you can still get into trouble with a file named "-r" appearing >at the front of an argument list that might also mention directories. But this is easily taken care of by suppling `--' as the last argument to rm (ie, find . -name '*.dvi' -print | xargs rm --) Pax, Keith
emv@math.lsa.umich.edu (Edward Vielmetti) (10/22/90)
In article <4203@umbc3.UMBC.EDU> rouben@math9.math.umbc.edu (Rouben Rostamian) writes:
I ran this test on Ultrix V4.0 and on a Stardent 3000 (a hybrid SysV/bsd
beast.) In neither test the file was removed. So no quoting from xargs
in these cases.
SunOS 4.0.3 also does not remove the file. Instead it says
urania /tmp/foo % find . -print | xargs rm
rm: cannot remove `.' or `..'
--Ed
Edward Vielmetti, U of Michigan math dept <emv@math.lsa.umich.edu>
moderator, comp.archives
pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (10/22/90)
In article <2113@sixhub.UUCP> davidsen@sixhub.UUCP (bill davidsen) writes: > It *appears* that xenix quotes its arguments in xargs, since I did a >small and cautious test and it worked all right. How about testing your Even if the arguments are quoted, xargs still presents a security problem if it calls system. Just about any program that runs a shell is unsecure. If your system's xargs calls system, then someone could just create a file with the quote character in it. The only really safe way is to do an execve. -- Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD And Dinsdale said, "You've been a naughty boy, Clement," and splits me nostrils open, and saws me leg off, and pulls me liver out. And I said, "My name's not Clement." And then he loses his temper. And he nails me head to the floor.
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/23/90)
In article <1990Oct21.223729.10521@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell) writes: > Even if you eliminate part of the problem by using a '\0' delimiter > to syncronize find and xargs, you can still get into trouble with a > file named "-r" appearing at the front of an argument list that might > also mention directories. No, you can't. As long as find is invoked upon a fixed directory name (like . or / or /tmp), every name it prints will start with that. So find / -name core -atime +7 -print0 | xargs -0 rm will be safe. You can always use rm --, but there's no need to. ---Dan
davidsen@sixhub.UUCP (Wm E. Davidsen Jr) (10/23/90)
In article <4203@umbc3.UMBC.EDU> rouben@math9.math.umbc.edu.UUCP (Rouben Rostamian) writes: | Why "small and cautious"? To test whether xargs quotes its arguments, | in an empty directory do: | | touch "This is a test" | find . -print | xargs rm That's what I mean by small and cautions. Actually I tried creating a file called "abc;date" to see if the date command would be executed, and abc#x to see if the comment character was okay. These worked, but embedded blanks caused problems. Obviously either (a) a shell is not being called to process this, or (b) the shell is run with IFS redefined. Verdict: xenix xargs is better than some, not perfect. -- bill davidsen - davidsen@sixhub.uucp (uunet!crdgw1!sixhub!davidsen) sysop *IX BBS and Public Access UNIX moderator of comp.binaries.ibm.pc and 80386 mailing list "Stupidity, like virtue, is its own reward" -me
jeff@onion.pdx.com (Jeff Beadles) (10/23/90)
Well, under the 4.2 BSD based system I have here (Tektronix 4.1 UTek) it appears that xargs IS quoting it's arguements. Here's the test that I did, that's fairly safe to run. If xargs was not quoting it's arguements, then all files starting with 'a' would have been deleted. Script started on Mon Oct 22 22:29:31 1990 jo:jeff> cd /usr/tmp jo:tmp> ls -al total 2 drwxrwxrwx 2 root 512 Oct 22 22:29 . drwxr-xr-x 21 sys 512 Oct 19 23:18 .. jo:tmp> touch 'a' 'a*' 'aa' 'aaa' 'aaaa' jo:tmp> ls -al total 2 drwxrwxrwx 2 root 512 Oct 22 22:29 . drwxr-xr-x 21 sys 512 Oct 19 23:18 .. -rw-r--r-- 1 jeff 0 Oct 22 22:29 a -rw-r--r-- 1 jeff 0 Oct 22 22:29 a* -rw-r--r-- 1 jeff 0 Oct 22 22:29 aa -rw-r--r-- 1 jeff 0 Oct 22 22:29 aaa -rw-r--r-- 1 jeff 0 Oct 22 22:29 aaaa jo:tmp> find . -name 'a?' -print | xargs -t rm -f rm -f ./a* ./aa jo:tmp> ls -al total 2 drwxrwxrwx 2 root 512 Oct 22 22:30 . drwxr-xr-x 21 sys 512 Oct 19 23:18 .. -rw-r--r-- 1 jeff 0 Oct 22 22:29 a -rw-r--r-- 1 jeff 0 Oct 22 22:29 aaa -rw-r--r-- 1 jeff 0 Oct 22 22:29 aaaa jo:tmp> exit script done on Mon Oct 22 22:30:30 1990 A sigh of relief... :-) -Jeff -- Jeff Beadles jeff@onion.pdx.com
boyd@necisa.ho.necisa.oz (Boyd Roberts) (10/23/90)
In article <3940@awdprime.UUCP> tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: > >In any case, I've yet to see how "a malicious user [could] >remove every file on the system." > Nor can I. Since when did xargs(1) use system(3)? A malicious user may be able to embed newlines in filenames, but that's not going to trash the _whole_ file-system. If someone did change xargs(1) to use system(3) it's obviously been broken. Using system(3) raises all sorts of revolting shell quoting problems -- not to mention the security holes. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''
cpcahil@virtech.uucp (Conor P. Cahill) (10/23/90)
In article <1990Oct20.032718.1874@cbnews.att.com> res@cbnews.att.com (Robert E. Stampfli) writes: >No user, malicious or not, can remove "every file on the system." >In fact, I contend it is impossible to remove the last instance of >an executable that contains the unlink() system call. This is only true for system V. BSD allows you to unlink a running executable. -- Conor P. Cahill (703)430-9247 Virtual Technologies, Inc., uunet!virtech!cpcahil 46030 Manekin Plaza, Suite 160 Sterling, VA 22170
nomann@rimfaxe.diku.dk (Ole Nomann Thomsen) (10/23/90)
davidsen@sixhub.UUCP (Wm E. Davidsen Jr) writes: > It *appears* that xenix quotes its arguments in xargs, since I did a >small and cautious test and it worked all right. ... No: touch "foo bar" find . -type f -print | xargs ls -l # Produces: ./foo not found bar not found ... # ["ls -l"s deleted] # on Xenix 2.3.2 . - Ole. (nomann@diku.dk). "Information is not knowledge" - Frank Zappa.
emcguire@ccad.uiowa.edu (Ed McGuire) (10/23/90)
In article <1990Oct21.013603.25168@cbnewsh.att.com> wcs@cbnewsh.att.com (Bill Stewart 201-949-0705 erebus.att.com!wcs) writes: > Many systems, especially universities, have a convention that > filenames beginning with '#' are "marked for death". Among other things, `#' begins the name of a file created in /lost+found. -- peace. -- Ed "Vote. Because it's the Right Thing."
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/24/90)
In article <1890@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: > In article <3940@awdprime.UUCP> tif@doorstop.austin.ibm.com (Paul Chamberlain) writes: > >In any case, I've yet to see how "a malicious user [could] > >remove every file on the system." > A malicious user may be able to embed newlines in filenames, > but that's not going to trash the _whole_ file-system. Oh? Each filename he sets up can remove dozens of other files. There are only so many files in the entire system. > If someone did change xargs(1) to use system(3) it's obviously been broken. Agreed. ---Dan
ag@cbmvax.commodore.com (Keith Gabryelski) (10/24/90)
In article <1990Oct20.032718.1874@cbnews.att.com> res@cbnews.att.com (Robert E. Stampfli) writes: >No user, malicious or not, can remove "every file on the system." >In fact, I contend it is impossible to remove the last instance of >an executable that contains the unlink() system call. This was, infact, impossible on System V Release 3.x, but in SVR4 it is possible. BSD and SunOS varients get this `right', also. Pax, Keith
cpcahil@virtech.uucp (Conor P. Cahill) (10/24/90)
In article <1890@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >Nor can I. Since when did xargs(1) use system(3)? It dosn't matter what xargs uses to run the command. The problem is how it parses it's input. If the input is newline separated and a user can add newlines to a filename, then the user can create a file that will cause xargs to incorrectly parse it's input. -- Conor P. Cahill (703)430-9247 Virtual Technologies, Inc., uunet!virtech!cpcahil 46030 Manekin Plaza, Suite 160 Sterling, VA 22170
greywolf@unisoft.UUCP (The Grey Wolf) (10/25/90)
In article <4062:Oct1518:22:1290@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >In article <271653D6.1CE8@tct.uucp> chip@tct.uucp (Chip Salzenberg) writes: >> According to lml@cbnews.att.com (L. Mark Larsen): >> >I never much cared for xargs since it limits you to an argument list of >> >only 470 bytes. >> For the most common use of xargs -- "find ... | xargs command" -- the >> script below, called "many", does a good job. Since it doesn't spawn >> a subshell, it isn't prone to metacharacter-caused security problems. > >But it's still susceptible to filenames with carriage returns, and will >be until find has a -print0 option. Please, please, please don't claim >that your xargs is by any means secure when a standard command like > > find / -name '#*' -atime +7 -print | xargs rm > >lets a malicious user remove every file on the system. Maybe it's >unreasonable of me to want others to live up to my standard of security, >but in my eyes no \n-parsing xargs qualifies as ``a good job.'' Sorry. > >---Dan Having looked at the output of find and the input of xargs, there is definitely a hole ("NO SHIT, SHERLOCK!") (yeah, I saw the other posts). Just the same, xargs kind of loses functionality if you take away its ability to handle newlines. "find $fs -conditions ... -print | xargs cmd" certainly has more advantages to it than the hole can really offset. If you're worried about the above command running as root, then don't. Or don't use "xargs" in that case, use "-exec rm {} \;". It's that simple. Don't cripple an otherwise very useful command. -- "This is *not* going to work!" "Well, why didn't you say so before?" "I *did* say so before!" ...!{ucbvax,acad,uunet,amdahl,pyramid}!unisoft!greywolf
john@sco.COM (John R. MacMillan) (10/26/90)
|It dosn't matter what xargs uses to run the command. The problem is how |it parses it's input. If the input is newline separated and a user can |add newlines to a filename, then the user can create a file that will |cause xargs to incorrectly parse it's input. So check that xargs did indeed parse its input correctly. Instead of find / -name '#*' -print | xargs rm -f use find / -name '#*' -print | xargs patok '.*/#[^/]*' rm -f -- where patok elimnates arguments that don't match the pattern. Shouldn't be tough to write. It wouldn't remove files with newlines, but if patok complains about non-matches, you could find them later and go slap the file owner's wrist. Sound reasonable? -- John R. MacMillan | I'm in love with a McDonald's girl SCO Canada, Inc. | She's an angel in a polyester uniform. john@sco.COM | -- barenaked ladies
david@cs.uow.edu.au (David E A Wilson) (10/26/90)
At least with SunOS 4.1 the manual page describes exactly what characters will cause problems. Arguments read in from the standard input are defined to be contiguous strings of characters delimited by white space. Empty lines are always discarded. Blanks and tabs may be embedded as part of an argument if they are escaped or quoted. Characters enclosed in quotes (single or double) are taken literally, and the delimiting quotes are removed. Outside of quoted strings, a `\' (backslash) will escape the character it precedes. Newlines cannot be part of an argument and spaces & quotes would cause so many problems that you would have to preceed each character with a \ to be sure. -- David Wilson Dept Comp Sci, Uni of Wollongong david@cs.uow.edu.au
karl@ficc.ferranti.com (Karl Lehenbauer) (10/27/90)
In article <1990Oct20.032718.1874@cbnews.att.com> res@cbnews.att.com (Robert E. Stampfli) writes: >No user, malicious or not, can remove "every file on the system." >In fact, I contend it is impossible to remove the last instance of >an executable that contains the unlink() system call. Oh, then I guess it's not a problem... -- -- uunet!sugar!ficc!karl (wk), uunet!sugar!karl (hm) "The computer programmer is a creator of universes for which he alone is responsible. Universes of virtually unlimited complexity can be created in the form of computer programs." -- Joseph Weizenbaum
bhoughto@cmdnfs.intel.com (Blair P. Houghton) (10/27/90)
In article <john.656921455@troch> john@sco.COM (John R. MacMillan) writes: > >find / -name '#*' -print | xargs patok '.*/#[^/]*' rm -f -- > >where patok elimnates arguments that don't match the pattern. >[patok] shouldn't be too hard to write. find / -name '#*' -print | egrep -v '.*/#[^/]*' | xargs rm -f -- --Blair "Took longer to type."
bhoughto@cmdnfs.intel.com (Blair P. Houghton) (10/27/90)
In article <649@inews.intel.com> bhoughto@cmdnfs.intel.com (Blair P. Houghton) writes: >In article <john.656921455@troch> john@sco.COM (John R. MacMillan) writes: >> >>find / -name '#*' -print | xargs patok '.*/#[^/]*' rm -f -- >> >>where patok elimnates arguments that don't match the pattern. >>[patok] shouldn't be too hard to write. > >find / -name '#*' -print | egrep -v '.*/#[^/]*' | xargs rm -f -- Lose the -v, dimwit. > "Took longer to type." --Blair "Egotistical, overreaching, pretentious, typographically unsound geek!"
john@sco.COM (John R. MacMillan) (10/29/90)
|> |>find / -name '#*' -print | xargs patok '.*/#[^/]*' rm -f -- |> |>where patok elimnates arguments that don't match the pattern. |>[patok] shouldn't be too hard to write. | |find / -name '#*' -print | egrep -v '.*/#[^/]*' | xargs rm -f -- Of course by the time I'd realized this, Blair had already pointed it out. It's so much more painless when you catch your own mistakes. Speaking of which, you probably don't want the -v to egrep unless you want to remove only the files the nasty guy wanted you to, and the pattern should probably have been '/#[^/]*$'. So now that we can all safely and automatically remove files I think we should kill this thread before I embarass myself further. -- John R. MacMillan | I'm in love with a McDonald's girl SCO Canada, Inc. | She's an angel in a polyester uniform. john@sco.COM | -- barenaked ladies
levy@mtcchi.uucp (2656-Daniel R. Levy(0000000)0000) (10/29/90)
>>But it's still susceptible to filenames with carriage returns, and will >>be until find has a -print0 option. Please, please, please don't claim >>that your xargs is by any means secure when a standard command like >> >> find / -name '#*' -atime +7 -print | xargs rm >> >>lets a malicious user remove every file on the system. Maybe it's >>unreasonable of me to want others to live up to my standard of security, >>but in my eyes no \n-parsing xargs qualifies as ``a good job.'' Sorry. For a brief moment there I thought one could do an end run by telling find not to match files whose names contain newline (e.g. ! -name '*^J*' where ^J is an actual newline character). But alas, that does not exclude files within directories whose names (the directories' that is) contain newlines. Oh well. -- * Daniel R. Levy * uunet!tellab5!mtcchi!levy * | * These views are live; they are not Memorex' * --+-- "Because we love something else more than this world we love even | this world better than those who know no other" -- C. S. Lewis |
staff@cadlab.sublink.ORG (Alex Martelli) (10/29/90)
bhoughto@cmdnfs.intel.com (Blair P. Houghton) writes: ... >>find / -name '#*' -print | egrep -v '.*/#[^/]*' | xargs rm -f -- >Lose the -v, dimwit. Won't "egrep '/#'" pass EXACTLY the same lines as "egrep '.*/#[^/]*'"??? After all, it's not as if the RE had to match ALL of the incoming line! Yours for simpler, more regular expression of Regular Expressions... -- Alex Martelli - CAD.LAB s.p.a., v. Stalingrado 45, Bologna, Italia Email: (work:) staff@cadlab.sublink.org, (home:) alex@am.sublink.org Phone: (work:) ++39 (51) 371099, (home:) ++39 (51) 250434; Fax: ++39 (51) 366964 (work only), Fidonet: 332/401.3 (home only).
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/30/90)
In article <john.657158675@troch> john@sco.COM (John R. MacMillan) writes: > |find / -name '#*' -print | egrep -v '.*/#[^/]*' | xargs rm -f -- No! Think about links. > So now that we can all safely and automatically remove files I think > we should kill this thread before I embarass myself further. Perhaps people should think about their supposed solutions before posting them. Not to flame, but you're the eighth person to post an insecure pipeline in this thread. Folks, just don't use find | xargs as root until it has -0 to parse nulls and find has -print0 to match. You'll sleep better at night using -exec rm than somebody's supposedly secure pipeline from hell. ---Dan
engbert@cs.vu.nl (=Engbert Gerrit IJff) (10/30/90)
In article <303@cadlab.sublink.ORG>, staff@cadlab.sublink.ORG (Alex Martelli) writes: ) bhoughto@cmdnfs.intel.com (Blair P. Houghton) writes: ) ... ) >>find / -name '#*' -print | egrep -v '.*/#[^/]*' | xargs rm -f -- ) >Lose the -v, dimwit. ) ) Won't "egrep '/#'" pass EXACTLY the same lines as "egrep '.*/#[^/]*'"??? ) After all, it's not as if the RE had to match ALL of the incoming line! ) Yours for simpler, more regular expression of Regular Expressions... Yes, you're right. However, if I am right, the original intention was to delete files whose names started with the # character. Shouldn't it be "egrep '/#[^/]*$'" then, to check on the basename? ^ Bert IJff
kimcm@diku.dk (Kim Christian Madsen) (11/01/90)
Just my $0.02 to the ongoing discussion of: find .... | xargs rm If you're really worried about *NASTY* users and embedded newlines in files, why use xargs at the receiving end of find, and not just settle with: find .... -exec /bin/rm {} \; Yes I know that it spawns a lot of processes compared to the xargs solution, but it is also a secure way of removal of files with embedded newlines. Kim Chr. Madsen
iand@labtam.labtam.oz (Ian Donaldson) (11/23/90)
karl@ficc.ferranti.com (Karl Lehenbauer) writes: >In article <1990Oct20.032718.1874@cbnews.att.com> res@cbnews.att.com (Robert E. Stampfli) writes: >>No user, malicious or not, can remove "every file on the system." >>In fact, I contend it is impossible to remove the last instance of >>an executable that contains the unlink() system call. If the executable is built with non-shared text (ie unpure) then its possible on most UNIXen. On some UNIXen its even possible with shared text binaries (eg: SVR4, SUNOS4.1) Ian D