@@ -, +, @@ malloc: Check for integer overflow in memalign. A large bytes parameter to memalign could cause an integer overflow and corrupt allocator internals. Check the overflow does not occur before continuing with the allocation. ChangeLog: 2013-09-11 Will Newton [BZ #15857] * malloc/malloc.c (__libc_memalign): Check the value of bytes does not overflow. --- a/malloc/malloc.c +++ a/malloc/malloc.c @@ -3015,6 +3015,13 @@ __libc_memalign(size_t alignment, size_t bytes) /* Otherwise, ensure that it is at least a minimum chunk size */ if (alignment < MINSIZE) alignment = MINSIZE; + /* Check for overflow. */ + if (bytes > SIZE_MAX - alignment - MINSIZE) + { + __set_errno (ENOMEM); + return 0; + } + arena_get(ar_ptr, bytes + alignment + MINSIZE); if(!ar_ptr) return 0; malloc: Check for integer overflow in pvalloc. A large bytes parameter to pvalloc could cause an integer overflow and corrupt allocator internals. Check the overflow does not occur before continuing with the allocation. ChangeLog: 2013-09-11 Will Newton [BZ #15855] * malloc/malloc.c (__libc_pvalloc): Check the value of bytes does not overflow. --- a/malloc/malloc.c +++ a/malloc/malloc.c @@ -3082,6 +3082,13 @@ __libc_pvalloc(size_t bytes) size_t page_mask = GLRO(dl_pagesize) - 1; size_t rounded_bytes = (bytes + page_mask) & ~(page_mask); + /* Check for overflow. */ + if (bytes > SIZE_MAX - 2*pagesz - MINSIZE) + { + __set_errno (ENOMEM); + return 0; + } + __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t, const __malloc_ptr_t)) = force_reg (__memalign_hook); malloc: Check for integer overflow in valloc. A large bytes parameter to valloc could cause an integer overflow and corrupt allocator internals. Check the overflow does not occur before continuing with the allocation. ChangeLog: 2013-09-11 Will Newton [BZ #15856] * malloc/malloc.c (__libc_valloc): Check the value of bytes does not overflow. --- a/malloc/malloc.c +++ a/malloc/malloc.c @@ -3046,6 +3046,13 @@ __libc_valloc(size_t bytes) size_t pagesz = GLRO(dl_pagesize); + /* Check for overflow. */ + if (bytes > SIZE_MAX - pagesz - MINSIZE) + { + __set_errno (ENOMEM); + return 0; + } + __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t, const __malloc_ptr_t)) = force_reg (__memalign_hook); --- eglibc-2.17.orig/sysdeps/posix/dirstream.h 2013-10-02 08:35:10.479670086 -0400 +++ eglibc-2.17.orig/sysdeps/posix/dirstream.h 2013-10-02 08:35:10.471670085 -0400 @@ -39,6 +39,8 @@ off_t filepos; /* Position of next entry to read. */ + int errcode; /* Delayed error code. */ + /* Directory block. */ char data[0] __attribute__ ((aligned (__alignof__ (void*)))); }; --- eglibc-2.17.orig/sysdeps/posix/opendir.c 2013-10-02 08:35:10.479670086 -0400 +++ eglibc-2.17.orig/sysdeps/posix/opendir.c 2013-10-02 08:35:10.471670085 -0400 @@ -230,6 +230,7 @@ dirp->size = 0; dirp->offset = 0; dirp->filepos = 0; + dirp->errcode = 0; return dirp; } --- eglibc-2.17.orig/sysdeps/posix/readdir_r.c 2013-10-02 08:35:10.479670086 -0400 +++ eglibc-2.17.orig/sysdeps/posix/readdir_r.c 2013-10-02 08:35:10.471670085 -0400 @@ -41,6 +41,7 @@ DIRENT_TYPE *dp; size_t reclen; const int saved_errno = errno; + int ret; __libc_lock_lock (dirp->lock); @@ -71,10 +72,10 @@ bytes = 0; __set_errno (saved_errno); } + if (bytes < 0) + dirp->errcode = errno; dp = NULL; - /* Reclen != 0 signals that an error occurred. */ - reclen = bytes != 0; break; } dirp->size = (size_t) bytes; @@ -107,29 +108,46 @@ dirp->filepos += reclen; #endif - /* Skip deleted files. */ +#ifdef NAME_MAX + if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1) + { + /* The record is very long. It could still fit into the + caller-supplied buffer if we can skip padding at the + end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) + reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1; + else + { + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; + continue; + } + } +#endif + + /* Skip deleted and ignored files. */ } while (dp->d_ino == 0); if (dp != NULL) { -#ifdef GETDENTS_64BIT_ALIGNED - /* The d_reclen value might include padding which is not part of - the DIRENT_TYPE data structure. */ - reclen = MIN (reclen, - offsetof (DIRENT_TYPE, d_name) + sizeof (dp->d_name)); -#endif *result = memcpy (entry, dp, reclen); -#ifdef GETDENTS_64BIT_ALIGNED +#ifdef _DIRENT_HAVE_D_RECLEN entry->d_reclen = reclen; #endif + ret = 0; } else - *result = NULL; + { + *result = NULL; + ret = dirp->errcode; + } __libc_lock_unlock (dirp->lock); - return dp != NULL ? 0 : reclen ? errno : 0; + return ret; } #ifdef __READDIR_R_ALIAS --- eglibc-2.17.orig/sysdeps/posix/rewinddir.c 2013-10-02 08:35:10.479670086 -0400 +++ eglibc-2.17.orig/sysdeps/posix/rewinddir.c 2013-10-02 08:35:10.471670085 -0400 @@ -33,6 +33,7 @@ dirp->filepos = 0; dirp->offset = 0; dirp->size = 0; + dirp->errcode = 0; #ifndef NOT_IN_libc __libc_lock_unlock (dirp->lock); #endif --- eglibc-2.17.orig/sysdeps/unix/sysv/linux/i386/readdir64_r.c 2013-10-02 08:35:10.479670086 -0400 +++ eglibc-2.17.orig/sysdeps/unix/sysv/linux/i386/readdir64_r.c 2013-10-02 08:35:10.471670085 -0400 @@ -18,7 +18,6 @@ #define __READDIR_R __readdir64_r #define __GETDENTS __getdents64 #define DIRENT_TYPE struct dirent64 -#define GETDENTS_64BIT_ALIGNED 1 #include --- eglibc-2.17.orig/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c 2013-10-02 08:35:10.479670086 -0400 +++ eglibc-2.17.orig/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c 2013-10-02 08:35:10.475670086 -0400 @@ -1,5 +1,4 @@ #define readdir64_r __no_readdir64_r_decl -#define GETDENTS_64BIT_ALIGNED 1 #include #undef readdir64_r weak_alias (__readdir_r, readdir64_r) BZ #15754: CVE-2013-4788 The pointer guard used for pointer mangling was not initialized for static applications resulting in the security feature being disabled. The pointer guard is now correctly initialized to a random value for static applications. Existing static applications need to be recompiled to take advantage of the fix. The test tst-ptrguard1-static and tst-ptrguard1 add regression coverage to ensure the pointer guards are sufficiently random and initialized to a default value. --- a/csu/libc-start.c +++ a/csu/libc-start.c @@ -37,6 +37,12 @@ extern void __pthread_initialize_minimal (void); in thread local area. */ uintptr_t __stack_chk_guard attribute_relro; # endif +# ifndef THREAD_SET_POINTER_GUARD +/* Only exported for architectures that don't store the pointer guard + value in thread local area. */ +uintptr_t __pointer_chk_guard_local + attribute_relro attribute_hidden __attribute__ ((nocommon)); +# endif #endif #ifdef HAVE_PTR_NTHREADS @@ -195,6 +201,16 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), # else __stack_chk_guard = stack_chk_guard; # endif + + /* Set up the pointer guard value. */ + uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random, + stack_chk_guard); +# ifdef THREAD_SET_POINTER_GUARD + THREAD_SET_POINTER_GUARD (pointer_chk_guard); +# else + __pointer_chk_guard_local = pointer_chk_guard; +# endif + #endif /* Register the destructor of the dynamic linker if there is any. */ --- a/elf/Makefile +++ a/elf/Makefile @@ -121,7 +121,8 @@ endif tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1 \ tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static \ - tst-leaks1-static tst-array1-static tst-array5-static + tst-leaks1-static tst-array1-static tst-array5-static \ + tst-ptrguard1-static ifeq (yes,$(build-shared)) tests-static += tst-tls9-static tst-tls9-static-ENV = \ @@ -145,7 +146,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ tst-audit1 tst-audit2 tst-audit8 \ tst-stackguard1 tst-addr1 tst-thrlock \ tst-unique1 tst-unique2 tst-unique3 tst-unique4 \ - tst-initorder tst-initorder2 tst-relsort1 + tst-initorder tst-initorder2 tst-relsort1 \ + tst-ptrguard1 # reldep9 test-srcs = tst-pathopt selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null) @@ -1016,6 +1018,9 @@ LDFLAGS-order2mod2.so = $(no-as-needed) tst-stackguard1-ARGS = --command "$(host-built-program-cmd) --child" tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child" +tst-ptrguard1-ARGS = --command "$(host-built-program-cmd) --child" +tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child" + $(objpfx)tst-leaks1: $(libdl) $(objpfx)tst-leaks1-mem: $(objpfx)tst-leaks1.out $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@ --- a/elf/tst-ptrguard1-static.c +++ a/elf/tst-ptrguard1-static.c @@ -0,0 +1, @@ +#include "tst-ptrguard1.c" --- a/elf/tst-ptrguard1.c +++ a/elf/tst-ptrguard1.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef POINTER_CHK_GUARD +extern uintptr_t __pointer_chk_guard; +# define POINTER_CHK_GUARD __pointer_chk_guard +#endif + +static const char *command; +static bool child; +static uintptr_t ptr_chk_guard_copy; +static bool ptr_chk_guard_copy_set; +static int fds[2]; + +static void __attribute__ ((constructor)) +con (void) +{ + ptr_chk_guard_copy = POINTER_CHK_GUARD; + ptr_chk_guard_copy_set = true; +} + +static int +uintptr_t_cmp (const void *a, const void *b) +{ + if (*(uintptr_t *) a < *(uintptr_t *) b) + return 1; + if (*(uintptr_t *) a > *(uintptr_t *) b) + return -1; + return 0; +} + +static int +do_test (void) +{ + if (!ptr_chk_guard_copy_set) + { + puts ("constructor has not been run"); + return 1; + } + + if (ptr_chk_guard_copy != POINTER_CHK_GUARD) + { + puts ("POINTER_CHK_GUARD changed between constructor and do_test"); + return 1; + } + + if (child) + { + write (2, &ptr_chk_guard_copy, sizeof (ptr_chk_guard_copy)); + return 0; + } + + if (command == NULL) + { + puts ("missing --command or --child argument"); + return 1; + } + +#define N 16 + uintptr_t child_ptr_chk_guards[N + 1]; + child_ptr_chk_guards[N] = ptr_chk_guard_copy; + int i; + for (i = 0; i < N; ++i) + { + if (pipe (fds) < 0) + { + printf ("couldn't create pipe: %m\n"); + return 1; + } + + pid_t pid = fork (); + if (pid < 0) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (!pid) + { + if (ptr_chk_guard_copy != POINTER_CHK_GUARD) + { + puts ("POINTER_CHK_GUARD changed after fork"); + exit (1); + } + + close (fds[0]); + close (2); + dup2 (fds[1], 2); + close (fds[1]); + + system (command); + exit (0); + } + + close (fds[1]); + + if (TEMP_FAILURE_RETRY (read (fds[0], &child_ptr_chk_guards[i], + sizeof (uintptr_t))) != sizeof (uintptr_t)) + { + puts ("could not read ptr_chk_guard value from child"); + return 1; + } + + close (fds[0]); + + pid_t termpid; + int status; + termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); + if (termpid == -1) + { + printf ("waitpid failed: %m\n"); + return 1; + } + else if (termpid != pid) + { + printf ("waitpid returned %ld != %ld\n", + (long int) termpid, (long int) pid); + return 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + puts ("child hasn't exited with exit status 0"); + return 1; + } + } + + qsort (child_ptr_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp); + + /* The default pointer guard is the same as the default stack guard. + They are only set to default if dl_random is NULL. */ + uintptr_t default_guard = 0; + unsigned char *p = (unsigned char *) &default_guard; + p[sizeof (uintptr_t) - 1] = 255; + p[sizeof (uintptr_t) - 2] = '\n'; + p[0] = 0; + + /* Test if the pointer guard canaries are either randomized, + or equal to the default pointer guard value. + Even with randomized pointer guards it might happen + that the random number generator generates the same + values, but if that happens in more than half from + the 16 runs, something is very wrong. */ + int ndifferences = 0; + int ndefaults = 0; + for (i = 0; i < N; ++i) + { + if (child_ptr_chk_guards[i] != child_ptr_chk_guards[i+1]) + ndifferences++; + else if (child_ptr_chk_guards[i] == default_guard) + ndefaults++; + } + + printf ("differences %d defaults %d\n", ndifferences, ndefaults); + + if (ndifferences < N / 2 && ndefaults < N / 2) + { + puts ("pointer guard values are not randomized enough"); + puts ("nor equal to the default value"); + return 1; + } + + return 0; +} + +#define OPT_COMMAND 10000 +#define OPT_CHILD 10001 +#define CMDLINE_OPTIONS \ + { "command", required_argument, NULL, OPT_COMMAND }, \ + { "child", no_argument, NULL, OPT_CHILD }, +#define CMDLINE_PROCESS \ + case OPT_COMMAND: \ + command = optarg; \ + break; \ + case OPT_CHILD: \ + child = true; \ + break; +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- a/ports/sysdeps/ia64/stackguard-macros.h +++ a/ports/sysdeps/ia64/stackguard-macros.h @@ -2,3 +2,6 @@ #define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("adds %0 = -8, r13;; ld8 %0 = [%0]" : "=r" (x)); x; }) + +#define POINTER_CHK_GUARD \ + ({ uintptr_t x; asm ("adds %0 = -16, r13;; ld8 %0 = [%0]" : "=r" (x)); x; }) --- a/ports/sysdeps/tile/stackguard-macros.h +++ a/ports/sysdeps/tile/stackguard-macros.h @@ -4,11 +4,17 @@ # if __WORDSIZE == 64 # define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("addi %0, tp, -16; ld %0, %0" : "=r" (x)); x; }) +# define POINTER_CHK_GUARD \ + ({ uintptr_t x; asm ("addi %0, tp, -24; ld %0, %0" : "=r" (x)); x; }) # else # define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("addi %0, tp, -8; ld4s %0, %0" : "=r" (x)); x; }) +# define POINTER_CHK_GUARD \ + ({ uintptr_t x; asm ("addi %0, tp, -12; ld4s %0, %0" : "=r" (x)); x; }) # endif #else # define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("addi %0, tp, -8; lw %0, %0" : "=r" (x)); x; }) +# define POINTER_CHK_GUARD \ + ({ uintptr_t x; asm ("addi %0, tp, -12; lw %0, %0" : "=r" (x)); x; }) #endif --- a/sysdeps/generic/stackguard-macros.h +++ a/sysdeps/generic/stackguard-macros.h @@ -2,3 +2,6 @@ extern uintptr_t __stack_chk_guard; #define STACK_CHK_GUARD __stack_chk_guard + +extern uintptr_t __pointer_chk_guard_local; +#define POINTER_CHK_GUARD __pointer_chk_guard_local --- a/sysdeps/i386/stackguard-macros.h +++ a/sysdeps/i386/stackguard-macros.h @@ -2,3 +2,11 @@ #define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("movl %%gs:0x14, %0" : "=r" (x)); x; }) + +#define POINTER_CHK_GUARD \ + ({ \ + uintptr_t x; \ + asm ("movl %%gs:%c1, %0" : "=r" (x) \ + : "i" (offsetof (tcbhead_t, pointer_guard))); \ + x; \ + }) --- a/sysdeps/powerpc/powerpc32/stackguard-macros.h +++ a/sysdeps/powerpc/powerpc32/stackguard-macros.h @@ -2,3 +2,13 @@ #define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("lwz %0,-28680(2)" : "=r" (x)); x; }) + +#define POINTER_CHK_GUARD \ + ({ \ + uintptr_t x; \ + asm ("lwz %0,%1(2)" \ + : "=r" (x) \ + : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) \ + ); \ + x; \ + }) --- a/sysdeps/powerpc/powerpc64/stackguard-macros.h +++ a/sysdeps/powerpc/powerpc64/stackguard-macros.h @@ -2,3 +2,13 @@ #define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("ld %0,-28688(13)" : "=r" (x)); x; }) + +#define POINTER_CHK_GUARD \ + ({ \ + uintptr_t x; \ + asm ("ld %0,%1(2)" \ + : "=r" (x) \ + : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) \ + ); \ + x; \ + }) --- a/sysdeps/s390/s390-32/stackguard-macros.h +++ a/sysdeps/s390/s390-32/stackguard-macros.h @@ -2,3 +2,14 @@ #define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("ear %0,%%a0; l %0,0x14(%0)" : "=a" (x)); x; }) + +/* On s390/s390x there is no unique pointer guard, instead we use the + same value as the stack guard. */ +#define POINTER_CHK_GUARD \ + ({ \ + uintptr_t x; \ + asm ("ear %0,%%a0; l %0,%1(%0)" \ + : "=a" (x) \ + : "i" (offsetof (tcbhead_t, stack_guard))); \ + x; \ + }) --- a/sysdeps/s390/s390-64/stackguard-macros.h +++ a/sysdeps/s390/s390-64/stackguard-macros.h @@ -2,3 +2,17 @@ #define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("ear %0,%%a0; sllg %0,%0,32; ear %0,%%a1; lg %0,0x28(%0)" : "=a" (x)); x; }) + +/* On s390/s390x there is no unique pointer guard, instead we use the + same value as the stack guard. */ +#define POINTER_CHK_GUARD \ + ({ \ + uintptr_t x; \ + asm ("ear %0,%%a0;" \ + "sllg %0,%0,32;" \ + "ear %0,%%a1;" \ + "lg %0,%1(%0)" \ + : "=a" (x) \ + : "i" (offsetof (tcbhead_t, stack_guard))); \ + x; \ + }) --- a/sysdeps/sparc/sparc32/stackguard-macros.h +++ a/sysdeps/sparc/sparc32/stackguard-macros.h @@ -2,3 +2,6 @@ #define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("ld [%%g7+0x14], %0" : "=r" (x)); x; }) + +#define POINTER_CHK_GUARD \ + ({ uintptr_t x; asm ("ld [%%g7+0x18], %0" : "=r" (x)); x; }) --- a/sysdeps/sparc/sparc64/stackguard-macros.h +++ a/sysdeps/sparc/sparc64/stackguard-macros.h @@ -2,3 +2,6 @@ #define STACK_CHK_GUARD \ ({ uintptr_t x; asm ("ldx [%%g7+0x28], %0" : "=r" (x)); x; }) + +#define POINTER_CHK_GUARD \ + ({ uintptr_t x; asm ("ldx [%%g7+0x30], %0" : "=r" (x)); x; }) --- a/sysdeps/x86_64/stackguard-macros.h +++ a/sysdeps/x86_64/stackguard-macros.h @@ -4,3 +4,8 @@ ({ uintptr_t x; \ asm ("mov %%fs:%c1, %0" : "=r" (x) \ : "i" (offsetof (tcbhead_t, stack_guard))); x; }) + +#define POINTER_CHK_GUARD \ + ({ uintptr_t x; \ + asm ("mov %%fs:%c1, %0" : "=r" (x) \ + : "i" (offsetof (tcbhead_t, pointer_guard))); x; }) BZ #15754: Fix test case for ARM. Statically built binaries use __pointer_chk_guard_local, while dynamically built binaries use __pointer_chk_guard. Provide the right definition depending on the test case we are building. [BZ #15754] --- a/elf/Makefile +++ a/elf/Makefile @@ -1019,6 +1019,9 @@ tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child" tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child" tst-ptrguard1-ARGS = --command "$(host-built-program-cmd) --child" +# When built statically, the pointer guard interface uses +# __pointer_chk_guard_local. +CFLAGS-tst-ptrguard1-static.c = -DPTRGUARD_LOCAL tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child" $(objpfx)tst-leaks1: $(libdl) --- a/sysdeps/generic/stackguard-macros.h +++ a/sysdeps/generic/stackguard-macros.h @@ -3,5 +3,10 @@ extern uintptr_t __stack_chk_guard; #define STACK_CHK_GUARD __stack_chk_guard +#ifdef PTRGUARD_LOCAL extern uintptr_t __pointer_chk_guard_local; -#define POINTER_CHK_GUARD __pointer_chk_guard_local +# define POINTER_CHK_GUARD __pointer_chk_guard_local +#else +extern uintptr_t __pointer_chk_guard; +# define POINTER_CHK_GUARD __pointer_chk_guard +#endif Fix readdir regressions on sparc 32-bit. * sysdeps/posix/dirstream.h (struct __dirstream): Fix alignment of directory block. --- a/sysdeps/posix/dirstream.h +++ a/sysdeps/posix/dirstream.h @@ -41,8 +41,13 @@ struct __dirstream int errcode; /* Delayed error code. */ - /* Directory block. */ - char data[0] __attribute__ ((aligned (__alignof__ (void*)))); + /* Directory block. We must make sure that this block starts + at an address that is aligned adequately enough to store + dirent entries. Using the alignment of "void *" is not + sufficient because dirents on 32-bit platforms can require + 64-bit alignment. We use "long double" here to be consistent + with what malloc uses. */ + char data[0] __attribute__ ((aligned (__alignof__ (long double)))); }; #define _DIR_dirfd(dirp) ((dirp)->fd) --- locale/loadarchive.c | 4 ++++ 1 file changed, 4 insertions(+) --- a/locale/loadarchive.c +++ a/locale/loadarchive.c @@ -274,6 +274,10 @@ _nl_load_locale_from_archive (int category, const char **namep) namehashtab = (struct namehashent *) ((char *) head + head->namehash_offset); + /* Avoid division by 0 if the file is corrupted. */ + if (__builtin_expect (head->namehash_size == 0, 0)) + goto close_and_out; + idx = hval % head->namehash_size; incr = 1 + hval % (head->namehash_size - 2); --