Description: fix use-after-free via posix_spawn_file_actions_addopen
 failing to copy the path argument
Origin: backport, https://sourceware.org/git/?p=glibc.git;h=89e435f3559c53084498e9baad22172b64429362
Origin: backport, https://sourceware.org/git/?p=glibc.git;h=35a5e3e338ae17f3d42c60a708763c5d498fb840
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=17048
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=751774

Index: eglibc-2.19/posix/spawn_faction_addopen.c
===================================================================
--- eglibc-2.19.orig/posix/spawn_faction_addopen.c	2014-01-03 12:51:28.000000000 -0500
+++ eglibc-2.19/posix/spawn_faction_addopen.c	2014-07-25 08:52:06.166911382 -0400
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <spawn.h>
 #include <unistd.h>
+#include <string.h>
 
 #include "spawn_int.h"
 
@@ -35,17 +36,24 @@
   if (fd < 0 || fd >= maxfd)
     return EBADF;
 
+  char *path_copy = strdup (path);
+  if (path_copy == NULL)
+    return ENOMEM;
+
   /* Allocate more memory if needed.  */
   if (file_actions->__used == file_actions->__allocated
       && __posix_spawn_file_actions_realloc (file_actions) != 0)
-    /* This can only mean we ran out of memory.  */
-    return ENOMEM;
+    {
+      /* This can only mean we ran out of memory.  */
+      free (path_copy);
+      return ENOMEM;
+    }
 
   /* Add the new value.  */
   rec = &file_actions->__actions[file_actions->__used];
   rec->tag = spawn_do_open;
   rec->action.open_action.fd = fd;
-  rec->action.open_action.path = path;
+  rec->action.open_action.path = path_copy;
   rec->action.open_action.oflag = oflag;
   rec->action.open_action.mode = mode;
 
Index: eglibc-2.19/posix/spawn_faction_destroy.c
===================================================================
--- eglibc-2.19.orig/posix/spawn_faction_destroy.c	2014-01-03 12:51:28.000000000 -0500
+++ eglibc-2.19/posix/spawn_faction_destroy.c	2014-07-25 08:52:01.954911403 -0400
@@ -18,11 +18,29 @@
 #include <spawn.h>
 #include <stdlib.h>
 
-/* Initialize data structure for file attribute for `spawn' call.  */
+#include "spawn_int.h"
+
+/* Deallocate the file actions.  */
 int
 posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions)
 {
-  /* Free the memory allocated.  */
+  /* Free the paths in the open actions.  */
+  for (int i = 0; i < file_actions->__used; ++i)
+    {
+      struct __spawn_action *sa = &file_actions->__actions[i];
+      switch (sa->tag)
+	{
+	case spawn_do_open:
+	  free (sa->action.open_action.path);
+	  break;
+	case spawn_do_close:
+	case spawn_do_dup2:
+	  /* No cleanup required.  */
+	  break;
+	}
+    }
+
+  /* Free the array of actions.  */
   free (file_actions->__actions);
   return 0;
 }
Index: eglibc-2.19/posix/spawn_int.h
===================================================================
--- eglibc-2.19.orig/posix/spawn_int.h	2011-09-06 11:08:18.000000000 -0400
+++ eglibc-2.19/posix/spawn_int.h	2014-07-25 08:52:01.954911403 -0400
@@ -22,7 +22,7 @@
     struct
     {
       int fd;
-      const char *path;
+      char *path;
       int oflag;
       mode_t mode;
     } open_action;
Index: eglibc-2.19/posix/tst-spawn.c
===================================================================
--- eglibc-2.19.orig/posix/tst-spawn.c	2014-01-03 12:51:28.000000000 -0500
+++ eglibc-2.19/posix/tst-spawn.c	2014-07-25 08:52:01.954911403 -0400
@@ -168,6 +168,7 @@
   char fd2name[18];
   char fd3name[18];
   char fd4name[18];
+  char *name3_copy;
   char *spargv[12];
   int i;
 
@@ -222,9 +223,15 @@
    if (posix_spawn_file_actions_addclose (&actions, fd1) != 0)
      error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addclose");
    /* We want to open the third file.  */
-   if (posix_spawn_file_actions_addopen (&actions, fd3, name3,
+   name3_copy = strdup (name3);
+   if (name3_copy == NULL)
+     error (EXIT_FAILURE, errno, "strdup");
+   if (posix_spawn_file_actions_addopen (&actions, fd3, name3_copy,
 					 O_RDONLY, 0666) != 0)
      error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addopen");
+   /* Overwrite the name to check that a copy has been made.  */
+   memset (name3_copy, 'X', strlen (name3_copy));
+
    /* We dup the second descriptor.  */
    fd4 = MAX (2, MAX (fd1, MAX (fd2, fd3))) + 1;
    if (posix_spawn_file_actions_adddup2 (&actions, fd2, fd4) != 0)
@@ -253,6 +260,7 @@
    /* Cleanup.  */
    if (posix_spawn_file_actions_destroy (&actions) != 0)
      error (EXIT_FAILURE, errno, "posix_spawn_file_actions_destroy");
+   free (name3_copy);
 
   /* Wait for the child.  */
   if (waitpid (pid, &status, 0) != pid)
