bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
* posix_spawn fixes
@ 2019-06-10 15:29 Bruno Haible
  0 siblings, 0 replies; only message in thread
From: Bruno Haible @ 2019-06-10 15:29 UTC (permalink / raw)
  To: bug-gnulib

[-- Attachment #1: Type: text/plain, Size: 2693 bytes --]

2019-06-10  Bruno Haible  <bruno@clisp.org>

	doc: Document existence of posix_spawn_file_actions_addchdir module.
	* doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi: Mention
	the posix_spawn_file_actions_addchdir module.

2019-06-10  Bruno Haible  <bruno@clisp.org>

	posix_spawn_file_actions_addfchdir: New module.
	* lib/spawn.in.h (posix_spawn_file_actions_addfchdir): New declaration.
	* lib/spawn_int.h (struct __spawn_action): Add tag 'spawn_do_fchdir' and
	union member 'fchdir_action'.
	* lib/spawn_faction_addfchdir.c: New file.
	* lib/spawni.c (__spawni): Implement the spawn_do_fchdir action.
	* m4/posix_spawn_faction_addfchdir.m4: New file.
	* m4/posix_spawn.m4 (gl_POSIX_SPAWN_BODY): Test whether module
	'posix_spawn_file_actions_addfchdir' is present and whether
	posix_spawn_file_actions_addfchdir_np exists. Set REPLACE_POSIX_SPAWN.
	* m4/spawn_h.m4 (gl_SPAWN_H): Test whether
	posix_spawn_file_actions_addfchdir is declared.
	(gl_SPAWN_H_DEFAULTS): Initialize
	GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
	HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
	REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR.
	* modules/spawn (Makefile.am): Substitute
	GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
	HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
	REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR.
	* modules/posix_spawn_file_actions_addfchdir: New file.
	* tests/test-spawn-c++.cc (posix_spawn_file_actions_addfchdir): Check
	signature.
	* doc/posix-functions/posix_spawn.texi: Mention the new module.
	* doc/posix-functions/posix_spawnp.texi: Likewise.
	* doc/glibc-functions/posix_spawn_file_actions_addfchdir_np.texi:
	Likewise.

2019-06-10  Bruno Haible  <bruno@clisp.org>

	posix_spawn_file_actions_addfchdir: Add tests.
	* tests/test-posix_spawn_file_actions_addfchdir.c: New file.
	* tests/test-posix_spawn5.c: New file.
	* modules/posix_spawn_file_actions_addfchdir-tests: New file.

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_addchdir: Fix possible use-after-free bug.
	* lib/spawn_int.h (struct __spawn_action): Remove 'const' from path.
	* lib/spawn_faction_addchdir.c (posix_spawn_file_actions_addchdir): Make
	a copy of the path argument.
	* lib/spawn_faction_destroy.c (posix_spawn_file_actions_destroy): Free
	it.


[-- Attachment #2: 0001-doc-Document-existence-of-posix_spawn_file_actions_a.patch --]
[-- Type: text/x-patch, Size: 1866 bytes --]

From 2ad7a33b829d0378fb6765e778e4170a3fec9697 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Mon, 10 Jun 2019 16:26:03 +0200
Subject: [PATCH 1/5] doc: Document existence of
 posix_spawn_file_actions_addchdir module.

* doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi: Mention
the posix_spawn_file_actions_addchdir module.
---
 ChangeLog                                                     | 6 ++++++
 doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index d1b8854..ac79aac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2019-06-10  Bruno Haible  <bruno@clisp.org>
 
+	doc: Document existence of posix_spawn_file_actions_addchdir module.
+	* doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi: Mention
+	the posix_spawn_file_actions_addchdir module.
+
+2019-06-10  Bruno Haible  <bruno@clisp.org>
+
 	posix_spawn-internal: Fix module description.
 	* modules/posix_spawn (configure.ac): Move request to compile spawni.c
 	from here...
diff --git a/doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi b/doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi
index a40a3d7..1c4c0a4 100644
--- a/doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi
+++ b/doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi
@@ -14,3 +14,6 @@ Portability problems not fixed by Gnulib:
 This function is missing on many non-glibc platforms:
 glibc 2.28, Mac OS X 10.5, FreeBSD 12.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.0, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
 @end itemize
+
+Note: Gnulib has a module @code{posix_spawn_file_actions_addchdir} that
+provides equivalent functionality, just without the suffix @code{_np}.
-- 
2.7.4


[-- Attachment #3: 0002-posix_spawn_file_actions_addfchdir-New-module.patch --]
[-- Type: text/x-patch, Size: 24402 bytes --]

From d822de87e4d1c97e422e48332542dfe7261c7d82 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Mon, 10 Jun 2019 16:16:16 +0200
Subject: [PATCH 2/5] posix_spawn_file_actions_addfchdir: New module.

* lib/spawn.in.h (posix_spawn_file_actions_addfchdir): New declaration.
* lib/spawn_int.h (struct __spawn_action): Add tag 'spawn_do_fchdir' and
union member 'fchdir_action'.
* lib/spawn_faction_addfchdir.c: New file.
* lib/spawni.c (__spawni): Implement the spawn_do_fchdir action.
* m4/posix_spawn_faction_addfchdir.m4: New file.
* m4/posix_spawn.m4 (gl_POSIX_SPAWN_BODY): Test whether module
'posix_spawn_file_actions_addfchdir' is present and whether
posix_spawn_file_actions_addfchdir_np exists. Set REPLACE_POSIX_SPAWN.
* m4/spawn_h.m4 (gl_SPAWN_H): Test whether
posix_spawn_file_actions_addfchdir is declared.
(gl_SPAWN_H_DEFAULTS): Initialize
GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR.
* modules/spawn (Makefile.am): Substitute
GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR.
* modules/posix_spawn_file_actions_addfchdir: New file.
* tests/test-spawn-c++.cc (posix_spawn_file_actions_addfchdir): Check
signature.
* doc/posix-functions/posix_spawn.texi: Mention the new module.
* doc/posix-functions/posix_spawnp.texi: Likewise.
* doc/glibc-functions/posix_spawn_file_actions_addfchdir_np.texi:
Likewise.
---
 ChangeLog                                          | 30 ++++++++++
 .../posix_spawn_file_actions_addfchdir_np.texi     |  3 +
 doc/posix-functions/posix_spawn.texi               |  7 ++-
 doc/posix-functions/posix_spawnp.texi              |  7 ++-
 lib/spawn.in.h                                     | 35 +++++++++++
 lib/spawn_faction_addfchdir.c                      | 68 ++++++++++++++++++++++
 lib/spawn_int.h                                    |  7 ++-
 lib/spawni.c                                       |  6 ++
 m4/posix_spawn.m4                                  | 11 +++-
 m4/posix_spawn_faction_addfchdir.m4                | 20 +++++++
 m4/spawn_h.m4                                      | 54 +++++++++--------
 modules/posix_spawn_file_actions_addfchdir         | 30 ++++++++++
 modules/spawn                                      |  3 +
 tests/test-spawn-c++.cc                            |  5 ++
 14 files changed, 254 insertions(+), 32 deletions(-)
 create mode 100644 lib/spawn_faction_addfchdir.c
 create mode 100644 m4/posix_spawn_faction_addfchdir.m4
 create mode 100644 modules/posix_spawn_file_actions_addfchdir

diff --git a/ChangeLog b/ChangeLog
index ac79aac..ecf1d47 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
 2019-06-10  Bruno Haible  <bruno@clisp.org>
 
+	posix_spawn_file_actions_addfchdir: New module.
+	* lib/spawn.in.h (posix_spawn_file_actions_addfchdir): New declaration.
+	* lib/spawn_int.h (struct __spawn_action): Add tag 'spawn_do_fchdir' and
+	union member 'fchdir_action'.
+	* lib/spawn_faction_addfchdir.c: New file.
+	* lib/spawni.c (__spawni): Implement the spawn_do_fchdir action.
+	* m4/posix_spawn_faction_addfchdir.m4: New file.
+	* m4/posix_spawn.m4 (gl_POSIX_SPAWN_BODY): Test whether module
+	'posix_spawn_file_actions_addfchdir' is present and whether
+	posix_spawn_file_actions_addfchdir_np exists. Set REPLACE_POSIX_SPAWN.
+	* m4/spawn_h.m4 (gl_SPAWN_H): Test whether
+	posix_spawn_file_actions_addfchdir is declared.
+	(gl_SPAWN_H_DEFAULTS): Initialize
+	GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
+	HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
+	REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR.
+	* modules/spawn (Makefile.am): Substitute
+	GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
+	HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR,
+	REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR.
+	* modules/posix_spawn_file_actions_addfchdir: New file.
+	* tests/test-spawn-c++.cc (posix_spawn_file_actions_addfchdir): Check
+	signature.
+	* doc/posix-functions/posix_spawn.texi: Mention the new module.
+	* doc/posix-functions/posix_spawnp.texi: Likewise.
+	* doc/glibc-functions/posix_spawn_file_actions_addfchdir_np.texi:
+	Likewise.
+
+2019-06-10  Bruno Haible  <bruno@clisp.org>
+
 	doc: Document existence of posix_spawn_file_actions_addchdir module.
 	* doc/glibc-functions/posix_spawn_file_actions_addchdir_np.texi: Mention
 	the posix_spawn_file_actions_addchdir module.
diff --git a/doc/glibc-functions/posix_spawn_file_actions_addfchdir_np.texi b/doc/glibc-functions/posix_spawn_file_actions_addfchdir_np.texi
index bb82195..6da90fd 100644
--- a/doc/glibc-functions/posix_spawn_file_actions_addfchdir_np.texi
+++ b/doc/glibc-functions/posix_spawn_file_actions_addfchdir_np.texi
@@ -14,3 +14,6 @@ Portability problems not fixed by Gnulib:
 This function is missing on all non-glibc platforms:
 glibc 2.28, Mac OS X 10.5, FreeBSD 12.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, OSF/1 5.1, Solaris 11.4, Cygwin, mingw, MSVC 14, Interix 3.5, BeOS, Android 9.0.
 @end itemize
+
+Note: Gnulib has a module @code{posix_spawn_file_actions_addfchdir} that
+provides equivalent functionality, just without the suffix @code{_np}.
diff --git a/doc/posix-functions/posix_spawn.texi b/doc/posix-functions/posix_spawn.texi
index bed0e79..6513608 100644
--- a/doc/posix-functions/posix_spawn.texi
+++ b/doc/posix-functions/posix_spawn.texi
@@ -24,6 +24,7 @@ This function does not work on some platforms:
 AIX 6.1 (under particular circumstances), mingw.
 @end itemize
 
-The Gnulib module @code{posix_spawn_file_actions_addchdir} provides an
-additional action, that consists in changing the current directory of
-the child process before starting the specified program.
+The Gnulib modules @code{posix_spawn_file_actions_addchdir} and
+@code{posix_spawn_file_actions_addfchdir} provide additional actions,
+that consist in changing the current directory of the child process
+before starting the specified program.
diff --git a/doc/posix-functions/posix_spawnp.texi b/doc/posix-functions/posix_spawnp.texi
index 6cfec28..3dd8ed4 100644
--- a/doc/posix-functions/posix_spawnp.texi
+++ b/doc/posix-functions/posix_spawnp.texi
@@ -24,6 +24,7 @@ This function does not work on some platforms:
 AIX 6.1 (under particular circumstances), mingw.
 @end itemize
 
-The Gnulib module @code{posix_spawn_file_actions_addchdir} provides an
-additional action, that consists in changing the current directory of
-the child process before starting the specified program.
+The Gnulib modules @code{posix_spawn_file_actions_addchdir} and
+@code{posix_spawn_file_actions_addfchdir} provide additional actions,
+that consist in changing the current directory of the child process
+before starting the specified program.
diff --git a/lib/spawn.in.h b/lib/spawn.in.h
index df95e4a..721d70f 100644
--- a/lib/spawn.in.h
+++ b/lib/spawn.in.h
@@ -913,6 +913,41 @@ _GL_WARN_ON_USE (posix_spawn_file_actions_addchdir,
 # endif
 #endif
 
+#if @GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR@
+/* Add an action to FILE-ACTIONS which tells the implementation to call
+   'fchdir' to the given directory during the 'spawn' call.  */
+# if @REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   define posix_spawn_file_actions_addfchdir rpl_posix_spawn_file_actions_addfchdir
+#  endif
+_GL_FUNCDECL_RPL (posix_spawn_file_actions_addfchdir, int,
+                  (posix_spawn_file_actions_t *_Restrict_ __file_actions,
+                   int __fd)
+                  __THROW _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (posix_spawn_file_actions_addfchdir, int,
+                  (posix_spawn_file_actions_t *_Restrict_ __file_actions,
+                   int __fd));
+# else
+#  if !@HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR@
+_GL_FUNCDECL_SYS (posix_spawn_file_actions_addfchdir, int,
+                  (posix_spawn_file_actions_t *_Restrict_ __file_actions,
+                   int __fd)
+                  __THROW _GL_ARG_NONNULL ((1)));
+#  endif
+_GL_CXXALIAS_SYS (posix_spawn_file_actions_addfchdir, int,
+                  (posix_spawn_file_actions_t *_Restrict_ __file_actions,
+                   int __fd));
+# endif
+_GL_CXXALIASWARN (posix_spawn_file_actions_addfchdir);
+#elif defined GNULIB_POSIXCHECK
+# undef posix_spawn_file_actions_addfchdir
+# if HAVE_RAW_DECL_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR
+_GL_WARN_ON_USE (posix_spawn_file_actions_addfchdir,
+                 "posix_spawn_file_actions_addfchdir is unportable - "
+                 "use gnulib module posix_spawn_file_actions_addfchdir for portability");
+# endif
+#endif
+
 
 #endif /* _@GUARD_PREFIX@_SPAWN_H */
 #endif /* _@GUARD_PREFIX@_SPAWN_H */
diff --git a/lib/spawn_faction_addfchdir.c b/lib/spawn_faction_addfchdir.c
new file mode 100644
index 0000000..504856d
--- /dev/null
+++ b/lib/spawn_faction_addfchdir.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2018-2019 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <spawn.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#if !_LIBC
+# define __sysconf(open_max) getdtablesize ()
+#endif
+
+#if REPLACE_POSIX_SPAWN
+# include "spawn_int.h"
+#endif
+
+/* Add an action to FILE-ACTIONS which tells the implementation to call
+   'fchdir' to the given directory during the 'spawn' call.  */
+int
+posix_spawn_file_actions_addfchdir (posix_spawn_file_actions_t *file_actions,
+                                    int fd)
+#undef posix_spawn_file_actions_addfchdir
+{
+  int maxfd = __sysconf (_SC_OPEN_MAX);
+
+  /* Test for the validity of the file descriptor.  */
+  if (fd < 0 || fd >= maxfd)
+    return EBADF;
+
+#if !REPLACE_POSIX_SPAWN
+  return posix_spawn_file_actions_addfchdir_np (file_actions, fd);
+#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;
+
+    /* Add the new value.  */
+    rec = &file_actions->_actions[file_actions->_used];
+    rec->tag = spawn_do_fchdir;
+    rec->action.fchdir_action.fd = fd;
+
+    /* Account for the new entry.  */
+    ++file_actions->_used;
+
+    return 0;
+  }
+#endif
+}
diff --git a/lib/spawn_int.h b/lib/spawn_int.h
index 06b8004..584c1bb 100644
--- a/lib/spawn_int.h
+++ b/lib/spawn_int.h
@@ -24,7 +24,8 @@ struct __spawn_action
     spawn_do_close,
     spawn_do_dup2,
     spawn_do_open,
-    spawn_do_chdir
+    spawn_do_chdir,
+    spawn_do_fchdir
   } tag;
 
   union
@@ -49,6 +50,10 @@ struct __spawn_action
     {
       const char *path;
     } chdir_action;
+    struct
+    {
+      int fd;
+    } fchdir_action;
   } action;
 };
 
diff --git a/lib/spawni.c b/lib/spawni.c
index 39e99a0..087f45c 100644
--- a/lib/spawni.c
+++ b/lib/spawni.c
@@ -290,6 +290,12 @@ __spawni (pid_t *pid, const char *file,
                 /* The 'chdir' call failed.  */
                 _exit (SPAWN_ERROR);
               break;
+
+            case spawn_do_fchdir:
+              if (fchdir (action->action.fchdir_action.fd) < 0)
+                /* The 'fchdir' call failed.  */
+                _exit (SPAWN_ERROR);
+              break;
             }
         }
     }
diff --git a/m4/posix_spawn.m4 b/m4/posix_spawn.m4
index d50dcc9..0128390 100644
--- a/m4/posix_spawn.m4
+++ b/m4/posix_spawn.m4
@@ -1,4 +1,4 @@
-# posix_spawn.m4 serial 16
+# posix_spawn.m4 serial 17
 dnl Copyright (C) 2008-2019 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -42,6 +42,15 @@ AC_DEFUN([gl_POSIX_SPAWN_BODY],
          REPLACE_POSIX_SPAWN=1
        fi
       ])
+    m4_ifdef([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR],
+      [dnl Module 'posix_spawn_file_actions_addfchdir' is present.
+       AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_addfchdir_np])
+       if test $ac_cv_func_posix_spawn_file_actions_addfchdir_np = no; then
+         dnl In order to implement the posix_spawn_file_actions_addfchdir
+         dnl function, we need to replace the entire posix_spawn facility.
+         REPLACE_POSIX_SPAWN=1
+       fi
+      ])
     if test $REPLACE_POSIX_SPAWN = 0; then
       gl_POSIX_SPAWN_WORKS
       case "$gl_cv_func_posix_spawn_works" in
diff --git a/m4/posix_spawn_faction_addfchdir.m4 b/m4/posix_spawn_faction_addfchdir.m4
new file mode 100644
index 0000000..ef2f9d6
--- /dev/null
+++ b/m4/posix_spawn_faction_addfchdir.m4
@@ -0,0 +1,20 @@
+# posix_spawn_faction_addfchdir.m4 serial 1
+dnl Copyright (C) 2018-2019 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR],
+[
+  AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
+  AC_REQUIRE([AC_PROG_CC])
+  gl_POSIX_SPAWN
+  AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_addfchdir posix_spawn_file_actions_addfchdir_np])
+  if test $ac_cv_func_posix_spawn_file_actions_addfchdir = yes; then
+    dnl This function is not yet standardized. Therefore override the
+    dnl system's implementation always.
+    REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR=1
+  else
+    HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR=0
+  fi
+])
diff --git a/m4/spawn_h.m4 b/m4/spawn_h.m4
index 561caa7..95cb25d 100644
--- a/m4/spawn_h.m4
+++ b/m4/spawn_h.m4
@@ -1,4 +1,4 @@
-# spawn_h.m4 serial 17
+# spawn_h.m4 serial 18
 dnl Copyright (C) 2008-2019 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -53,7 +53,8 @@ AC_DEFUN([gl_SPAWN_H],
     posix_spawnattr_getschedparam posix_spawnattr_setschedparam
     posix_spawn_file_actions_init posix_spawn_file_actions_destroy
     posix_spawn_file_actions_addopen posix_spawn_file_actions_addclose
-    posix_spawn_file_actions_adddup2 posix_spawn_file_actions_addchdir])
+    posix_spawn_file_actions_adddup2 posix_spawn_file_actions_addchdir
+    posix_spawn_file_actions_addfchdir])
 ])
 
 dnl Checks whether the system has the functions posix_spawn.
