On Thu, Nov 17, 2005 at 03:59:58PM +0100, Michael Kerrisk wrote:
> > It appears you *have* to open in blocking mode in order to
> > open a leased file at all,
>
> Yes.
>
> > but that's not clear from the description.
>
> Again, I would say that's fairly clear from the man page:
> if the open() call returns (i.e., fails) with EWOULDBLOCK,
> then clearly the file was not opened. But again, it might
> help to add a little more text.
>
> > It wouldn't be so bad to open in blocking mode since a lease is
> > guaranteed
> > to be broken after a certain timeout. But a naive implementation would
> > introduce a security hole since the file might be replaced by surprise
> > with a FIFO, which has no open timeout at all.
>
> I do not understand this last piece.
The above three things tie together: if you're correct and the
lease-breaking steps are followed even with O_NONBLOCK, it's obvious that
you could *potentially* be able to open a leased file with O_NONBLOCK
eventually, by following steps like this:
- open() -> EWOULDBLOCK
- wait a while
- open() -> success
That's because the lease *starts* to get broken on the first open(), and
probably is finished being broken by your second or third try. So the first
claim above, that you *have* to open in blocking mode, is not strictly true.
It would be true if opening with O_NONBLOCK definitely *doesn't* ask to
start the lease breaking-steps; that's the part I thought was unclear. (The
clarification you added about it is good, assuming it's correct.)
But essentially, even if this might work eventually, it's unsafe, because
what *might* happen is this:
- open() -> EWOULDBLOCK
- lease gets broken
- lease gets reacquired
- open() -> EWOULDBLOCK
- ...
The only way to guarantee that you'll ever get to open the file within some
reasonable time is to open it in blocking mode.
This might be a very common case. I know that if I was writing a
lease-using program, and I knew that giving up my lease was part of a chain
of events that guaranteed the next guy he *could* open the file immediately,
and the open succeeded immediately when I gave up my lease, then I might
simply give up the lease and then blocking-reacquire it. That minimizes the
time I *don't* have my lease, while supposedly not getting in anyone's way.
And so:
> If the lease breaker's blocked open() or truncate() is
> interrupted by a signal handler, then the system call
> fails with the error EINTR, but the other steps still
> occur as described above. If the lease breaker is
> killed by a signal while blocked in open() or trun-
> cate(), then the other steps still occur as described
> above. If the lease breaker specifies the O_NONBLOCK
> flag when calling open(), then the call immediately
> fails with the error EWOULDBLOCK, but the other steps
> still occur as described above.
In this paragraph, which generally I find good, you might want to caution
that although the steps still occur with O_NONBLOCK, you introduce a race
condition and are not guaranteed to ever successfully open the file unless
you open it in blocking mode. So I might do this:
- open(O_NONBLOCK) -> EWOULDBLOCK
- (no special time delay)
- open(^O_NONBLOCK) -> success within a short time
And that leads me to explain my final point about the security problem,
which doesn't seem to have an obvious workaround if you use the above method:
- open(O_NONBLOCK) -> EWOULDBLOCK
- someone replaces the leased file with a fifo
- open(^O_NONBLOCK) -> blocks forever
My totally nonblocking daemon may be forced to block in order to acquire a
lease, but the blocking period has a guaranteed maximum, so it's not so bad.
However, the file might suddenly become a fifo, which has no guaranteed
maximum timeout, and that's bad.
At this point the workarounds are getting slightly crazy, but it looks like
a fork()-and-open()-with-timeout mechanism might be the only safe way to go.
Not sure if you care to document anything to this extent, but my point is
that you might caution about O_NONBLOCK and leases; basically it's not very
useful because there's no guarantee it'll ever work.
Have fun,
Avery
--
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]