revokefs-fuse: Add --with-exit-fd arg to monitor parent process's exit

This is necessary so as to not leave the revokefs backend around
when the system-helper exits abruptly (e.g. OOM killer). It would
be a vulnerability if revokefs backend continues to live even after
the system-helper is killed as it might lead to write access to the
underlying directory.

Closes: #2657
Approved by: alexlarsson
This commit is contained in:
Umang Jain
2019-02-28 17:38:08 +05:30
committed by Atomic Bot
parent c9d0705ae9
commit cd53f71f9e
4 changed files with 49 additions and 7 deletions

View File

@@ -444,6 +444,7 @@ usage (const char *progname)
" -h --help print help\n"
" --socket=fd Pass in the socket fd\n"
" --backend Run the backend instead of fuse\n"
" --exit-with-fd=fd With --backend, exit when the given file descriptor is closed\n"
"\n", progname);
}
@@ -478,6 +479,7 @@ revokefs_opt_proc (void *data,
struct revokefs_config {
int socket_fd;
int exit_with_fd;
int backend;
};
@@ -485,6 +487,7 @@ struct revokefs_config {
static struct fuse_opt revokefs_opts[] = {
REVOKEFS_OPT ("--socket=%i", socket_fd, -1),
REVOKEFS_OPT ("--exit-with-fd=%i", exit_with_fd, -1),
REVOKEFS_OPT ("--backend", backend, 1),
FUSE_OPT_KEY ("-h", KEY_HELP),
@@ -497,7 +500,7 @@ main (int argc, char *argv[])
{
struct fuse_args args = FUSE_ARGS_INIT (argc, argv);
int res;
struct revokefs_config conf = { -1 };
struct revokefs_config conf = { -1, -1 };
res = fuse_opt_parse (&args, &conf, revokefs_opts, revokefs_opt_proc);
if (res != 0)
@@ -529,7 +532,7 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
do_writer (basefd, conf.socket_fd);
do_writer (basefd, conf.socket_fd, conf.exit_with_fd);
exit (0);
}
@@ -559,7 +562,7 @@ main (int argc, char *argv[])
{
/* writer process */
close (sockets[0]);
do_writer (basefd, sockets[1]);
do_writer (basefd, sockets[1], -1);
exit (0);
}

View File

@@ -32,6 +32,7 @@
#include <sys/xattr.h>
#include <dirent.h>
#include <unistd.h>
#include <poll.h>
#include <fuse.h>
#include <glib.h>
@@ -759,7 +760,8 @@ request_access (int writer_socket, const char *path, int mode)
void
do_writer (int basefd_arg,
int fuse_socket)
int fuse_socket,
int exit_with_fd)
{
guchar request_buffer[MAX_REQUEST_SIZE];
RevokefsRequest *request = (RevokefsRequest *)&request_buffer;
@@ -773,6 +775,27 @@ do_writer (int basefd_arg,
{
ssize_t data_size, size;
ssize_t response_data_size, response_size, written_size;
int res;
struct pollfd pollfds[2] = {
{fuse_socket, POLLIN, 0 },
{exit_with_fd, POLLIN, 0 },
};
res = poll(pollfds, exit_with_fd >= 0 ? 2 : 1, -1);
if (res < 0)
{
perror ("Got error polling sockets: ");
exit (1);
}
if (exit_with_fd >= 0 && (pollfds[1].revents & (POLLERR|POLLHUP)) != 0)
{
g_printerr ("Received EOF on exit-with-fd argument");
exit (1);
}
if (pollfds[0].revents & POLLIN == 0)
continue;
size = TEMP_FAILURE_RETRY (read (fuse_socket, request_buffer, sizeof (request_buffer)));
if (size == -1)

View File

@@ -39,7 +39,7 @@ int request_fsync (int writer_socket, int fd);
int request_close (int writer_socket, int fd);
int request_access (int writer_socket, const char *path, int mode);
void do_writer (int basefd, int socket);
void do_writer (int basefd, int socket, int exit_with_fd);
typedef enum {

View File

@@ -72,6 +72,8 @@ typedef struct
uid_t uid; /* uid of the client initiating the pull */
gint client_socket; /* fd that is send back to the client for spawning revoke-fuse */
gint backend_exit_socket; /* write end of a pipe which helps terminating revokefs backend if
system helper exits abruptly */
gchar *src_dir; /* source directory containing the actual child repo */
gchar *unique_name;
@@ -131,6 +133,7 @@ ongoing_pull_free (OngoingPull *pull)
g_clear_pointer (&pull->src_dir, g_free);
g_clear_pointer (&pull->unique_name, g_free);
close (pull->client_socket);
close (pull->backend_exit_socket);
g_slice_free (OngoingPull, pull);
}
@@ -1497,7 +1500,7 @@ ongoing_pull_new (FlatpakSystemHelper *object,
GDBusConnection *connection = g_dbus_method_invocation_get_connection (invocation);
g_autoptr(OngoingPull) pull = NULL;
g_autoptr(GSubprocessLauncher) launcher = NULL;
int sockets[2];
int sockets[2], exit_sockets[2];
pull = g_slice_new0 (OngoingPull);
pull->object = object;
@@ -1521,17 +1524,30 @@ ongoing_pull_new (FlatpakSystemHelper *object,
return NULL;
}
if (pipe2 (exit_sockets, O_CLOEXEC) == -1)
{
glnx_throw_errno_prefix (error, "Failed to create a pipe");
close (sockets[0]);
close (sockets[1]);
return NULL;
}
launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
g_subprocess_launcher_set_child_setup (launcher, revokefs_fuse_backend_child_setup, passwd, NULL);
g_subprocess_launcher_take_fd (launcher, sockets[0], 3);
fcntl (sockets[1], F_SETFD, FD_CLOEXEC);
pull->client_socket = sockets[1];
g_subprocess_launcher_take_fd (launcher, exit_sockets[0], 4);
pull->backend_exit_socket = exit_sockets[1];
pull->revokefs_backend = g_subprocess_launcher_spawn (launcher,
error,
"revokefs-fuse",
"--backend",
"--socket=3", src, NULL);
"--socket=3",
"--exit-with-fd=4",
src, NULL);
if (pull->revokefs_backend == NULL)
return NULL;