diff options
-rw-r--r-- | libelf/ChangeLog | 20 | ||||
-rw-r--r-- | libelf/elf32_getphdr.c | 12 | ||||
-rw-r--r-- | libelf/elf32_getshdr.c | 15 | ||||
-rw-r--r-- | libelf/elf32_newphdr.c | 8 | ||||
-rw-r--r-- | libelf/elf32_updatefile.c | 9 | ||||
-rw-r--r-- | libelf/elf_begin.c | 32 | ||||
-rw-r--r-- | libelf/elf_getarsym.c | 5 | ||||
-rw-r--r-- | libelf/elf_getshdrstrndx.c | 44 | ||||
-rw-r--r-- | libelf/elf_newscn.c | 12 |
9 files changed, 139 insertions, 18 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 148c9453..ee070e05 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,23 @@ +2014-01-17 Jakub Jelinek <jakub@redhat.com> + + * elf32_getphdr.c (elfw2(LIBELFBITS,getphdr)): Check if program header + table fits into object's bounds. + * elf_getshdrstrndx.c (elf_getshstrndx): Add elf->start_offset to + elf->map_address. Check if first section header fits into object's + bounds. + * elf32_getshdr.c (elfw2(LIBELFBITS,getshdr)): + Check if section header table fits into object's bounds. + * elf_begin.c (get_shnum): Ensure section headers fits into + object's bounds. + (file_read_elf): Make sure scncnt is small enough to allocate both + ElfXX_Shdr and Elf_Scn array. Make sure section and program header + tables fit into object's bounds. Avoid memory leak on failure. + * elf_newscn.c (elf_newscn): Check for overflow. + * elf32_updatefile.c (__elfw2(LIBELFBITS,updatemmap)): Likewise. + (__elfw2(LIBELFBITS,updatefile)): Likewise. + * elf32_newphdr.c (elfw2(LIBELFBITS,newphdr)): Likewise. + * elf_getarsym.c (elf_getarsym): Likewise. + 2013-11-08 Mark Wielaard <mjw@redhat.com> * elf32_updatefile.c (elfXX_updatemmap): Only memcpy ehdr when not diff --git a/libelf/elf32_getphdr.c b/libelf/elf32_getphdr.c index a47c9f7a..e74e63fd 100644 --- a/libelf/elf32_getphdr.c +++ b/libelf/elf32_getphdr.c @@ -1,5 +1,5 @@ /* Get ELF program header table. - Copyright (C) 1998-2010 Red Hat, Inc. + Copyright (C) 1998-2010, 2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -93,6 +93,16 @@ __elfw2(LIBELFBITS,getphdr_wrlock) (elf) if (elf->map_address != NULL) { + /* First see whether the information in the ELF header is + valid and it does not ask for too much. */ + if (unlikely (ehdr->e_phoff >= elf->maximum_size) + || unlikely (elf->maximum_size - ehdr->e_phoff < size)) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_PHDR); + goto out; + } + /* All the data is already mapped. Use it. */ void *file_phdr = ((char *) elf->map_address + elf->start_offset + ehdr->e_phoff); diff --git a/libelf/elf32_getshdr.c b/libelf/elf32_getshdr.c index bd9340dd..74170473 100644 --- a/libelf/elf32_getshdr.c +++ b/libelf/elf32_getshdr.c @@ -1,5 +1,5 @@ /* Return section header. - Copyright (C) 1998-2002, 2005, 2007, 2009, 2012 Red Hat, Inc. + Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -60,7 +60,8 @@ load_shdr_wrlock (Elf_Scn *scn) goto out; size_t shnum; - if (__elf_getshdrnum_rdlock (elf, &shnum) != 0) + if (__elf_getshdrnum_rdlock (elf, &shnum) != 0 + || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr))) goto out; size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr)); @@ -77,6 +78,16 @@ load_shdr_wrlock (Elf_Scn *scn) if (elf->map_address != NULL) { + /* First see whether the information in the ELF header is + valid and it does not ask for too much. */ + if (unlikely (ehdr->e_shoff >= elf->maximum_size) + || unlikely (elf->maximum_size - ehdr->e_shoff < size)) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + goto free_and_out; + } + ElfW2(LIBELFBITS,Shdr) *notcvt; /* All the data is already mapped. If we could use it diff --git a/libelf/elf32_newphdr.c b/libelf/elf32_newphdr.c index 1db20806..01038e73 100644 --- a/libelf/elf32_newphdr.c +++ b/libelf/elf32_newphdr.c @@ -1,5 +1,5 @@ /* Create new ELF program header table. - Copyright (C) 1999-2010 Red Hat, Inc. + Copyright (C) 1999-2010, 2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -114,6 +114,12 @@ elfw2(LIBELFBITS,newphdr) (elf, count) || count == PN_XNUM || elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) { + if (unlikely (count > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr)))) + { + result = NULL; + goto out; + } + /* Allocate a new program header with the appropriate number of elements. */ result = (ElfW2(LIBELFBITS,Phdr) *) diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c index b39e2841..153e377f 100644 --- a/libelf/elf32_updatefile.c +++ b/libelf/elf32_updatefile.c @@ -1,5 +1,5 @@ /* Write changed data structures. - Copyright (C) 2000-2010 Red Hat, Inc. + Copyright (C) 2000-2010, 2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2000. @@ -202,6 +202,9 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) /* Write all the sections. Well, only those which are modified. */ if (shnum > 0) { + if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *))) + return 1; + Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns; Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *)); char *const shdr_start = ((char *) elf->map_address + elf->start_offset @@ -624,6 +627,10 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) /* Write all the sections. Well, only those which are modified. */ if (shnum > 0) { + if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *) + + sizeof (ElfW2(LIBELFBITS,Shdr))))) + return 1; + off_t shdr_offset = elf->start_offset + ehdr->e_shoff; #if EV_NUM != 2 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]; diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index b9d5cea4..a592fbf7 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -1,5 +1,5 @@ /* Create descriptor for processing file. - Copyright (C) 1998-2010, 2012 Red Hat, Inc. + Copyright (C) 1998-2010, 2012, 2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -144,7 +144,8 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, if (unlikely (result == 0) && ehdr.e32->e_shoff != 0) { - if (ehdr.e32->e_shoff + sizeof (Elf32_Shdr) > maxsize) + if (unlikely (ehdr.e32->e_shoff >= maxsize) + || unlikely (maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr))) /* Cannot read the first section header. */ return 0; @@ -192,7 +193,8 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, if (unlikely (result == 0) && ehdr.e64->e_shoff != 0) { - if (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize) + if (unlikely (ehdr.e64->e_shoff >= maxsize) + || unlikely (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize)) /* Cannot read the first section header. */ return 0; @@ -264,6 +266,15 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, /* Could not determine the number of sections. */ return NULL; + /* Check for too many sections. */ + if (e_ident[EI_CLASS] == ELFCLASS32) + { + if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf32_Shdr))) + return NULL; + } + else if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf64_Shdr))) + return NULL; + /* We can now allocate the memory. Even if there are no section headers, we allocate space for a zeroth section in case we need it later. */ const size_t scnmax = (scncnt ?: (cmd == ELF_C_RDWR || cmd == ELF_C_RDWR_MMAP) @@ -303,6 +314,16 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, { /* We can use the mmapped memory. */ elf->state.elf32.ehdr = ehdr; + + if (unlikely (ehdr->e_shoff >= maxsize) + || unlikely (maxsize - ehdr->e_shoff + < scncnt * sizeof (Elf32_Shdr))) + { + free_and_out: + free (elf); + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } elf->state.elf32.shdr = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff); @@ -389,6 +410,11 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, { /* We can use the mmapped memory. */ elf->state.elf64.ehdr = ehdr; + + if (unlikely (ehdr->e_shoff >= maxsize) + || unlikely (ehdr->e_shoff + + scncnt * sizeof (Elf32_Shdr) > maxsize)) + goto free_and_out; elf->state.elf64.shdr = (Elf64_Shdr *) ((char *) ehdr + ehdr->e_shoff); diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c index d0bb28a9..7325190a 100644 --- a/libelf/elf_getarsym.c +++ b/libelf/elf_getarsym.c @@ -1,5 +1,5 @@ /* Return symbol table of archive. - Copyright (C) 1998-2000, 2002, 2005, 2012 Red Hat, Inc. + Copyright (C) 1998-2000, 2002, 2005, 2009, 2012, 2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -183,6 +183,9 @@ elf_getarsym (elf, ptr) size_t index_size = atol (tmpbuf); if (SARMAG + sizeof (struct ar_hdr) + index_size > elf->maximum_size +#if SIZE_MAX <= 4294967295U + || n >= SIZE_MAX / sizeof (Elf_Arsym) +#endif || n * w > index_size) { /* This index table cannot be right since it does not fit into diff --git a/libelf/elf_getshdrstrndx.c b/libelf/elf_getshdrstrndx.c index 57ad8005..1dbed4c8 100644 --- a/libelf/elf_getshdrstrndx.c +++ b/libelf/elf_getshdrstrndx.c @@ -1,5 +1,5 @@ /* Return section index of section header string table. - Copyright (C) 2002, 2005, 2009 Red Hat, Inc. + Copyright (C) 2002, 2005, 2009, 2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -104,10 +104,25 @@ elf_getshdrstrndx (elf, dst) if (elf->map_address != NULL && elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA && (ALLOW_UNALIGNED - || (((size_t) ((char *) elf->map_address + offset)) + || (((size_t) ((char *) elf->map_address + + elf->start_offset + offset)) & (__alignof__ (Elf32_Shdr) - 1)) == 0)) - /* We can directly access the memory. */ - num = ((Elf32_Shdr *) (elf->map_address + offset))->sh_link; + { + /* First see whether the information in the ELF header is + valid and it does not ask for too much. */ + if (unlikely (elf->maximum_size - offset + < sizeof (Elf32_Shdr))) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + result = -1; + goto out; + } + + /* We can directly access the memory. */ + num = ((Elf32_Shdr *) (elf->map_address + elf->start_offset + + offset))->sh_link; + } else { /* We avoid reading in all the section headers. Just read @@ -142,10 +157,25 @@ elf_getshdrstrndx (elf, dst) if (elf->map_address != NULL && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA && (ALLOW_UNALIGNED - || (((size_t) ((char *) elf->map_address + offset)) + || (((size_t) ((char *) elf->map_address + + elf->start_offset + offset)) & (__alignof__ (Elf64_Shdr) - 1)) == 0)) - /* We can directly access the memory. */ - num = ((Elf64_Shdr *) (elf->map_address + offset))->sh_link; + { + /* First see whether the information in the ELF header is + valid and it does not ask for too much. */ + if (unlikely (elf->maximum_size - offset + < sizeof (Elf64_Shdr))) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + result = -1; + goto out; + } + + /* We can directly access the memory. */ + num = ((Elf64_Shdr *) (elf->map_address + elf->start_offset + + offset))->sh_link; + } else { /* We avoid reading in all the section headers. Just read diff --git a/libelf/elf_newscn.c b/libelf/elf_newscn.c index 70d29b66..6e0029ed 100644 --- a/libelf/elf_newscn.c +++ b/libelf/elf_newscn.c @@ -1,5 +1,5 @@ /* Append new section. - Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -83,10 +83,18 @@ elf_newscn (elf) else { /* We must allocate a new element. */ - Elf_ScnList *newp; + Elf_ScnList *newp = NULL; assert (elf->state.elf.scnincr > 0); + if ( +#if SIZE_MAX <= 4294967295U + likely (elf->state.elf.scnincr + < SIZE_MAX / 2 / sizeof (Elf_Scn) - sizeof (Elf_ScnList)) +#else + 1 +#endif + ) newp = (Elf_ScnList *) calloc (sizeof (Elf_ScnList) + ((elf->state.elf.scnincr *= 2) * sizeof (Elf_Scn)), 1); |