kern/164793: 'write' system call violates POSIX standard

Bruce Evans brde at optusnet.com.au
Wed Feb 15 15:00:24 UTC 2012


The following reply was made to PR standards/164793; it has been noted by GNATS.

From: Bruce Evans <brde at optusnet.com.au>
To: Nicolas Bourdaud <nicolas.bourdaud at gmail.com>
Cc: Bruce Evans <brde at optusnet.com.au>, freebsd-gnats-submit at freebsd.org,
        freebsd-bugs at freebsd.org
Subject: Re: kern/164793: 'write' system call violates POSIX standard
Date: Thu, 16 Feb 2012 01:55:54 +1100 (EST)

 On Wed, 15 Feb 2012, Nicolas Bourdaud wrote:
 
 > On 05/02/2012 19:54, Bruce Evans wrote:
 >> I think this is actually a bug in POSIX (XSI).  Most programs aren't
 >> prepared to deal with short writes, and returning an error like
 >> truncate() is specified to is adequate.
 >
 > I disagree, I think that most programs that check that the write
 > succeeded also check that the write was complete. Actually it was
 
 Well, in BSD, programs that don't understand short writes start with
 the cp utility in 4.4BSD (it checks for short writes, but then mishandles
 them by treating them as errors).  This wasn't fixed in FreeBSD until
 1998.
 
 > because my programs were assuming the POSIX behavior that I notice the
 > bug. In addition, I think (this must be confirmed) that the bug don't
 > affect the version 8.2... So the programs are already facing the POSIX
 
 No, it was in 4.4BSD, and hasn't been changed in FreeBSD since 1994.
 8.2 only differs in having the check in all file systems instead of
 in vfs.  Perhaps some file systems got it right, but ffs didn't.
 
 > behavior. Moreover the programs that are cross platform (in particular
 > ported to Linux) are already facing this behavior.
 >
 > Whatever is decided, either freebsd should conform to the POSIX
 > standard, either the standard should be changed.
 
 It must conform, since it is too late to fix standards.
 
 I forgot about this when I looked at ffs's handling of i/o errors recently.
 There are many more bugs.  ffs normally tries to back out of writes
 completely after an i/o error, by using ftruncate() to return to the
 original file size.  Garbage written to the disk or memory is too hard
 to back out of, but ffs avoids security holes by zeroing it memory (in
 case it is memmap()ed) and by making it inaccessible by normal means on
 the disk (ftruncate() does this.  When the error is ENOSPC due to a
 full disk, this gives the same behaviour as ffs has now for EFBIG for
 the file size being too big (due to the maximum size for the file
 system, or the rlimit).  POSIX has looser wording for the ENOSPC error.
 It says that ENOSPC shall be returned if there "was" no space...  This
 can be interpreted as requiring the same things as EFBIG -- that if there
 was any space to begin with, ENOSPC is not required to be returned;
 presumably the write() should succeed in writing as much as possible since
 there is no other reasonable error.
 
 But ffs's behaviour is "correct" here.  The most broken case here is for
 an i/o error for a write in the middle of a file.  Then it is not reasonable
 to try to back out.  ffs doesn't do the ftruncate() in this case.  But it
 still tries to back out.  This results in write() returning -1/EIO.  This
 is wrong if something has been successfully written.  On second thoughts
 is it is the best possible behaviour.  Everything in the region of the
 file covered by the write() may have been clobbered, either by writing
 the requested bytes, or by a hardware or software error writing garbage,
 or by the intentional zeroing for security.  The only way to tell the
 application about this is to say that the whole write failed.  The
 application should assume that the entire region has been clobbered,
 and take steps to check and limit the extent of the damage, perhaps
 by trying to rewrite it all in smaller pieces.
 
 There seem to be more bugs in [f]truncate():
 - POSIX requires SIGXFSZ for attempts to exceed the file size rlimit
    in truncate() too, but FreeBSD doesn't even check the rlimit for
    truncate().
 
 Checking the rlimit in vfs makes all this easier to fix.  I think
 write() can be fixed in a couple of lines in vfs.  All file systems
 call back to vfs to check, though I don't know of any requirement for
 other errors to have precedence, so vfs could check up front.  zfs's
 write vnop actually calls back to vfs before doing anything else, so
 this error already has precedence over all fs-specific errors for zfs.
 All other file systems' write vnop do the check a fair way into the
 vnop in much the same place as ffs.  No file systems check the limit
 for truncate().  The limit checking is commented out in xfs's write
 vnop.
 
 Bruce


More information about the freebsd-bugs mailing list