bug-gnu-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: igawk unsafe temporary file handling


From: Paul Eggert
Subject: Re: igawk unsafe temporary file handling
Date: Sun, 27 May 2001 13:11:47 -0700 (PDT)

> From: address@hidden
> Date: Sun, 27 May 2001 05:30:50 +0400
> 
> igawk from gawk-3.0.6 creates its temporary files unsafely.
> 
> The attached patch is based on report and an older patch from
> Jarno Huuskonen <address@hidden>.  The patch requires
> mktemp and thus isn't very portable.

How about the following patch instead?  It works around the problem by
avoiding temporary files entirely.  I found a few other bugs and
portability problems in igawk and fixed them too, while I was at it.

This patch assumes the patches I've already submitted for gawk 3.0.98
gawk.texi.

2001-05-27  Paul Eggert  <address@hidden>

        * gawk.texi: Do not put temporary files in /tmp, as that has
        some security problems.  This fixes a problem originally reported
        by Jarno Huuskonen via address@hidden

        Fix the following problems with igawk while we're at it.

        * Report missing operands of options; this fixes e.g. an
          infinite loop with "igawk -W".

        * Check for --source and -Wsource only, not -.source (which matches
          errors).  Similarly for other multichar options.

        * Do not use 'echo', as that mishandles backslashes on some hosts.

        * Use ${1+"$@"} instead of "$@" to work around an incompatibility
          of traditional (Unix version 7) sh, when there are no arguments.

===================================================================
RCS file: gawk.texi,v
retrieving revision 3.0.98.2
retrieving revision 3.0.98.3
diff -pu -r3.0.98.2 -r3.0.98.3
--- gawk.texi   2001/05/16 08:01:55     3.0.98.2
+++ gawk.texi   2001/05/27 20:02:49     3.0.98.3
@@ -14378,7 +14378,7 @@ done with temporary files:
 
 @example
 # write the data for processing
-tempfile = ("/tmp/mydata." PROCINFO["pid"])
+tempfile = ("mydata." PROCINFO["pid"])
 while (@var{not done with data})
     print @var{data} | ("subprogram > " tempfile)
 close("subprogram > " tempfile)
@@ -14391,7 +14391,10 @@ system("rm " tempfile)
 @end example
 
 @noindent
-This works, but not elegantly.
+This works, but not elegantly.  Among other things, it requires that
+the program be run in a directory that cannot be shared among users;
+for example, @file{/tmp} will not do, as another user might happen
+to be using a temporary file with the same name.
 
 @cindex coprocess
 @cindex two-way I/O
@@ -20323,25 +20326,24 @@ Loop through the arguments, saving anyth
 
 @item
 For any arguments that do represent @command{awk} text, put the arguments into
-a temporary file that will be expanded.  There are two cases:
+a shell variable that will be expanded.  There are two cases:
 
 @enumerate a
 @item
 Literal text, provided with @option{--source} or @option{--source=}.  This
-text is just echoed directly.  The @command{echo} program automatically
-supplies a trailing newline.
+text is just appended directly.
 
 @item
-Source @value{FN}s provided with @option{-f}.  We use a neat trick and echo
address@hidden@@include @var{filename}} into the temporary file.  Since the file
+Source @value{FN}s provided with @option{-f}.  We use a neat trick and append
address@hidden@@include @var{filename}} to the shell variable.  Since the file
 inclusion program works the way @command{gawk} does, this gets the text
 of the file included into the program at the correct point.
 @end enumerate
 
 @item
-Run an @command{awk} program (naturally) over the temporary file to expand
+Run an @command{awk} program (naturally) over the shell variable to expand
 @samp{@@include} statements.  The expanded program is placed in a second
-temporary file.
+shell variable.
 
 @item
 Run the expanded program with @command{gawk} and any other original 
