Date: Fri, 17 Feb 2012 03:32:42 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Bruce Evans <brde@optusnet.com.au> Cc: freebsd-standards@freebsd.org, Nicolas Bourdaud <nicolas.bourdaud@gmail.com> Subject: Re: write system call violates POSIX standard Message-ID: <20120217031824.R760@besplex.bde.org> In-Reply-To: <20120216054457.H3935@besplex.bde.org> References: <4F3BC2DB.6080703@gmail.com> <20120215163800.GA3283@deviant.kiev.zoral.com.ua> <20120216054457.H3935@besplex.bde.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 16 Feb 2012, Bruce Evans wrote: > ... > Here is a corresponding test to show the complete brokenness of > RLIMIT_FSIZE for [f]truncate(): I tried this under Linux-2.6.10. Linux worked like I think is correct for truncate, but not for write. > %%% > #include <sys/resource.h> > #include <sys/stat.h> > > #include <err.h> > #include <fcntl.h> > #include <signal.h> > #include <stdint.h> > #include <stdio.h> > > #define LIMSIZE 60000 > > int > main(void) > { > struct rlimit lim; > struct stat sb; > int fd; > > if (signal(SIGXFSZ, SIG_IGN) == SIG_ERR) > err(1, "signal"); > if (getrlimit(RLIMIT_FSIZE, &lim) != 0) > err(1, "getrlimit"); > lim.rlim_cur = LIMSIZE; > if (setrlimit(RLIMIT_FSIZE, &lim) != 0) > err(1, "setrlimit"); > > fd = open("result.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); > if (fd < 0) > err(1, "open"); > if (fstat(fd, &sb) != 0) > err(1, "first stat"); > if (sb.st_size != 0) > errx(1, "O_TRUNC failed to truncate the file"); > if (ftruncate(fd, 2 * LIMSIZE) != 0) > err(1, "ftruncate"); I had to fix this. With a working truncate, this is expected to fail. Linux failed correctly. > if (fstat(fd, &sb) != 0) > err(1, "stat"); > warnx("size = %jd", (intmax_t)sb.st_size); > if (sb.st_size == 2 * LIMSIZE) > errx(1, "ftruncate failed to honour RLIMIT_FSIZE, as expected"); > if (sb.st_size != 0) > errx(1, "ftruncate worked incorrectly, but not as expected"); > errx(0, "ftruncate worked correctly, but not as expected"); > } > %%% > ... > POSIX has fuzzy wording for the interaction of these bugs. Suppose > that the file size is already larger than the rlimit, and we try to > truncate it to its current size. Is this a null change or an EFBIG > error? POSIX only says (for [f]truncate) that "if the request _would_ > _cause_ the file size to exceed the soft file limit, [then it is an > error]". I think a null change "wouldn't cause" the file to exceed > the limit in this case, because the cause of exceeding the limit is > that the limit was already exceeded. However, it takes a delicate > reading of "would case" to get this interpretation, and FreeBSD never > did it this way in cases where it actually checks the limit -- for > write(), the limit is checked before even looking at the current > file size. The centralization of the limit checking makes it harder > to change this, because the central function doesn't know the file > size. > > Truncations that would reduce the file size from beyond the limit to less > beyond the limit are also interesting. Are these allowed? Now they > cause something, but they don't cause the file size to exceed the limit, > so a strict reading of "would cause" again allows them. Linux allows such truncations. To test this, remove the O_TRUNC from the above and copy a file larger than 120000 bytes to result.txt before running the program. > write() has some very nice, different bugs depending on the > interpretation of to the corresponding "would cause" for it. In > FreeBSD, because the limit checking is done before even looking at the > size of the file, write()s to the middle of a big file are rejected > if they would extend past the limit. But the POSIX specification is > that "if the request _would_ _cause_ the file size to exceed the soft > file limit, [then as for truncate, except it is not an error if the > write starts before the limit, and bytes shall be written if possible > up to the limit in this case]". This wording is not very different > that that for ftruncate, but now it seems even harder to blame the > write for causing the limit to be exceeded if the write would be in > the middle of the file. It seems useful to allow writing in the middle > of a big file irrespective of the limit, to allow not-fully-trusted > applications to scribble in a big file that you have reserved for them. > But the above bug in ftruncate becomes enormous if you allow writing > in the middle of a big file that the bug has allowed creation of. Linux doesn't allow writing beyond the limit in a file whose size is already beyond the limit. To test this, remove the O_TRUNC and the ftruncate from the original program, then start with a large file. Hmm, I was sloppy in testing and might have forgotten to remove the ftruncate. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120217031824.R760>