spawn: Don't set a search path if we don't want to search PATH

do_exec() and g_execute() rely on being passed a NULL search path
if we intend to avoid searching the PATH, but since the refactoring
in commit 62ce66d4, this was never done. This resulted in some spawn
calls searching the PATH when it was not intended.

Spawn calls that go through the posix_spawn fast-path were unaffected.

The deprecated gtester utility, as used in GTK 3, relies on the
ability to run an executable from the current working directory by
omitting the G_SPAWN_SEARCH_PATH flag. This *mostly* worked, because
our fallback PATH ends with ".". However, if an executable of the
same name existed in /usr/bin or /bin, it would run that instead of the
intended test: in particular, GTK 3's build-time tests failed if
ImageMagick happens to be installed, because gtester would accidentally
run display(1) instead of testsuite/gdk/display.

Fixes: 62ce66d4 "gspawn: Don’t use getenv() in async-signal-safe context"
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=977961
This commit is contained in:
Simon McVittie 2021-01-27 10:53:22 +00:00 committed by Philip Withnall
parent 872181c4f8
commit 0d50c6bbe6

View File

@ -1819,7 +1819,7 @@ fork_exec_with_fds (gboolean intermediate_child,
if (search_path && chosen_search_path == NULL) if (search_path && chosen_search_path == NULL)
chosen_search_path = g_getenv ("PATH"); chosen_search_path = g_getenv ("PATH");
if (chosen_search_path == NULL) if ((search_path || search_path_from_envp) && chosen_search_path == NULL)
{ {
/* There is no 'PATH' in the environment. The default /* There is no 'PATH' in the environment. The default
* * search path in libc is the current directory followed by * * search path in libc is the current directory followed by
@ -1834,14 +1834,27 @@ fork_exec_with_fds (gboolean intermediate_child,
chosen_search_path = "/bin:/usr/bin:."; chosen_search_path = "/bin:/usr/bin:.";
} }
if (search_path || search_path_from_envp)
g_assert (chosen_search_path != NULL);
else
g_assert (chosen_search_path == NULL);
/* Allocate a buffer which the fork()ed child can use to assemble potential /* Allocate a buffer which the fork()ed child can use to assemble potential
* paths for the binary to exec(), combining the argv[0] and elements from * paths for the binary to exec(), combining the argv[0] and elements from
* the chosen_search_path. This cant be done in the child because malloc() * the chosen_search_path. This cant be done in the child because malloc()
* (or alloca()) are not async-signal-safe (see `man 7 signal-safety`). * (or alloca()) are not async-signal-safe (see `man 7 signal-safety`).
* *
* Add 2 for the nul terminator and a leading `/`. */ * Add 2 for the nul terminator and a leading `/`. */
search_path_buffer_len = strlen (chosen_search_path) + strlen (argv[0]) + 2; if (chosen_search_path != NULL)
search_path_buffer = g_malloc (search_path_buffer_len); {
search_path_buffer_len = strlen (chosen_search_path) + strlen (argv[0]) + 2;
search_path_buffer = g_malloc (search_path_buffer_len);
}
if (search_path || search_path_from_envp)
g_assert (search_path_buffer != NULL);
else
g_assert (search_path_buffer == NULL);
/* And allocate a buffer which is 2 elements longer than @argv, so that if /* And allocate a buffer which is 2 elements longer than @argv, so that if
* script_execute() has to be called later on, it can build a wrapper argv * script_execute() has to be called later on, it can build a wrapper argv