Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20110807040212.GF132@brightrain.aerifal.cx>
Date: Sun, 7 Aug 2011 00:02:12 -0400
From: Rich Felker <dalias@...ifal.cx>
To: musl@...ts.openwall.com
Subject: close() failure, EINTR, cancellation

I've been following up on the previous thread where Vasiliy Kulikov
and I discussed dangers of close failure, and this is what I've found.
On Linux,

1. The close syscall always deallocates the file descriptor, even if
it "fails". There's never any danger of "leaking" file descriptors
from close failure.

2. As such, the close syscall is not restartable if interrupted by a
signal, because the resource it's operating on was already
deallocated. The kernel takes care to replace ERESTARTSYS etc. with
EINTR before returning to userspace.

3. This means close can fail with EINTR even when signal handlers were
all installed with SA_RESTART.

Hopefully the previously discussed security issue has been laid to
rest by this, but a new issue has been raised: what should pthread
cancellation do to close?

There are two considerations: what does POSIX require, and what's
necessary to write robust applications?

For POSIX conformance, close must check for cancellation at least once
somewhere during the operation, and it must not remain
blocked/sleeping while a cancellation request is pending.

For the latter consideration, an application must always be able to
detect whether the file descriptor was deallocated or not. Otherwise
it will leak a file descriptor (if the application thinks it was
deallocated but it wasn't) or it will wrongly retry closing a file
descriptor that was already closed, possibly closing the wrong file.

The possible behaviors compatible with both requirements are:
1. close always closes the fd, but may never return if cancelled.
2. close is only cancellable before closing the fd, and always returns
if it successfully deallocated the fd.

I don't like option 1 because it's very counter-intuitive (differs
from the usual expectation that cancellation indicates the operation
did not successfully complete) and hard to implement without race
conditions that could lead to uncancellable blocking.

For now I'm going with option 2. It seems like the natural behavior
and it requires only minimal changes (special-casing of SYS_close, the
only syscall that fails with EINTR after succeeding) to musl.

If anyone thinks this sounds wrong, please jump in with ideas.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.