command-line
@@ -20349,12 +20351,7 @@ arguments that the user supplied (such a
 @end enumerate
 
 The initial part of the program turns on shell tracing if the first
-argument is @samp{debug}.  Otherwise, a shell @code{trap} statement
-arranges to clean up any temporary files on program exit or upon an
-interrupt.
-
address@hidden 2e: For the temp file handling, go with Darrel's 
ig=${TMP:-/tmp}/igs.$$
address@hidden 2e: or something as similar as possible.
+argument is @samp{debug}.
 
 The next part loops through all the command-line arguments.
 There are several cases of interest:
@@ -20375,13 +20372,13 @@ programming trick.  Don't worry about it
 These are saved and passed on to @command{gawk}.
 
 @item address@hidden,} address@hidden,} address@hidden,} -Wfile=
-The @value{FN} is saved to the temporary file @file{/tmp/ig.s.$$} with an
+The @value{FN} is appended to the shell variable @code{program} with an
 @samp{@@include} statement.
-The @command{sed} utility is used to remove the leading option part of the
+The @command{expr} utility is used to remove the leading option part of the
 argument (e.g., @samp{--file=}).
 
 @item address@hidden,} address@hidden,} -Wsource=
-The source text is echoed into @file{/tmp/ig.s.$$}.
+The source text is appended to @code{program}.
 
 @item address@hidden,} -Wversion
 @command{igawk} prints its version number, runs @samp{gawk --version}
@@ -20392,17 +20389,11 @@ If none of the @option{-f}, @option{--fi
 or @option{-Wsource} arguments are supplied, then the first non-option argument
 should be the @command{awk} program.  If there are no command-line
 arguments left, @command{igawk} prints an error message and exits.
-Otherwise, the first argument is echoed into @file{/tmp/ig.s.$$}.
+Otherwise, the first argument is appended to @code{program}.
 In any case, after the arguments have been processed,
address@hidden/tmp/ig.s.$$} contains the complete text of the original 
@command{awk}
address@hidden contains the complete text of the original @command{awk}
 program.
 
address@hidden @command{sed} utility
address@hidden stream editor
-The @samp{$$} in @command{sh} represents the current process ID number.
-It is often used in shell programs to generate unique temporary @value{FN}s.
-This allows multiple users to run @command{igawk} without worrying
-that the temporary @value{FN}s will clash.
 The program is as follows:
 
 @cindex @code{igawk.sh} program
@@ -20424,48 +20415,50 @@ if [ "$1" = debug ]
 then
     set -x
     shift
-else
-    # cleanup on exit, hangup, interrupt, quit, termination
-    trap 'rm -f /tmp/ig.[se].$$' 0 1 2 3 15
 fi
 
+n='
+'
+program=''
+opts=''
+
 while [ $# -ne 0 ] # loop over arguments
 do
     case $1 in
     --)     shift; break;;
 
     -W)     shift
-            set -- -W"$@@"
+            set -- -W"address@hidden@@?'missing operand'@}"
             continue;;
 
-    -[vF])  opts="$opts $1 '$2'"
+    -[vF])  opts="$opts $1 'address@hidden'missing operand'@}'"
             shift;;
 
     -[vF]*) opts="$opts '$1'" ;;
 
-    -f)     echo @@include "$2" >> /tmp/ig.s.$$
+    -f)     program="$program$n@@include address@hidden'missing operand'@}"
             shift;;
 
-    -f*)    f=`echo "$1" | sed 's/-f//'`
-            echo @@include "$f" >> /tmp/ig.s.$$ ;;
+    -f*)    f=`expr "$1" : '-f\(.*\)'`
+            program="$program$n@@include $f";;
 
-    -?file=*)    # -Wfile or --file
-            f=`echo "$1" | sed 's/-.file=//'`
-            echo @@include "$f" >> /tmp/ig.s.$$ ;;
+    -[W-]file=*)
+            f=`expr "$1" : '-.file=\(.*\)'`
+            program="$program$n@@include $f";;
 
-    -?file)      # get arg, $2
-            echo @@include "$2" >> /tmp/ig.s.$$
+    -[W-]file)
+            program="$program$n@@include address@hidden'missing operand'@}"
             shift;;
 
