]> Savannah Git Hosting - gnulib.git/commitdiff
posix_spawn, posix_spawnp: Fix execution of scripts.
authorBruno Haible <bruno@clisp.org>
Thu, 24 Dec 2020 02:49:20 +0000 (03:49 +0100)
committerBruno Haible <bruno@clisp.org>
Thu, 24 Dec 2020 05:52:27 +0000 (06:52 +0100)
* m4/posix_spawn.m4 (gl_POSIX_SPAWN_SECURE): New macro.
(gl_POSIX_SPAWN_BODY): Invoke it. Set REPLACE_POSIX_SPAWN if posix_spawn
or posix_spawnp allows unsecure execution of scripts.
* doc/posix-functions/posix_spawn.texi: Document the script execution
problem.
* doc/posix-functions/posix_spawnp.texi: Likewise.

ChangeLog
doc/posix-functions/posix_spawn.texi
doc/posix-functions/posix_spawnp.texi
m4/posix_spawn.m4

index bfb7f882517cf323778cf87560cf4fd263f76150..e7e5f11ed95e4601af78034f781ae71ac154b0d9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2020-12-23  Bruno Haible  <bruno@clisp.org>
+
+       posix_spawn, posix_spawnp: Fix execution of scripts.
+       * m4/posix_spawn.m4 (gl_POSIX_SPAWN_SECURE): New macro.
+       (gl_POSIX_SPAWN_BODY): Invoke it. Set REPLACE_POSIX_SPAWN if posix_spawn
+       or posix_spawnp allows unsecure execution of scripts.
+       * doc/posix-functions/posix_spawn.texi: Document the script execution
+       problem.
+       * doc/posix-functions/posix_spawnp.texi: Likewise.
+
 2020-12-23  Bruno Haible  <bruno@clisp.org>
 
        Add unit tests regarding execution of scripts.
index 7a3a2f603e7ca37f78305973b2be8fc24b002ba6..e0b39b0dd7a16ef46f7cb5e500d65f91e578d8f9 100644 (file)
@@ -15,6 +15,11 @@ FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5,
 When this function fails, it causes the stdio buffer contents to be output
 twice on some platforms:
 AIX 6.1.
+@item
+When the program to be invoked is an executable script without a @samp{#!}
+marker in the first line, this function executes the script as if it were
+a shell script, on some platforms:
+GNU/Hurd.
 @end itemize
 
 Portability problems not fixed by Gnulib:
index c420db9a8e8c13423018bbc683a6ce3dcedb8246..2dd9f689bcecea61d8d3a2121d4840e69e93914d 100644 (file)
@@ -15,6 +15,11 @@ FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5,
 When this function fails, it causes the stdio buffer contents to be output
 twice on some platforms:
 AIX 6.1.
+@item
+When the program to be invoked is an executable script without a @samp{#!}
+marker in the first line, this function executes the script as if it were
+a shell script, on some platforms:
+glibc 2.14, GNU/Hurd, Mac OS X 10.13, FreeBSD 12.0, OpenBSD 6.7, AIX 7.2, Solaris 11.4, Cygwin 2.9.
 @end itemize
 
 Portability problems not fixed by Gnulib:
index 625b2ad0e8a5089bc9be732a35cf1eff412a29ad..59e56fcb5f2ec9dad26f5bb664a7fdb70ff3a8fe 100644 (file)
@@ -1,4 +1,4 @@
-# posix_spawn.m4 serial 18
+# posix_spawn.m4 serial 19
 dnl Copyright (C) 2008-2020 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -54,40 +54,52 @@ AC_DEFUN([gl_POSIX_SPAWN_BODY],
     if test $REPLACE_POSIX_SPAWN = 0; then
       gl_POSIX_SPAWN_WORKS
       case "$gl_cv_func_posix_spawn_works" in
-        *yes)
-          dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDULER
-          dnl evaluates to nonzero.
-          dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedpolicy])
-          dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedpolicy])
-          AC_CACHE_CHECK([whether posix_spawnattr_setschedpolicy is supported],
-            [gl_cv_func_spawnattr_setschedpolicy],
-            [AC_EGREP_CPP([POSIX scheduling supported], [
+        *yes) ;;
+        *) REPLACE_POSIX_SPAWN=1 ;;
+      esac
+    fi
+    if test $REPLACE_POSIX_SPAWN = 0; then
+      gl_POSIX_SPAWN_SECURE
+      case "$gl_cv_func_posix_spawn_secure_exec" in
+        *yes) ;;
+        *) REPLACE_POSIX_SPAWN=1 ;;
+      esac
+      case "$gl_cv_func_posix_spawnp_secure_exec" in
+        *yes) ;;
+        *) REPLACE_POSIX_SPAWN=1 ;;
+      esac
+    fi
+    if test $REPLACE_POSIX_SPAWN = 0; then
+      dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDULER
+      dnl evaluates to nonzero.
+      dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedpolicy])
+      dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedpolicy])
+      AC_CACHE_CHECK([whether posix_spawnattr_setschedpolicy is supported],
+        [gl_cv_func_spawnattr_setschedpolicy],
+        [AC_EGREP_CPP([POSIX scheduling supported], [
 #include <spawn.h>
 #if POSIX_SPAWN_SETSCHEDULER
  POSIX scheduling supported
 #endif
 ],
-               [gl_cv_func_spawnattr_setschedpolicy=yes],
-               [gl_cv_func_spawnattr_setschedpolicy=no])
-            ])
-          dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDPARAM
-          dnl evaluates to nonzero.
-          dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedparam])
-          dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedparam])
-          AC_CACHE_CHECK([whether posix_spawnattr_setschedparam is supported],
-            [gl_cv_func_spawnattr_setschedparam],
-            [AC_EGREP_CPP([POSIX scheduling supported], [
+           [gl_cv_func_spawnattr_setschedpolicy=yes],
+           [gl_cv_func_spawnattr_setschedpolicy=no])
+        ])
+      dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDPARAM
+      dnl evaluates to nonzero.
+      dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedparam])
+      dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedparam])
+      AC_CACHE_CHECK([whether posix_spawnattr_setschedparam is supported],
+        [gl_cv_func_spawnattr_setschedparam],
+        [AC_EGREP_CPP([POSIX scheduling supported], [
 #include <spawn.h>
 #if POSIX_SPAWN_SETSCHEDPARAM
  POSIX scheduling supported
 #endif
 ],
-               [gl_cv_func_spawnattr_setschedparam=yes],
-               [gl_cv_func_spawnattr_setschedparam=no])
-            ])
-          ;;
-        *) REPLACE_POSIX_SPAWN=1 ;;
-      esac
+           [gl_cv_func_spawnattr_setschedparam=yes],
+           [gl_cv_func_spawnattr_setschedparam=no])
+        ])
     fi
   fi
   if test $ac_cv_func_posix_spawn != yes || test $REPLACE_POSIX_SPAWN = 1; then
