Xref: utzoo comp.unix.shell:565 comp.lang.perl:2564 Path: utzoo!attcan!uunet!know!zaphod.mps.ohio-state.edu!uakari.primate.wisc.edu!ames!vsi1!daver!tscs!tct!chip From: chip@tct.uucp (Chip Salzenberg) Newsgroups: comp.unix.shell,comp.lang.perl Subject: Re: Beware xargs security holes Message-ID: <271653D6.1CE8@tct.uucp> Date: 12 Oct 90 23:37:57 GMT References: <1990Oct9.060954.25690@watcgl.waterloo.edu> <63404@iuvax.cs.indiana.edu> <1990Oct9.172621.13484@cbnews.att.com> Distribution: na Organization: Teltronics/TCT, Sarasota, FL Lines: 168 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 '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 <) { 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 , "I've been cranky ever since my comp.unix.wizards was removed by that evil Chip Salzenberg." -- John F. Haugh II