Re: [PATCH 0/5] fuse: handle release synchronously (v4)

From: Miklos Szeredi
Date: Fri Sep 26 2014 - 11:28:24 EST


[Adding CC's]

On Thu, Sep 25, 2014 at 2:05 PM, Maxim Patlasov <MPatlasov@xxxxxxxxxxxxx> wrote:

> In short, the problem is that fuse_release (that's usually called on last
> user close(2)) sends FUSE_RELEASE to userspace and returns without waiting
> for ACK from userspace. Consequently, there is a gap when user regards the
> file released while userspace fuse is still working on it. An attempt to
> access the file from another node leads to complicated synchronization
> problems because the first node still "holds" the file.
>
> The patch-set resolves the problem by making fuse_release synchronous:
> wait for ACK from userspace for FUSE_RELEASE if the feature is ON.
>
> It must be emphasized that even if the feature is enabled (i.e. fuse_release
> is synchronous), nothing guarantees that fuse_release() will be called
> in the context of close(2). In fact, it may happen later, on last fput().
> However, there are still a lot of use cases when close(2) is synchronous,
> so the feature must be regarded as an optimization maximizing chances of
> synchronous behaviour of close(2).

Okay, we have the common case of close -> last-fput ->release. This
being synchronous is fine. Related cases are munmap(), and weird
corner cases including I/O on file descriptor being done in parallel
with close() in another thread. Synchronous behavior is also fine in
these cases, since the task calling the last fput() is in fact
responsible for releasing the file.

And then we have the uncommon cases when fput() is called from
something unrelated. Take the following DoS example: malicious app
creates a socket loop (sockA is sent over sockB and sockB is sent over
sockA) and in addition it tacks a fuse fd onto one of the sockets.
The fuse fd is implemented to block forever on release. In this case
the loop will persist after the sockets are closed due to refcounting.
Later, a garbage collection is triggered from a completely unrelated
socket operation. This result in the unrelated task being blocked
forever.

The simplest way to avoid such an attack is to make the sync-release
feature privileged. But even if it's privileged, the fact that
->release can take a lot of time and a completely unrelated task could
be waiting for it to finish is not a good thing.

So I'm wondering: could we have some way of distinguishing "good
release" from "bad release"? Maybe adding an fput_sync() variant that
passes an "sync" flag to ->release()?

Al, Linus?

Thanks,
Miklos
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/