=== modified file 'debian/changelog' --- debian/changelog 2017-05-24 13:02:51 +0000 +++ debian/changelog 2017-05-24 13:18:44 +0000 @@ -1,3 +1,15 @@ +libytnef (1.5-9ubuntu0.16.04.1) xenial-security; urgency=medium + + * SECURITY UPDATE: multiple security issues (LP: #1666884) + - debian/patches/*: synchronize security fixes with Debian's + 1.5-6+deb8u1 release. Thanks to Jordi Mallach. + - CVE-2017-6298, CVE-2017-6299, CVE-2017-6300, CVE-2017-6301, + CVE-2017-6302, CVE-2017-6303, CVE-2017-6304, CVE-2017-6305, + CVE-2017-6306, CVE-2017-6800, CVE-2017-6801, CVE-2017-6802, + CVE-2017-9058. + + -- Jeremy Bicha Wed, 24 May 2017 09:04:02 -0400 + libytnef (1.5-9) unstable; urgency=medium * QA upload. === modified file 'debian/control' --- debian/control 2017-05-24 13:02:51 +0000 +++ debian/control 2017-05-24 13:18:44 +0000 @@ -1,7 +1,8 @@ Source: libytnef Section: utils Priority: extra -Maintainer: Debian QA Group +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian QA Group Build-Depends: debhelper (>= 9), autotools-dev, dh-autoreconf Standards-Version: 3.9.6 Homepage: http://sourceforge.net/projects/ytnef/ === added file 'debian/patches/0001-Fixes-for-CVE-2017-6298-to-6306.patch' --- debian/patches/0001-Fixes-for-CVE-2017-6298-to-6306.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/0001-Fixes-for-CVE-2017-6298-to-6306.patch 2017-05-24 13:18:44 +0000 @@ -0,0 +1,415 @@ +From 26296590dfaa065aa64c1ee58209d780e7bd4d6c Mon Sep 17 00:00:00 2001 +From: Jordi Mallach +Date: Tue, 21 Mar 2017 04:01:36 +0100 +Subject: [PATCH 1/2] Fixes for CVE-2017-6298 to 6306. + +--- + tnef-types.h | 2 +- + ytnef.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- + ytnef.h | 2 +- + 3 files changed, 83 insertions(+), 15 deletions(-) + +Index: ytnef/tnef-types.h +=================================================================== +--- ytnef.orig/tnef-types.h ++++ ytnef/tnef-types.h +@@ -91,7 +91,7 @@ typedef struct + + typedef struct + { +- char version[10]; ++ char version[16]; + variableLength from; + variableLength subject; + dtr dateSent; +Index: ytnef/ytnef.c +=================================================================== +--- ytnef.orig/ytnef.c ++++ ytnef/ytnef.c +@@ -1,6 +1,7 @@ + #include + #include + #include ++#include + #include "ytnef.h" + #include "tnef-errors.h" + #include "mapi.h" +@@ -32,7 +33,12 @@ + } + + #define MIN(x,y) (((x)<(y))?(x):(y)) +-void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p); ++ ++#define ALLOCCHECK(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(-1); } } ++#define ALLOCCHECK_CHAR(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(NULL); } } ++#define SIZECHECK(x) { if ((((char *)d - (char *)data) + x) > size) { printf("Corrupted file detected at %s : %i\n", __FILE__, __LINE__); return(-1); } } ++ ++int TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p); + void SetFlip(void); + + int TNEFDefaultHandler STD_ARGLIST; +@@ -151,10 +157,14 @@ DDWORD SwapDDWord(BYTE *p) + } + + /* convert 16-bit unicode to UTF8 unicode */ +-char* to_utf8(int len, char* buf) ++char* to_utf8(size_t len, char* buf) + { + int i, j = 0; + /* worst case length */ ++ if (len > 10000) { // deal with this by adding an arbitrary limit ++ printf("suspecting a corrupt file in UTF8 conversion\n"); ++ exit(-1); ++ } + char *utf8 = malloc(3 * len/2 + 1); + + for (i=0; iCodePage.size = size; + TNEF->CodePage.data = calloc(size, sizeof(BYTE)); ++ ALLOCCHECK(TNEF->CodePage.data); + memcpy(TNEF->CodePage.data, data, size); + return 0; + } +@@ -209,6 +220,7 @@ int TNEFMessageID STD_ARGLIST { + int TNEFBody STD_ARGLIST { + TNEF->body.size = size; + TNEF->body.data = calloc(size, sizeof(BYTE)); ++ ALLOCCHECK(TNEF->body.data); + memcpy(TNEF->body.data, data, size); + return 0; + } +@@ -216,6 +228,7 @@ int TNEFBody STD_ARGLIST { + int TNEFOriginalMsgClass STD_ARGLIST { + TNEF->OriginalMessageClass.size = size; + TNEF->OriginalMessageClass.data = calloc(size, sizeof(BYTE)); ++ ALLOCCHECK(TNEF->OriginalMessageClass.data); + memcpy(TNEF->OriginalMessageClass.data, data, size); + return 0; + } +@@ -227,6 +240,7 @@ int TNEFMessageClass STD_ARGLIST { + // ----------------------------------------------------------------------------- + int TNEFFromHandler STD_ARGLIST { + TNEF->from.data = calloc(size, sizeof(BYTE)); ++ ALLOCCHECK(TNEF->from.data); + TNEF->from.size = size; + memcpy(TNEF->from.data, data,size); + return 0; +@@ -234,6 +248,7 @@ int TNEFFromHandler STD_ARGLIST { + // ----------------------------------------------------------------------------- + int TNEFSubjectHandler STD_ARGLIST { + TNEF->subject.data = calloc(size, sizeof(BYTE)); ++ ALLOCCHECK(TNEF->subject.data); + TNEF->subject.size = size; + memcpy(TNEF->subject.data, data,size); + return 0; +@@ -248,6 +263,7 @@ int TNEFRendData STD_ARGLIST { + + // Add a new one + p->next = calloc(1,sizeof(Attachment)); ++ ALLOCCHECK(p->next); + p=p->next; + + TNEFInitAttachment(p); +@@ -263,7 +279,7 @@ int TNEFVersion STD_ARGLIST { + major = SwapWord(data+2); + minor = SwapWord(data); + +- sprintf(TNEF->version, "TNEF%i.%i", major, minor); ++ snprintf(TNEF->version, sizeof(TNEF->version), "TNEF%i.%i", major, minor); + return 0; + } + +@@ -276,6 +292,7 @@ int TNEFIcon STD_ARGLIST { + + p->IconData.size = size; + p->IconData.data = calloc(size, sizeof(BYTE)); ++ ALLOCCHECK(p->IconData.data); + memcpy(p->IconData.data, data, size); + } + +@@ -313,17 +330,19 @@ int TNEFAttachmentMAPI STD_ARGLIST { + // + p = &(TNEF->starting_attach); + while (p->next!=NULL) p=p->next; +- TNEFFillMapi(TNEF, data, size, &(p->MAPI)); +- +- return 0; ++ return TNEFFillMapi(TNEF, (BYTE*)data, size, &(p->MAPI)); + } + // ----------------------------------------------------------------------------- + int TNEFMapiProperties STD_ARGLIST { + TNEFFillMapi(TNEF, data, size, &(TNEF->MapiProperties)); ++ if (TNEFFillMapi(TNEF, (BYTE*)data, size, &(TNEF->MapiProperties)) < 0) { ++ printf("ERROR Parsing MAPI block\n"); ++ return -1; ++ }; + return 0; + } + +-void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p) { ++int TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p) { + int i,j; + DWORD num; + BYTE *d; +@@ -342,6 +361,7 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + p->count = SwapDWord(data); + d += 4; + p->properties = calloc(p->count, sizeof(MAPIProperty)); ++ ALLOCCHECK(p->properties); + mp = p->properties; + + for(i=0; icount; i++) { +@@ -354,20 +374,26 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + length = -1; + if (PROP_ID(mp->id) >= 0x8000) { + // Read the GUID ++ SIZECHECK(16); + memcpy(&(mp->guid[0]), d, 16); + d+=16; +- ++ ++ SIZECHECK(4); + length = SwapDWord(d); + d+=sizeof(DWORD); + if (length > 0) { + mp->namedproperty = length; + mp->propnames = calloc(length, sizeof(variableLength)); ++ ALLOCCHECK(mp->propnames); + while (length > 0) { ++ SIZECHECK(4); + type = SwapDWord(d); + mp->propnames[length-1].data = calloc(type, sizeof(BYTE)); ++ ALLOCCHECK(mp->propnames[length - 1].data); + mp->propnames[length-1].size = type; + d+=4; + for(j=0; j<(type>>1); j++) { ++ SIZECHECK(j*2); + mp->propnames[length-1].data[j] = d[j*2]; + } + d += type + ((type % 4) ? (4 - type%4) : 0); +@@ -375,6 +401,7 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + } + } else { + // READ the type ++ SIZECHECK(sizeof(DWORD)); + type = SwapDWord(d); + d+=sizeof(DWORD); + mp->id = PROP_TAG(PROP_TYPE(mp->id), type); +@@ -385,11 +412,13 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + //printf("Type id = %04x\n", PROP_TYPE(mp->id)); + if (PROP_TYPE(mp->id) & MV_FLAG) { + mp->id = PROP_TAG(PROP_TYPE(mp->id) - MV_FLAG, PROP_ID(mp->id)); ++ SIZECHECK(4); + mp->count = SwapDWord(d); + d+=4; + count = 0; + } + mp->data = calloc(mp->count, sizeof(variableLength)); ++ ALLOCCHECK(mp->data); + vl = mp->data; + } else { + i--; +@@ -404,19 +433,23 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + case PT_UNICODE: + // First number of objects (assume 1 for now) + if (count == -1) { ++ SIZECHECK(4); + vl->size = SwapDWord(d); + d+=4; + } + // now size of object ++ SIZECHECK(4); + vl->size = SwapDWord(d); + d+=4; + + // now actual object ++ SIZECHECK(vl->size); + if (PROP_TYPE(mp->id) == PT_UNICODE) { + vl->data = to_utf8(vl->size, d); + } + else { + vl->data = calloc(vl->size, sizeof(BYTE)); ++ ALLOCCHECK(vl->data); + memcpy(vl->data, d, vl->size); + } + +@@ -430,6 +463,8 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + // Read in 2 bytes, but proceed by 4 bytes + vl->size = 2; + vl->data = calloc(vl->size, sizeof(WORD)); ++ ALLOCCHECK(vl->data); ++ SIZECHECK(sizeof(WORD)); + temp_word = SwapWord(d); + memcpy(vl->data, &temp_word, vl->size); + d += 4; +@@ -442,6 +477,8 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + case PT_ERROR: + vl->size = 4; + vl->data = calloc(vl->size, sizeof(BYTE)); ++ ALLOCCHECK(vl->data); ++ SIZECHECK(4); + temp_dword = SwapDWord(d); + memcpy(vl->data, &temp_dword, vl->size); + d += 4; +@@ -451,10 +488,15 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + case PT_SYSTIME: + vl->size = 8; + vl->data = calloc(vl->size, sizeof(BYTE)); ++ ALLOCCHECK(vl->data); ++ SIZECHECK(8); + temp_ddword = SwapDDWord(d); + memcpy(vl->data, &temp_ddword, vl->size); + d+=8; + break; ++ default: ++ printf("Bad file\n"); ++ exit(-1); + } + if (count == (mp->count-1)) { + count = -1; +@@ -476,7 +518,7 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE + printf("%i bytes extra\n", (d-data)-size); + } + } +- return; ++ return 0; + } + // ----------------------------------------------------------------------------- + int TNEFSentFor STD_ARGLIST { +@@ -486,12 +528,14 @@ int TNEFSentFor STD_ARGLIST { + d=data; + + while ((d-data)Debug >= 1) + printf("Sent For : %s", d); + d+=name_length; + ++ SIZECHECK(sizeof(WORD)); + addr_length = SwapWord(d); + d+=sizeof(WORD); + if (TNEF->Debug >= 1) +@@ -598,6 +642,7 @@ int TNEFAttachmentFilename STD_ARGLIST { + + p->Title.size = size; + p->Title.data = calloc(size, sizeof(BYTE)); ++ ALLOCCHECK(p->Title.data); + memcpy(p->Title.data, data, size); + + return 0; +@@ -610,6 +655,7 @@ int TNEFAttachmentSave STD_ARGLIST { + while (p->next!=NULL) p=p->next; + + p->FileData.data = calloc(sizeof(unsigned char), size); ++ ALLOCCHECK(p->FileData.data); + p->FileData.size = size; + + memcpy(p->FileData.data, data, size); +@@ -995,6 +1041,7 @@ int TNEFParse(TNEFStruct *TNEF) { + DEBUG2(TNEF->Debug, 2, "Header says type=%i, size=%i", type, size); + if (size > 0) { + data = calloc(size, sizeof(BYTE)); ++ ALLOCCHECK(data); + if (TNEFRawRead(TNEF, data, size, &header_checksum)< 0) { + printf("ERROR: Unable to read data.\n"); + if (TNEF->IO.CloseProc != NULL) { +@@ -1296,6 +1343,9 @@ int IsCompressedRTF(variableLength *p) { + unsigned char *src; + ULONG compressedSize, uncompressedSize, magic, crc32; + ++ if (p->size < 4) ++ return 0; ++ + src = p->data; + in = 0; + +@@ -1328,11 +1378,16 @@ unsigned char *DecompressRTF(variableLen + + comp_Prebuf.size = strlen(RTF_PREBUF); + comp_Prebuf.data = calloc(comp_Prebuf.size, 1); ++ ALLOCCHECK_CHAR(comp_Prebuf.data); + memcpy(comp_Prebuf.data, RTF_PREBUF, comp_Prebuf.size); + + src = p->data; + in = 0; + ++ if (p->size < 20) { ++ printf("File too small\n"); ++ return(NULL); ++ } + compressedSize = (ULONG)SwapDWord(src+in); + in += 4; + uncompressedSize = (ULONG)SwapDWord(src+in); +@@ -1352,21 +1407,28 @@ unsigned char *DecompressRTF(variableLen + if (magic == 0x414c454d) { + // magic number that identifies the stream as a uncompressed stream + dst = calloc(uncompressedSize,1); ++ ALLOCCHECK_CHAR(dst); + memcpy(dst, src+4, uncompressedSize); + } else if (magic == 0x75465a4c) { + // magic number that identifies the stream as a compressed stream + int flagCount = 0; + int flags = 0; ++ // Prevent overflow on 32 Bit Systems ++ if (comp_Prebuf.size >= INT_MAX - uncompressedSize) { ++ printf("Corrupted file\n"); ++ exit(-1); ++ } + dst = calloc(comp_Prebuf.size + uncompressedSize,1); ++ ALLOCCHECK_CHAR(dst); + memcpy(dst, comp_Prebuf.data, comp_Prebuf.size); + out = comp_Prebuf.size; + while (out < (comp_Prebuf.size+uncompressedSize)) { + // each flag byte flags 8 literals/references, 1 per bit + flags = (flagCount++ % 8 == 0) ? src[in++] : flags >> 1; + if ((flags & 1) == 1) { // each flag bit is 1 for reference, 0 for literal +- int offset = src[in++]; +- int length = src[in++]; +- int end; ++ unsigned int offset = src[in++]; ++ unsigned int length = src[in++]; ++ unsigned int end; + offset = (offset << 4) | (length >> 4); // the offset relative to block start + length = (length & 0xF) + 2; // the number of bytes to copy + // the decompression buffer is supposed to wrap around back +@@ -1380,15 +1442,22 @@ unsigned char *DecompressRTF(variableLen + // note: can't use System.arraycopy, because the referenced + // bytes can cross through the current out position. + end = offset + length; +- while (offset < end) ++ while ((offset < end) && (out < (comp_Prebuf.size + uncompressedSize)) ++ && (offset < (comp_Prebuf.size + uncompressedSize))) + dst[out++] = dst[offset++]; + } else { // literal ++ if ((out >= (comp_Prebuf.size + uncompressedSize)) || ++ (in >= p->size)) { ++ printf("Corrupted stream\n"); ++ exit(-1); ++ } + dst[out++] = src[in++]; + } + } + // copy it back without the prebuffered data + src = dst; + dst = calloc(uncompressedSize,1); ++ ALLOCCHECK_CHAR(dst); + memcpy(dst, src + comp_Prebuf.size, uncompressedSize); + free(src); + *size = uncompressedSize; +Index: ytnef/ytnef.h +=================================================================== +--- ytnef.orig/ytnef.h ++++ ytnef/ytnef.h +@@ -23,7 +23,7 @@ variableLength *MAPIFindUserProp(MAPIPro + variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID); + int MAPISysTimetoDTR(BYTE *data, dtr *thedate); + void MAPIPrint(MAPIProps *p); +-char* to_utf8(int len, char* buf); ++char* to_utf8(size_t len, char* buf); + WORD SwapWord(BYTE *p); + DWORD SwapDWord(BYTE *p); + DDWORD SwapDDWord(BYTE *p); === added file 'debian/patches/0002-Fixes-for-CVE-2017-6800-CVE-2017-6801-and-CVE-2017-6.patch' --- debian/patches/0002-Fixes-for-CVE-2017-6800-CVE-2017-6801-and-CVE-2017-6.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/0002-Fixes-for-CVE-2017-6800-CVE-2017-6801-and-CVE-2017-6.patch 2017-05-24 13:18:44 +0000 @@ -0,0 +1,43 @@ +From 21b1593d80461ecb839484005d49e32b092ed975 Mon Sep 17 00:00:00 2001 +From: Jordi Mallach +Date: Tue, 21 Mar 2017 04:11:09 +0100 +Subject: [PATCH 2/2] Fixes for CVE-2017-6800, CVE-2017-6801 and CVE-2017-6802. + +--- + ytnef.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +Index: ytnef/ytnef.c +=================================================================== +--- ytnef.orig/ytnef.c ++++ ytnef/ytnef.c +@@ -1039,7 +1039,10 @@ int TNEFParse(TNEFStruct *TNEF) { + + while (TNEFGetHeader(TNEF, &type, &size) == 0) { + DEBUG2(TNEF->Debug, 2, "Header says type=%i, size=%i", type, size); +- if (size > 0) { ++ if (size == 0) { ++ printf("ERROR: Field with size of 0\n"); ++ return YTNEF_ERROR_READING_DATA; ++ } else if (size > 0) { + data = calloc(size, sizeof(BYTE)); + ALLOCCHECK(data); + if (TNEFRawRead(TNEF, data, size, &header_checksum)< 0) { +@@ -1279,7 +1282,7 @@ void MAPIPrint(MAPIProps *p) + printf("\n"); + break; + case PT_LONG: +- printf(" Value: %li\n", *(mapidata->data)); ++ printf(" Value: %i\n", *(mapidata->data)); + break; + case PT_I2: + printf(" Value: %hi\n", *(mapidata->data)); +@@ -1422,7 +1425,7 @@ unsigned char *DecompressRTF(variableLen + ALLOCCHECK_CHAR(dst); + memcpy(dst, comp_Prebuf.data, comp_Prebuf.size); + out = comp_Prebuf.size; +- while (out < (comp_Prebuf.size+uncompressedSize)) { ++ while ((out < (comp_Prebuf.size+uncompressedSize)) && (in < p->size)) { + // each flag byte flags 8 literals/references, 1 per bit + flags = (flagCount++ % 8 == 0) ? src[in++] : flags >> 1; + if ((flags & 1) == 1) { // each flag bit is 1 for reference, 0 for literal === added file 'debian/patches/CVE-2017-9058.patch' --- debian/patches/CVE-2017-9058.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/CVE-2017-9058.patch 2017-05-24 13:18:44 +0000 @@ -0,0 +1,13 @@ +Index: ytnef/lib/ytnef.c +=================================================================== +--- ytnef.orig/ytnef.c ++++ ytnef/ytnef.c +@@ -57,7 +57,7 @@ + + #define ALLOCCHECK(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(-1); } } + #define ALLOCCHECK_CHAR(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(NULL); } } +-#define SIZECHECK(x) { if ((((char *)d - (char *)data) + x) > size) { printf("Corrupted file detected at %s : %i\n", __FILE__, __LINE__); return(-1); } } ++#define SIZECHECK(x) { if ((((char *)d - (char *)data) + x) >= size) { printf("Corrupted file detected at %s : %i\n", __FILE__, __LINE__); return(-1); } } + + int TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p); + void SetFlip(void); === modified file 'debian/patches/handle_pt_clsid.diff' --- debian/patches/handle_pt_clsid.diff 2017-05-24 13:02:51 +0000 +++ debian/patches/handle_pt_clsid.diff 2017-05-24 13:18:44 +0000 @@ -20,12 +20,3 @@ case PT_I2: // Read in 2 bytes, but proceed by 4 bytes vl->size = 2; -@@ -455,6 +462,8 @@ void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p) { - memcpy(vl->data, &temp_ddword, vl->size); - d+=8; - break; -+ default: -+ fprintf(stderr, "%s: Fatal BUG: unknown MAPI ID type (%u), (%u)\n", __func__, PROP_TYPE(mp->id), mp->id); - } - if (count == (mp->count-1)) { - count = -1; === modified file 'debian/patches/series' --- debian/patches/series 2017-05-24 13:02:51 +0000 +++ debian/patches/series 2017-05-24 13:18:44 +0000 @@ -2,3 +2,6 @@ CVE-2010-5109.diff handle_pt_clsid.diff clang_FTBFS_Wreturn-type.patch +0001-Fixes-for-CVE-2017-6298-to-6306.patch +0002-Fixes-for-CVE-2017-6800-CVE-2017-6801-and-CVE-2017-6.patch +CVE-2017-9058.patch