summaryrefslogtreecommitdiff
path: root/libelf/libelf_ar.c
diff options
context:
space:
mode:
Diffstat (limited to 'libelf/libelf_ar.c')
-rw-r--r--libelf/libelf_ar.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/libelf/libelf_ar.c b/libelf/libelf_ar.c
index 8fce7419726e..6634d2c73c33 100644
--- a/libelf/libelf_ar.c
+++ b/libelf/libelf_ar.c
@@ -33,7 +33,7 @@
#include "_libelf.h"
#include "_libelf_ar.h"
-ELFTC_VCSID("$Id: libelf_ar.c 3446 2016-05-03 01:31:17Z emaste $");
+ELFTC_VCSID("$Id: libelf_ar.c 3712 2019-03-16 22:23:34Z jkoshy $");
#define LIBELF_NALLOC_SIZE 16
@@ -123,8 +123,16 @@ _libelf_ar_gethdr(Elf *e)
arh = (struct ar_hdr *) (uintptr_t) e->e_hdr.e_rawhdr;
assert((uintptr_t) arh >= (uintptr_t) parent->e_rawfile + SARMAG);
- assert((uintptr_t) arh <= (uintptr_t) parent->e_rawfile +
- parent->e_rawsize - sizeof(struct ar_hdr));
+
+ /*
+ * There needs to be enough space remaining in the file for the
+ * archive header.
+ */
+ if ((uintptr_t) arh > (uintptr_t) parent->e_rawfile +
+ (uintptr_t) parent->e_rawsize - sizeof(struct ar_hdr)) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
if ((eh = malloc(sizeof(Elf_Arhdr))) == NULL) {
LIBELF_SET_ERROR(RESOURCE, 0);
@@ -199,8 +207,8 @@ Elf *
_libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
{
Elf *e;
- off_t next;
size_t nsz, sz;
+ off_t next, end;
struct ar_hdr *arh;
char *member, *namelen;
@@ -217,6 +225,17 @@ _libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
assert((next & 1) == 0);
+ /*
+ * There needs to be enough space in the file to contain an
+ * ar(1) header.
+ */
+ end = next + (off_t) sizeof(struct ar_hdr);
+ if ((uintmax_t) end < (uintmax_t) next || /* Overflow. */
+ end > (off_t) elf->e_rawsize) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
arh = (struct ar_hdr *) (elf->e_rawfile + next);
/*
@@ -229,6 +248,17 @@ _libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
}
/*
+ * Check if the archive member that follows will fit in the
+ * containing archive.
+ */
+ end += (off_t) sz;
+ if (end < next || /* Overflow. */
+ end > (off_t) elf->e_rawsize) {
+ LIBELF_SET_ERROR(ARCHIVE, 0);
+ return (NULL);
+ }
+
+ /*
* Adjust the size field for members in BSD archives using
* extended naming.
*/
@@ -286,7 +316,8 @@ Elf_Arsym *
_libelf_ar_process_bsd_symtab(Elf *e, size_t *count)
{
Elf_Arsym *symtab, *sym;
- unsigned int n, nentries;
+ unsigned int n;
+ size_t nentries;
unsigned char *end, *p, *p0, *s, *s0;
const size_t entrysize = 2 * sizeof(long);
long arraysize, fileoffset, stroffset, strtabsize;
@@ -343,7 +374,7 @@ _libelf_ar_process_bsd_symtab(Elf *e, size_t *count)
GET_LONG(p, fileoffset);
if (stroffset < 0 || fileoffset < 0 ||
- (size_t) fileoffset >= e->e_rawsize)
+ (off_t) fileoffset >= e->e_rawsize)
goto symtaberror;
s = s0 + stroffset;