diff options
author | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2017-04-06 17:01:56 -0300 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2017-04-12 11:04:28 -0300 |
commit | 158d5fa0e1906e7810bdc6ecb7bf598dcc3cd17d (patch) | |
tree | 4314d7eeee6694b56c5c12153686f6a58d5ab890 /posix/tst-mmap-offset.c | |
parent | 4fee33f8c11447d345b2b1118a98958b54d5fda3 (diff) | |
download | glibc-158d5fa0e1906e7810bdc6ecb7bf598dcc3cd17d.tar glibc-158d5fa0e1906e7810bdc6ecb7bf598dcc3cd17d.tar.gz glibc-158d5fa0e1906e7810bdc6ecb7bf598dcc3cd17d.tar.bz2 glibc-158d5fa0e1906e7810bdc6ecb7bf598dcc3cd17d.zip |
Consolidate Linux mmap implementation (BZ#21270)
This patch consolidates all Linux mmap implementations on default
sysdeps/unix/sysv/linux/mmap{64}.c one. To accomodate all required
architecture specific requeriments a new internal header is created
(mmap_internal.h) where each architecture add its specific code
requirements. Currently only x86_64 (to define MMAP_PREPARE to add
MAP_32BITS), s390 (which have a different kernel ABI for mmap), m68k
(which have variable minimum page sizes), and MIPS n32 (which zero
extend the offset to handle negative one correctly) redefine the new
header.
The patch also fixes BZ#21270 where default mmap64 on architectures
which uses mmap2 silent truncates large offsets value (larger than
1 << (page shift + 8 * sizeof (off_t)) or 1<<44 on architectures with
4096 bytes page size). The new consolidate implementation returns
EINVAL as allowed by POSIX.
It also adds a tests for on current tst-mmap-offset one. I have run
a full make check on x86_64, x86_64-32, i686, aarch64, armhf, powerpc,
powerpc64le, sparc64, and sparcv9 without any regressions. I also ran
some basic tests (tst-mmap-offset) on sh4, m68k, and on qemu simulated
MIPS32 and MIPS64.
[BZ #21270]
* posix/tst-mmap-offset.c (do_prepare): New function.
(do_test): Rename to do_test_bz18877 and use FAIL_RET.
(do_test_bz21270): New function.
* sysdeps/unix/sysv/linux/aarch64/mmap.c: Remove file.
* sysdeps/unix/sysv/linux/arm/mmap.c: Remove file.
* sysdeps/unix/sysv/linux/generic/wordsize-32/mmap.c: Likewise.
* sysdeps/unix/sysv/linux/hppa/mmap.c: Likewise.
* sysdeps/unix/sysv/linux/i386/mmap.c: Likewise.
* sysdeps/unix/sysv/linux/m68k/mmap.S: Likewise.
* sysdeps/unix/sysv/linux/m68k/mmap64.c: Likewise.
* sysdeps/unix/sysv/linux/microblaze/mmap.S: Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/mmap.c: Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n32/mmap.c: Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n64/mmap64.c: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/mmap.S: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/mmap64.S: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/mmap.S: Likewise.
* sysdeps/unix/sysv/linux/wordsize-64/mmap.c: Likewise.
* sysdeps/unix/sysv/linux/wordsize-64/mmap64.c: Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/mmap.c: Likewise.
* sysdeps/unix/sysv/linux/mmap_internal.h: New file.
* sysdeps/unix/sysv/linux/m68k/mmap_internal.h: Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n32/mmap_internal.h: Likewise.
* sysdeps/unix/sysv/linux/s390/mmap_internal.h: Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h: Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list: Remove mmap
from auto-generation list.
* sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list: Likewise.
* sysdeps/unix/sysv/linux/wordsize-64/syscalls.list: Likewise.
* sysdeps/unix/sysv/linux/mmap.c: New file.
* sysdeps/unix/sysv/linux/mmap64.c (__mmap64): Add check for invalid
offsets and support for mmap2 syscall.
Diffstat (limited to 'posix/tst-mmap-offset.c')
-rw-r--r-- | posix/tst-mmap-offset.c | 88 |
1 files changed, 69 insertions, 19 deletions
diff --git a/posix/tst-mmap-offset.c b/posix/tst-mmap-offset.c index d139c301d7..385df289e6 100644 --- a/posix/tst-mmap-offset.c +++ b/posix/tst-mmap-offset.c @@ -1,4 +1,4 @@ -/* BZ #18877 mmap offset test. +/* BZ #18877 and #21270 mmap offset test. Copyright (C) 2015-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -21,18 +21,37 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <errno.h> #include <sys/mman.h> -static int -printmsg (int rc, const char *msg) +#include <support/check.h> + +static int fd; +static long int page_shift; +static char fname[] = "tst-mmap-offset-XXXXXX"; + +static void +do_prepare (int argc, char **argv) { - printf ("%s failed: %m\n", msg); - return rc; + fd = mkstemp64 (fname); + if (fd < 0) + FAIL_EXIT1 ("mkstemp failed"); + + if (unlink (fname)) + FAIL_EXIT1 ("unlink failed"); + + long sz = sysconf(_SC_PAGESIZE); + if (sz == -1) + sz = 4096L; + page_shift = ffs (sz) - 1; } +#define PREPARE do_prepare + + /* Check if negative offsets are handled correctly by mmap. */ static int -do_test (void) +do_test_bz18877 (void) { const int prot = PROT_READ | PROT_WRITE; const int flags = MAP_SHARED; @@ -40,22 +59,13 @@ do_test (void) const unsigned long offset = 0xace00000; const unsigned long size = offset + length; void *addr; - int fd; - char fname[] = "tst-mmap-offset-XXXXXX"; - - fd = mkstemp64 (fname); - if (fd < 0) - return printmsg (1, "mkstemp"); - - if (unlink (fname)) - return printmsg (1, "unlink"); if (ftruncate64 (fd, size)) - return printmsg (0, "ftruncate64"); + FAIL_RET ("ftruncate64 failed"); addr = mmap (NULL, length, prot, flags, fd, offset); if (MAP_FAILED == addr) - return printmsg (1, "mmap"); + FAIL_RET ("mmap failed"); /* This memcpy is likely to SIGBUS if mmap has messed up with offset. */ memcpy (addr, fname, sizeof (fname)); @@ -63,5 +73,45 @@ do_test (void) return 0; } -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +/* Check if invalid offset are handled correctly by mmap. */ +static int +do_test_bz21270 (void) +{ + /* For architectures with sizeof (off_t) < sizeof (off64_t) mmap is + implemented with __SYS_mmap2 syscall and the offset is represented in + multiples of page size. For offset larger than + '1 << (page_shift + 8 * sizeof (off_t))' (that is, 1<<44 on system with + page size of 4096 bytes) the system call silently truncates the offset. + For this case glibc mmap implementation returns EINVAL. */ + const int prot = PROT_READ | PROT_WRITE; + const int flags = MAP_SHARED; + const int64_t offset = 1ULL << (page_shift + 8 * sizeof (uint32_t)); + const size_t length = 4096; + + void *addr = mmap64 (NULL, length, prot, flags, fd, offset); + if (sizeof (off_t) < sizeof (off64_t)) + { + if ((addr != MAP_FAILED) && (errno != EINVAL)) + FAIL_RET ("mmap succeed"); + } + else + { + if (addr == MAP_FAILED) + FAIL_RET ("mmap failed"); + } + + return 0; +} + +int +do_test (void) +{ + int ret = 0; + + ret += do_test_bz18877 (); + ret += do_test_bz21270 (); + + return ret; +} + +#include <support/test-driver.c> |