#758170 linux-image-3.14-1-amd64: read() cannot return more than 0x7ffff000, even on a regular file, breaking POSIX compliance

#758170#5
Date:
2014-08-15 00:18:02 UTC
From:
To:
Consider the following program:
------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main (void)
{
  size_t count = (size_t) 3 << 30;
  ssize_t ret;
  void *buf;
  int fd;

  printf ("SSIZE_MAX   = 0x%zx\n", (ssize_t) SSIZE_MAX);
  printf ("count       = 0x%zx\n", count);

  if (count > SSIZE_MAX)
    {
      fprintf (stderr, "count is too large\n");
      return 1;
    }

  buf = malloc (count);
  if (buf == NULL)
    {
      fprintf (stderr, "malloc() failed\n");
      return 1;
    }

  fd = open ("text", O_RDONLY);
  if (fd == -1)
    {
      fprintf (stderr, "open() failed\n");
      return 1;
    }

  ret = read (fd, buf, count);
  printf ("#bytes read = 0x%zx\n", ret);

  return 0;
}
------------------------------------------------------------

When I create a regular 6GB file "text" and run this program, I get:

SSIZE_MAX   = 0x7fffffffffffffff
count       = 0xc0000000
#bytes read = 0x7ffff000

i.e. read() has returned a value less than the byte count provided
in argument (nbyte in POSIX).

http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html
says:

  The value returned may be less than nbyte if the number of bytes left
  in the file is less than nbyte, if the read() request was interrupted
  by a signal, or if the file is a pipe or FIFO or special file and has
  fewer than nbyte bytes immediately available for reading.

Here, the file has more than nbyte bytes, there wasn't any signal,
and the file is a regular file. Therefore nbyte bytes should have
been read, not less!

#758170#10
Date:
2014-09-13 05:39:04 UTC
From:
To:
On Fri, 2014-08-15 at 02:18 +0200, Vincent Lefevre wrote:
[...]
[...]

Linux limits the length of reads and writes to around INT_MAX because
we're not confident that every implementation of read and write
correctly uses ssize_t for its arithmetic.  This limit was introduced in
2.6.37 in reaction to CVE-2010-3859.

If this limitation is removed, any implementation that makes use of int
or (on 32-bit systems) long will become a security vulnerability and/or
data loss bug.  And there are *lots* of implementations in different
filesystems, character device drivers and network protocols.  Maybe if
someone audited them thoroughly this could change, but until then I
don't think so.

Ben.