allow passing open /dev/fuse file descriptors (#124)
allows passing open /dev/fuse file descriptors so that the FUSE process can run fully unprivileged. uses the /dev/fd/N mountpoint format from libfuse3.notifications
parent
37d63df227
commit
21122235c7
31
mount.go
31
mount.go
|
@ -20,6 +20,7 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
@ -41,16 +42,8 @@ func Mount(
|
|||
config *MountConfig) (*MountedFileSystem, error) {
|
||||
// Sanity check: make sure the mount point exists and is a directory. This
|
||||
// saves us from some confusing errors later on OS X.
|
||||
fi, err := os.Stat(dir)
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
if err := checkMountPoint(dir); err != nil {
|
||||
return nil, err
|
||||
|
||||
case err != nil:
|
||||
return nil, fmt.Errorf("Statting mount point: %v", err)
|
||||
|
||||
case !fi.IsDir():
|
||||
return nil, fmt.Errorf("Mount point %s is not a directory", dir)
|
||||
}
|
||||
|
||||
// Initialize the struct.
|
||||
|
@ -97,6 +90,26 @@ func Mount(
|
|||
return mfs, nil
|
||||
}
|
||||
|
||||
func checkMountPoint(dir string) error {
|
||||
if strings.HasPrefix(dir, "/dev/fd") {
|
||||
return nil
|
||||
}
|
||||
|
||||
fi, err := os.Stat(dir)
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
return err
|
||||
|
||||
case err != nil:
|
||||
return fmt.Errorf("Statting mount point: %v", err)
|
||||
|
||||
case !fi.IsDir():
|
||||
return fmt.Errorf("Mount point %s is not a directory", dir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fusermount(binary string, argv []string, additionalEnv []string, wait bool) (*os.File, error) {
|
||||
// Create a socket pair.
|
||||
fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
@ -106,6 +108,14 @@ func mount(dir string, cfg *MountConfig, ready chan<- error) (*os.File, error) {
|
|||
// On linux, mounting is never delayed.
|
||||
ready <- nil
|
||||
|
||||
// If the mountpoint is /dev/fd/N, assume that the file descriptor N is an
|
||||
// already open FUSE channel. Parse it, cast it to an fd, and don't do any
|
||||
// other part of the mount dance.
|
||||
if fd, err := parseFuseFd(dir); err == nil {
|
||||
dev := os.NewFile(uintptr(fd), "/dev/fuse")
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
// Try mounting without fusermount(1) first: we might be running as root or
|
||||
// have the CAP_SYS_ADMIN capability.
|
||||
dev, err := directmount(dir, cfg)
|
||||
|
@ -123,3 +133,16 @@ func mount(dir string, cfg *MountConfig, ready chan<- error) (*os.File, error) {
|
|||
}
|
||||
return dev, err
|
||||
}
|
||||
|
||||
func parseFuseFd(dir string) (int, error) {
|
||||
if !strings.HasPrefix(dir, "/dev/fd/") {
|
||||
return -1, fmt.Errorf("not a /dev/fd path")
|
||||
}
|
||||
|
||||
fd, err := strconv.ParseUint(strings.TrimPrefix(dir, "/dev/fd/"), 10, 32)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("invalid /dev/fd/N path: N must be a positive integer")
|
||||
}
|
||||
|
||||
return int(fd), nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package fuse
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseFuseFd(t *testing.T) {
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
fd, err := parseFuseFd("/dev/fd/42")
|
||||
if fd != 42 {
|
||||
t.Errorf("expected 42, got %d", fd)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %#v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("negative", func(t *testing.T) {
|
||||
fd, err := parseFuseFd("/dev/fd/-42")
|
||||
if fd != -1 {
|
||||
t.Errorf("expected an invalid fd, got %d", fd)
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("expected an error, nil")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("not an int", func(t *testing.T) {
|
||||
fd, err := parseFuseFd("/dev/fd/3.14159")
|
||||
if fd != -1 {
|
||||
t.Errorf("expected an invalid fd, got %d", fd)
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("expected an error, nil")
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue