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:
Pino Toscano
2015-12-15 15:00:11 +01:00
parent 6c6c3ea675
commit 9c3b4f6ad8
3 changed files with 38 additions and 24 deletions

View File

@@ -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);

View File

@@ -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));

View File

@@ -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]);