From: Csaba H. <csa...@cr...> - 2005-11-07 23:44:46
|
On Mon, Nov 07, 2005 at 08:52:56PM +0100, Miklos Szeredi wrote: > Commit for VFS infrastructure supporting this: > > http://tinyurl.com/9f5tf > > Commit for FUSE part: > > http://tinyurl.com/cbx8a Thanks. > But the fd sending is better. Is that not an option? Yes, that's a much cleaner way of doing something I don't wanna do. I make yet another attempt to explain why not. Say we want our superuser mount a daemon running as "nobody". How can we do it in FreeBSD? We make fuse devices (or at least one of them) rw-able for nobody. Nobody's daemon can then occupy a fuse device. She doesn't care about mounting, she's just expecting the messages. As root we mount that device on a totally independent event chain. Given that it is done directly by root, there is no doubt about sufficient credentials. How can we do it in Linux? "Nobody" starts the daemon, and the daemon invokes a "gatekeeper" process. The gatekeeper behaves like a rich uncle when it's time to cook up a good marriage: he takes care about all the small details -- checking credentials (if they didn't match by default, they are to be adjusted by a config file pre festam), opening the device, passing the fd to the daemon and doing the mount. Why does the latter work? Because the gatekeeper is setuid root. Otherwise the whole thing would break, we couldn't get nobody's daemon mounted. There is no sensible compromise between the two approaches. If you keep mounting on the event chain of the daemon, you need a setuid dispatcher to do the touchy part of the job. And the presence of a setuid dispatcher is as much acceptable under Linux as much unacceptable under FreeBSD. In Linux, the mount utility itself is setuid, so it's the most common thing that invocation of the mount syscall always happens with root privileges (the kernel would refuse refuse it otherwise, or at least noone uses a setup where it would not). Privilege checking is done by the setuid binary which wraps the mount syscall. Whether that's called "mount" or "fusermount" is not that big deal. In FreeBSD, mount is just an ordinary executable, and anyone can throw mount syscalls at the kernel. It's the kernel who does the non-trivial privilege check (the policy is tunable via sysctl). So making a setuid dispatcher is not an option under FBSD, and without that the daemon-initiates-mount scheme is broken. Canonicalizing a Linux style but setuid-free half-broken interface and keeping a properly working alternate mount interface in the backyard for the stormy days would be utterly ugly, please don't ask me to do that. > Why then do you have a choice of passing the file descriptor to the > daemon? It's only a complication that goes against 1-2. I don't feel it too much complicated. At least, it's at most half as complicated as passing a socket fd forward and use the socket to pass the device fd backward :) As I already described, the basic method of mounting is getting the daemon to open a fuse device, then identifying the device in use, and mount that device. In this basic form it involves human interaction: finding out whom to mount. How to do it programmatically? First approach: 1) find a free fuse device, say, /dev/fuse3 2) start the daemon with FUSE_DEV_NAME=/dev/fuse3 3) mount /dev/fuse3 But this is error prone as between identifying /dev/fuse3 as a free device and opening it by the daemon it could be taken away by a third party (getting involved into such races would lead to a pretty poor security record). And how would you find a free fuse device? Open /dev/fuse, the path name controlled by the "clone" event handler, this then prepares a free fuse device, and delegates the syscall to that one (similarly to /dev/ptmx in Linux). So between 1) and 2) the mount util should find out the device name to which the result of open("/dev/fuse", ...) belongs, close the fd to make the device free, and set FUSE_DEV_NAME to the device name. (Yes, it's like Heisenberg's uncertainity relation: in fact you won't see a free fuse device, because the action which makes it visible makes it busy too...) But then it's better then to keep the fd with us, and pass that one to the daemon as is. And it's race free. If you feel that this is a blunt environmental pollution I could transform the FBSD fuse_mount() so that it would utilize only one variable called FUSE_DEVICE; if it matched /^\d+$/, the daemon would think of it as a file descriptor, if it matched /^\//, then the daemon would think of it as a device name, otherwise she would bail out. This change would be indifferent to me, but maybe you'd find it more aesthetic... > $ grep "#if" *.c | wc -l > 5 > > Now you are planning to add a _lot_ more. So please don't take this > lightly, I'm serious about minimizing ifdef usage. OK, I do support your unmacrofication efforts. If you get really bored on some rainy afternoon, you should take a look into nnpfs code (the userspace fs component of the Arla project, an AFS implementation -- I briefly considered utilizing their kernel module for my userspace fs before deciding on to write a Fuse module from scratch), that would be better fun for you than watching a horror movie... They are really cross platform and they look exactly so :) > The fd to the device is not closed at any other place. So it _has_ to > be open. Hmm... then what kind of beast is closed in fuse_kern_chan_destroy()? (If it's not the device, then I am wrong about reason for the fallacy of my fuse_unmount(); in that case, I'd say don't do anything about fuse_umount() this time (apart from castrating it), it's not a top priority for me.) -- Csaba Henk My sense of humour is often too subtle to cope with getting smileyd. Please don't take it personal. |