On Wed, Feb 15, 2023 at 03:11:46PM +0100, Laszlo Ersek wrote:
> Per POSIX, execvp() is not safe to call in a child process forked from a
> multi-threaded process. We can now replace the execvp() call in the child
> process with a call to our fork-safe (async-signal-safe) variant.
> 
> Prepare our internal execvpe context on the parent's construction path,
> use the context in the child, and release the context in the parent on the
> way out, regardless of whether the handler as a whole succeeded or not.
> (The context is only a temporary resource.)
> 
> Signed-off-by: Laszlo Ersek <ler...@redhat.com>
> ---
> 
> Notes:
>     context:-U11
> 
>  generator/states-connect-socket-activation.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/generator/states-connect-socket-activation.c 
> b/generator/states-connect-socket-activation.c
> index 81bb850c7d8c..cb3b1c6f4ede 100644
> --- a/generator/states-connect-socket-activation.c
> +++ b/generator/states-connect-socket-activation.c
> @@ -93,22 +93,23 @@ prepare_socket_activation_environment (string_vector *env)
>    string_vector_empty (env);
>    return -1;
>  }
>  
>  STATE_MACHINE {
>   CONNECT_SA.START:
>    enum state next;
>    char *tmpdir;
>    char *sockpath;
>    int s;
>    struct sockaddr_un addr;
> +  struct execvpe execvpe_ctx;
>    string_vector env;
>    pid_t pid;
>  
>    assert (!h->sock);
>    assert (h->argv.ptr);
>    assert (h->argv.ptr[0]);
>  
>    next = %.DEAD;
>  
>    /* Use /tmp instead of TMPDIR because we must ensure the path is
>     * short enough to store in the sockaddr_un.  On some platforms this
> @@ -140,25 +141,31 @@  CONNECT_SA.START:
>    memcpy (addr.sun_path, sockpath, strlen (sockpath) + 1);
>    if (bind (s, (struct sockaddr *) &addr, sizeof addr) == -1) {
>      set_error (errno, "bind: %s", sockpath);
>      goto close_socket;
>    }
>  
>    if (listen (s, SOMAXCONN) == -1) {
>      set_error (errno, "listen");
>      goto unlink_sockpath;
>    }
>  
> +  if (nbd_internal_execvpe_init (&execvpe_ctx, h->argv.ptr[0], h->argv.len) 
> ==
> +      -1) {
> +    set_error (errno, "nbd_internal_execvpe_init");
> +    goto unlink_sockpath;
> +  }
> +
>    if (prepare_socket_activation_environment (&env) == -1) {
>      set_error (errno, "prepare_socket_activation_environment");
> -    goto unlink_sockpath;
> +    goto uninit_execvpe;
>    }
>  
>    pid = fork ();
>    if (pid == -1) {
>      set_error (errno, "fork");
>      goto empty_env;
>    }
>  
>    if (pid == 0) {         /* child - run command */
>      if (s != FIRST_SOCKET_ACTIVATION_FD) {
>        if (dup2 (s, FIRST_SOCKET_ACTIVATION_FD) == -1) {
> @@ -189,45 +196,47 @@  CONNECT_SA.START:
>      char buf[32];
>      const char *v =
>        nbd_internal_fork_safe_itoa ((long) getpid (), buf, sizeof buf);
>      strcpy (&env.ptr[0][PREFIX_LENGTH], v);
>  
>      /* Restore SIGPIPE back to SIG_DFL. */
>      if (signal (SIGPIPE, SIG_DFL) == SIG_ERR) {
>        nbd_internal_fork_safe_perror ("signal");
>        _exit (126);
>      }
>  
> -    environ = env.ptr;
> -    execvp (h->argv.ptr[0], h->argv.ptr);
> +    (void)nbd_internal_fork_safe_execvpe (&execvpe_ctx, &h->argv, env.ptr);
>      nbd_internal_fork_safe_perror (h->argv.ptr[0]);
>      if (errno == ENOENT)
>        _exit (127);
>      else
>        _exit (126);
>    }
>  
>    /* Parent -- we're done; commit. */
>    h->sact_tmpdir = tmpdir;
>    h->sact_sockpath = sockpath;
>    h->pid = pid;
>  
>    h->connaddrlen = sizeof addr;
>    memcpy (&h->connaddr, &addr, h->connaddrlen);
>    next = %^CONNECT.START;
>  
>    /* fall through, for releasing the temporaries */
>  
>  empty_env:
>    string_vector_empty (&env);
>  
> +uninit_execvpe:
> +  nbd_internal_execvpe_uninit (&execvpe_ctx);
> +
>  unlink_sockpath:
>    if (next == %.DEAD)
>      unlink (sockpath);
>  
>  close_socket:
>    close (s);
>  
>  free_sockpath:
>    if (next == %.DEAD)
>      free (sockpath);

Reviewed-by: Richard W.M. Jones <rjo...@redhat.com>


-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-builder quickly builds VMs from scratch
http://libguestfs.org/virt-builder.1.html
_______________________________________________
Libguestfs mailing list
Libguestfs@redhat.com
https://listman.redhat.com/mailman/listinfo/libguestfs

Reply via email to