-    -?source=*)  # -Wsource or --source
-            t=`echo "$1" | sed 's/-.source=//'`
-            echo "$t" >> /tmp/ig.s.$$ ;;
+    -[W-]source=*)
+            t=`expr "$1" : '-.source=\(.*\)'`
+            program="$program$n$t";;
 
-    -?source)    # get arg, $2
-            echo "$2" >> /tmp/ig.s.$$
+    -[W-]source)
+            program="address@hidden'missing operand'@}"
             shift;;
 
-    -?version)
+    -[W-]version)
             echo igawk: version 1.0 1>&2
             gawk --version
             exit 0 ;;
@@ -20477,21 +20470,13 @@ do
     shift
 done
 
-if [ ! -s /tmp/ig.s.$$ ]
+if [ -z "$program" ]
 then
address@hidden
-    if [ -z "$1" ]
-    then
-         echo igawk: no program! 1>&2
-         exit 1
address@hidden group
-    else
-        echo "$1" > /tmp/ig.s.$$
-        shift
-    fi
+     address@hidden'missing program'@}
+     shift
 fi
 
-# at this point, /tmp/ig.s.$$ has the program
+# At this point, 'program' has the program.
 @c endfile
 @end example
 
@@ -20530,8 +20515,7 @@ slower.
 
 @example
 @c file eg/prog/igawk.sh
-gawk -- '
-# process @@include directives
+process_include_directives='
 
 function pathto(file,    i, t, junk)
 @{
@@ -20570,7 +20554,7 @@ BEGIN @{
 @c endfile
 @end example
 
-The stack is initialized with @code{ARGV[1]}, which will be 
@file{/tmp/ig.s.$$}.
+The stack is initialized with @code{ARGV[1]}, which will be @file{/dev/stdin}.
 The main loop comes next.  Input lines are read in succession. Lines that
 do not start with @samp{@@include} are printed verbatim.
 If the line does start with @samp{@@include}, the @value{FN} is in @code{$2}.
@@ -20616,14 +20600,21 @@ the program is done:
         @}
         close(input[stackptr])
     @}
address@hidden' /tmp/ig.s.$$ > /tmp/ig.e.$$
address@hidden'
+
+processed_program=`gawk -- "$process_include_directives" /dev/stdin <<EOF
+$program
+EOF
+`
 @c endfile
 @end example
 
 The last step is to call @command{gawk} with the expanded program,
 along with the original
-options and command-line arguments that the user supplied.  @command{gawk}'s
-exit status is passed back on to @command{igawk}'s calling program:
+options and command-line arguments that the user supplied.
+The @address@hidden"$@@"@}} construct expands to the remaining arguments;
+it is equivalent to @code{"$@@"} but works around a common bug in
+older shells.
 
 @c this causes more problems than it solves, so leave it out.
 @ignore
@@ -20642,13 +20633,11 @@ end of file indication.
 
 @example
 @c file eg/prog/igawk.sh
-eval gawk -f /tmp/ig.e.$$ $opts -- "$@@"
-
-exit $?
+eval gawk $opts -- '"$processed_program"' 'address@hidden"$@@"@}'
 @c endfile
 @end example
 
-This version of @command{igawk} represents my third attempt at this program.
+This version of @command{igawk} represents my fourth attempt at this program.
 There are three key simplifications that make the program work better:
 
 @itemize @bullet
@@ -20668,6 +20657,10 @@ this line for use with the main program 
 Using a @code{getline} loop in the @code{BEGIN} rule does it all in one
 place.  It is not necessary to call out to a separate loop for processing
 nested @samp{@@include} statements.
+
address@hidden
+Instead of saving the program in a temporary file, put it in a shell variable.
+This avoids some potential security problems.
 @end itemize
 
 Also, this program illustrates that it is often worthwhile to combine



reply via email to

[Prev in Thread] Current Thread [Next in Thread]