aboutsummaryrefslogtreecommitdiff
path: root/tools/virtiofsd/passthrough_ll.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/virtiofsd/passthrough_ll.c')
-rw-r--r--tools/virtiofsd/passthrough_ll.c57
1 files changed, 55 insertions, 2 deletions
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index 13fdb12367..f03b1f9a69 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -137,8 +137,14 @@ enum {
CACHE_ALWAYS,
};
+enum {
+ SANDBOX_NAMESPACE,
+ SANDBOX_CHROOT,
+};
+
struct lo_data {
pthread_mutex_t mutex;
+ int sandbox;
int debug;
int writeback;
int flock;
@@ -163,6 +169,12 @@ struct lo_data {
};
static const struct fuse_opt lo_opts[] = {
+ { "sandbox=namespace",
+ offsetof(struct lo_data, sandbox),
+ SANDBOX_NAMESPACE },
+ { "sandbox=chroot",
+ offsetof(struct lo_data, sandbox),
+ SANDBOX_CHROOT },
{ "writeback", offsetof(struct lo_data, writeback), 1 },
{ "no_writeback", offsetof(struct lo_data, writeback), 0 },
{ "source=%s", offsetof(struct lo_data, source), 0 },
@@ -2661,14 +2673,54 @@ static void setup_capabilities(char *modcaps_in)
}
/*
+ * Use chroot as a weaker sandbox for environments where the process is
+ * launched without CAP_SYS_ADMIN.
+ */
+static void setup_chroot(struct lo_data *lo)
+{
+ lo->proc_self_fd = open("/proc/self/fd", O_PATH);
+ if (lo->proc_self_fd == -1) {
+ fuse_log(FUSE_LOG_ERR, "open(\"/proc/self/fd\", O_PATH): %m\n");
+ exit(1);
+ }
+
+ /*
+ * Make the shared directory the file system root so that FUSE_OPEN
+ * (lo_open()) cannot escape the shared directory by opening a symlink.
+ *
+ * The chroot(2) syscall is later disabled by seccomp and the
+ * CAP_SYS_CHROOT capability is dropped so that tampering with the chroot
+ * is not possible.
+ *
+ * However, it's still possible to escape the chroot via lo->proc_self_fd
+ * but that requires first gaining control of the process.
+ */
+ if (chroot(lo->source) != 0) {
+ fuse_log(FUSE_LOG_ERR, "chroot(\"%s\"): %m\n", lo->source);
+ exit(1);
+ }
+
+ /* Move into the chroot */
+ if (chdir("/") != 0) {
+ fuse_log(FUSE_LOG_ERR, "chdir(\"/\"): %m\n");
+ exit(1);
+ }
+}
+
+/*
* Lock down this process to prevent access to other processes or files outside
* source directory. This reduces the impact of arbitrary code execution bugs.
*/
static void setup_sandbox(struct lo_data *lo, struct fuse_session *se,
bool enable_syslog)
{
- setup_namespaces(lo, se);
- setup_mounts(lo->source);
+ if (lo->sandbox == SANDBOX_NAMESPACE) {
+ setup_namespaces(lo, se);
+ setup_mounts(lo->source);
+ } else {
+ setup_chroot(lo);
+ }
+
setup_seccomp(enable_syslog);
setup_capabilities(g_strdup(lo->modcaps));
}
@@ -2815,6 +2867,7 @@ int main(int argc, char *argv[])
struct fuse_session *se;
struct fuse_cmdline_opts opts;
struct lo_data lo = {
+ .sandbox = SANDBOX_NAMESPACE,
.debug = 0,
.writeback = 0,
.posix_lock = 0,