From 20e3cfc08ac6da5b695f09502e5d39304aff54b8 Mon Sep 17 00:00:00 2001 From: Micah Snyder Date: Sun, 9 Sep 2018 10:00:12 -0400 Subject: [PATCH] bb12170: Added pointer arithmetic guards to PE MEW unpacking code. --- libclamav/mew.c | 49 +++++++++++++++++++++++++++++++++++++++++++++---- libclamav/pe.c | 18 +++++++++++++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/libclamav/mew.c b/libclamav/mew.c index 54826ccfa..461e2dd28 100644 --- a/libclamav/mew.c +++ b/libclamav/mew.c @@ -784,18 +784,59 @@ uint32_t lzma_upack_esi_54(struct lzmastate *p, uint32_t old_eax, uint32_t *old_ return 0; } - +/** + * @brief Unpack MEW 11 packed PE file + * + * @param src buffer to unpack + * @param off offset of diff + * @param ssize pe section size + * @param dsize diff size + * @param base OPTIONAL_HEADER32.ImageBase + * @param vadd RVA of pe section + * @param uselzma Bool - use LZMA + * @param filedesc File descriptor + * @return int Returns -1 on failure, 1 on success. + */ int unmew11(char *src, uint32_t off, uint32_t ssize, uint32_t dsize, uint32_t base, uint32_t vadd, int uselzma, int filedesc) { uint32_t entry_point, newedi, loc_ds=dsize, loc_ss=ssize; - char *source = src + dsize + off; - const char *lesi = source + 12; + char *source = NULL; + const char *lesi = NULL; char *ledi; const char *f1; char *f2; int i; struct cli_exe_section *section = NULL; - uint32_t vma = base + vadd, size_sum = ssize + dsize; + uint32_t vma = base + vadd; + uint32_t size_sum = ssize + dsize; + + /* Guard against integer overflows */ + if (base + vadd < base) { + cli_dbgmsg("MEW: base (%08x) + PE section RVA (%08x) exceeds max size of unsigned int (%08x)\n", + base, vadd, UINT32_MAX); + return -1; + } + if (ssize + dsize < ssize) { + cli_dbgmsg("MEW: section size (%08x) + diff size (%08x) exceeds max size of unsigned int (%08x)\n", + ssize, dsize, UINT32_MAX); + return -1; + } + if (((size_t)(src + off) < (size_t)(src)) || + ((size_t)(src + off) < (size_t)(off))) + { + cli_dbgmsg("MEW: Buffer pointer (%08zx) + offset (%08zx) exceeds max size of pointer (%08lx)\n", + (size_t)src, (size_t)off, SIZE_MAX); + return -1; + } + + /* Ensure that off + required data exists within buffer */ + if (!CLI_ISCONTAINED(src, size_sum, src + off, 12)) { + cli_dbgmsg("MEW: Data reference exceeds size of provided buffer.\n"); + return -1; + } + + source = src + dsize + off; + lesi = source + 12; entry_point = cli_readint32(source + 4); newedi = cli_readint32(source + 8); diff --git a/libclamav/pe.c b/libclamav/pe.c index 92bb9149f..ccf6135fd 100644 --- a/libclamav/pe.c +++ b/libclamav/pe.c @@ -47,6 +47,7 @@ #include #include +#include #if HAVE_STRING_H #include @@ -3899,7 +3900,10 @@ int cli_scanpe(cli_ctx *ctx) else cli_dbgmsg("MEW: Win9x compatibility was NOT set!\n"); - if((offdiff = cli_readint32(tbuff+1) - EC32(optional_hdr32.ImageBase)) <= exe_sections[i + 1].rva || offdiff >= exe_sections[i + 1].rva + exe_sections[i + 1].raw - 4) { + offdiff = cli_readint32(tbuff+1) - EC32(optional_hdr32.ImageBase); + if ((offdiff <= exe_sections[i + 1].rva) || + (offdiff >= exe_sections[i + 1].rva + exe_sections[i + 1].raw - 4)) + { cli_dbgmsg("MEW: ESI is not in proper section\n"); break; } @@ -3914,6 +3918,18 @@ int cli_scanpe(cli_ctx *ctx) ssize = exe_sections[i + 1].vsz; dsize = exe_sections[i].vsz; + /* Guard against integer overflow */ + if ((ssize + dsize < ssize) || (ssize + dsize < dsize)) { + cli_dbgmsg("MEW: section size (%08x) + diff size (%08x) exceeds max size of unsigned int (%08x)\n", ssize, dsize, UINT32_MAX); + break; + } + + /* Verify that offdiff does not exceed the ssize + sdiff */ + if (offdiff >= ssize + dsize) { + cli_dbgmsg("MEW: offdiff (%08x) exceeds section size + diff size (%08x)\n", offdiff, ssize + dsize); + break; + } + cli_dbgmsg("MEW: ssize %08x dsize %08x offdiff: %08x\n", ssize, dsize, offdiff); CLI_UNPSIZELIMITS("MEW", MAX(ssize, dsize));