Skip to content

Broken handling of commas and backslashes in MountOption #424

@bemoody

Description

@bemoody

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 fuser itself, and passed to the mount system call.
  • Options may be passed to the fusermount or fusermount3 executable, which passes them to the mount system call.
  • Options may be passed to the fuse_session_new function (fuse3). fuse_session_new may in turn call mount or may invoke fusermount3.
  • Options may be passed to the fuse_mount_compat25 function (fuse2). fuse_mount_compat25 may in turn call mount or may invoke fusermount.

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 fsname option is escaped using fuse_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_group in lib/fuse_opt.c) looks the same.

  • Re-encoding (fuse_mount_opt_proc in lib/mount.c) looks the same except for some obsolete options that fuse3 doesn't support. In particular, it looks like fsname is re-escaped and subtype isn'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):

  1. MountOption::FSName should be allowed to contain any characters except NUL. When the option is passed to fuse_session_new, fuse_mount_compat25, or to fusermount or fusermount3, the value should be escaped by replacing , with \, and \ with \\. When it's passed to the kernel directly, it should not be escaped.

  2. MountOption::Subtype should 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.

  3. MountOption::CUSTOM should 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions