Security Concerns

Writing and using a FUSE filesystem can have some Metrodome-sized security concerns that may or may not be obvious, but deserve some mention. In this section, I'll be talking about privilege escalation, giving some notes on checking access rights, and mentioning race conditions.

Privilege Escalation

The main point to make is that the filesystem itself executes with the access privileges of the process running it, not those of the process making use of the filesystem. Here's how this plays out in some typical scenarios:

The Common Case: a User Runs the Filesystem Without the allow_other Option

This is the normal case; the filesystem runs with the privileges of the user that ran it, and only that user can access the filesystem. FUSE doesn't open up any particular security issues in this case.

A User Runs the Filesystem With the allow_other Option

In this case, the filesystem runs with the privileges of the user that invoked it, not the privileges of any user who happens to make use of the filesystem. It's the responsibility of the user who mounts the filesystem to ensure inappropriate access privileges aren't being granted to other users. In general, users can only hurt themselves this way, since they can only grant privileges that they themselves already have.

It should be noted that an option, user_allow_other, must be set in /etc/fuse.conf to enable this option.

Root Runs a Filesystem

This is really the same as the previous two cases (depending on whether the allow_other option is set), but root is a sufficiently special case that it deserves mention. In this case, any user making use of the filesystem has root privileges on that filesystem! If the process has access to the actual filesystem, this could easily be used to gain pretty much unlimited access.

The next subsection will talk a little bit about checking access rights, but the simplest way out here is to not allow root to mount the filesystem. Due to BBFS's intended role as a simple tutorial, that's what I do. There's a little bit of code right at the start of main():

if ((getuid() == 0) || (geteuid() == 0)) {
    fprintf(stderr, "Running BBFS as root opens unnacceptable security holes\n");
    return 1;
}

Of course, this means that while I've got code for bb_chown(), it doesn't actually work since only root is able to change the ownership of a file in the underlying filesystem.

Checking Access Rights

In general, a filesystem that might be executed with the allow_other flag will need to take steps to ensure its own security. fuse.h documents that several calls need to check that the requested access is permitted; in addition to those, there are several others that also require access checks (such as chown(). It is strictly the programmer's responsibility to make sure these cautions are followed!

The most important function for checking access rights is fuse_get_context() which (as the name implies) returns a pointer to a struct fuse_context object. The UID and GID of the process performing the operation is in fields named uid and gid.

Simultaneous Access and Race Conditions

By default, FUSE runs multi-threaded: this means (in brief) that a second request can be handled by the filesystem before an earlier request has completed; this in turn raises the possibility that different threads can be simultaneously modifying a single data structure, which will cause very difficult-to-debug bugs.

There are a couple of things that can be done about the problem:

Note that even if you do make your filesystem single-threaded, that doesn't guard against access to the underlying data structures through some other means. Taking BBFS as an example:

Either of these facts is sufficient to completely negate any efforts made in your filesystem to guard atomicity.

I should note that the FUSE code itself is careful about locking its own code and data structures. So far as I know, dangerous race conditions won't occur outside of your code.

Next: Thanks and Other Resources


Last modified: Sat Jan 1 21:53:06 MST 2011