@@ -89,28 +90,29 @@ AC_DEFUN([gl_SPAWN_MODULE_INDICATOR],
 
 AC_DEFUN([gl_SPAWN_H_DEFAULTS],
 [
-  GNULIB_POSIX_SPAWN=0;                       AC_SUBST([GNULIB_POSIX_SPAWN])
-  GNULIB_POSIX_SPAWNP=0;                      AC_SUBST([GNULIB_POSIX_SPAWNP])
-  GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT=0;     AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT])
-  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR=0; AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR])
-  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=0; AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE])
-  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=0;  AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2])
-  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=0;  AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN])
-  GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY=0;  AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY])
-  GNULIB_POSIX_SPAWNATTR_INIT=0;              AC_SUBST([GNULIB_POSIX_SPAWNATTR_INIT])
-  GNULIB_POSIX_SPAWNATTR_GETFLAGS=0;          AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETFLAGS])
-  GNULIB_POSIX_SPAWNATTR_SETFLAGS=0;          AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETFLAGS])
-  GNULIB_POSIX_SPAWNATTR_GETPGROUP=0;         AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETPGROUP])
-  GNULIB_POSIX_SPAWNATTR_SETPGROUP=0;         AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETPGROUP])
-  GNULIB_POSIX_SPAWNATTR_GETSCHEDPARAM=0;     AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETSCHEDPARAM])
-  GNULIB_POSIX_SPAWNATTR_SETSCHEDPARAM=0;     AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETSCHEDPARAM])
-  GNULIB_POSIX_SPAWNATTR_GETSCHEDPOLICY=0;    AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETSCHEDPOLICY])
-  GNULIB_POSIX_SPAWNATTR_SETSCHEDPOLICY=0;    AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETSCHEDPOLICY])
-  GNULIB_POSIX_SPAWNATTR_GETSIGDEFAULT=0;     AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETSIGDEFAULT])
-  GNULIB_POSIX_SPAWNATTR_SETSIGDEFAULT=0;     AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETSIGDEFAULT])
-  GNULIB_POSIX_SPAWNATTR_GETSIGMASK=0;        AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETSIGMASK])
-  GNULIB_POSIX_SPAWNATTR_SETSIGMASK=0;        AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETSIGMASK])
-  GNULIB_POSIX_SPAWNATTR_DESTROY=0;           AC_SUBST([GNULIB_POSIX_SPAWNATTR_DESTROY])
+  GNULIB_POSIX_SPAWN=0;                        AC_SUBST([GNULIB_POSIX_SPAWN])
+  GNULIB_POSIX_SPAWNP=0;                       AC_SUBST([GNULIB_POSIX_SPAWNP])
+  GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT=0;      AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT])
+  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR=0;  AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR])
+  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=0;  AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE])
+  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=0;   AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2])
+  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR=0; AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR])
+  GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=0;   AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN])
+  GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY=0;   AC_SUBST([GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY])
+  GNULIB_POSIX_SPAWNATTR_INIT=0;               AC_SUBST([GNULIB_POSIX_SPAWNATTR_INIT])
+  GNULIB_POSIX_SPAWNATTR_GETFLAGS=0;           AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETFLAGS])
+  GNULIB_POSIX_SPAWNATTR_SETFLAGS=0;           AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETFLAGS])
+  GNULIB_POSIX_SPAWNATTR_GETPGROUP=0;          AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETPGROUP])
+  GNULIB_POSIX_SPAWNATTR_SETPGROUP=0;          AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETPGROUP])
+  GNULIB_POSIX_SPAWNATTR_GETSCHEDPARAM=0;      AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETSCHEDPARAM])
+  GNULIB_POSIX_SPAWNATTR_SETSCHEDPARAM=0;      AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETSCHEDPARAM])
+  GNULIB_POSIX_SPAWNATTR_GETSCHEDPOLICY=0;     AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETSCHEDPOLICY])
+  GNULIB_POSIX_SPAWNATTR_SETSCHEDPOLICY=0;     AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETSCHEDPOLICY])
+  GNULIB_POSIX_SPAWNATTR_GETSIGDEFAULT=0;      AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETSIGDEFAULT])
+  GNULIB_POSIX_SPAWNATTR_SETSIGDEFAULT=0;      AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETSIGDEFAULT])
+  GNULIB_POSIX_SPAWNATTR_GETSIGMASK=0;         AC_SUBST([GNULIB_POSIX_SPAWNATTR_GETSIGMASK])
+  GNULIB_POSIX_SPAWNATTR_SETSIGMASK=0;         AC_SUBST([GNULIB_POSIX_SPAWNATTR_SETSIGMASK])
+  GNULIB_POSIX_SPAWNATTR_DESTROY=0;            AC_SUBST([GNULIB_POSIX_SPAWNATTR_DESTROY])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_POSIX_SPAWN=1;        AC_SUBST([HAVE_POSIX_SPAWN])
   HAVE_POSIX_SPAWNATTR_T=1;  AC_SUBST([HAVE_POSIX_SPAWNATTR_T])
@@ -118,6 +120,8 @@ AC_DEFUN([gl_SPAWN_H_DEFAULTS],
                              AC_SUBST([HAVE_POSIX_SPAWN_FILE_ACTIONS_T])
   HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR=1;
                              AC_SUBST([HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR])
+  HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR=1;
+                             AC_SUBST([HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR])
   REPLACE_POSIX_SPAWN=0;     AC_SUBST([REPLACE_POSIX_SPAWN])
   REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR=0;
                              AC_SUBST([REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR])
@@ -125,6 +129,8 @@ AC_DEFUN([gl_SPAWN_H_DEFAULTS],
                              AC_SUBST([REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE])
   REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=0;
                              AC_SUBST([REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2])
+  REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR=0;
+                             AC_SUBST([REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR])
   REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=0;
                              AC_SUBST([REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN])
 ])
diff --git a/modules/posix_spawn_file_actions_addfchdir b/modules/posix_spawn_file_actions_addfchdir
new file mode 100644
index 0000000..cd9cb99
--- /dev/null
+++ b/modules/posix_spawn_file_actions_addfchdir
@@ -0,0 +1,30 @@
+Description:
+posix_spawn_file_actions_addfchdir() function: augment a child process actions
+specification.
+
+Files:
+lib/spawn_faction_addfchdir.c
+lib/spawn_int.h
+m4/posix_spawn_faction_addfchdir.m4
+
+Depends-on:
+spawn
+posix_spawn_file_actions_init [test $HAVE_POSIX_SPAWN = 0 || test $REPLACE_POSIX_SPAWN = 1 || test $HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR = 0 || test $REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR = 1]
+
+configure.ac:
+gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR
+if test $HAVE_POSIX_SPAWN = 0 || test $REPLACE_POSIX_SPAWN = 1 || test $HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR = 0 || test $REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR = 1; then
+  AC_LIBOBJ([spawn_faction_addfchdir])
+fi
+gl_SPAWN_MODULE_INDICATOR([posix_spawn_file_actions_addfchdir])
+
+Makefile.am:
+
+Include:
+<spawn.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
diff --git a/modules/spawn b/modules/spawn
index dc861d3..6e03294 100644
--- a/modules/spawn
+++ b/modules/spawn
@@ -35,6 +35,7 @@ spawn.h: spawn.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
 	      -e 's/@''GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR''@/$(GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR)/g' \
 	      -e 's/@''GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE''@/$(GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE)/g' \
 	      -e 's/@''GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2''@/$(GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2)/g' \
