mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
daemon: improve internal commandrvf
- add a flag to request chroot for the process, which is done only as
very last (before chdir) operation before exec'ing the process in the
child: this avoids using CHROOT_IN & CHROOT_OUT around command*
invocations, and reduces the code spent in chroot mode
- add failure checks for dup2, open, and chdir done in child, not
proceeding to executing the process if they fail
- open /dev/null without O_CLOEXEC, so it stays available for the
exec'ed process, and thus we don't need to provide an own fd for stdin
Followup of commit fd2f175ee7, thanks also
to the notes and hints provided by Mateusz Guzik.
This commit is contained in:
@@ -244,7 +244,7 @@ do_command (char *const *argv)
|
||||
{
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r, dev_null_fd, flags;
|
||||
int r, flags;
|
||||
CLEANUP_BIND_STATE struct bind_state bind_state = { .mounted = false };
|
||||
CLEANUP_RESOLVER_STATE struct resolver_state resolver_state =
|
||||
{ .mounted = false };
|
||||
@@ -261,17 +261,6 @@ do_command (char *const *argv)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Provide /dev/null as stdin for the command, since we want
|
||||
* to make sure processes have an open stdin, and it is not
|
||||
* possible to rely on the guest to provide it (Linux guests
|
||||
* get /dev dynamically populated at runtime by udev).
|
||||
*/
|
||||
dev_null_fd = open ("/dev/null", O_RDONLY|O_CLOEXEC);
|
||||
if (dev_null_fd == -1) {
|
||||
reply_with_perror ("/dev/null");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bind_mount (&bind_state) == -1)
|
||||
return NULL;
|
||||
if (enable_network) {
|
||||
@@ -279,11 +268,9 @@ do_command (char *const *argv)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flags = COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN | dev_null_fd;
|
||||
flags = COMMAND_FLAG_DO_CHROOT;
|
||||
|
||||
CHROOT_IN;
|
||||
r = commandvf (&out, &err, flags, (const char * const *) argv);
|
||||
CHROOT_OUT;
|
||||
|
||||
free_bind_state (&bind_state);
|
||||
free_resolver_state (&resolver_state);
|
||||
|
||||
@@ -128,6 +128,7 @@ extern char **empty_list (void);
|
||||
#define COMMAND_FLAG_FD_MASK (1024-1)
|
||||
#define COMMAND_FLAG_FOLD_STDOUT_ON_STDERR 1024
|
||||
#define COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN 2048
|
||||
#define COMMAND_FLAG_DO_CHROOT 4096
|
||||
|
||||
extern int commandf (char **stdoutput, char **stderror, int flags,
|
||||
const char *name, ...) __attribute__((sentinel));
|
||||
|
||||
@@ -932,22 +932,48 @@ commandrvf (char **stdoutput, char **stderror, int flags,
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
close (0);
|
||||
if (flag_copy_stdin) {
|
||||
dup2 (flag_copy_fd, STDIN_FILENO);
|
||||
if (dup2 (flag_copy_fd, STDIN_FILENO) == -1) {
|
||||
perror ("dup2/flag_copy_fd");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
/* Set stdin to /dev/null (ignore failure) */
|
||||
ignore_value (open ("/dev/null", O_RDONLY|O_CLOEXEC));
|
||||
/* Set stdin to /dev/null. */
|
||||
if (open ("/dev/null", O_RDONLY) == -1) {
|
||||
perror ("open: /dev/null");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
close (so_fd[PIPE_READ]);
|
||||
close (se_fd[PIPE_READ]);
|
||||
if (!(flags & COMMAND_FLAG_FOLD_STDOUT_ON_STDERR))
|
||||
dup2 (so_fd[PIPE_WRITE], STDOUT_FILENO);
|
||||
else
|
||||
dup2 (se_fd[PIPE_WRITE], STDOUT_FILENO);
|
||||
dup2 (se_fd[PIPE_WRITE], STDERR_FILENO);
|
||||
if (!(flags & COMMAND_FLAG_FOLD_STDOUT_ON_STDERR)) {
|
||||
if (dup2 (so_fd[PIPE_WRITE], STDOUT_FILENO) == -1) {
|
||||
perror ("dup2/so_fd[PIPE_WRITE]");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (dup2 (se_fd[PIPE_WRITE], STDOUT_FILENO) == -1) {
|
||||
perror ("dup2/se_fd[PIPE_WRITE]");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (dup2 (se_fd[PIPE_WRITE], STDERR_FILENO) == -1) {
|
||||
perror ("dup2/se_fd[PIPE_WRITE]");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
close (so_fd[PIPE_WRITE]);
|
||||
close (se_fd[PIPE_WRITE]);
|
||||
|
||||
ignore_value (chdir ("/"));
|
||||
if (flags & COMMAND_FLAG_DO_CHROOT && sysroot_len > 0) {
|
||||
if (chroot (sysroot) == -1) {
|
||||
perror ("chroot in sysroot");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (chdir ("/") == -1) {
|
||||
perror ("chdir");
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
execvp (argv[0], (void *) argv);
|
||||
perror (argv[0]);
|
||||
|
||||
Reference in New Issue
Block a user