diff --git a/SOURCES/glibc-rh2065588-1.patch b/SOURCES/glibc-rh2065588-1.patch new file mode 100644 index 0000000..3b4db3f --- /dev/null +++ b/SOURCES/glibc-rh2065588-1.patch @@ -0,0 +1,253 @@ +commit 2a973ab7f1a6f6cd9be1c7257fd7b5d331515eab +Author: Adhemerval Zanella +Date: Wed Sep 12 10:30:46 2018 -0300 + + posix: Add internal symbols for posix_spawn interface + + This patch adds internal hidden definition for mostly of the posix_spawn + function so it can be used internally on both popen and system + implementations. + + Checked on x86_64-linux-gnu. + + * include/spawn.h (__posix_spawn, posix_spawn_file_actions_addclose, + __posix_spawn_file_actions_adddup2, __posix_spawn_file_actions_destroy, + __posix_spawn_file_actions_init, __posix_spawnattr_init, + __posix_spawnattr_destroy, __posix_spawnattr_setflags, + __posix_spawnattr_setsigdefault, __posix_spawnattr_setsigmask): New + prototype. + * posix/spawn.c (__posix_spawn): Add libc_hidden_def. + * posix/spawn_faction_addclose.c + (__posix_spawn_file_actions_addclose): Add hidden definition. + * posix/spawn_faction_adddup2.c + (__posix_spawn_file_actions_adddup2): Likewise. + * posix/spawn_faction_destroy.c + (__posix_spawn_file_actions_destroy): Likewise. + * posix/spawn_faction_init.c (__posix_spawn_file_actions_init): + Likewise. + * posix/spawnattr_destroy.c (__posix_spawnattr_destroy): Likewise. + * posix/spawnattr_init.c (__posix_spawnattr_init): Likewise. + * posix/spawnattr_setdefault.c (__posix_spawnattr_setsigdefault): + Likewise. + * posix/spawnattr_setflags.c (__posix_spawnattr_setflags): Likewise. + * posix/spawnattr_setsigmask.c (__posix_spawnattr_setsigmask): + Likewise. + +diff --git a/include/spawn.h b/include/spawn.h +index a6c7a8adc361927e..7fdd965bd780f8de 100644 +--- a/include/spawn.h ++++ b/include/spawn.h +@@ -1 +1,36 @@ ++#ifndef _SPAWN_H + #include ++ ++# ifndef _ISOMAC ++__typeof (posix_spawn) __posix_spawn; ++libc_hidden_proto (__posix_spawn) ++ ++__typeof (posix_spawn_file_actions_addclose) ++ __posix_spawn_file_actions_addclose attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_adddup2) ++ __posix_spawn_file_actions_adddup2 attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_destroy) ++ __posix_spawn_file_actions_destroy attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_init) __posix_spawn_file_actions_init ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_init) __posix_spawnattr_init ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_destroy) __posix_spawnattr_destroy ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setflags) __posix_spawnattr_setflags ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setsigdefault) __posix_spawnattr_setsigdefault ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setsigmask) __posix_spawnattr_setsigmask ++ attribute_hidden; ++ ++# endif /* !_ISOMAC */ ++#endif /* spawn.h */ +diff --git a/posix/spawn.c b/posix/spawn.c +index 51f67b2755bd4949..a82f1c84e299f018 100644 +--- a/posix/spawn.c ++++ b/posix/spawn.c +@@ -30,6 +30,7 @@ __posix_spawn (pid_t *pid, const char *path, + return __spawni (pid, path, file_actions, attrp, argv, envp, 0); + } + versioned_symbol (libc, __posix_spawn, posix_spawn, GLIBC_2_15); ++libc_hidden_def (__posix_spawn) + + + #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) +diff --git a/posix/spawn_faction_addclose.c b/posix/spawn_faction_addclose.c +index 21081e19b55db44c..e1fafe438cf15c91 100644 +--- a/posix/spawn_faction_addclose.c ++++ b/posix/spawn_faction_addclose.c +@@ -24,8 +24,8 @@ + /* Add an action to FILE-ACTIONS which tells the implementation to call + `close' for the given file descriptor during the `spawn' call. */ + int +-posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, +- int fd) ++__posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, ++ int fd) + { + struct __spawn_action *rec; + +@@ -48,3 +48,5 @@ posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, + + return 0; + } ++weak_alias (__posix_spawn_file_actions_addclose, ++ posix_spawn_file_actions_addclose) +diff --git a/posix/spawn_faction_adddup2.c b/posix/spawn_faction_adddup2.c +index 363bc29ae502bd60..371b1de3e6f1979a 100644 +--- a/posix/spawn_faction_adddup2.c ++++ b/posix/spawn_faction_adddup2.c +@@ -24,8 +24,8 @@ + /* Add an action to FILE-ACTIONS which tells the implementation to call + `dup2' for the given file descriptors during the `spawn' call. */ + int +-posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, +- int fd, int newfd) ++__posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, ++ int fd, int newfd) + { + struct __spawn_action *rec; + +@@ -49,3 +49,5 @@ posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, + + return 0; + } ++weak_alias (__posix_spawn_file_actions_adddup2, ++ posix_spawn_file_actions_adddup2) +diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c +index 46061ee3473d4475..2a2de4e41d6bd6d0 100644 +--- a/posix/spawn_faction_destroy.c ++++ b/posix/spawn_faction_destroy.c +@@ -22,7 +22,7 @@ + + /* Deallocate the file actions. */ + int +-posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) ++__posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) + { + /* Free the paths in the open actions. */ + for (int i = 0; i < file_actions->__used; ++i) +@@ -44,3 +44,5 @@ posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) + free (file_actions->__actions); + return 0; + } ++weak_alias (__posix_spawn_file_actions_destroy, ++ posix_spawn_file_actions_destroy) +diff --git a/posix/spawn_faction_init.c b/posix/spawn_faction_init.c +index ddb42e6a77ba41ec..98432067c645021e 100644 +--- a/posix/spawn_faction_init.c ++++ b/posix/spawn_faction_init.c +@@ -45,9 +45,10 @@ __posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *file_actions) + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions) ++__posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions) + { + /* Simply clear all the elements. */ + memset (file_actions, '\0', sizeof (*file_actions)); + return 0; + } ++weak_alias (__posix_spawn_file_actions_init, posix_spawn_file_actions_init) +diff --git a/posix/spawnattr_destroy.c b/posix/spawnattr_destroy.c +index 603e00fffefae2bf..043386778588913a 100644 +--- a/posix/spawnattr_destroy.c ++++ b/posix/spawnattr_destroy.c +@@ -19,8 +19,9 @@ + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawnattr_destroy (posix_spawnattr_t *attr) ++__posix_spawnattr_destroy (posix_spawnattr_t *attr) + { + /* Nothing to do in the moment. */ + return 0; + } ++weak_alias (__posix_spawnattr_destroy, posix_spawnattr_destroy) +diff --git a/posix/spawnattr_init.c b/posix/spawnattr_init.c +index bab464e62bdf7889..4e1218ab44e3f779 100644 +--- a/posix/spawnattr_init.c ++++ b/posix/spawnattr_init.c +@@ -20,7 +20,7 @@ + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawnattr_init (posix_spawnattr_t *attr) ++__posix_spawnattr_init (posix_spawnattr_t *attr) + { + /* All elements have to be initialized to the default values which + is generally zero. */ +@@ -28,3 +28,4 @@ posix_spawnattr_init (posix_spawnattr_t *attr) + + return 0; + } ++weak_alias (__posix_spawnattr_init, posix_spawnattr_init) +diff --git a/posix/spawnattr_setdefault.c b/posix/spawnattr_setdefault.c +index c77cda59be3dda20..174bcfa423dc5666 100644 +--- a/posix/spawnattr_setdefault.c ++++ b/posix/spawnattr_setdefault.c +@@ -20,11 +20,12 @@ + + /* Set signal mask for signals with default handling in ATTR to SIGDEFAULT. */ + int +-posix_spawnattr_setsigdefault (posix_spawnattr_t *attr, +- const sigset_t *sigdefault) ++__posix_spawnattr_setsigdefault (posix_spawnattr_t *attr, ++ const sigset_t *sigdefault) + { + /* Copy the sigset_t data to the user buffer. */ + memcpy (&attr->__sd, sigdefault, sizeof (sigset_t)); + + return 0; + } ++weak_alias (__posix_spawnattr_setsigdefault, posix_spawnattr_setsigdefault) +diff --git a/posix/spawnattr_setflags.c b/posix/spawnattr_setflags.c +index cf9a60181dc91ccd..0a42e94770224a94 100644 +--- a/posix/spawnattr_setflags.c ++++ b/posix/spawnattr_setflags.c +@@ -30,7 +30,7 @@ + + /* Store flags in the attribute structure. */ + int +-posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) ++__posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) + { + /* Check no invalid bits are set. */ + if (flags & ~ALL_FLAGS) +@@ -41,3 +41,4 @@ posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) + + return 0; + } ++weak_alias (__posix_spawnattr_setflags, posix_spawnattr_setflags) +diff --git a/posix/spawnattr_setsigmask.c b/posix/spawnattr_setsigmask.c +index 7ae81ad47025db6f..12c0111af441dd13 100644 +--- a/posix/spawnattr_setsigmask.c ++++ b/posix/spawnattr_setsigmask.c +@@ -20,7 +20,7 @@ + + /* Set signal mask for the new process in ATTR to SIGMASK. */ + int +-posix_spawnattr_setsigmask (posix_spawnattr_t *attr, ++__posix_spawnattr_setsigmask (posix_spawnattr_t *attr, + const sigset_t *sigmask) + { + /* Copy the sigset_t data to the user buffer. */ +@@ -28,3 +28,4 @@ posix_spawnattr_setsigmask (posix_spawnattr_t *attr, + + return 0; + } ++weak_alias (__posix_spawnattr_setsigmask, posix_spawnattr_setsigmask) diff --git a/SOURCES/glibc-rh2065588-10.patch b/SOURCES/glibc-rh2065588-10.patch new file mode 100644 index 0000000..3016994 --- /dev/null +++ b/SOURCES/glibc-rh2065588-10.patch @@ -0,0 +1,21 @@ +commit 5fce0e095bc413f908f472074c2235198cd76bf4 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:36:23 2020 -0300 + + support/shell-container.c: Return 127 if execve fails + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index e87ac5cf1baa84e5..e9eea64bca7e949d 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -238,7 +238,7 @@ run_command_array (char **argv) + + fprintf (stderr, "sh: execing %s failed: %s", + argv[0], strerror (errno)); +- exit (1); ++ exit (127); + } + + waitpid (pid, &status, 0); diff --git a/SOURCES/glibc-rh2065588-11.patch b/SOURCES/glibc-rh2065588-11.patch new file mode 100644 index 0000000..a1ef4a7 --- /dev/null +++ b/SOURCES/glibc-rh2065588-11.patch @@ -0,0 +1,39 @@ +commit 5a5a3a3234bc220a5192d620e0cbc5360da46f14 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:40:36 2020 -0300 + + support/shell-container.c: Add builtin exit + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index e9eea64bca7e949d..aeaf6d2733abce61 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -135,6 +135,18 @@ copy_func (char **argv) + + } + ++/* Emulate the 'exit' builtin. The exit value is optional. */ ++static int ++exit_func (char **argv) ++{ ++ int exit_val = 0; ++ ++ if (argv[0] != 0) ++ exit_val = atoi (argv[0]) & 0xff; ++ exit (exit_val); ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -143,6 +155,7 @@ static struct { + { "true", true_func }, + { "echo", echo_func }, + { "cp", copy_func }, ++ { "exit", exit_func }, + { NULL, NULL } + }; + diff --git a/SOURCES/glibc-rh2065588-12.patch b/SOURCES/glibc-rh2065588-12.patch new file mode 100644 index 0000000..7f4223f --- /dev/null +++ b/SOURCES/glibc-rh2065588-12.patch @@ -0,0 +1,60 @@ +commit 1c17100c43c0913ec94f3bcc966bf3792236c690 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:47:13 2020 -0300 + + support/shell-container.c: Add builtin kill + + No options supported. + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index aeaf6d2733abce61..3869e14683fb74dd 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -147,6 +147,25 @@ exit_func (char **argv) + return 0; + } + ++/* Emulate the "/bin/kill" command. Options are ignored. */ ++static int ++kill_func (char **argv) ++{ ++ int signum = SIGTERM; ++ int i; ++ ++ for (i = 0; argv[i]; i++) ++ { ++ pid_t pid; ++ if (strcmp (argv[i], "$$") == 0) ++ pid = getpid (); ++ else ++ pid = atoi (argv[i]); ++ kill (pid, signum); ++ } ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -156,6 +175,7 @@ static struct { + { "echo", echo_func }, + { "cp", copy_func }, + { "exit", exit_func }, ++ { "kill", kill_func }, + { NULL, NULL } + }; + +@@ -264,6 +284,11 @@ run_command_array (char **argv) + if (rv) + exit (rv); + } ++ else if (WIFSIGNALED (status)) ++ { ++ int sig = WTERMSIG (status); ++ raise (sig); ++ } + else + exit (1); + } diff --git a/SOURCES/glibc-rh2065588-13.patch b/SOURCES/glibc-rh2065588-13.patch new file mode 100644 index 0000000..e4e9d70 --- /dev/null +++ b/SOURCES/glibc-rh2065588-13.patch @@ -0,0 +1,66 @@ +commit 75fe6d1a1620d84e0e487868feba9b2c0f109610 +Author: Siddhesh Poyarekar +Date: Wed May 12 10:13:41 2021 +0530 + + support: Close fds in copy_func + + copy_func may leave file descriptors open on error, so close them on + function exit. + +diff --git a/support/shell-container.c b/support/shell-container.c +index 3869e14683fb74dd..f0a9814ae230d167 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -93,8 +93,9 @@ copy_func (char **argv) + { + char *sname = argv[0]; + char *dname = argv[1]; +- int sfd, dfd; ++ int sfd = -1, dfd = -1; + struct stat st; ++ int ret = 1; + + sfd = open (sname, O_RDONLY); + if (sfd < 0) +@@ -108,7 +109,7 @@ copy_func (char **argv) + { + fprintf (stderr, "cp: unable to fstat %s: %s\n", + sname, strerror (errno)); +- return 1; ++ goto out; + } + + dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600); +@@ -116,22 +117,26 @@ copy_func (char **argv) + { + fprintf (stderr, "cp: unable to open %s for writing: %s\n", + dname, strerror (errno)); +- return 1; ++ goto out; + } + + if (support_copy_file_range (sfd, 0, dfd, 0, st.st_size, 0) != st.st_size) + { + fprintf (stderr, "cp: cannot copy file %s to %s: %s\n", + sname, dname, strerror (errno)); +- return 1; ++ goto out; + } + +- close (sfd); +- close (dfd); +- ++ ret = 0; + chmod (dname, st.st_mode & 0777); + +- return 0; ++out: ++ if (sfd >= 0) ++ close (sfd); ++ if (dfd >= 0) ++ close (dfd); ++ ++ return ret; + + } + diff --git a/SOURCES/glibc-rh2065588-2.patch b/SOURCES/glibc-rh2065588-2.patch new file mode 100644 index 0000000..c671cf9 --- /dev/null +++ b/SOURCES/glibc-rh2065588-2.patch @@ -0,0 +1,231 @@ +commit 14d0e87d9b8caaa2eca7ca81f1189596671fe4fb +Author: Adhemerval Zanella +Date: Wed Sep 12 10:32:05 2018 -0300 + + posix: Use posix_spawn on popen + + This patch uses posix_spawn on popen instead of fork and execl. On Linux + this has the advantage of much lower memory consumption (usually 32 Kb + minimum for the mmap stack area). + + Two issues are also fixed with this change: + + * BZ#17490: although POSIX pthread_atfork description only list 'fork' + as the function that should execute the atfork handlers, popen + description states that: + + '[...] shall be *as if* a child process were created within the popen() + call using the fork() function [...]' + + Other libc/system seems to follow the idea atfork handlers should not be + executed for popen: + + libc/system | run atfork handles | notes + ------------|----------------------|--------------------------------------- + Freebsd | no | uses vfork + Solaris 11 | no | + MacOSX 11 | no | implemented through posix_spawn syscall + ------------|----------------------|---------------------------------------- + + Similar to posix_spawn and system, popen idea is to spawn a different + binary so all the POSIX rationale to run the atfork handlers to avoid + internal process inconsistency is not really required and in some cases + might be unsafe. + + * BZ#22834: the described scenario, where the forked process might access + invalid memory due an inconsistent state in multithreaded environment, + should not happen because posix_spawn does not access the affected + data structure (proc_file_chain). + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + [BZ #22834] + [BZ #17490] + * NEWS: Add new semantic for atfork with popen and system. + * libio/iopopen.c (_IO_new_proc_open): use posix_spawn instead of + fork and execl. + +diff --git a/libio/iopopen.c b/libio/iopopen.c +index 2eff45b4c80b5cd6..c768295180fdf809 100644 +--- a/libio/iopopen.c ++++ b/libio/iopopen.c +@@ -34,7 +34,8 @@ + #include + #include + #include +-#include ++#include ++#include + + struct _IO_proc_file + { +@@ -59,13 +60,60 @@ unlock (void *not_used) + } + #endif + ++/* POSIX states popen shall ensure that any streams from previous popen() ++ calls that remain open in the parent process should be closed in the new ++ child process. ++ To avoid a race-condition between checking which file descriptors need to ++ be close (by transversing the proc_file_chain list) and the insertion of a ++ new one after a successful posix_spawn this function should be called ++ with proc_file_chain_lock acquired. */ ++static bool ++spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command, ++ int do_cloexec, int pipe_fds[2], int parent_end, int child_end, ++ int child_pipe_fd) ++{ ++ ++ for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next) ++ { ++ int fd = _IO_fileno ((FILE *) p); ++ ++ /* If any stream from previous popen() calls has fileno ++ child_pipe_fd, it has been already closed by the adddup2 action ++ above. */ ++ if (fd != child_pipe_fd ++ && __posix_spawn_file_actions_addclose (fa, fd) != 0) ++ return false; ++ } ++ ++ if (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0, ++ (char *const[]){ (char*) "sh", (char*) "-c", ++ (char *) command, NULL }, __environ) != 0) ++ return false; ++ ++ __close_nocancel (pipe_fds[child_end]); ++ ++ if (!do_cloexec) ++ /* Undo the effects of the pipe2 call which set the ++ close-on-exec flag. */ ++ __fcntl (pipe_fds[parent_end], F_SETFD, 0); ++ ++ _IO_fileno (fp) = pipe_fds[parent_end]; ++ ++ ((_IO_proc_file *) fp)->next = proc_file_chain; ++ proc_file_chain = (_IO_proc_file *) fp; ++ ++ return true; ++} ++ + FILE * + _IO_new_proc_open (FILE *fp, const char *command, const char *mode) + { + int read_or_write; ++ /* These are indexes for pipe_fds. */ + int parent_end, child_end; + int pipe_fds[2]; +- pid_t child_pid; ++ int child_pipe_fd; ++ bool spawn_ok; + + int do_read = 0; + int do_write = 0; +@@ -108,72 +156,62 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode) + + if (do_read) + { +- parent_end = pipe_fds[0]; +- child_end = pipe_fds[1]; ++ parent_end = 0; ++ child_end = 1; + read_or_write = _IO_NO_WRITES; ++ child_pipe_fd = 1; + } + else + { +- parent_end = pipe_fds[1]; +- child_end = pipe_fds[0]; ++ parent_end = 1; ++ child_end = 0; + read_or_write = _IO_NO_READS; ++ child_pipe_fd = 0; + } + +- ((_IO_proc_file *) fp)->pid = child_pid = __fork (); +- if (child_pid == 0) +- { +- int child_std_end = do_read ? 1 : 0; +- struct _IO_proc_file *p; +- +- if (child_end != child_std_end) +- __dup2 (child_end, child_std_end); +- else +- /* The descriptor is already the one we will use. But it must +- not be marked close-on-exec. Undo the effects. */ +- __fcntl (child_end, F_SETFD, 0); +- /* POSIX.2: "popen() shall ensure that any streams from previous +- popen() calls that remain open in the parent process are closed +- in the new child process." */ +- for (p = proc_file_chain; p; p = p->next) +- { +- int fd = _IO_fileno ((FILE *) p); ++ posix_spawn_file_actions_t fa; ++ /* posix_spawn_file_actions_init does not fail. */ ++ __posix_spawn_file_actions_init (&fa); + +- /* If any stream from previous popen() calls has fileno +- child_std_end, it has been already closed by the dup2 syscall +- above. */ +- if (fd != child_std_end) +- __close_nocancel (fd); +- } +- +- execl ("/bin/sh", "sh", "-c", command, (char *) 0); +- _exit (127); +- } +- __close_nocancel (child_end); +- if (child_pid < 0) ++ /* The descriptor is already the one the child will use. In this case ++ it must be moved to another one otherwise, there is no safe way to ++ remove the close-on-exec flag in the child without creating a FD leak ++ race in the parent. */ ++ if (pipe_fds[child_end] == child_pipe_fd) + { +- __close_nocancel (parent_end); +- return NULL; ++ int tmp = __fcntl (child_pipe_fd, F_DUPFD_CLOEXEC, 0); ++ if (tmp < 0) ++ goto spawn_failure; ++ __close_nocancel (pipe_fds[child_end]); ++ pipe_fds[child_end] = tmp; + } + +- if (!do_cloexec) +- /* Undo the effects of the pipe2 call which set the +- close-on-exec flag. */ +- __fcntl (parent_end, F_SETFD, 0); ++ if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end], ++ child_pipe_fd) != 0) ++ goto spawn_failure; + +- _IO_fileno (fp) = parent_end; +- +- /* Link into proc_file_chain. */ + #ifdef _IO_MTSAFE_IO + _IO_cleanup_region_start_noarg (unlock); + _IO_lock_lock (proc_file_chain_lock); + #endif +- ((_IO_proc_file *) fp)->next = proc_file_chain; +- proc_file_chain = (_IO_proc_file *) fp; ++ spawn_ok = spawn_process (&fa, fp, command, do_cloexec, pipe_fds, ++ parent_end, child_end, child_pipe_fd); + #ifdef _IO_MTSAFE_IO + _IO_lock_unlock (proc_file_chain_lock); + _IO_cleanup_region_end (0); + #endif + ++ __posix_spawn_file_actions_destroy (&fa); ++ ++ if (!spawn_ok) ++ { ++ spawn_failure: ++ __close_nocancel (pipe_fds[child_end]); ++ __close_nocancel (pipe_fds[parent_end]); ++ __set_errno (ENOMEM); ++ return NULL; ++ } ++ + _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES); + return fp; + } diff --git a/SOURCES/glibc-rh2065588-3.patch b/SOURCES/glibc-rh2065588-3.patch new file mode 100644 index 0000000..d168d88 --- /dev/null +++ b/SOURCES/glibc-rh2065588-3.patch @@ -0,0 +1,527 @@ +commit 5fb7fc96350575c9adb1316833e48ca11553be49 +Author: Adhemerval Zanella +Date: Wed Oct 24 16:29:38 2018 -0300 + + posix: Use posix_spawn on system + + This patch uses posix_spawn on system implementation. On Linux this has + the advantage of much lower memory consumption (usually 32 Kb minimum for + the mmap stack area). + + Although POSIX does not require, glibc system implementation aims to be + thread and cancellation safe. The cancellation code is moved to generic + implementation and enabled iff SIGCANCEL is defined (similar on how the + cancellation handler is enabled on nptl-init.c). + + Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, + arm-linux-gnueabihf, and powerpc64le-linux-gnu. + + * sysdeps/unix/sysv/linux/spawni.c (__spawni_child): Use + __sigismember instead of sigismember. + * sysdeps/posix/system.c [SIGCANCEL] (cancel_handler_args, + cancel_handler): New definitions. + (CLEANUP_HANDLER, CLEANUP_RESET): Likewise. + (DO_LOCK, DO_UNLOCK, INIT_LOCK, ADD_REF, SUB_REF): Remove. + (do_system): Use posix_spawn instead of fork and execl and remove + reentracy code. + * sysdeps/generic/not-errno.h (__kill_noerrno): New prototype. + * sysdeps/unix/sysv/linux/not-errno.h (__kill_noerrno): Likewise. + * sysdeps/unix/sysv/linux/ia64/system.c: Remove file. + * sysdeps/unix/sysv/linux/s390/system.c: Likewise. + * sysdeps/unix/sysv/linux/sparc/system.c: Likewise. + * sysdeps/unix/sysv/linux/system.c: Likewise. + +diff --git a/sysdeps/generic/not-errno.h b/sysdeps/generic/not-errno.h +index 93617a3266fd4aad..0fd66b5c5ed82315 100644 +--- a/sysdeps/generic/not-errno.h ++++ b/sysdeps/generic/not-errno.h +@@ -17,3 +17,5 @@ + . */ + + extern __typeof (__access) __access_noerrno attribute_hidden; ++ ++extern __typeof (__kill) __kill_noerrno attribute_hidden; +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index d7594436ed59906f..8a51a6b9919ec39b 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -17,20 +17,36 @@ + + #include + #include +-#include + #include + #include ++#include ++#include ++#include + #include + #include +-#include +-#include +-#include ++#include + ++#include ++#include ++#include ++#include + + #define SHELL_PATH "/bin/sh" /* Path of the shell. */ + #define SHELL_NAME "sh" /* Name to give it. */ + + ++/* This system implementation aims to be thread-safe, which requires to ++ restore the signal dispositions for SIGINT and SIGQUIT correctly and to ++ deal with cancellation by terminating the child process. ++ ++ The signal disposition restoration on the single-thread case is ++ straighfoward. For multithreaded case, a reference-counter with a lock ++ is used, so the first thread will set the SIGINT/SIGQUIT dispositions and ++ last thread will restore them. ++ ++ Cancellation handling is done with thread cancellation clean-up handlers ++ on waitpid call. */ ++ + #ifdef _LIBC_REENTRANT + static struct sigaction intr, quit; + static int sa_refcntr; +@@ -50,17 +66,45 @@ __libc_lock_define_initialized (static, lock); + #endif + + ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++struct cancel_handler_args ++{ ++ struct sigaction *quit; ++ struct sigaction *intr; ++ pid_t pid; ++}; ++ ++static void ++cancel_handler (void *arg) ++{ ++ struct cancel_handler_args *args = (struct cancel_handler_args *) (arg); ++ ++ __kill_noerrno (args->pid, SIGKILL); ++ ++ TEMP_FAILURE_RETRY (__waitpid_nocancel (args->pid, NULL, 0)); ++ ++ DO_LOCK (); ++ if (SUB_REF () == 0) ++ { ++ __sigaction (SIGQUIT, args->quit, NULL); ++ __sigaction (SIGINT, args->intr, NULL); ++ } ++ DO_UNLOCK (); ++} ++#endif ++ + /* Execute LINE as a shell command, returning its status. */ + static int + do_system (const char *line) + { +- int status, save; ++ int status; + pid_t pid; + struct sigaction sa; + #ifndef _LIBC_REENTRANT + struct sigaction intr, quit; + #endif + sigset_t omask; ++ sigset_t reset; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; +@@ -69,105 +113,72 @@ do_system (const char *line) + DO_LOCK (); + if (ADD_REF () == 0) + { +- if (__sigaction (SIGINT, &sa, &intr) < 0) +- { +- (void) SUB_REF (); +- goto out; +- } +- if (__sigaction (SIGQUIT, &sa, &quit) < 0) +- { +- save = errno; +- (void) SUB_REF (); +- goto out_restore_sigint; +- } ++ /* sigaction can not fail with SIGINT/SIGQUIT used with SIG_IGN. */ ++ __sigaction (SIGINT, &sa, &intr); ++ __sigaction (SIGQUIT, &sa, &quit); + } + DO_UNLOCK (); + +- /* We reuse the bitmap in the 'sa' structure. */ + __sigaddset (&sa.sa_mask, SIGCHLD); +- save = errno; +- if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) ++ /* sigprocmask can not fail with SIG_BLOCK used with valid input ++ arguments. */ ++ __sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask); ++ ++ __sigemptyset (&reset); ++ if (intr.sa_handler != SIG_IGN) ++ __sigaddset(&reset, SIGINT); ++ if (quit.sa_handler != SIG_IGN) ++ __sigaddset(&reset, SIGQUIT); ++ ++ posix_spawnattr_t spawn_attr; ++ /* None of the posix_spawnattr_* function returns an error, including ++ posix_spawnattr_setflags for the follow specific usage (using valid ++ flags). */ ++ __posix_spawnattr_init (&spawn_attr); ++ __posix_spawnattr_setsigmask (&spawn_attr, &omask); ++ __posix_spawnattr_setsigdefault (&spawn_attr, &reset); ++ __posix_spawnattr_setflags (&spawn_attr, ++ POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); ++ ++ status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, ++ (char *const[]){ (char*) SHELL_NAME, ++ (char*) "-c", ++ (char *) line, NULL }, ++ __environ); ++ __posix_spawnattr_destroy (&spawn_attr); ++ ++ if (status == 0) + { +-#ifndef _LIBC +- if (errno == ENOSYS) +- __set_errno (save); +- else +-#endif +- { +- DO_LOCK (); +- if (SUB_REF () == 0) +- { +- save = errno; +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- out_restore_sigint: +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- __set_errno (save); +- } +- out: +- DO_UNLOCK (); +- return -1; +- } +- } +- +-#ifdef CLEANUP_HANDLER +- CLEANUP_HANDLER; +-#endif +- +-#ifdef FORK +- pid = FORK (); +-#else +- pid = __fork (); ++ /* Cancellation results in cleanup handlers running as exceptions in ++ the block where they were installed, so it is safe to reference ++ stack variable allocate in the broader scope. */ ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++ struct cancel_handler_args cancel_args = ++ { ++ .quit = &quit, ++ .intr = &intr, ++ .pid = pid ++ }; ++ __libc_cleanup_region_start (1, cancel_handler, &cancel_args); + #endif +- if (pid == (pid_t) 0) +- { +- /* Child side. */ +- const char *new_argv[4]; +- new_argv[0] = SHELL_NAME; +- new_argv[1] = "-c"; +- new_argv[2] = line; +- new_argv[3] = NULL; +- +- /* Restore the signals. */ +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); +- INIT_LOCK (); +- +- /* Exec the shell. */ +- (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); +- _exit (127); +- } +- else if (pid < (pid_t) 0) +- /* The fork failed. */ +- status = -1; +- else +- /* Parent side. */ +- { + /* Note the system() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not + have to do anything here. */ + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid) + status = -1; +- } +- +-#ifdef CLEANUP_HANDLER +- CLEANUP_RESET; ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++ __libc_cleanup_region_end (0); + #endif ++ } + +- save = errno; + DO_LOCK (); +- if ((SUB_REF () == 0 +- && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL) +- | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) +- || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) ++ if (SUB_REF () == 0) + { +-#ifndef _LIBC +- /* glibc cannot be used on systems without waitpid. */ +- if (errno == ENOSYS) +- __set_errno (save); +- else +-#endif +- status = -1; ++ /* sigaction can not fail with SIGINT/SIGQUIT used with old ++ disposition. Same applies for sigprocmask. */ ++ __sigaction (SIGINT, &intr, NULL); ++ __sigaction (SIGQUIT, &quit, NULL); ++ __sigprocmask (SIG_SETMASK, &omask, NULL); + } + DO_UNLOCK (); + +diff --git a/sysdeps/unix/sysv/linux/ia64/system.c b/sysdeps/unix/sysv/linux/ia64/system.c +deleted file mode 100644 +index d09fefefe64753ab..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/system.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* Copyright (C) 2002-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ +- &pid, NULL, NULL) +- +-#include +diff --git a/sysdeps/unix/sysv/linux/not-errno.h b/sysdeps/unix/sysv/linux/not-errno.h +index 106ba5c72e3d7dda..b2f72cfb3d412c56 100644 +--- a/sysdeps/unix/sysv/linux/not-errno.h ++++ b/sysdeps/unix/sysv/linux/not-errno.h +@@ -16,6 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++#include ++ + /* This function is used on maybe_enable_malloc_check (elf/dl-tunables.c) + and to avoid having to build/use multiple versions if stack protection + in enabled it is defined as inline. */ +@@ -33,3 +36,14 @@ __access_noerrno (const char *pathname, int mode) + return INTERNAL_SYSCALL_ERRNO (res, err); + return 0; + } ++ ++static inline int ++__kill_noerrno (pid_t pid, int sig) ++{ ++ int res; ++ INTERNAL_SYSCALL_DECL (err); ++ res = INTERNAL_SYSCALL_CALL (kill, err, pid, sig); ++ if (INTERNAL_SYSCALL_ERROR_P (res, err)) ++ return INTERNAL_SYSCALL_ERRNO (res, err); ++ return 0; ++} +diff --git a/sysdeps/unix/sysv/linux/s390/system.c b/sysdeps/unix/sysv/linux/s390/system.c +deleted file mode 100644 +index d8ef46133419dd89..0000000000000000 +--- a/sysdeps/unix/sysv/linux/s390/system.c ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* Copyright (C) 2003-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid) +- +-#include "../system.c" +diff --git a/sysdeps/unix/sysv/linux/sparc/system.c b/sysdeps/unix/sysv/linux/sparc/system.c +deleted file mode 100644 +index 1f65c83399f920d6..0000000000000000 +--- a/sysdeps/unix/sysv/linux/sparc/system.c ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* Copyright (C) 2003-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL) +- +-#include "../system.c" +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index 85239cedbf2a5ab5..6a8bd2ed2e1c29b7 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -138,11 +138,11 @@ __spawni_child (void *arguments) + for (int sig = 1; sig < _NSIG; ++sig) + { + if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) +- && sigismember (&attr->__sd, sig)) ++ && __sigismember (&attr->__sd, sig)) + { + sa.sa_handler = SIG_DFL; + } +- else if (sigismember (&hset, sig)) ++ else if (__sigismember (&hset, sig)) + { + if (__is_internal_signal (sig)) + sa.sa_handler = SIG_IGN; +diff --git a/sysdeps/unix/sysv/linux/system.c b/sysdeps/unix/sysv/linux/system.c +deleted file mode 100644 +index 7cc68a1528ee8f99..0000000000000000 +--- a/sysdeps/unix/sysv/linux/system.c ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* Copyright (C) 2002-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include +-#include +-#include /* For the real memset prototype. */ +-#include +-#include +-#include +-#include +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#ifndef FORK +-# define FORK() \ +- INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid) +-#endif +- +-#ifdef _LIBC_REENTRANT +-static void cancel_handler (void *arg); +- +-# define CLEANUP_HANDLER \ +- __libc_cleanup_region_start (1, cancel_handler, &pid) +- +-# define CLEANUP_RESET \ +- __libc_cleanup_region_end (0) +-#endif +- +- +-/* Linux has waitpid(), so override the generic unix version. */ +-#include +- +- +-#ifdef _LIBC_REENTRANT +-/* The cancellation handler. */ +-static void +-cancel_handler (void *arg) +-{ +- pid_t child = *(pid_t *) arg; +- +- INTERNAL_SYSCALL_DECL (err); +- INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL); +- +- TEMP_FAILURE_RETRY (__waitpid (child, NULL, 0)); +- +- DO_LOCK (); +- +- if (SUB_REF () == 0) +- { +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- } +- +- DO_UNLOCK (); +-} +-#endif diff --git a/SOURCES/glibc-rh2065588-4.patch b/SOURCES/glibc-rh2065588-4.patch new file mode 100644 index 0000000..33a0cce --- /dev/null +++ b/SOURCES/glibc-rh2065588-4.patch @@ -0,0 +1,194 @@ +commit f09542c584b121da0322fde4b55306d512b85d93 +Author: Adhemerval Zanella +Date: Mon Mar 23 15:23:20 2020 -0300 + + posix: Fix system error return value [BZ #25715] + + It fixes 5fb7fc9635 when posix_spawn fails. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + Reviewed-by: Carlos O'Donell + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index d14839f3ec3a7bad..b61bd347df7ec46a 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -17,14 +17,128 @@ + . */ + + #include ++#include ++#include ++#include ++#include + ++#include ++#include ++#include ++#include ++ ++static char *tmpdir; ++static long int namemax; ++ ++static void ++do_prepare (int argc, char *argv[]) ++{ ++ tmpdir = support_create_temp_directory ("tst-system-"); ++ /* Include the last '/0'. */ ++ namemax = pathconf (tmpdir, _PC_NAME_MAX) + 1; ++ TEST_VERIFY_EXIT (namemax != -1); ++} ++#define PREPARE do_prepare ++ ++struct args ++{ ++ const char *command; ++ int exit_status; ++ int term_sig; ++ const char *path; ++}; ++ ++static void ++call_system (void *closure) ++{ ++ struct args *args = (struct args *) closure; ++ int ret; ++ ++ if (args->path != NULL) ++ TEST_COMPARE (setenv ("PATH", args->path, 1), 0); ++ ret = system (args->command); ++ if (args->term_sig == 0) ++ { ++ /* Expect regular termination. */ ++ TEST_VERIFY (WIFEXITED (ret) != 0); ++ TEST_COMPARE (WEXITSTATUS (ret), args->exit_status); ++ } ++ else ++ { ++ /* status_or_signal < 0. Expect termination by signal. */ ++ TEST_VERIFY (WIFSIGNALED (ret) != 0); ++ TEST_COMPARE (WTERMSIG (ret), args->term_sig); ++ } ++} + + static int + do_test (void) + { +- return system (":"); +-} ++ TEST_VERIFY (system (NULL) != 0); + ++ { ++ char cmd[namemax]; ++ memset (cmd, 'a', sizeof(cmd)); ++ cmd[sizeof(cmd) - 1] = '\0'; ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ cmd, 127, 0, tmpdir ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); ++ ++ char *returnerr = xasprintf ("%s: 1: %s: not found\n", ++ basename(_PATH_BSHELL), cmd); ++ TEST_COMPARE_STRING (result.err.buffer, returnerr); ++ free (returnerr); ++ } ++ ++ { ++ char cmd[namemax + 1]; ++ memset (cmd, 'a', sizeof(cmd)); ++ cmd[sizeof(cmd) - 1] = '\0'; ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ cmd, 127, 0, tmpdir ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); ++ ++ char *returnerr = xasprintf ("%s: 1: %s: File name too long\n", ++ basename(_PATH_BSHELL), cmd); ++ TEST_COMPARE_STRING (result.err.buffer, returnerr); ++ free (returnerr); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ "kill -USR1 $$", 0, SIGUSR1 ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { "echo ...", 0 }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stdout); ++ TEST_COMPARE_STRING (result.out.buffer, "...\n"); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { "exit 1", 1 }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ } ++ ++ TEST_COMPARE (system (":"), 0); ++ ++ return 0; ++} + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 8a51a6b9919ec39b..7db09a05c3fbca43 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -97,7 +97,8 @@ cancel_handler (void *arg) + static int + do_system (const char *line) + { +- int status; ++ int status = -1; ++ int ret; + pid_t pid; + struct sigaction sa; + #ifndef _LIBC_REENTRANT +@@ -140,14 +141,14 @@ do_system (const char *line) + __posix_spawnattr_setflags (&spawn_attr, + POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); + +- status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, +- (char *const[]){ (char*) SHELL_NAME, +- (char*) "-c", +- (char *) line, NULL }, +- __environ); ++ ret = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, ++ (char *const[]){ (char *) SHELL_NAME, ++ (char *) "-c", ++ (char *) line, NULL }, ++ __environ); + __posix_spawnattr_destroy (&spawn_attr); + +- if (status == 0) ++ if (ret == 0) + { + /* Cancellation results in cleanup handlers running as exceptions in + the block where they were installed, so it is safe to reference +@@ -182,6 +183,9 @@ do_system (const char *line) + } + DO_UNLOCK (); + ++ if (ret != 0) ++ __set_errno (ret); ++ + return status; + } + diff --git a/SOURCES/glibc-rh2065588-5.patch b/SOURCES/glibc-rh2065588-5.patch new file mode 100644 index 0000000..368e759 --- /dev/null +++ b/SOURCES/glibc-rh2065588-5.patch @@ -0,0 +1,64 @@ +commit 7a7226543611897103c7483bec160547294dcf0d +Author: Alexandra Hájková +Date: Sat Dec 26 20:44:34 2020 +0100 + + Add xfchmod to libsupport + +diff --git a/support/Makefile b/support/Makefile +index d2b95539403e416c..4875f52495ef292d 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -91,6 +91,7 @@ libsupport-routines = \ + xdlfcn \ + xdlmopen \ + xdup2 \ ++ xfchmod \ + xfclose \ + xfopen \ + xfork \ +diff --git a/support/xfchmod.c b/support/xfchmod.c +new file mode 100644 +index 0000000000000000..4323b9ca8e078c98 +--- /dev/null ++++ b/support/xfchmod.c +@@ -0,0 +1,28 @@ ++/* fchmod with error checking. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xfchmod (int fd, mode_t mode) ++{ ++ if (fchmod (fd, mode) != 0) ++ FAIL_EXIT1 ("fchmod (%d, 0%o): %m", fd, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index 74fd2771d12c36fe..ced8cb1dd9ee356c 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -45,6 +45,7 @@ long long xlseek (int fd, long long offset, int whence); + void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); ++void xfchmod (int fd, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/SOURCES/glibc-rh2065588-6.patch b/SOURCES/glibc-rh2065588-6.patch new file mode 100644 index 0000000..16fdb47 --- /dev/null +++ b/SOURCES/glibc-rh2065588-6.patch @@ -0,0 +1,56 @@ +commit 7b9c3260bcca73781dda6bc2ddee84869bedfb8c +Author: Adhemerval Zanella +Date: Mon Dec 14 11:42:33 2020 -0300 + + support: Add xchmod wrapper + + Checked on x86_64-linux-gnu. + +diff --git a/support/xchmod.c b/support/xchmod.c +new file mode 100644 +index 0000000000000000..5e403c7cc2705aef +--- /dev/null ++++ b/support/xchmod.c +@@ -0,0 +1,30 @@ ++/* chmod with error checking. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++#include ++ ++void ++xchmod (const char *pathname, mode_t mode) ++{ ++ int r = chmod (pathname, mode); ++ if (r < 0) ++ FAIL_EXIT1 ("chmod (%s, %d): %m", pathname, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index ced8cb1dd9ee356c..e92056c65efe8d6a 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -46,6 +46,7 @@ void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); + void xfchmod (int fd, mode_t mode); ++void xchmod (const char *pathname, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/SOURCES/glibc-rh2065588-7.patch b/SOURCES/glibc-rh2065588-7.patch new file mode 100644 index 0000000..b16b79e --- /dev/null +++ b/SOURCES/glibc-rh2065588-7.patch @@ -0,0 +1,73 @@ +commit 4eda036f5b897fa8bc20ddd2099b5a6ed4239dc9 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:48:34 2020 -0300 + + stdlib: Move tst-system to tests-container + + Fix some issues with different shell and error messages. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 01194bbf7cc96851..9d0edcf6a7749b28 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -70,7 +70,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + test-canon test-canon2 tst-strtoll tst-environ \ + tst-xpg-basename tst-random tst-random2 tst-bsearch \ + tst-limits tst-rand48 bug-strtod tst-setcontext \ +- tst-setcontext2 test-a64l tst-qsort tst-system testmb2 \ ++ tst-setcontext2 test-a64l tst-qsort testmb2 \ + bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 \ + tst-rand48-2 tst-makecontext tst-strtod5 \ + tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \ +@@ -92,6 +92,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ + tst-tls-atexit tst-tls-atexit-nodelete + tests-static := tst-secure-getenv ++tests-container := tst-system + + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-empty-env +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index b61bd347df7ec46a..194e09828dd5c206 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -88,7 +88,8 @@ do_test (void) + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); + +- char *returnerr = xasprintf ("%s: 1: %s: not found\n", ++ char *returnerr = xasprintf ("%s: execing %s failed: " ++ "No such file or directory", + basename(_PATH_BSHELL), cmd); + TEST_COMPARE_STRING (result.err.buffer, returnerr); + free (returnerr); +@@ -106,7 +107,8 @@ do_test (void) + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); + +- char *returnerr = xasprintf ("%s: 1: %s: File name too long\n", ++ char *returnerr = xasprintf ("%s: execing %s failed: " ++ "File name too long", + basename(_PATH_BSHELL), cmd); + TEST_COMPARE_STRING (result.err.buffer, returnerr); + free (returnerr); +@@ -116,7 +118,7 @@ do_test (void) + struct support_capture_subprocess result; + result = support_capture_subprocess (call_system, + &(struct args) { +- "kill -USR1 $$", 0, SIGUSR1 ++ "kill $$", 0, SIGTERM + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } +@@ -136,7 +138,7 @@ do_test (void) + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } + +- TEST_COMPARE (system (":"), 0); ++ TEST_COMPARE (system (""), 0); + + return 0; + } diff --git a/SOURCES/glibc-rh2065588-8.patch b/SOURCES/glibc-rh2065588-8.patch new file mode 100644 index 0000000..102b72a --- /dev/null +++ b/SOURCES/glibc-rh2065588-8.patch @@ -0,0 +1,74 @@ +commit 42dda89dcb0407f6799dbfd0b9dab1529666ad51 +Author: Adhemerval Zanella +Date: Fri Dec 11 15:23:05 2020 -0300 + + posix: Fix return value of system if shell can not be executed [BZ #27053] + + POSIX states that system returned code for failure to execute the shell + shall be as if the shell had terminated using _exit(127). This + behaviour was removed with 5fb7fc96350575. + + Checked on x86_64-linux-gnu. + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index 194e09828dd5c206..8681584f15ef3b47 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + static char *tmpdir; + static long int namemax; +@@ -138,6 +139,22 @@ do_test (void) + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } + ++ { ++ struct stat64 st; ++ xstat (_PATH_BSHELL, &st); ++ mode_t mode = st.st_mode; ++ xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH)); ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ "exit 1", 127, 0 ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ ++ xchmod (_PATH_BSHELL, st.st_mode); ++ } ++ + TEST_COMPARE (system (""), 0); + + return 0; +diff --git a/support/Makefile b/support/Makefile +index 4875f52495ef292d..09b41b0d57e9239a 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -86,6 +86,7 @@ libsupport-routines = \ + xchroot \ + xclone \ + xclose \ ++ xchmod \ + xconnect \ + xcopy_file_range \ + xdlfcn \ +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 7db09a05c3fbca43..047ded4badfddcab 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -171,6 +171,10 @@ do_system (const char *line) + __libc_cleanup_region_end (0); + #endif + } ++ else ++ /* POSIX states that failure to execute the shell should return ++ as if the shell had terminated using _exit(127). */ ++ status = W_EXITCODE (127, 0); + + DO_LOCK (); + if (SUB_REF () == 0) diff --git a/SOURCES/glibc-rh2065588-9.patch b/SOURCES/glibc-rh2065588-9.patch new file mode 100644 index 0000000..6d259d8 --- /dev/null +++ b/SOURCES/glibc-rh2065588-9.patch @@ -0,0 +1,21 @@ +commit 542160f0b6a7c26758c9575a8876f6624a5dd65f +Author: Girish Joshi +Date: Mon Mar 2 15:19:29 2020 -0500 + + Fixed typo in run_command_array() in support/shell-container.c + + https://sourceware.org/bugzilla/show_bug.cgi?id=23991 + +diff --git a/support/shell-container.c b/support/shell-container.c +index 9bd90d3f60529079..e87ac5cf1baa84e5 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -228,7 +228,7 @@ run_command_array (char **argv) + if (new_stderr != 2) + { + dup2 (new_stderr, 2); +- close (new_stdout); ++ close (new_stderr); + } + + if (builtin_func != NULL) diff --git a/SOURCES/glibc-rh2072329.patch b/SOURCES/glibc-rh2072329.patch new file mode 100644 index 0000000..e26331e --- /dev/null +++ b/SOURCES/glibc-rh2072329.patch @@ -0,0 +1,86 @@ +commit 33e03f9cd2be4f2cd62f93fda539cc07d9c8130e +Author: Joan Bruguera +Date: Mon Apr 11 19:49:56 2022 +0200 + + misc: Fix rare fortify crash on wchar funcs. [BZ 29030] + + If `__glibc_objsize (__o) == (size_t) -1` (i.e. `__o` is unknown size), fortify + checks should pass, and `__whatever_alias` should be called. + + Previously, `__glibc_objsize (__o) == (size_t) -1` was explicitly checked, but + on commit a643f60c53876b, this was moved into `__glibc_safe_or_unknown_len`. + + A comment says the -1 case should work as: "The -1 check is redundant because + since it implies that __glibc_safe_len_cond is true.". But this fails when: + * `__s > 1` + * `__osz == -1` (i.e. unknown size at compile time) + * `__l` is big enough + * `__l * __s <= __osz` can be folded to a constant + (I only found this to be true for `mbsrtowcs` and other functions in wchar2.h) + + In this case `__l * __s <= __osz` is false, and `__whatever_chk_warn` will be + called by `__glibc_fortify` or `__glibc_fortify_n` and crash the program. + + This commit adds the explicit `__osz == -1` check again. + moc crashes on startup due to this, see: https://bugs.archlinux.org/task/74041 + + Minimal test case (test.c): + #include + + int main (void) + { + const char *hw = "HelloWorld"; + mbsrtowcs (NULL, &hw, (size_t)-1, NULL); + return 0; + } + + Build with: + gcc -O2 -Wp,-D_FORTIFY_SOURCE=2 test.c -o test && ./test + + Output: + *** buffer overflow detected ***: terminated + + Fixes: BZ #29030 + Signed-off-by: Joan Bruguera + Signed-off-by: Siddhesh Poyarekar + +diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c +index 1668294e48b5c63c..701bffd1d664f289 100644 +--- a/debug/tst-fortify.c ++++ b/debug/tst-fortify.c +@@ -1505,6 +1505,11 @@ do_test (void) + CHK_FAIL_END + #endif + ++ /* Bug 29030 regresion check */ ++ cp = "HelloWorld"; ++ if (mbsrtowcs (NULL, &cp, (size_t)-1, &s) != 10) ++ FAIL (); ++ + cp = "A"; + if (mbstowcs (wenough, cp, 10) != 1 + || wcscmp (wenough, L"A") != 0) +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index a17ae0ed87e6163f..404496c7d6da4fb3 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -143,13 +143,13 @@ + || (__builtin_constant_p (__l) && (__l) > 0)) + + /* Length is known to be safe at compile time if the __L * __S <= __OBJSZ +- condition can be folded to a constant and if it is true. The -1 check is +- redundant because since it implies that __glibc_safe_len_cond is true. */ ++ condition can be folded to a constant and if it is true, or unknown (-1) */ + #define __glibc_safe_or_unknown_len(__l, __s, __osz) \ +- (__glibc_unsigned_or_positive (__l) \ +- && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ +- __s, __osz)) \ +- && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz)) ++ ((__osz) == (__SIZE_TYPE__) -1 \ ++ || (__glibc_unsigned_or_positive (__l) \ ++ && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ ++ (__s), (__osz))) \ ++ && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), (__s), (__osz)))) + + /* Conversely, we know at compile time that the length is unsafe if the + __L * __S <= __OBJSZ condition can be folded to a constant and if it is diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index 96e229e..fd45e83 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.28 %define glibcversion 2.28 -%define glibcrelease 197%{?dist} +%define glibcrelease 199%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -879,6 +879,20 @@ Patch684: glibc-rh2033684-12.patch Patch685: glibc-rh2063712.patch Patch686: glibc-rh2063042.patch Patch687: glibc-rh2071745.patch +Patch688: glibc-rh2065588-1.patch +Patch689: glibc-rh2065588-2.patch +Patch690: glibc-rh2065588-3.patch +Patch691: glibc-rh2065588-4.patch +Patch692: glibc-rh2065588-5.patch +Patch693: glibc-rh2065588-6.patch +Patch694: glibc-rh2065588-7.patch +Patch695: glibc-rh2065588-8.patch +Patch696: glibc-rh2065588-9.patch +Patch697: glibc-rh2065588-10.patch +Patch698: glibc-rh2065588-11.patch +Patch699: glibc-rh2065588-12.patch +Patch700: glibc-rh2065588-13.patch +Patch701: glibc-rh2072329.patch ############################################################################## # Continued list of core "glibc" package information: @@ -2709,6 +2723,12 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Tue Apr 26 2022 Siddhesh Poyarekar - 2.28-199 +- Fix fortify false positive with mbsrtowcs and mbsnrtowcs (#2072329). + +* Fri Apr 22 2022 Carlos O'Donell - 2.28-198 +- Fix multi-threaded popen defect leading to segfault (#2065588) + * Tue Apr 05 2022 Arjun Shankar - 2.28-197 - timezone: Fix a test that causes occasional build failure (#2071745)