This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

libiberty/pex-unix vfork abuse?


    Hey all,

  This is what posix says about vfork:

http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html
"The vfork() function shall be equivalent to fork(), except that the behavior
is undefined if the process created by vfork() either modifies any data other
than a variable of type pid_t used to store the return value from vfork(), or
returns from the function in which vfork() was called, or calls any other
function before successfully calling _exit() or one of the exec family of
functions."

  This is how pex-unix.c uses vfork:

static long
pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
		     char * const * argv, char * const * env,
                     int in, int out, int errdes,
		     int toclose, const char **errmsg, int *err)
{
  pid_t pid;

  /* We declare these to be volatile to avoid warnings from gcc about
     them being clobbered by vfork.  */
  volatile int sleep_interval;
  volatile int retries;

  sleep_interval = 1;
  pid = -1;
  for (retries = 0; retries < 4; ++retries)
    {
      pid = vfork ();
      if (pid >= 0)
	break;
      sleep (sleep_interval);
      sleep_interval *= 2;
    }

  switch (pid)
    {
    case -1:
      *err = errno;
      *errmsg = VFORK_STRING;
      return -1;

    case 0:
      /* Child process.  */
      if (in != STDIN_FILE_NO)
	{
	  if (dup2 (in, STDIN_FILE_NO) < 0)
	    pex_child_error (obj, executable, "dup2", errno);
	  if (close (in) < 0)
	    pex_child_error (obj, executable, "close", errno);
	}
      if (out != STDOUT_FILE_NO)
	{
	  if (dup2 (out, STDOUT_FILE_NO) < 0)
	    pex_child_error (obj, executable, "dup2", errno);
	  if (close (out) < 0)
	    pex_child_error (obj, executable, "close", errno);
	}
      if (errdes != STDERR_FILE_NO)
	{
	  if (dup2 (errdes, STDERR_FILE_NO) < 0)
	    pex_child_error (obj, executable, "dup2", errno);
	  if (close (errdes) < 0)
	    pex_child_error (obj, executable, "close", errno);
	}
      if (toclose >= 0)
	{
	  if (close (toclose) < 0)
	    pex_child_error (obj, executable, "close", errno);
	}
      if ((flags & PEX_STDERR_TO_STDOUT) != 0)
	{
	  if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
	    pex_child_error (obj, executable, "dup2", errno);
	}

      if (env)
        environ = (char**) env;

      if ((flags & PEX_SEARCH) != 0)
	{
	  execvp (executable, argv);
	  pex_child_error (obj, executable, "execvp", errno);
	}
      else
	{
	  execv (executable, argv);
	  pex_child_error (obj, executable, "execv", errno);
	}



  Note the several calls to dup2() and close(), which seem to me to be "calls
[to] any other function", and the setting of environ, which seem to me to be
modification of "any data other than a variable of type pid_t used to store
the return value from vfork()".  The comment on pex_child_error (which uses
write() to do output) gives a hint at the thinking here:


/* Report an error from a child process.  We don't use stdio routines,
   because we might be here due to a vfork call.  */

static void
pex_child_error (struct pex_obj *obj, const char *executable,
		 const char *errmsg, int err)
{
#define writeerr(s) (void) write (STDERR_FILE_NO, s, strlen (s))
  writeerr (obj->pname);


  But I don't see any reason to assume the restriction only applies to f*()
stdio functions, in fact by my reading I don't think you're [technically] even
allowed to call a pure const inline function that's part of your own code.  (I
assume that that would in fact work ok in practice at least most of the time).

  Are we ok here?  This code seems like it's doing the wrong thing to me.  As
far as I can tell, we only get away with this in cygwin because of paranoid
defensive programming that backs up the fd table before running the vfork'd
child's code in the parent's context up to the first exec*() call, and then
restores it afterward, but I'm fairly sure that this implementation will still
overwrite the parent's environment.... which could well be Not A Good Thing!


    cheers,
      DaveK
-- 
Can't think of a witty .sigline today....


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]