-
Notifications
You must be signed in to change notification settings - Fork 163
Description
The MountOption enum allows the caller to provide arbitrary (UTF-8) strings as mount options. This can be a problem because such strings may contain special characters - comma, backslash, and NUL - that currently are handled in inconsistent ways.
For example, suppose that you specify MountOption::FSName("foo,rw".into()). In most cases, this will not be interpreted as "the name of the filesystem is foo,rw". Instead, it will be interpreted as two options "the name of the filesystem is foo" and "mount the filesystem read-write". This is bad.
In order to understand the issue, I've tried to dig through the various ways that MountOption may be used:
- Options may be handled by
fuseritself, and passed to themountsystem call. - Options may be passed to the
fusermountorfusermount3executable, which passes them to themountsystem call. - Options may be passed to the
fuse_session_newfunction (fuse3).fuse_session_newmay in turn callmountor may invokefusermount3. - Options may be passed to the
fuse_mount_compat25function (fuse2).fuse_mount_compat25may in turn callmountor may invokefusermount.
I've ignored (for now) questions about how options are represented in /etc/fstab, /etc/mtab, and /proc/mounts. Those questions are somewhat tangential to fuser.
In Linux
The "source" of a FUSE mount can be any zero-terminated string. (In /proc/mounts, any special characters will be displayed as escape sequences.)
The "subtype" of a FUSE mount can likewise be any zero-terminated string.
Other mount options are passed to the kernel as a zero-terminated, comma-separated string, and therefore an option cannot contain NUL or comma.
(See generic_parse_monolithic in Linux's fs/fs_context.c.)
In fusermount and fusermount3
The behavior of fusermount and fusermount3 appears to be the same.
All mount options, including "fsname" and "subtype", must be passed as a single comma-separated command-line argument.
Arguments to the fsname and subtype options may use a backslash to escape the following character. For all other options, backslash is not special and comma marks the end of the option. Note that fusermount rejects unknown future options.
(See do_mount in FUSE's util/fusermount.c.)
In fuse_session_new (libfuse3)
All -o argument strings are decoded in the same way:
- Backslash followed by three octal digits (000 to 377) represents an arbitrary byte.
- Backslash followed by anything else represents a literal character.
- Otherwise, comma separates options.
(See process_real_option_group in FUSE's lib/fuse_opt.c.)
If the options are passed to fusermount3, they are re-encoded:
- The
fsnameoption is escaped usingfuse_opt_add_opt_escaped. - Other options, including
subtype, are not escaped.
(See fuse_mount_opt_proc and fuse_mount_opts in lib/mount.c. See fuse_kern_mount for how the results are used.)
In fuse_mount_compat25 (libfuse2)
I haven't tested it, but the behavior looks the same as libfuse3.
-
Decoding logic (
process_real_option_groupinlib/fuse_opt.c) looks the same. -
Re-encoding (
fuse_mount_opt_procinlib/mount.c) looks the same except for some obsolete options that fuse3 doesn't support. In particular, it looks likefsnameis re-escaped andsubtypeisn't.
What should fuser do?
fuser should not silently pass option strings that will not be reliably interpreted by the lower layers (libfuse, fusermount, and kernel.) Nor should the caller be expected to do its own escaping, because the rules are complicated and unpredictable.
I also don't think fuser ought to panic (as it currently does when an option contains a NUL.)
If the caller passes a mount option containing special characters, then fuser should escape the special characters if it can, or return an error if not.
Based on my notes above, it appears to me that (on Linux):
-
MountOption::FSNameshould be allowed to contain any characters except NUL. When the option is passed tofuse_session_new,fuse_mount_compat25, or tofusermountorfusermount3, the value should be escaped by replacing,with\,and\with\\. When it's passed to the kernel directly, it should not be escaped. -
MountOption::Subtypeshould not be allowed to contain NUL, comma, or backslash (because it's not possible to handle these consistently when using libfuse.) An invalid string should result in an error. -
MountOption::CUSTOMshould not be allowed to contain NUL or comma (because the ABI doesn't support them), or backslash (because libfuse will mangle them.)
An entirely separate question is whether the deprecated fuser::mount and fuser::spawn_mount should support libfuse-like option escaping. Probably these functions should be kept as they are.
BSD and MacOS?
If I'm reading correctly, fuse_mount_opt_proc (FUSE's lib/mount_bsd.c) doesn't appear to do any escaping at all, and mount_fusefs (FreeBSD's sbin/mount_fusefs/mount_fusefs.c) doesn't appear to support any escaping. So commas should be forbidden in all options. Backslashes seem dicey.
macFUSE is non-free so I leave it to those who care about it to figure out how to support it.