+	      -e 's/@''GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR''@/$(GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR)/g' \
 	      -e 's/@''GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN''@/$(GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN)/g' \
 	      -e 's/@''GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY''@/$(GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY)/g' \
 	      -e 's/@''GNULIB_POSIX_SPAWNATTR_INIT''@/$(GNULIB_POSIX_SPAWNATTR_INIT)/g' \
@@ -55,10 +56,12 @@ spawn.h: spawn.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
 	      -e 's|@''HAVE_POSIX_SPAWNATTR_T''@|$(HAVE_POSIX_SPAWNATTR_T)|g' \
 	      -e 's|@''HAVE_POSIX_SPAWN_FILE_ACTIONS_T''@|$(HAVE_POSIX_SPAWN_FILE_ACTIONS_T)|g' \
 	      -e 's|@''HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR''@|$(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR)|g' \
+	      -e 's|@''HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR''@|$(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR)|g' \
 	      -e 's|@''REPLACE_POSIX_SPAWN''@|$(REPLACE_POSIX_SPAWN)|g' \
 	      -e 's|@''REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR''@|$(REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR)|g' \
 	      -e 's|@''REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE''@|$(REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE)|g' \
 	      -e 's|@''REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2''@|$(REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2)|g' \
+	      -e 's|@''REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR''@|$(REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR)|g' \
 	      -e 's|@''REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN''@|$(REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN)|g' \
 	      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
 	      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
