posix_spawn_file_actions_addopen: Fix possible use-after-free bug.
authorBruno Haible <bruno@clisp.org>
Mon, 10 Jun 2019 14:50:04 +0000 (16:50 +0200)
committerBruno Haible <bruno@clisp.org>
Mon, 10 Jun 2019 15:24:58 +0000 (17:24 +0200)
Reported at <https://sourceware.org/bugzilla/show_bug.cgi?id=17048>.

* lib/spawn_int.h (struct __spawn_action): Remove 'const' from path.
* lib/spawn_faction_addopen.c (posix_spawn_file_actions_addopen): Make
a copy of the path argument.
* lib/spawn_faction_destroy.c (posix_spawn_file_actions_destroy): Free
it.

ChangeLog
lib/spawn_faction_addopen.c
lib/spawn_faction_destroy.c
lib/spawn_int.h

index 7bbf5fafc076d8685c22af65b2e1cdac7b7beb46..16f720d7900b705a7fe081a05a458d6fd211342d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2019-06-10  Bruno Haible  <bruno@clisp.org>
+
+       posix_spawn_file_actions_addopen: Fix possible use-after-free bug.
+       Reported at <https://sourceware.org/bugzilla/show_bug.cgi?id=17048>.
+       * lib/spawn_int.h (struct __spawn_action): Remove 'const' from path.
+       * lib/spawn_faction_addopen.c (posix_spawn_file_actions_addopen): Make
+       a copy of the path argument.
+       * lib/spawn_faction_destroy.c (posix_spawn_file_actions_destroy): Free
+       it.
+
 2019-06-10  Bruno Haible  <bruno@clisp.org>
 
        posix_spawn_file_actions_addfchdir: Add tests.
index 6b4422fd127554afc8ac876fc8e59cf448b2eae4..ab4f727f338c48879e4ea55ac13a85e20986d908 100644 (file)
@@ -20,6 +20,8 @@
 #include <spawn.h>
 
 #include <errno.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #if !_LIBC
@@ -47,27 +49,38 @@ posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions,
 #if !REPLACE_POSIX_SPAWN
   return posix_spawn_file_actions_addopen (file_actions, fd, path, oflag, mode);
 #else
-  /* 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;
-
   {
-    struct __spawn_action *rec;
+    /* Copy PATH, because the caller may free it before calling posix_spawn()
+       or posix_spawnp().  */
+    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.  */
+        free (path_copy);
+        return ENOMEM;
+      }
+
+    {
+      struct __spawn_action *rec;
 
-    /* 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.oflag = oflag;
-    rec->action.open_action.mode = mode;
+      /* 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_copy;
+      rec->action.open_action.oflag = oflag;
+      rec->action.open_action.mode = mode;
 
-    /* Account for the new entry.  */
-    ++file_actions->_used;
+      /* Account for the new entry.  */
+      ++file_actions->_used;
 
-    return 0;
+      return 0;
+    }
   }
 #endif
 }
index 6d9ec800f251eef2319bb7e0b350c3a251986e6d..0640da483f7fd85be6bf9674bc7be6ef13b41c1e 100644 (file)
 
 #include <stdlib.h>
 
+#if REPLACE_POSIX_SPAWN
+# include "spawn_int.h"
+#endif
+
 /* Initialize data structure for file attribute for 'spawn' call.  */
 int
 posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions)
+#undef posix_spawn_file_actions_destroy
 {
-  /* Free the memory allocated.  */
+#if !REPLACE_POSIX_SPAWN
+  return posix_spawn_file_actions_destroy (file_actions);
+#else
+  int i;
+
+  /* Free the paths in the open actions.  */
+  for (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;
+        default:
+          /* No cleanup required.  */
+          break;
+        }
+    }
+
+  /* Free the array of actions.  */
   free (file_actions->_actions);
+
   return 0;
+#endif
 }
index 584c1bbcc3f8bf9372ffb2b60c9790d3ce110b99..08c477a9cbee3182a8627e0428d917a85839c05c 100644 (file)
@@ -42,7 +42,7 @@ struct __spawn_action
     struct
     {
       int fd;
-      const char *path;
+      char *path;
       int oflag;
       mode_t mode;
     } open_action;