> This has been changed deliberately, otherwise
> the execp functions have a potential security problem.  If you omit the
> NNF flag, the function returns the original path unchanged, instead of
> NULL.

I see that my conjecture about the root cause of the observed inconsistency was 
incorrect.  But my conjecture was only secondary to the patch.  The conjecture 
was about spawnvpe() succeeding where execvp() failed.  Your answer means that 
spawnvpe() should also call find_exec() with the extra 2 parameters, "PATH=" 
and FE_NNF.

Is my primary concern still valid?  I.e., should execvp..()/spawnvp..() succeed 
in executing backslash notation of relative and absolute paths?  If these 
inputs should be allowed, did my patch address the issue correctly?

I agree that a basename-only path should not resolve against current directory 
according to the execvp..() specs.  I believe the relative and absolute paths 
are allowed to resolve.

-- 
Index: spawn.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/spawn.cc,v
retrieving revision 1.288
diff -u -r1.288 spawn.cc
--- spawn.cc    25 Jan 2010 11:21:56 -0000      1.288
+++ spawn.cc    9 Mar 2010 00:20:54 -0000
@@ -112,15 +112,16 @@
   char *tmp = tp.c_get ();
   const char *posix = (opt & FE_NATIVE) ? NULL : name;
   bool has_slash = strchr (name, '/');
+  bool has_backslash = strchr (name, '\\');
   int err;
 
   /* Check to see if file can be opened as is first.
      Win32 systems always check . first, but PATH may not be set up to
      do this. */
-  if ((has_slash || opt & FE_CWD)
+  if ((has_slash || has_backslash || opt & FE_CWD)
       && (suffix = perhaps_suffix (name, buf, err, opt)) != NULL)
     {
-      if (posix && !has_slash)
+      if (posix && !has_slash && !has_backslash)
        {
          tmp[0] = '.';
          tmp[1] = '/';
@@ -147,7 +148,7 @@
       path = s;
       posix_path = mywinenv - 1;
     }
-  else if (has_slash || strchr (name, '\\') || isdrive (name)
+  else if (has_slash || has_backslash || isdrive (name)
       || !(winpath = getwinenv (mywinenv))
       || !(path = winpath->get_native ()) || *path == '\0')
     /* Return the error condition if this is an absolute path or if there
#include <process.h>    // for spawnvpe() (not specified by The Open Group)
#include <unistd.h>     // for execvp()
#include <stdio.h>      // for printf()
#include <errno.h>      // for errno
#include <string.h>     // for strdup(), strerror()
#include <stdlib.h>     // for getenv()

int
main (int argc, const char *argv[])
{
    const char const *args[3];
    char *mutable_args[3];
    // See http://c-faq.com/ansi/constmismatch.html explaining that a promise
    // of constness of values pointed to by pointer elements requires constness
    // of pointers as well.  In other words, a const char** parameter cannot
    // accept a char ** argument.
    const char *envp[2];
    const char *pathvalue = NULL;
    char *pathenv = NULL;
    int ec;

    if ( argc < 2 ) {
        return 2;
    }
 
    args[ 0 ] = argv[1];
    args[ 1 ] = "abc";
    args[ 2 ] = NULL;

    mutable_args[ 0 ] = strdup( args[ 0 ] );
    mutable_args[ 1 ] = strdup( args[ 1 ] );
    mutable_args[ 2 ] = NULL;

    pathvalue = getenv( "PATH" );
    if (pathvalue) {
        int pathlen = strlen( pathvalue );
        pathenv = malloc( 5 + pathlen + 1 );
        if ( pathenv ) {
            memcpy( pathenv, "PATH=", 5 );
            memcpy( pathenv + 5, pathvalue, pathlen + 1 );
        }
    }
    envp[ 0 ] = pathenv;
    envp[ 1 ] = NULL;

    setbuf( stdout, NULL );
    setbuf( stderr, NULL );

    printf( "Spawning %s with search in $PATH and a limited environment...\n", 
args[ 0 ] );
    ec = spawnvpe( _P_WAIT, args[ 0 ], args, envp );
    printf( "Exit code: %d\n\n", ec );

    printf( "Loading %s with search in $PATH and inherited environment...\n", 
args[ 0 ] );
    // The prototype in unistd.h differs from the one in process.h.  The former
    // does not promise to keep the pointers intact.
    execvp( args[ 0 ], mutable_args );
    ec = errno;
    printf( "Load error: %s (%d)\n", strerror( ec ), ec );
    return ec;
}

C:\WORK>.\exec.exe ..\echo.exe
Spawning ..\echo.exe with search in $PATH and a limited environment...
abc
Exit code: 0

Loading ..\echo.exe with search in $PATH and inherited environment...
Load error: No such file or directory (2)

C:\WORK>copy \cygwin\bin\cygwin1.dll.new \cygwin\bin\cygwin1.dll
Overwrite \cygwin\bin\cygwin1.dll? (Yes/No/All): y
        1 file(s) copied.

C:\WORK>.\exec.exe ..\echo.exe
Spawning ..\echo.exe with search in $PATH and a limited environment...
abc
Exit code: 0

Loading ..\echo.exe with search in $PATH and inherited environment...
abc

C:\WORK>

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

Reply via email to