diff --git a/tests/test-spawn-c++.cc b/tests/test-spawn-c++.cc
index 2ba1cc4..119917f 100644
--- a/tests/test-spawn-c++.cc
+++ b/tests/test-spawn-c++.cc
@@ -137,6 +137,11 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::posix_spawn_file_actions_addchdir, int,
                  (posix_spawn_file_actions_t *, const char *));
 #endif
 
+#if GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR
+SIGNATURE_CHECK (GNULIB_NAMESPACE::posix_spawn_file_actions_addfchdir, int,
+                 (posix_spawn_file_actions_t *, int));
+#endif
+
 
 int
 main ()
-- 
2.7.4


[-- Attachment #4: 0003-posix_spawn_file_actions_addfchdir-Add-tests.patch --]
[-- Type: text/x-patch, Size: 8418 bytes --]

From fbb40ec10e333cff0b9845572065edd9e66eac79 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Mon, 10 Jun 2019 16:17:35 +0200
Subject: [PATCH 3/5] posix_spawn_file_actions_addfchdir: Add tests.

* tests/test-posix_spawn_file_actions_addfchdir.c: New file.
* tests/test-posix_spawn5.c: New file.
* modules/posix_spawn_file_actions_addfchdir-tests: New file.
---
 ChangeLog                                        |   7 ++
 modules/posix_spawn_file_actions_addfchdir-tests |  20 +++
 tests/test-posix_spawn5.c                        | 148 +++++++++++++++++++++++
 tests/test-posix_spawn_file_actions_addfchdir.c  |  44 +++++++
 4 files changed, 219 insertions(+)
 create mode 100644 modules/posix_spawn_file_actions_addfchdir-tests
 create mode 100644 tests/test-posix_spawn5.c
 create mode 100644 tests/test-posix_spawn_file_actions_addfchdir.c

diff --git a/ChangeLog b/ChangeLog
index ecf1d47..7bbf5fa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2019-06-10  Bruno Haible  <bruno@clisp.org>
 
+	posix_spawn_file_actions_addfchdir: Add tests.
+	* tests/test-posix_spawn_file_actions_addfchdir.c: New file.
+	* tests/test-posix_spawn5.c: New file.
+	* modules/posix_spawn_file_actions_addfchdir-tests: New file.
+
+2019-06-10  Bruno Haible  <bruno@clisp.org>
+
 	posix_spawn_file_actions_addfchdir: New module.
 	* lib/spawn.in.h (posix_spawn_file_actions_addfchdir): New declaration.
 	* lib/spawn_int.h (struct __spawn_action): Add tag 'spawn_do_fchdir' and
diff --git a/modules/posix_spawn_file_actions_addfchdir-tests b/modules/posix_spawn_file_actions_addfchdir-tests
new file mode 100644
index 0000000..5e50695
--- /dev/null
+++ b/modules/posix_spawn_file_actions_addfchdir-tests
@@ -0,0 +1,20 @@
+Files:
+tests/test-posix_spawn_file_actions_addfchdir.c
+tests/test-posix_spawn5.c
+tests/signature.h
+tests/macros.h
+
+Depends-on:
+posix_spawn_file_actions_init
+posix_spawnp-tests
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-posix_spawn_file_actions_addfchdir
+check_PROGRAMS += test-posix_spawn_file_actions_addfchdir
+
+if POSIX_SPAWN_PORTED
+TESTS += test-posix_spawn5
+check_PROGRAMS += test-posix_spawn5
+endif
diff --git a/tests/test-posix_spawn5.c b/tests/test-posix_spawn5.c
new file mode 100644
index 0000000..805f666
--- /dev/null
+++ b/tests/test-posix_spawn5.c
@@ -0,0 +1,148 @@
+/* Test of posix_spawn() function with 'fchdir' action.
+   Copyright (C) 2008-2019 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2018.  */
+
+#include <config.h>
+
+#include <spawn.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static int
+fd_safer (int fd)
+{
+  if (0 <= fd && fd <= 2)
+    {
+      int f = fd_safer (dup (fd));
+      int e = errno;
+      close (fd);
+      errno = e;
+      fd = f;
+    }
+
+  return fd;
+}
+
+int
+main ()
+{
+  char *argv[2] = { (char *) "pwd", NULL };
+  int rootfd;
+  int ifd[2];
+  sigset_t blocked_signals;
+  sigset_t fatal_signal_set;
+  posix_spawn_file_actions_t actions;
+  bool actions_allocated;
+  posix_spawnattr_t attrs;
+  bool attrs_allocated;
+  int err;
+  pid_t child;
+  int fd;
+  FILE *fp;
+  char line[80];
+  int status;
+  int exitstatus;
+
+  rootfd = open ("/", O_RDONLY);
+  if (rootfd < 0)
+    {
+      perror ("cannot open directory");
+      exit (1);
+    }
+  if (pipe (ifd) < 0 || (ifd[0] = fd_safer (ifd[0])) < 0)
+    {
+      perror ("cannot create pipe");
+      exit (1);
+    }
+  sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
+  sigemptyset (&fatal_signal_set);
+  sigaddset (&fatal_signal_set, SIGINT);
+  sigaddset (&fatal_signal_set, SIGTERM);
+  sigaddset (&fatal_signal_set, SIGHUP);
+  sigaddset (&fatal_signal_set, SIGPIPE);
+  sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
+  actions_allocated = false;
+  attrs_allocated = false;
+  if ((err = posix_spawn_file_actions_init (&actions)) != 0
+      || (actions_allocated = true,
+          (err = posix_spawn_file_actions_adddup2 (&actions, ifd[1], STDOUT_FILENO)) != 0
+          || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
+          || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
+          || (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, "/dev/null", O_RDONLY, 0)) != 0
+          || (err = posix_spawn_file_actions_addfchdir (&actions, rootfd)) != 0
+          || (err = posix_spawnattr_init (&attrs)) != 0
+          || (attrs_allocated = true,
+              (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0
+              || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0)
+          || (err = posix_spawnp (&child, "pwd", &actions, &attrs, argv, environ)) != 0))
+    {
+      if (actions_allocated)
+        posix_spawn_file_actions_destroy (&actions);
+      if (attrs_allocated)
+        posix_spawnattr_destroy (&attrs);
+      sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+      errno = err;
+      perror ("subprocess failed");
+      exit (1);
+    }
+  posix_spawn_file_actions_destroy (&actions);
+  posix_spawnattr_destroy (&attrs);
+  sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+  close (ifd[1]);
+  fd = ifd[0];
+  fp = fdopen (fd, "r");
+  if (fp == NULL)
+    {
+      fprintf (stderr, "fdopen() failed\n");
+      exit (1);
+    }
+  if (fread (line, 1, 80, fp) < 2)
+    {
+      fprintf (stderr, "could not read expected output\n");
+      exit (1);
+    }
+  if (memcmp (line, "/\n", 2) != 0)
+    {
+      fprintf (stderr, "read output is not the expected output");
+      exit (1);
+    }
+  fclose (fp);
+  status = 0;
+  while (waitpid (child, &status, 0) != child)
+    ;
+  if (!WIFEXITED (status))
+    {
+      fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
+      exit (1);
+    }
+  exitstatus = WEXITSTATUS (status);
+  if (exitstatus != 0)
+    {
+      fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
+      exit (1);
+    }
+  return 0;
+}
diff --git a/tests/test-posix_spawn_file_actions_addfchdir.c b/tests/test-posix_spawn_file_actions_addfchdir.c
new file mode 100644
index 0000000..d7df690
--- /dev/null
+++ b/tests/test-posix_spawn_file_actions_addfchdir.c
@@ -0,0 +1,44 @@
+/* Test posix_spawn_file_actions_addfchdir() function.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include <spawn.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (posix_spawn_file_actions_addfchdir, int,
+                 (posix_spawn_file_actions_t *, int));
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "macros.h"
+
+int
+main (void)
+{
+  posix_spawn_file_actions_t actions;
+
+  ASSERT (posix_spawn_file_actions_init (&actions) == 0);
+
+  ASSERT (posix_spawn_file_actions_addfchdir (&actions, 3) == 0);
+
+  posix_spawn_file_actions_destroy (&actions);
+
+  return 0;
+}
-- 
2.7.4


[-- Attachment #5: 0004-posix_spawn_file_actions_addopen-Fix-possible-use-af.patch --]
[-- Type: text/x-patch, Size: 5111 bytes --]

From 765146c33361b46aa2c592e980b16069094c6000 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Mon, 10 Jun 2019 16:50:04 +0200
Subject: [PATCH 4/5] 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.
---
 ChangeLog                   | 10 ++++++++++
 lib/spawn_faction_addopen.c | 47 +++++++++++++++++++++++++++++----------------
 lib/spawn_faction_destroy.c | 29 +++++++++++++++++++++++++++-
 lib/spawn_int.h             |  2 +-
 4 files changed, 69 insertions(+), 19 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7bbf5fa..16f720d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 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.
 	* tests/test-posix_spawn_file_actions_addfchdir.c: New file.
 	* tests/test-posix_spawn5.c: New file.
diff --git a/lib/spawn_faction_addopen.c b/lib/spawn_faction_addopen.c
index 6b4422f..ab4f727 100644
--- a/lib/spawn_faction_addopen.c
+++ b/lib/spawn_faction_addopen.c
@@ -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
 }
diff --git a/lib/spawn_faction_destroy.c b/lib/spawn_faction_destroy.c
index 6d9ec80..0640da4 100644
--- a/lib/spawn_faction_destroy.c
+++ b/lib/spawn_faction_destroy.c
@@ -21,11 +21,38 @@
 
 #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
 }
diff --git a/lib/spawn_int.h b/lib/spawn_int.h
index 584c1bb..08c477a 100644
--- a/lib/spawn_int.h
+++ b/lib/spawn_int.h
@@ -42,7 +42,7 @@ struct __spawn_action
     struct
     {
       int fd;
-      const char *path;
+      char *path;
       int oflag;
       mode_t mode;
     } open_action;
-- 
2.7.4


[-- Attachment #6: 0005-posix_spawn_file_actions_addchdir-Fix-possible-use-a.patch --]
[-- Type: text/x-patch, Size: 4098 bytes --]

From b827d8a6fab0c25eaf0c59b94c5bbef00efeeae5 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Mon, 10 Jun 2019 16:51:51 +0200
Subject: [PATCH 5/5] posix_spawn_file_actions_addchdir: Fix possible
 use-after-free bug.

* lib/spawn_int.h (struct __spawn_action): Remove 'const' from path.
* lib/spawn_faction_addchdir.c (posix_spawn_file_actions_addchdir): Make
a copy of the path argument.
* lib/spawn_faction_destroy.c (posix_spawn_file_actions_destroy): Free
it.
---
 ChangeLog                    |  9 +++++++++
 lib/spawn_faction_addchdir.c | 41 +++++++++++++++++++++++++++--------------
 lib/spawn_faction_destroy.c  |  1 +
 lib/spawn_int.h              |  2 +-
 4 files changed, 38 insertions(+), 15 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 16f720d..217779e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2019-06-10  Bruno Haible  <bruno@clisp.org>
 
+	posix_spawn_file_actions_addchdir: Fix possible use-after-free bug.
+	* lib/spawn_int.h (struct __spawn_action): Remove 'const' from path.
+	* lib/spawn_faction_addchdir.c (posix_spawn_file_actions_addchdir): 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_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.
diff --git a/lib/spawn_faction_addchdir.c b/lib/spawn_faction_addchdir.c
index b270e1f..925874c 100644
--- a/lib/spawn_faction_addchdir.c
+++ b/lib/spawn_faction_addchdir.c
@@ -19,6 +19,8 @@
 #include <spawn.h>
 
 #include <errno.h>
+#include <stdlib.h>
+#include <string.h>
 
 #if REPLACE_POSIX_SPAWN
 # include "spawn_int.h"
@@ -34,24 +36,35 @@ posix_spawn_file_actions_addchdir (posix_spawn_file_actions_t *file_actions,
 #if !REPLACE_POSIX_SPAWN
   return posix_spawn_file_actions_addchdir_np (file_actions, path);
 #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_chdir;
-    rec->action.chdir_action.path = path;
+      /* Add the new value.  */
+      rec = &file_actions->_actions[file_actions->_used];
+      rec->tag = spawn_do_chdir;
+      rec->action.chdir_action.path = path_copy;
 
-    /* Account for the new entry.  */
-    ++file_actions->_used;
+      /* Account for the new entry.  */
+      ++file_actions->_used;
 
-    return 0;
+      return 0;
+    }
   }
 #endif
 }
diff --git a/lib/spawn_faction_destroy.c b/lib/spawn_faction_destroy.c
index 0640da4..d7156a0 100644
--- a/lib/spawn_faction_destroy.c
+++ b/lib/spawn_faction_destroy.c
@@ -42,6 +42,7 @@ posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions)
       switch (sa->tag)
         {
         case spawn_do_open:
+        case spawn_do_chdir:
           free (sa->action.open_action.path);
           break;
         default:
diff --git a/lib/spawn_int.h b/lib/spawn_int.h
index 08c477a..bcf8bbf 100644
--- a/lib/spawn_int.h
+++ b/lib/spawn_int.h
@@ -48,7 +48,7 @@ struct __spawn_action
     } open_action;
     struct
     {
-      const char *path;
+      char *path;
     } chdir_action;
     struct
     {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2019-06-10 15:29 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-10 15:29 posix_spawn fixes Bruno Haible

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).