diff --git a/lib/component.c b/lib/component.c index ee07d013..89d2bd21 100644 --- a/lib/component.c +++ b/lib/component.c @@ -51,7 +51,9 @@ UnshieldComponent* unshield_component_new(Header* header, uint32_t offset) self->file_group_count = READ_UINT16(p); p += 2; if (self->file_group_count > MAX_FILE_GROUP_COUNT) - abort(); + { + UNSHIELD_THROW_EXCEPTION(&header->exception, "file_group_count > MAX_FILE_GROUP_COUNT"); + } self->file_group_names = NEW(const char*, self->file_group_count); diff --git a/lib/helper.c b/lib/helper.c index 6de22b96..41312192 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -174,11 +174,17 @@ bool unshield_read_common_header(uint8_t** buffer, CommonHeader* common) */ uint8_t* unshield_header_get_buffer(Header* header, uint32_t offset) { - if (offset) - return + if (offset){ + if (header->common.cab_descriptor_offset + offset > header->size) + { + UNSHIELD_THROW_EXCEPTION(&header->exception, "cab_descriptor_offset + offset > header->size"); + } + + return header->data + header->common.cab_descriptor_offset + offset; + } else return NULL; } diff --git a/lib/internal.h b/lib/internal.h index 8120475e..ddf1fd20 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -11,11 +11,22 @@ #include #endif +#include #include #include /* for FILE */ #include "cabfile.h" +typedef struct _Exception Exception; + +struct _Exception +{ + jmp_buf environment; + const char* function; + int line; + const char* message; +}; + typedef struct _StringBuffer StringBuffer; struct _StringBuffer @@ -28,6 +39,7 @@ typedef struct _Header Header; struct _Header { + Exception exception; Header* next; int index; uint8_t* data; @@ -63,7 +75,7 @@ UnshieldComponent* unshield_component_new(Header* header, uint32_t offset); void unshield_component_destroy(UnshieldComponent* self); -/* +/* Internal file group functions */ @@ -84,6 +96,19 @@ const char* unshield_header_get_string(Header* header, uint32_t offset); uint8_t* unshield_header_get_buffer(Header* header, uint32_t offset); +#define UNSHIELD_HANDLE_EXCEPTION(e) (setjmp(e.environment) != 0) + +static inline void _unshield_throw_exception(Exception* exception, const char* function, int line, const char* message) +{ + exception->function = function; + exception->line = line; + exception->message = message; + longjmp(exception->environment, 1); +} + +#define UNSHIELD_THROW_EXCEPTION(exception, message) { _unshield_throw_exception(exception, __FUNCTION__, __LINE__, message); } + + /* Constants */ diff --git a/lib/libunshield.c b/lib/libunshield.c index f9531162..1f2a7b82 100644 --- a/lib/libunshield.c +++ b/lib/libunshield.c @@ -240,6 +240,12 @@ static bool unshield_read_headers(Unshield* unshield, int version)/*{{{*/ Header* header = NEW1(Header); header->index = i; + if (UNSHIELD_HANDLE_EXCEPTION(header->exception)) { + unshield_error("An exception occurred while reading .hdr file %i: [%s:%i] %s", + i, header->exception.function, header->exception.line, header->exception.message); + goto error; + } + header->size = FSIZE(file); if (header->size < 4) { diff --git a/test/bugs/debian-776238/data1.cab b/test/bugs/debian-776238/data1.cab new file mode 100644 index 00000000..57dd88cd Binary files /dev/null and b/test/bugs/debian-776238/data1.cab differ diff --git a/test/bugs/debian-776238/data1.hdr b/test/bugs/debian-776238/data1.hdr new file mode 100644 index 00000000..c58ad7f7 Binary files /dev/null and b/test/bugs/debian-776238/data1.hdr differ diff --git a/test/bugs/debian-776238/debian-776238.sh b/test/bugs/debian-776238/debian-776238.sh new file mode 100755 index 00000000..8fb3b4e0 --- /dev/null +++ b/test/bugs/debian-776238/debian-776238.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e +cd `dirname $0` +MD5_FILE=`pwd`/`basename $0 .sh`.md5 +CAB_FILE=`pwd`/data1.cab +UNSHIELD=${UNSHIELD:-/var/tmp/unshield/bin/unshield} + +if [ \! -x ${UNSHIELD} ]; then + echo "unshield executable not found at $UNSHIELD" >&2 + exit 1 +fi + +DIR=`mktemp -d` +#trap 'rm -rf ${DIR}' TERM INT EXIT +cd ${DIR} + +set +e +rm -f /tmp/moo + +timeout 10 ${UNSHIELD} -d extract1 x "$CAB_FILE" > log1 2>&1 +CODE=$? +if [ -e /tmp/moo ]; then + cat log1 >&2 + echo "unshield vulnerable to CVE-2015-1386" >&2 + echo "See https://github.com/twogood/unshield/issues/42" >&2 + exit 2 +fi + +if [ ${CODE} -ne 1 ]; then + cat log1 >&2 + echo "unshield should have failed with error 1 but was $CODE" >&2 + exit 3 +fi + +exit 0 diff --git a/test/bugs/debian-776239/data1.cab b/test/bugs/debian-776239/data1.cab new file mode 100644 index 00000000..57dd88cd Binary files /dev/null and b/test/bugs/debian-776239/data1.cab differ diff --git a/test/bugs/debian-776239/data1.hdr b/test/bugs/debian-776239/data1.hdr new file mode 100644 index 00000000..85d74b2d Binary files /dev/null and b/test/bugs/debian-776239/data1.hdr differ diff --git a/test/bugs/debian-776239/debian-776239.sh b/test/bugs/debian-776239/debian-776239.sh new file mode 100755 index 00000000..8fb3b4e0 --- /dev/null +++ b/test/bugs/debian-776239/debian-776239.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e +cd `dirname $0` +MD5_FILE=`pwd`/`basename $0 .sh`.md5 +CAB_FILE=`pwd`/data1.cab +UNSHIELD=${UNSHIELD:-/var/tmp/unshield/bin/unshield} + +if [ \! -x ${UNSHIELD} ]; then + echo "unshield executable not found at $UNSHIELD" >&2 + exit 1 +fi + +DIR=`mktemp -d` +#trap 'rm -rf ${DIR}' TERM INT EXIT +cd ${DIR} + +set +e +rm -f /tmp/moo + +timeout 10 ${UNSHIELD} -d extract1 x "$CAB_FILE" > log1 2>&1 +CODE=$? +if [ -e /tmp/moo ]; then + cat log1 >&2 + echo "unshield vulnerable to CVE-2015-1386" >&2 + echo "See https://github.com/twogood/unshield/issues/42" >&2 + exit 2 +fi + +if [ ${CODE} -ne 1 ]; then + cat log1 >&2 + echo "unshield should have failed with error 1 but was $CODE" >&2 + exit 3 +fi + +exit 0