Debian Bug report logs -
#339037
open(2) man page doesn't document potential EWOULDBLOCK return code
Reported by: Avery Pennarun <apenwarr@nit.ca>
Date: Mon, 14 Nov 2005 17:03:02 UTC
Severity: normal
Tags: fixed-upstream
Found in version manpages-dev/1.60-2
Fixed in version manpages/2.14-1
Done: Martin Schulze <joey@infodrom.org>
Bug is archived. No further changes may be made.
Toggle useless messages
Report forwarded to debian-bugs-dist@lists.debian.org, Martin Schulze <joey@debian.org>:
Bug#339037; Package manpages-dev.
(full text, mbox, link).
Acknowledgement sent to Avery Pennarun <apenwarr@nit.ca>:
New Bug report received and forwarded. Copy sent to Martin Schulze <joey@debian.org>.
(full text, mbox, link).
Message #5 received at submit@bugs.debian.org (full text, mbox, reply):
Package: manpages-dev
Version: 1.60-2
We've just been bitten by this at work.
If you read the LEASES section of fcntl(2), it explains that open() with
O_NONBLOCK could cause open to return EWOULDBLOCK. This is not explained
anywhere on the open() page; open() has many possible return codes, none of
which are EWOULDBLOCK. (There is a comment about opening fifos in
nonblocking mode, but the error code description implies that this would
return ENXIO, not EWOULDBLOCK.)
Also, the fcntl(2) page doesn't say whether opening a leased file with
O_NONBLOCK will actually request the lease to be broken or not. It appears
you *have* to open in blocking mode in order to open a leased file at all,
but that's not clear from the description.
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.
Have fun,
Avery
Information forwarded to debian-bugs-dist@lists.debian.org, Martin Schulze <joey@debian.org>:
Bug#339037; Package manpages-dev.
(full text, mbox, link).
Acknowledgement sent to "Michael Kerrisk" <mtk-manpages@gmx.net>:
Extra info received and forwarded to list. Copy sent to Martin Schulze <joey@debian.org>.
(full text, mbox, link).
Message #10 received at 339037@bugs.debian.org (full text, mbox, reply):
tags 339037 fixed-upstream
thanks
Hello Avery,
> If you read the LEASES section of fcntl(2), it explains that open() with
> O_NONBLOCK could cause open to return EWOULDBLOCK. This is not explained
> anywhere on the open() page; open() has many possible return codes, none
> of which are EWOULDBLOCK. (There is a comment about opening fifos in
> nonblocking mode, but the error code description implies that this would
> return ENXIO, not EWOULDBLOCK.)
Thanks. In open.2, I have added the following text:
EWOULDBLOCK
The O_NONBLOCK flag was specified, and an incom-
patible lease was held on the file (see
fcntl(2)).
> Also, the fcntl(2) page doesn't say whether opening a leased file with
> O_NONBLOCK will actually request the lease to be broken or not.
It explains a sequence of steps, which include the lease being
broken. Those steps occur independently of O_NONBLOCK. The
man page does pretty much imply that IMO. But I do agree that
things could be stated a little more verbosely.
> 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.
In fcntl.2, I removed the phrase that you referred to that
specified O_NONBLOCK. Later in the description, I added
this new text:
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.
These changes will appear in man-pages-2.14.
Cheers,
Michael
--
Michael Kerrisk
maintainer of Linux man pages Sections 2, 3, 4, 5, and 7
Want to help with man page maintenance? Grab the latest
tarball at ftp://ftp.win.tue.nl/pub/linux-local/manpages/
and grep the source files for 'FIXME'.
Tags added: fixed-upstream
Request was from "Michael Kerrisk" <mtk-manpages@gmx.net>
to control@bugs.debian.org.
(full text, mbox, link).
Information forwarded to debian-bugs-dist@lists.debian.org, Martin Schulze <joey@debian.org>:
Bug#339037; Package manpages-dev.
(full text, mbox, link).
Acknowledgement sent to Avery Pennarun <apenwarr@nit.ca>:
Extra info received and forwarded to list. Copy sent to Martin Schulze <joey@debian.org>.
(full text, mbox, link).
Message #17 received at 339037@bugs.debian.org (full text, mbox, reply):
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
Information forwarded to debian-bugs-dist@lists.debian.org, Martin Schulze <joey@debian.org>:
Bug#339037; Package manpages-dev.
(full text, mbox, link).
Acknowledgement sent to "Michael Kerrisk" <mtk-manpages@gmx.net>:
Extra info received and forwarded to list. Copy sent to Martin Schulze <joey@debian.org>.
(full text, mbox, link).
Message #22 received at 339037@bugs.debian.org (full text, mbox, reply):
> Von: Avery Pennarun <apenwarr>
> An: 339037@bugs.debian.org
> Betreff: Re: Bug#339037: open(2) man page doesn't document potentia
> Datum: Thu, 17 Nov 2005 10:51:34 -0500
>
> 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.
Only if the delay is longer than lease-break-time (45 secs by
default, which is quite long), or the lease holder releases
the lease sooner.
> So the first
> claim above, that you *have* to open in blocking mode, is not strictly
> true.
It is true for that particular open() call. Of course *anything*
might happen by the time of another open() call (the lease holder
might remove the leae, someone might delete the file, or even
the directory containing it...)
> 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.)
Okay.
> 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
But the above steps gain nothing over simply doing:
- 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.
The thing is, the more general issue you are talking about here
is race conditions of a type which can apply in any number of
places when writing system programs. There is no compelling
reason to document especially this one.
There is also a second reason I'm inclined not to add more text.
File leases are poorly specified -- it is hard to get information
about what they *should* be doing. And it seems that really they
are only intended for use with the SMB/CIFS protcols.
Cheers,
Michael
--
Michael Kerrisk
maintainer of Linux man pages Sections 2, 3, 4, 5, and 7
Want to help with man page maintenance? Grab the latest
tarball at ftp://ftp.win.tue.nl/pub/linux-local/manpages/
and grep the source files for 'FIXME'.
Reply sent to Martin Schulze <joey@infodrom.org>:
You have taken responsibility.
(full text, mbox, link).
Notification sent to Avery Pennarun <apenwarr@nit.ca>:
Bug acknowledged by developer.
(full text, mbox, link).
Message #27 received at 339037-close@bugs.debian.org (full text, mbox, reply):
Source: manpages
Source-Version: 2.14-1
We believe that the bug you reported is fixed in the latest version of
manpages, which is due to be installed in the Debian FTP archive:
manpages-dev_2.14-1_all.deb
to pool/main/m/manpages/manpages-dev_2.14-1_all.deb
manpages_2.14-1.diff.gz
to pool/main/m/manpages/manpages_2.14-1.diff.gz
manpages_2.14-1.dsc
to pool/main/m/manpages/manpages_2.14-1.dsc
manpages_2.14-1_all.deb
to pool/main/m/manpages/manpages_2.14-1_all.deb
manpages_2.14.orig.tar.gz
to pool/main/m/manpages/manpages_2.14.orig.tar.gz
A summary of the changes between this version and the previous one is
attached.
Thank you for reporting the bug, which will now be closed. If you
have further comments please address them to 339037@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.
Debian distribution maintenance software
pp.
Martin Schulze <joey@infodrom.org> (supplier of updated manpages package)
(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmaster@debian.org)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Format: 1.7
Date: Sun, 11 Dec 2005 15:41:22 +0100
Source: manpages
Binary: manpages manpages-dev
Architecture: source all
Version: 2.14-1
Distribution: unstable
Urgency: low
Maintainer: Martin Schulze <joey@debian.org>
Changed-By: Martin Schulze <joey@infodrom.org>
Description:
manpages - Manual pages about using a GNU/Linux system
manpages-dev - Manual pages about using GNU/Linux for development
Closes: 336875 339037 339037
Changes:
manpages (2.14-1) unstable; urgency=low
.
* New upstream release, with the following changes
- New rexec(3) (Closes: Bug#336875)
- Clarified file leases in fcntl(2) (Closes: Bug#339037)
- Completed errors section in open(2) (Closes: Bug#339037)
Files:
3eec346638bba39f0d93d1114239d3c5 584 doc - manpages_2.14-1.dsc
dddd6cb167c71096b0a8164191f0fa22 1065989 doc - manpages_2.14.orig.tar.gz
600eb16e8b6f51db4fc7c801a306f068 47285 doc - manpages_2.14-1.diff.gz
ffb4681f1fd8dbd5d5cae40320a8adc6 406402 doc important manpages_2.14-1_all.deb
a7b32f93d360c41f706c3fd9c5190a36 1109608 doc standard manpages-dev_2.14-1_all.deb
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
iD8DBQFDnEbDW5ql+IAeqTIRAlT1AKCWuSmHU4LOlSHzh+u3E3UrTm0KZQCfVLTr
JQeF4sFsPwgn1/9qSwmIa5Q=
=I5zY
-----END PGP SIGNATURE-----
Bug archived.
Request was from Debbugs Internal Request <owner@bugs.debian.org>
to internal_control@bugs.debian.org.
(Mon, 25 Jun 2007 06:13:11 GMT) (full text, mbox, link).
Send a report that this bug log contains spam.
Debian bug tracking system administrator <owner@bugs.debian.org>.
Last modified:
Thu Mar 9 09:55:31 2023;
Machine Name:
buxtehude
Debian Bug tracking system
Debbugs is free software and licensed under the terms of the GNU
Public License version 2. The current version can be obtained
from https://bugs.debian.org/debbugs-source/.
Copyright © 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson,
2005-2017 Don Armstrong, and many other contributors.