cberner / fuser

Filesystem in Userspace (FUSE) for Rust
MIT License
804 stars 111 forks source link

Extract `Channel` FD and self-mount #300

Open colinmarc opened 4 days ago

colinmarc commented 4 days ago

Hi, I have a use case (containers) where I need to get the session FD and do the mounting myself. I took a look at changing the API to support this, but unfortunately, it seems like mnt::Mount and Session are pretty tied together at the moment.

Before I propose any significant API changes, do you have an idea how I could achieve this?

Thanks!

colinmarc commented 4 days ago

I poked around a bit more. First, let me clarify roughly what I'd like to do:

  1. Create a Session with my FileSystem.
  2. Call AsFd::as_fd on the Session. Then, take that FD, and pass it into my own mount(2) call with fd=123.
  3. Call Session::run to proceed as normal.

Fundamentally, this seems like it would require splitting Session into two types: one which holds the /dev/fuse FD (the Channel), and one which knows the mountpoint and calls umount when it's dropped.

However, The fact that a session is also a mountpoint, as far as the API is concerned, seems to stem from libfuse. That's because fuse_session_new takes the mount args already. So while the above change would be fairly trivial with fuse_pure, it's not easy with libfuse.

I don't suppose you'd consider dropping support for libfuse? :sweat_smile:

colinmarc commented 3 days ago

Huh, there's also a (very wacky) libfuse3 way to do this: https://github.com/libfuse/libfuse/pull/291

cberner commented 2 days ago

Can you tell me more about the use case? I'm trying to understand if this is common enough that it should be support in fuser

colinmarc commented 2 days ago

Can you tell me more about the use case? I'm trying to understand if this is common enough that it should be support in fuser

FUSE plays a special role in containers, where it can be used to simulate kernel-level stuff like sysfs or character devices. This is specifically permitted for unprivileged container runtimes by the kernel. However, various security safeguards mean that it requires a very specific dance:

  1. /dev/fuse has to be opened inside the container (inside the user namespace where the mount call happens)
  2. The mount (or fsconfig/move_mount) syscalls have to be done inside the container as well
  3. If the fuse daemon wants to run outside the container (e.g. in the runtime), the FD has to be passed back out to the supervisor process (using a socket or something)
  4. The channel can then be polled for requests normally (Session::run)
colinmarc commented 2 days ago

One less-invasive way achieve this would be to offer a way to just iterate the Requests given a /dev/fuse FD. That would mean users wouldn't have access to the Filesystem abstraction, however.

unexge commented 1 day ago

We also have a similar use-case in https://github.com/awslabs/mountpoint-s3-csi-driver. We want to run FUSE/fuser process inside an unprivileged Kubernetes Pod (so we can't do mount syscall). We already have a privileged Pod for doing the mount (i.e., opening /dev/fuse and performing mount syscall), and we want to pass obtained file descriptor to our unprivileged Pod where FUSE/fuser process lives.