aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.rst4
-rw-r--r--lib/fuse_lowlevel.c27
-rw-r--r--lib/helper.c7
-rw-r--r--lib/mount_util.c13
-rw-r--r--lib/mount_util.h1
5 files changed, 48 insertions, 4 deletions
diff --git a/ChangeLog.rst b/ChangeLog.rst
index 3d5c05b..65f57d7 100644
--- a/ChangeLog.rst
+++ b/ChangeLog.rst
@@ -8,6 +8,10 @@ Unreleased Changes
* The description of the FUSE_CAP_READDIRPLUS_AUTO flag has been
improved.
+* Allow open `/dev/fuse` file descriptors to be passed via mountpoints of the
+ special format `/dev/fd/%u`. This allows mounting to be handled by the parent
+ so the FUSE filesystem process can run fully unprivileged.
+
libfuse 3.2.6 (2018-08-31)
==========================
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index e6e3d8d..844e797 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -16,6 +16,7 @@
#include "fuse_kernel.h"
#include "fuse_opt.h"
#include "fuse_misc.h"
+#include "mount_util.h"
#include <stdio.h>
#include <stdlib.h>
@@ -2891,6 +2892,24 @@ int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
close(fd);
} while (fd >= 0 && fd <= 2);
+ /*
+ * To allow FUSE daemons to run without privileges, the caller may open
+ * /dev/fuse before launching the file system and pass on the file
+ * descriptor by specifying /dev/fd/N as the mount point. Note that the
+ * parent process takes care of performing the mount in this case.
+ */
+ fd = fuse_mnt_parse_fuse_fd(mountpoint);
+ if (fd != -1) {
+ if (fcntl(fd, F_GETFD) == -1) {
+ fprintf(stderr,
+ "fuse: Invalid file descriptor /dev/fd/%u\n",
+ fd);
+ return -1;
+ }
+ se->fd = fd;
+ return 0;
+ }
+
/* Open channel */
fd = fuse_kern_mount(mountpoint, se->mo);
if (fd == -1)
@@ -2916,9 +2935,11 @@ int fuse_session_fd(struct fuse_session *se)
void fuse_session_unmount(struct fuse_session *se)
{
- fuse_kern_unmount(se->mountpoint, se->fd);
- free(se->mountpoint);
- se->mountpoint = NULL;
+ if (se->mountpoint != NULL) {
+ fuse_kern_unmount(se->mountpoint, se->fd);
+ free(se->mountpoint);
+ se->mountpoint = NULL;
+ }
}
#ifdef linux
diff --git a/lib/helper.c b/lib/helper.c
index 07cef81..e1de362 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -15,6 +15,7 @@
#include "fuse_misc.h"
#include "fuse_opt.h"
#include "fuse_lowlevel.h"
+#include "mount_util.h"
#include <stdio.h>
#include <stdlib.h>
@@ -147,7 +148,11 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
switch (key) {
case FUSE_OPT_KEY_NONOPT:
if (!opts->mountpoint) {
- char mountpoint[PATH_MAX];
+ if (fuse_mnt_parse_fuse_fd(arg) != -1) {
+ return fuse_opt_add_opt(&opts->mountpoint, arg);
+ }
+
+ char mountpoint[PATH_MAX] = "";
if (realpath(arg, mountpoint) == NULL) {
fprintf(stderr,
"fuse: bad mount point `%s': %s\n",
diff --git a/lib/mount_util.c b/lib/mount_util.c
index 56ed85a..95e038f 100644
--- a/lib/mount_util.c
+++ b/lib/mount_util.c
@@ -352,3 +352,16 @@ int fuse_mnt_check_fuseblk(void)
fclose(f);
return 0;
}
+
+int fuse_mnt_parse_fuse_fd(const char *mountpoint)
+{
+ int fd = -1;
+ int len = 0;
+
+ if (sscanf(mountpoint, "/dev/fd/%u%n", &fd, &len) == 1 &&
+ len == strlen(mountpoint)) {
+ return fd;
+ }
+
+ return -1;
+}
diff --git a/lib/mount_util.h b/lib/mount_util.h
index 55c6c5e..0ef0fbe 100644
--- a/lib/mount_util.h
+++ b/lib/mount_util.h
@@ -15,3 +15,4 @@ int fuse_mnt_umount(const char *progname, const char *abs_mnt,
const char *rel_mnt, int lazy);
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
int fuse_mnt_check_fuseblk(void);
+int fuse_mnt_parse_fuse_fd(const char *mountpoint);