@@ -417,6 +429,113 @@ main (int argc, char *argv[])
     ])
 ])
 
+dnl Test whether posix_spawn and posix_spawnp are secure.
+AC_DEFUN([gl_POSIX_SPAWN_SECURE],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  dnl On many platforms, posix_spawn or posix_spawnp allow executing a
+  dnl script without a '#!' marker as a shell script. This is unsecure.
+  AC_CACHE_CHECK([whether posix_spawn rejects scripts without shebang],
+    [gl_cv_func_posix_spawn_secure_exec],
+    [echo ':' > conftest.scr
+     chmod a+x conftest.scr
+     AC_RUN_IFELSE([AC_LANG_SOURCE([[
+       #include <errno.h>
+       #include <spawn.h>
+       #include <stddef.h>
+       #include <sys/types.h>
+       #include <sys/wait.h>
+       int
+       main ()
+       {
+         const char *prog_path = "./conftest.scr";
+         const char *prog_argv[2] = { prog_path, NULL };
+         const char *environment[2] = { "PATH=.", NULL };
+         pid_t child;
+         int status;
+         int err = posix_spawn (&child, prog_path, NULL, NULL,
+                                (char **) prog_argv, (char **) environment);
+         if (err == ENOEXEC)
+           return 0;
+         if (err != 0)
+           return 1;
+         status = 0;
+         while (waitpid (child, &status, 0) != child)
+           ;
+         if (!WIFEXITED (status))
+           return 2;
+         if (WEXITSTATUS (status) != 127)
+           return 3;
+         return 0;
+       }
+       ]])],
+       [gl_cv_func_posix_spawn_secure_exec=yes],
+       [gl_cv_func_posix_spawn_secure_exec=no],
+       [case "$host_os" in
+          # Guess no on GNU/Hurd.
+          gnu*)
+            gl_cv_func_posix_spawn_secure_exec="guessing no" ;;
+          # Guess yes on all other platforms.
+          *)
+            gl_cv_func_posix_spawn_secure_exec="guessing yes" ;;
+        esac
+       ])
+     rm -f conftest.scr
+    ])
+  AC_CACHE_CHECK([whether posix_spawnp rejects scripts without shebang],
+    [gl_cv_func_posix_spawnp_secure_exec],
+    [echo ':' > conftest.scr
+     chmod a+x conftest.scr
+     AC_RUN_IFELSE([AC_LANG_SOURCE([[
+       #include <errno.h>
+       #include <spawn.h>
+       #include <stddef.h>
+       #include <sys/types.h>
+       #include <sys/wait.h>
+       int
+       main ()
+       {
+         const char *prog_path = "./conftest.scr";
+         const char *prog_argv[2] = { prog_path, NULL };
+         const char *environment[2] = { "PATH=.", NULL };
+         pid_t child;
+         int status;
+         int err = posix_spawnp (&child, prog_path, NULL, NULL,
+                                 (char **) prog_argv, (char **) environment);
+         if (err == ENOEXEC)
+           return 0;
+         if (err != 0)
+           return 1;
+         status = 0;
+         while (waitpid (child, &status, 0) != child)
+           ;
+         if (!WIFEXITED (status))
+           return 2;
+         if (WEXITSTATUS (status) != 127)
+           return 3;
+         return 0;
+       }
+       ]])],
+       [gl_cv_func_posix_spawnp_secure_exec=yes],
+       [gl_cv_func_posix_spawnp_secure_exec=no],
+       [case "$host_os" in
+          # Guess yes on glibc systems (glibc >= 2.15 actually) except GNU/Hurd,
+          # musl libc, NetBSD.
+          *-gnu* | *-musl* | netbsd*)
+            gl_cv_func_posix_spawnp_secure_exec="guessing yes" ;;
+          # Guess no on GNU/Hurd, macOS, FreeBSD, OpenBSD, AIX, Solaris, Cygwin.
+          gnu* | darwin* | freebsd* | dragonfly* | openbsd* | aix* | solaris* | cygwin*)
+            gl_cv_func_posix_spawnp_secure_exec="guessing no" ;;
+          # If we don't know, obey --enable-cross-guesses.
+          *)
+            gl_cv_func_posix_spawnp_secure_exec="$gl_cross_guess_normal" ;;
+        esac
+       ])
+     rm -f conftest.scr
+    ])
+])
+
 # Prerequisites of lib/spawni.c.
 AC_DEFUN([gl_PREREQ_POSIX_SPAWN_INTERNAL],
 [