Hi, I have backported to wheezy LTS the patches necessary to fix the integer overflows in libmtp that affect wheezy and jessie (CVE-2017-9831 and CVE-2017-9832).
The upstream patch to fix this includes a bunch of unrelated changes and because of this, is quite difficult to backport. I carefully removed the additional features including new camera support, queueing and caching systems that may introduce some instability and make the patch harder to review. I have not, however, audited the rest of the code to see if code that may have been removed in versions after wheezy would be vulnerable to integer overflows. Therefore, because there is no proof of concept, I am not completely sure all the issues are fixed. Furthermore, because there is no test suite, I am not completely confident the package still works properly. Doing even smoke testing with this is complicated as it requires a USB device and a host running wheezy, whereas I test against mostly in virtual machines. The patch does introduce ABI changes in function signatures, but because this is in the "ptp" functions that are copied over from libgphoto (!), I assume this is used only internally by libmtp and should not create compatibility problems. All that said, I figured it was a good idea to publish test packages in the usual location: https://people.debian.org/~anarcat/debian/wheezy-lts/ I'd be grateful if people could review the resulting patch and/or test the above packages. I will only be available to upload this by the end of next week, unfortunately. If someone else wants to complete the upload by then, be my guest. Thank you for your time. A. -- Perl is "some assembly required". Python is "batteries included". PHP is "kitchen sink, but it’s from Canada and both faucets are labeled C". - Alex Munroe, PHP: a fractal of bad design
diff -Nru libmtp-1.1.3-35-g0ece104/debian/changelog libmtp-1.1.3-35-g0ece104/debian/changelog --- libmtp-1.1.3-35-g0ece104/debian/changelog 2013-02-17 17:38:42.000000000 -0500 +++ libmtp-1.1.3-35-g0ece104/debian/changelog 2017-07-06 16:17:50.000000000 -0400 @@ -1,3 +1,11 @@ +libmtp (1.1.3-35-g0ece104-5+deb7u1) UNRELEASED; urgency=high + + * Non-maintainer upload by the Security Team. + * upstream patch to import ptp* from libgphoto2 to fix CVE-2017-9831 and + CVE-2017-9832 + + -- Antoine Beaupré <[email protected]> Thu, 06 Jul 2017 16:17:50 -0400 + libmtp (1.1.3-35-g0ece104-5) unstable; urgency=low * Add support for Google/LG Nexus 4 phones. diff -Nru libmtp-1.1.3-35-g0ece104/debian/patches/CVE-2017-9832-aa7d91.patch libmtp-1.1.3-35-g0ece104/debian/patches/CVE-2017-9832-aa7d91.patch --- libmtp-1.1.3-35-g0ece104/debian/patches/CVE-2017-9832-aa7d91.patch 1969-12-31 19:00:00.000000000 -0500 +++ libmtp-1.1.3-35-g0ece104/debian/patches/CVE-2017-9832-aa7d91.patch 2017-07-06 16:17:50.000000000 -0400 @@ -0,0 +1,826 @@ +From aa7d91a789873a9d86969028e57f888a1241c085 Mon Sep 17 00:00:00 2001 +From: Marcus Meissner <[email protected]> +Date: Thu, 16 Mar 2017 15:59:48 +0100 +Subject: [PATCH] imported ptp* from libgphoto2 + +lots of buffer overread checks +--- + src/libmtp.c | 1 + + src/ptp-pack.c | 312 ++++++++++++++++++++++++++++++++++++++++------------ + src/ptp.c | 340 ++++++++++++++++++++++++++++++++++++++++++++++++--------- + src/ptp.h | 89 ++++++++++++++- + 4 files changed, 618 insertions(+), 124 deletions(-) + +--- a/src/ptp-pack.c ++++ b/src/ptp-pack.c +@@ -4,6 +4,8 @@ + #include <iconv.h> + #endif + ++#include <limits.h> ++ + static inline uint16_t + htod16p (PTPParams *params, uint16_t var) + { +@@ -97,7 +99,7 @@ dtoh64ap (PTPParams *params, const unsig + + + static inline char* +-ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len) ++ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t total, uint8_t *len) + { + uint8_t length; + uint16_t string[PTP_MAXSTRLEN+1]; +@@ -106,10 +108,16 @@ ptp_unpack_string(PTPParams *params, uns + size_t nconv, srclen, destlen; + char *src, *dest; + ++ if (offset + 1 >= total) ++ return NULL; ++ + length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */ + *len = length; + if (length == 0) /* nothing to do? */ +- return(NULL); ++ return NULL; ++ ++ if (offset + 1 + length*sizeof(string[0]) > total) ++ return NULL; + + /* copy to string[] to ensure correct alignment for iconv(3) */ + memcpy(string, &data[offset+1], length * sizeof(string[0])); +@@ -231,8 +239,13 @@ ptp_unpack_uint32_t_array(PTPParams *par + { + uint32_t n, i=0; + ++ if (!data) ++ return 0; ++ + n=dtoh32a(&data[offset]); + *array = malloc (n*sizeof(uint32_t)); ++ if (!*array) ++ return 0; + while (n>i) { + (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]); + i++; +@@ -246,6 +259,8 @@ ptp_pack_uint32_t_array(PTPParams *param + uint32_t i=0; + + *data = malloc ((arraylen+1)*sizeof(uint32_t)); ++ if (!*data) ++ return 0; + htod32a(&(*data)[0],arraylen); + for (i=0;i<arraylen;i++) + htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]); +@@ -257,8 +272,13 @@ ptp_unpack_uint16_t_array(PTPParams *par + { + uint32_t n, i=0; + ++ if (!data) ++ return 0; ++ + n=dtoh32a(&data[offset]); + *array = malloc (n*sizeof(uint16_t)); ++ if (!*array) ++ return 0; + while (n>i) { + (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]); + i++; +@@ -275,14 +295,15 @@ ptp_unpack_uint16_t_array(PTPParams *par + #define PTP_di_FunctionalMode 8 + #define PTP_di_OperationsSupported 10 + +-static inline void ++static inline int + ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen) + { + uint8_t len; + unsigned int totallen; + +- if (!data) return; +- if (datalen < 12) return; ++ if (!data) return 0; ++ if (datalen < 12) return 0; ++ memset (di, 0, sizeof(*di)); + di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]); + di->VendorExtensionID = + dtoh32a(&data[PTP_di_VendorExtensionID]); +@@ -290,46 +311,65 @@ ptp_unpack_DI (PTPParams *params, unsign + dtoh16a(&data[PTP_di_VendorExtensionVersion]); + di->VendorExtensionDesc = + ptp_unpack_string(params, data, +- PTP_di_VendorExtensionDesc, &len); ++ PTP_di_VendorExtensionDesc, ++ datalen, ++ &len); + totallen=len*2+1; +- di->FunctionalMode = ++ if (datalen <= totallen) return 0; ++ di->FunctionalMode = + dtoh16a(&data[PTP_di_FunctionalMode+totallen]); + di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->OperationsSupported); + totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); ++ if (datalen <= totallen+PTP_di_OperationsSupported) return 0; + di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->EventsSupported); + totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); ++ if (datalen <= totallen+PTP_di_OperationsSupported) return 0; + di->DevicePropertiesSupported_len = + ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->DevicePropertiesSupported); + totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t); ++ if (datalen <= totallen+PTP_di_OperationsSupported) return 0; + di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->CaptureFormats); + totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t); ++ if (datalen <= totallen+PTP_di_OperationsSupported) return 0; + di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->ImageFormats); + totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t); ++ if (datalen <= totallen+PTP_di_OperationsSupported) return 0; + di->Manufacturer = ptp_unpack_string(params, data, + PTP_di_OperationsSupported+totallen, ++ datalen, + &len); + totallen+=len*2+1; ++ /* be more relaxed ... as these are optional its ok if they are not here */ ++ if (datalen <= totallen+PTP_di_OperationsSupported) return 1; + di->Model = ptp_unpack_string(params, data, + PTP_di_OperationsSupported+totallen, ++ datalen, + &len); + totallen+=len*2+1; ++ /* be more relaxed ... as these are optional its ok if they are not here */ ++ if (datalen <= totallen+PTP_di_OperationsSupported) return 1; + di->DeviceVersion = ptp_unpack_string(params, data, + PTP_di_OperationsSupported+totallen, ++ datalen, + &len); + totallen+=len*2+1; ++ /* be more relaxed ... as these are optional its ok if they are not here */ ++ if (datalen <= totallen+PTP_di_OperationsSupported) return 1; + di->SerialNumber = ptp_unpack_string(params, data, + PTP_di_OperationsSupported+totallen, ++ datalen, + &len); ++ return 1; + } + + static void inline +@@ -344,35 +384,36 @@ ptp_free_DI (PTPDeviceInfo *di) { + if (di->OperationsSupported) free (di->OperationsSupported); + if (di->EventsSupported) free (di->EventsSupported); + if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported); ++ memset(di, 0, sizeof(*di)); + } + + /* EOS Device Info unpack */ +-static inline void ++static inline int + ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen) + { + int totallen = 4; + + memset (di,0, sizeof(*di)); +- if (datalen < 8) return; ++ if (datalen < 8) return 0; + + /* uint32_t struct len - ignore */ + di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data, + totallen, &di->EventsSupported); +- if (!di->EventsSupported) return; ++ if (!di->EventsSupported) return 0; + totallen += di->EventsSupported_len*sizeof(uint32_t)+4; +- if (totallen >= datalen) return; ++ if (totallen >= datalen) return 0; + + di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data, + totallen, &di->DevicePropertiesSupported); +- if (!di->DevicePropertiesSupported) return; ++ if (!di->DevicePropertiesSupported) return 0; + totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4; +- if (totallen >= datalen) return; ++ if (totallen >= datalen) return 0; + + di->unk_len = ptp_unpack_uint32_t_array(params, data, + totallen, &di->unk); +- if (!di->unk) return; ++ if (!di->unk) return 0; + totallen += di->unk_len*sizeof(uint32_t)+4; +- return; ++ return 1; + } + + static inline void +@@ -405,11 +446,11 @@ ptp_unpack_OH (PTPParams *params, unsign + static inline void + ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len) + { +- if (!data && !len) { +- sids->n = 0; +- sids->Storage = NULL; ++ sids->n = 0; ++ sids->Storage = NULL; ++ if (!data && !len) + return; +- } ++ + sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids, + &sids->Storage); + } +@@ -424,11 +465,12 @@ ptp_unpack_SIDs (PTPParams *params, unsi + #define PTP_si_FreeSpaceInImages 22 + #define PTP_si_StorageDescription 26 + +-static inline void ++static inline int + ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len) + { + uint8_t storagedescriptionlen; + ++ if (len < 26) return 0; + si->StorageType=dtoh16a(&data[PTP_si_StorageType]); + si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]); + si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]); +@@ -436,10 +478,14 @@ ptp_unpack_SI (PTPParams *params, unsign + si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]); + si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]); + si->StorageDescription=ptp_unpack_string(params, data, +- PTP_si_StorageDescription, &storagedescriptionlen); ++ PTP_si_StorageDescription, ++ len, ++ &storagedescriptionlen); + si->VolumeLabel=ptp_unpack_string(params, data, + PTP_si_StorageDescription+storagedescriptionlen*2+1, ++ len, + &storagedescriptionlen); ++ return 1; + } + + /* ObjectInfo pack/unpack */ +@@ -601,10 +647,10 @@ ptp_unpack_OI (PTPParams *params, unsign + oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]); + oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]); + +- oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen); ++ oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, len, &filenamelen); + + capture_date = ptp_unpack_string(params, data, +- PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen); ++ PTP_oi_filenamelen+filenamelen*2+1, len, &capturedatelen); + /* subset of ISO 8601, without '.s' tenths of second and + * time zone + */ +@@ -614,7 +660,7 @@ ptp_unpack_OI (PTPParams *params, unsign + /* now the modification date ... */ + capture_date = ptp_unpack_string(params, data, + PTP_oi_filenamelen+filenamelen*2 +- +capturedatelen*2+2,&capturedatelen); ++ +capturedatelen*2+2, len, &capturedatelen); + oi->ModificationDate = ptp_unpack_PTPTIME(capture_date); + free(capture_date); + } +@@ -636,6 +682,8 @@ ptp_unpack_OI (PTPParams *params, unsign + \ + val->a.count = n; \ + val->a.v = malloc(sizeof(val->a.v[0])*n); \ ++ if (n > (total - (*offset))/sizeof(val->a.v[0]))\ ++ return 0; \ + if (!val->a.v) return 0; \ + for (j=0;j<n;j++) \ + CTVAL(val->a.v[j].member, func); \ +@@ -646,6 +694,9 @@ ptp_unpack_DPV ( + PTPParams *params, unsigned char* data, int *offset, int total, + PTPPropertyValue* value, uint16_t datatype + ) { ++ if (*offset >= total) /* we are at the end or over the end of the buffer */ ++ return 0; ++ + switch (datatype) { + case PTP_DTC_INT8: + CTVAL(value->i8,dtoh8a); +@@ -712,7 +763,11 @@ ptp_unpack_DPV ( + case PTP_DTC_STR: { + uint8_t len; + /* XXX: max size */ +- value->str = ptp_unpack_string(params,data,*offset,&len); ++ ++ if (*offset >= total+1) ++ return 0; ++ ++ value->str = ptp_unpack_string(params,data,*offset,total,&len); + *offset += len*2+1; + if (!value->str) + return 1; +@@ -737,6 +792,8 @@ ptp_unpack_DPD (PTPParams *params, unsig + int offset=0, ret; + + memset (dpd, 0, sizeof(*dpd)); ++ if (dpdlen <= 5) ++ return 0; + dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]); + dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]); + dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]); +@@ -1062,8 +1119,11 @@ ptp_unpack_OPL (PTPParams *params, unsig + MTPProperties *props = NULL; + int offset = 0, i; + +- if (prop_count == 0) { +- *pprops = NULL; ++ *pprops = NULL; ++ if (prop_count == 0) ++ return 0; ++ if (prop_count >= INT_MAX/sizeof(MTPProperties)) { ++ ptp_debug (params ,"prop_count %d is too large", prop_count); + return 0; + } + ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count); +@@ -1074,7 +1134,7 @@ ptp_unpack_OPL (PTPParams *params, unsig + for (i = 0; i < prop_count; i++) { + if (len <= 0) { + ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count); +- ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i); ++ ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL"); + ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i); + qsort (props, i, sizeof(MTPProperties),_compare_func); + *pprops = props; +@@ -1093,7 +1153,12 @@ ptp_unpack_OPL (PTPParams *params, unsig + len -= sizeof(uint16_t); + + offset = 0; +- ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype); ++ if (!ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype)) { ++ ptp_debug (params ,"unpacking DPV of property %d encountered insufficient buffer. attack?", i); ++ qsort (props, i, sizeof(MTPProperties),_compare_func); ++ *pprops = props; ++ return i; ++ } + data += offset; + len -= offset; + } +@@ -1352,14 +1417,19 @@ ptp_unpack_EOS_CustomFuncEx (PTPParams* + { + uint32_t s = dtoh32a( *data ); + uint32_t n = s/4, i; +- char* str = (char*)malloc( s ); // n is size in uint32, average len(itoa(i)) < 4 -> alloc n chars ++ char *str, *p; ++ ++ if (s > 1024) { ++ ptp_debug (params, "customfuncex data is larger than 1k / %d... unexpected?", s); ++ return strdup("bad length"); ++ } ++ str = (char*)malloc( s*2+s/4+1 ); /* n is size in uint32, maximum %x len is 8 chars and \0*/ + if (!str) +- return str; +- char* p = str; ++ return strdup("malloc failed"); + ++ p = str; + for (i=0; i < n; ++i) + p += sprintf(p, "%x,", dtoh32a( *data + 4*i )); +- + return str; + } + +@@ -1416,27 +1486,60 @@ ptp_unpack_CANON_changes (PTPParams *par + + if (data==NULL) + return 0; +- while (curdata - data < datasize) { ++ while (curdata - data + 8 < datasize) { + uint32_t size = dtoh32a(&curdata[PTP_ece_Size]); + uint32_t type = dtoh32a(&curdata[PTP_ece_Type]); + +- curdata += size; ++ if (size > datasize) { ++ ptp_debug (params, "size %d is larger than datasize %d", size, datasize); ++ break; ++ } ++ if (size < 8) { ++ ptp_debug (params, "size %d is smaller than 8.", size); ++ break; ++ } + if ((size == 8) && (type == 0)) + break; ++ if ((curdata - data) + size >= datasize) { ++ ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries"); ++ break; ++ } ++ curdata += size; + entries++; + } + *ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1)); + if (!*ce) return 0; + + curdata = data; +- while (curdata - data < datasize) { ++ while (curdata - data + 8 < datasize) { + uint32_t size = dtoh32a(&curdata[PTP_ece_Size]); + uint32_t type = dtoh32a(&curdata[PTP_ece_Type]); + ++ if (size > datasize) { ++ ptp_debug (params, "size %d is larger than datasize %d", size, datasize); ++ break; ++ } ++ if (size < 8) { ++ ptp_debug (params, "size %d is smaller than 8.", size); ++ break; ++ } ++ ++ if ((size == 8) && (type == 0)) ++ break; ++ ++ if ((curdata - data) + size >= datasize) { ++ ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries"); ++ break; ++ } ++ + (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN; + (*ce)[i].u.info = NULL; + switch (type) { +- case PTP_EC_CANON_EOS_ObjectAddedEx: ++ case PTP_EC_CANON_EOS_ObjectAddedEx: ++ if (size < PTP_ece_OA_Name+1) { ++ ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OA_Name+1); ++ break; ++ } + (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO; + (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]); + (*ce)[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]); +@@ -1446,7 +1549,11 @@ ptp_unpack_CANON_changes (PTPParams *par + (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name])); + ptp_debug (params, "event %d: objectinfo added oid %08lx, parent %08lx, ofc %04x, size %d, filename %s", i, (*ce)[i].u.object.oid, (*ce)[i].u.object.oi.ParentObject, (*ce)[i].u.object.oi.ObjectFormat, (*ce)[i].u.object.oi.ObjectCompressedSize, (*ce)[i].u.object.oi.Filename); + break; +- case PTP_EC_CANON_EOS_RequestObjectTransfer: ++ case PTP_EC_CANON_EOS_RequestObjectTransfer: ++ if (size < PTP_ece_OI_Name+1) { ++ ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OI_Name+1); ++ break; ++ } + (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER; + (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]); + (*ce)[i].u.object.oi.StorageID = 0; /* use as marker */ +@@ -1465,6 +1572,11 @@ ptp_unpack_CANON_changes (PTPParams *par + int j; + PTPDevicePropDesc *dpd; + ++ if (size < PTP_ece_Prop_Desc_Data) { ++ ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_Prop_Desc_Data); ++ break; ++ } ++ + ptp_debug (params, "event %d: EOS prop %04x desc record, datasize %d, propxtype %d", i, proptype, size-PTP_ece_Prop_Desc_Data, propxtype); + for (j=0;j<params->nrofcanon_props;j++) + if (params->canon_props[j].proptype == proptype) +@@ -1479,7 +1591,7 @@ ptp_unpack_CANON_changes (PTPParams *par + * 7 - string? + */ + if (propxtype != 3) { +- ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype); ++ ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled, size %d.", i, propxtype, proptype, size); + for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++) + ptp_debug (params, " %d: %02x", j, xdata[j]); + break; +@@ -1510,8 +1622,12 @@ ptp_unpack_CANON_changes (PTPParams *par + /* 'normal' enumerated types */ + switch (dpd->DataType) { + #define XX( TYPE, CONV )\ +- for (j=0;j<propxcnt;j++) { \ +- dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \ ++ if (sizeof(dpd->FORM.Enum.SupportedValue[j].TYPE)*propxcnt + PTP_ece_Prop_Desc_Data > size) { \ ++ ptp_debug (params, "size %d does not match needed %d", sizeof(dpd->FORM.Enum.SupportedValue[j].TYPE)*propxcnt + PTP_ece_Prop_Desc_Data, size); \ ++ break; \ ++ } \ ++ for (j=0;j<propxcnt;j++) { \ ++ dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \ + ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, CONV(xdata)); \ + xdata += 4; /* might only be for propxtype 3 */ \ + } \ +@@ -1523,7 +1639,10 @@ ptp_unpack_CANON_changes (PTPParams *par + case PTP_DTC_UINT8: XX( u8, dtoh8a ); + #undef XX + default: +- ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata)); ++ free (dpd->FORM.Enum.SupportedValue); ++ dpd->FORM.Enum.SupportedValue = NULL; ++ dpd->FORM.Enum.NumberOfValues = 0; ++ ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, size %d, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata), size); + for (j=0;j<(size-PTP_ece_Prop_Desc_Data)/4;j++, xdata+=4) /* 4 is good for propxtype 3 */ + ptp_debug (params, " %3d: 0x%8x", j, dtoh32a(xdata)); + break; +@@ -1538,6 +1657,10 @@ ptp_unpack_CANON_changes (PTPParams *par + unsigned char *xdata = &curdata[PTP_ece_Prop_Val_Data]; + PTPDevicePropDesc *dpd; + ++ if (size < PTP_ece_Prop_Val_Data) { ++ ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_Prop_Val_Data); ++ break; ++ } + ptp_debug (params, "event %d: EOS prop %04x info record, datasize is %d", i, proptype, size-PTP_ece_Prop_Val_Data); + for (j=0;j<params->nrofcanon_props;j++) + if (params->canon_props[j].proptype == proptype) +@@ -1546,6 +1669,7 @@ ptp_unpack_CANON_changes (PTPParams *par + if ( (params->canon_props[j].size != size) || + (memcmp(params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data))) { + params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data); ++ params->canon_props[j].size = size; + memcpy (params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data); + } + } else { +@@ -1794,7 +1918,7 @@ ptp_unpack_CANON_changes (PTPParams *par + break; + case PTP_EC_CANON_EOS_BulbExposureTime: + (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN; +- (*ce)[i].u.info = malloc(strlen("BulbExposureTime 123456789")); ++ (*ce)[i].u.info = malloc(strlen("BulbExposureTime 123456789012345678")); + sprintf ((*ce)[i].u.info, "BulbExposureTime %d", dtoh32a(curdata+8)); + break; + default: +@@ -1837,8 +1961,9 @@ ptp_unpack_CANON_changes (PTPParams *par + } + curdata += size; + i++; +- if ((size == 8) && (type == 0)) +- break; ++ if (i >= entries) { ++ ptp_debug (params, "BAD: i %d, entries %d", i, entries); ++ } + } + if (!entries) { + free (*ce); +@@ -1865,8 +1990,10 @@ ptp_unpack_Nikon_EC (PTPParams *params, + if (len < PTP_nikon_ec_Code) + return; + *cnt = dtoh16a(&data[PTP_nikon_ec_Length]); +- if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */ ++ if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) { /* broken cnt? */ ++ *cnt = 0; + return; ++ } + if (!*cnt) + return; + +--- a/src/ptp.c ++++ b/src/ptp.c +@@ -1,7 +1,7 @@ + /* ptp.c + * + * Copyright (C) 2001-2004 Mariusz Woloszyn <[email protected]> +- * Copyright (C) 2003-2012 Marcus Meissner <[email protected]> ++ * Copyright (C) 2003-2016 Marcus Meissner <[email protected]> + * Copyright (C) 2006-2008 Linus Walleij <[email protected]> + * Copyright (C) 2007 Tero Saarni <[email protected]> + * Copyright (C) 2009 Axel Waggershauser <[email protected]> +@@ -215,7 +215,9 @@ ptp_transaction_new (PTPParams* params, + "PTP: Sequence number mismatch %d vs expected %d.", + ptp->Transaction_ID, params->transaction_id-1 + ); ++#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + return PTP_ERROR_BADPARAM; ++#endif + } + break; + } +@@ -446,9 +448,15 @@ ptp_getdeviceinfo (PTPParams* params, PT + ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler); + ptp_exit_recv_memory_handler (&handler, &di, &len); + if (!di) ret = PTP_RC_GeneralError; +- if (ret == PTP_RC_OK) ptp_unpack_DI(params, di, deviceinfo, len); ++ if (ret != PTP_RC_OK) { ++ return ret; ++ } ++ ret = ptp_unpack_DI(params, di, deviceinfo, len); + free(di); +- return ret; ++ if (ret) ++ return PTP_RC_OK; ++ else ++ return PTP_ERROR_IO; + } + + uint16_t +@@ -468,9 +476,15 @@ ptp_canon_eos_getdeviceinfo (PTPParams* + data=NULL; + ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler); + ptp_exit_recv_memory_handler (&handler, &data, &len); +- if (ret == PTP_RC_OK) ptp_unpack_EOS_DI(params, data, di, len); +- free (data); +- return ret; ++ if (ret != PTP_RC_OK) { ++ return ret; ++ } ++ ret = ptp_unpack_EOS_DI(params, data, di, len); ++ free(di); ++ if (ret) ++ return PTP_RC_OK; ++ else ++ return PTP_ERROR_IO; + } + + /** +@@ -622,7 +636,15 @@ ptp_getstorageinfo (PTPParams* params, u + ptp.Nparam=1; + len=0; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &si, &len); +- if (ret == PTP_RC_OK) ptp_unpack_SI(params, si, storageinfo, len); ++ if (ret != PTP_RC_OK) ++ return ret; ++ if (!si || !len) ++ return PTP_RC_GeneralError; ++ memset(storageinfo, 0, sizeof(*storageinfo)); ++ if (!ptp_unpack_SI(params, si, storageinfo, len)) { ++ free(si); ++ return PTP_RC_GeneralError; ++ } + free(si); + return ret; + } +@@ -651,6 +673,9 @@ ptp_getobjecthandles (PTPParams* params, + unsigned char* oh=NULL; + unsigned int len; + ++ objecthandles->Handler = NULL; ++ objecthandles->n = 0; ++ + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetObjectHandles; + ptp.Param1=storage; +@@ -1112,6 +1137,10 @@ ptp_getdevicepropdesc (PTPParams* params + ptp.Nparam=1; + len=0; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpd, &len); ++ if (!dpd) { ++ ptp_debug (params, "no data received for getdevicepropdesc"); ++ return PTP_RC_InvalidDevicePropFormat; ++ } + if (ret == PTP_RC_OK) ptp_unpack_DPD(params, dpd, devicepropertydesc, len); + free(dpd); + return ret; +@@ -1555,7 +1584,7 @@ ptp_canon_gettreesize (PTPParams* params + for (i=0;i<*cnt;i++) { + unsigned char len; + (*entries)[i].oid = dtoh32a(cur); +- (*entries)[i].str = ptp_unpack_string(params, cur, 4, &len); ++ (*entries)[i].str = ptp_unpack_string(params, cur, 4, size-(cur-out-4), &len); + cur += 4+(cur[4]*2+1); + } + free (out); +@@ -1855,6 +1884,16 @@ ptp_canon_eos_getobjectinfoex ( + if (ret != PTP_RC_OK) + return ret; + ++ if (size < 4) { ++ ret = PTP_RC_GeneralError; ++ goto exit; ++ } ++ /* check for integer overflow */ ++ if (dtoh32a(data) >= INT_MAX/sizeof(PTPCANONFolderEntry)) { ++ ret = PTP_RC_GeneralError; ++ goto exit; ++ } ++ + *nrofentries = dtoh32a(data); + *entries = malloc(*nrofentries * sizeof(PTPCANONFolderEntry)); + if (!*entries) +@@ -1862,10 +1901,20 @@ ptp_canon_eos_getobjectinfoex ( + + xdata = data+sizeof(uint32_t); + for (i=0;i<*nrofentries;i++) { ++ if ((dtoh32a(xdata) + (xdata-data)) > size) { ++ ptp_debug (params, "reading canon FEs run over read data size?\n"); ++ free (*entries); ++ *entries = NULL; ++ *nrofentries = 0; ++ ret = PTP_RC_GeneralError; ++ goto exit; ++ } + ptp_unpack_Canon_EOS_FE (params, &xdata[4], &((*entries)[i])); + xdata += dtoh32a(xdata); + } +- return PTP_RC_OK; ++exit: ++ free(data); ++ return ret; + } + + /** +@@ -2140,6 +2189,7 @@ ptp_canon_getobjectinfo (PTPParams* para + PTPContainer ptp; + unsigned char *data = NULL; + unsigned int len; ++ unsigned int i, size; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_GetObjectInfoEx; +@@ -2150,19 +2200,28 @@ ptp_canon_getobjectinfo (PTPParams* para + ptp.Nparam=4; + len=0; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &len); +- if (ret == PTP_RC_OK) { +- int i; +- *entnum=ptp.Param1; +- *entries=calloc(*entnum, sizeof(PTPCANONFolderEntry)); +- if (*entries!=NULL) { +- for(i=0; i<(*entnum); i++) +- ptp_unpack_Canon_FE(params, +- data+i*PTP_CANON_FolderEntryLen, +- &((*entries)[i]) ); +- } else { +- ret=PTP_ERROR_IO; /* Cannot allocate memory */ +- } ++ if (ret != PTP_RC_OK) ++ goto exit; ++ if (!data) ++ return ret; ++ if (ptp.Param1 > size/PTP_CANON_FolderEntryLen) { ++ ptp_debug (params, "param1 is %d, size is only %d", ptp.Param1, size); ++ ret = PTP_RC_GeneralError; ++ goto exit; ++ } ++ *entnum=ptp.Param1; ++ *entries=calloc(*entnum, sizeof(PTPCANONFolderEntry)); ++ if (*entries==NULL) { ++ ret=PTP_ERROR_IO; /* Cannot allocate memory */ ++ goto exit; ++ } ++ for(i=0; i<(*entnum); i++) { ++ if (size < i*PTP_CANON_FolderEntryLen) break; ++ ptp_unpack_Canon_FE(params, ++ data+i*PTP_CANON_FolderEntryLen, ++ &((*entries)[i]) ); + } ++exit: + free(data); + return ret; + } +@@ -2489,13 +2548,13 @@ ptp_nikon_getwifiprofilelist (PTPParams* + params->wifi_profiles[profn].device_type = data[pos++]; + params->wifi_profiles[profn].icon_type = data[pos++]; + +- buffer = ptp_unpack_string(params, data, pos, &len); ++ buffer = ptp_unpack_string(params, data, pos, size, &len); + strncpy(params->wifi_profiles[profn].creation_date, buffer, sizeof(params->wifi_profiles[profn].creation_date)); + free (buffer); + pos += (len*2+1); + if (pos+1 >= size) return PTP_RC_Undefined; + /* FIXME: check if it is really last usage date */ +- buffer = ptp_unpack_string(params, data, pos, &len); ++ buffer = ptp_unpack_string(params, data, pos, size, &len); + strncpy(params->wifi_profiles[profn].lastusage_date, buffer, sizeof(params->wifi_profiles[profn].lastusage_date)); + free (buffer); + pos += (len*2+1); +@@ -2657,6 +2716,7 @@ ptp_mtp_getobjectpropssupported (PTPPara + ptp.Nparam = 1; + ptp.Param1 = ofc; + ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size); ++ if (!data) return PTP_RC_GeneralError; + if (ret == PTP_RC_OK) + *propnum=ptp_unpack_uint16_t_array(params,data,0,props); + free(data); +@@ -3159,6 +3219,10 @@ struct fileinfo* ptp_chdk_readdir(PTPPar + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_ReadDir; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); ++ if (!data) { ++ ptp_error(params,"no data received"); ++ return PTP_ERROR_BADPARAM; ++ } + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); +@@ -4779,9 +4843,14 @@ ptp_render_property_value(PTPParams* par + switch (dpc) { + case PTP_DPC_MTP_SynchronizationPartner: + case PTP_DPC_MTP_DeviceFriendlyName: +- return snprintf(out, length, "%s", dpd->CurrentValue.str); ++ if (dpd->DataType == PTP_DTC_STR) ++ return snprintf(out, length, "%s", dpd->CurrentValue.str); ++ else ++ return snprintf(out, length, "invalid type, expected STR"); + case PTP_DPC_MTP_SecureTime: + case PTP_DPC_MTP_DeviceCertificate: { ++ if (dpd->DataType != PTP_DTC_AUINT16) ++ return snprintf(out, length, "invalid type, expected AUINT16"); + /* FIXME: Convert to use unicode demux functions */ + for (i=0;(i<dpd->CurrentValue.a.count) && (i<length);i++) + out[i] = dpd->CurrentValue.a.v[i].u16; +@@ -5344,7 +5413,12 @@ static int _cmp_ob (const void *a, const + PTPObject *oa = (PTPObject*)a; + PTPObject *ob = (PTPObject*)b; + +- return oa->oid - ob->oid; ++ /* Do not subtract the oids and return ... ++ * the unsigned int -> int conversion will overflow in cases ++ * like 0xfffc0000 vs 0x0004000. */ ++ if (oa->oid > ob->oid) return 1; ++ if (oa->oid < ob->oid) return -1; ++ return 0; + } + + void diff -Nru libmtp-1.1.3-35-g0ece104/debian/patches/series libmtp-1.1.3-35-g0ece104/debian/patches/series --- libmtp-1.1.3-35-g0ece104/debian/patches/series 2013-02-17 17:28:50.000000000 -0500 +++ libmtp-1.1.3-35-g0ece104/debian/patches/series 2017-07-06 15:36:16.000000000 -0400 @@ -1,3 +1,4 @@ 0001-devicedb_updates.patch 0002-udev_blacklist.patch 1002-udev_rules.patch +CVE-2017-9832-aa7d91.patch
>From aa7d91a789873a9d86969028e57f888a1241c085 Mon Sep 17 00:00:00 2001 From: Marcus Meissner <[email protected]> Date: Thu, 16 Mar 2017 15:59:48 +0100 Subject: [PATCH] imported ptp* from libgphoto2 lots of buffer overread checks --- src/libmtp.c | 1 + src/ptp-pack.c | 312 ++++++++++++++++++++++++++++++++++++++++------------ src/ptp.c | 340 ++++++++++++++++++++++++++++++++++++++++++++++++--------- src/ptp.h | 89 ++++++++++++++- 4 files changed, 618 insertions(+), 124 deletions(-) --- a/src/ptp-pack.c +++ b/src/ptp-pack.c @@ -4,6 +4,8 @@ #include <iconv.h> #endif +#include <limits.h> + static inline uint16_t htod16p (PTPParams *params, uint16_t var) { @@ -97,7 +99,7 @@ dtoh64ap (PTPParams *params, const unsig static inline char* -ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len) +ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t total, uint8_t *len) { uint8_t length; uint16_t string[PTP_MAXSTRLEN+1]; @@ -106,10 +108,16 @@ ptp_unpack_string(PTPParams *params, uns size_t nconv, srclen, destlen; char *src, *dest; + if (offset + 1 >= total) + return NULL; + length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */ *len = length; if (length == 0) /* nothing to do? */ - return(NULL); + return NULL; + + if (offset + 1 + length*sizeof(string[0]) > total) + return NULL; /* copy to string[] to ensure correct alignment for iconv(3) */ memcpy(string, &data[offset+1], length * sizeof(string[0])); @@ -231,8 +239,13 @@ ptp_unpack_uint32_t_array(PTPParams *par { uint32_t n, i=0; + if (!data) + return 0; + n=dtoh32a(&data[offset]); *array = malloc (n*sizeof(uint32_t)); + if (!*array) + return 0; while (n>i) { (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]); i++; @@ -246,6 +259,8 @@ ptp_pack_uint32_t_array(PTPParams *param uint32_t i=0; *data = malloc ((arraylen+1)*sizeof(uint32_t)); + if (!*data) + return 0; htod32a(&(*data)[0],arraylen); for (i=0;i<arraylen;i++) htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]); @@ -257,8 +272,13 @@ ptp_unpack_uint16_t_array(PTPParams *par { uint32_t n, i=0; + if (!data) + return 0; + n=dtoh32a(&data[offset]); *array = malloc (n*sizeof(uint16_t)); + if (!*array) + return 0; while (n>i) { (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]); i++; @@ -275,14 +295,15 @@ ptp_unpack_uint16_t_array(PTPParams *par #define PTP_di_FunctionalMode 8 #define PTP_di_OperationsSupported 10 -static inline void +static inline int ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen) { uint8_t len; unsigned int totallen; - if (!data) return; - if (datalen < 12) return; + if (!data) return 0; + if (datalen < 12) return 0; + memset (di, 0, sizeof(*di)); di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]); di->VendorExtensionID = dtoh32a(&data[PTP_di_VendorExtensionID]); @@ -290,46 +311,65 @@ ptp_unpack_DI (PTPParams *params, unsign dtoh16a(&data[PTP_di_VendorExtensionVersion]); di->VendorExtensionDesc = ptp_unpack_string(params, data, - PTP_di_VendorExtensionDesc, &len); + PTP_di_VendorExtensionDesc, + datalen, + &len); totallen=len*2+1; - di->FunctionalMode = + if (datalen <= totallen) return 0; + di->FunctionalMode = dtoh16a(&data[PTP_di_FunctionalMode+totallen]); di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data, PTP_di_OperationsSupported+totallen, &di->OperationsSupported); totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + if (datalen <= totallen+PTP_di_OperationsSupported) return 0; di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data, PTP_di_OperationsSupported+totallen, &di->EventsSupported); totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + if (datalen <= totallen+PTP_di_OperationsSupported) return 0; di->DevicePropertiesSupported_len = ptp_unpack_uint16_t_array(params, data, PTP_di_OperationsSupported+totallen, &di->DevicePropertiesSupported); totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + if (datalen <= totallen+PTP_di_OperationsSupported) return 0; di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data, PTP_di_OperationsSupported+totallen, &di->CaptureFormats); totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t); + if (datalen <= totallen+PTP_di_OperationsSupported) return 0; di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data, PTP_di_OperationsSupported+totallen, &di->ImageFormats); totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t); + if (datalen <= totallen+PTP_di_OperationsSupported) return 0; di->Manufacturer = ptp_unpack_string(params, data, PTP_di_OperationsSupported+totallen, + datalen, &len); totallen+=len*2+1; + /* be more relaxed ... as these are optional its ok if they are not here */ + if (datalen <= totallen+PTP_di_OperationsSupported) return 1; di->Model = ptp_unpack_string(params, data, PTP_di_OperationsSupported+totallen, + datalen, &len); totallen+=len*2+1; + /* be more relaxed ... as these are optional its ok if they are not here */ + if (datalen <= totallen+PTP_di_OperationsSupported) return 1; di->DeviceVersion = ptp_unpack_string(params, data, PTP_di_OperationsSupported+totallen, + datalen, &len); totallen+=len*2+1; + /* be more relaxed ... as these are optional its ok if they are not here */ + if (datalen <= totallen+PTP_di_OperationsSupported) return 1; di->SerialNumber = ptp_unpack_string(params, data, PTP_di_OperationsSupported+totallen, + datalen, &len); + return 1; } static void inline @@ -344,35 +384,36 @@ ptp_free_DI (PTPDeviceInfo *di) { if (di->OperationsSupported) free (di->OperationsSupported); if (di->EventsSupported) free (di->EventsSupported); if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported); + memset(di, 0, sizeof(*di)); } /* EOS Device Info unpack */ -static inline void +static inline int ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen) { int totallen = 4; memset (di,0, sizeof(*di)); - if (datalen < 8) return; + if (datalen < 8) return 0; /* uint32_t struct len - ignore */ di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data, totallen, &di->EventsSupported); - if (!di->EventsSupported) return; + if (!di->EventsSupported) return 0; totallen += di->EventsSupported_len*sizeof(uint32_t)+4; - if (totallen >= datalen) return; + if (totallen >= datalen) return 0; di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data, totallen, &di->DevicePropertiesSupported); - if (!di->DevicePropertiesSupported) return; + if (!di->DevicePropertiesSupported) return 0; totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4; - if (totallen >= datalen) return; + if (totallen >= datalen) return 0; di->unk_len = ptp_unpack_uint32_t_array(params, data, totallen, &di->unk); - if (!di->unk) return; + if (!di->unk) return 0; totallen += di->unk_len*sizeof(uint32_t)+4; - return; + return 1; } static inline void @@ -405,11 +446,11 @@ ptp_unpack_OH (PTPParams *params, unsign static inline void ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len) { - if (!data && !len) { - sids->n = 0; - sids->Storage = NULL; + sids->n = 0; + sids->Storage = NULL; + if (!data && !len) return; - } + sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids, &sids->Storage); } @@ -424,11 +465,12 @@ ptp_unpack_SIDs (PTPParams *params, unsi #define PTP_si_FreeSpaceInImages 22 #define PTP_si_StorageDescription 26 -static inline void +static inline int ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len) { uint8_t storagedescriptionlen; + if (len < 26) return 0; si->StorageType=dtoh16a(&data[PTP_si_StorageType]); si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]); si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]); @@ -436,10 +478,14 @@ ptp_unpack_SI (PTPParams *params, unsign si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]); si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]); si->StorageDescription=ptp_unpack_string(params, data, - PTP_si_StorageDescription, &storagedescriptionlen); + PTP_si_StorageDescription, + len, + &storagedescriptionlen); si->VolumeLabel=ptp_unpack_string(params, data, PTP_si_StorageDescription+storagedescriptionlen*2+1, + len, &storagedescriptionlen); + return 1; } /* ObjectInfo pack/unpack */ @@ -601,10 +647,10 @@ ptp_unpack_OI (PTPParams *params, unsign oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]); oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]); - oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen); + oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, len, &filenamelen); capture_date = ptp_unpack_string(params, data, - PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen); + PTP_oi_filenamelen+filenamelen*2+1, len, &capturedatelen); /* subset of ISO 8601, without '.s' tenths of second and * time zone */ @@ -614,7 +660,7 @@ ptp_unpack_OI (PTPParams *params, unsign /* now the modification date ... */ capture_date = ptp_unpack_string(params, data, PTP_oi_filenamelen+filenamelen*2 - +capturedatelen*2+2,&capturedatelen); + +capturedatelen*2+2, len, &capturedatelen); oi->ModificationDate = ptp_unpack_PTPTIME(capture_date); free(capture_date); } @@ -636,6 +682,8 @@ ptp_unpack_OI (PTPParams *params, unsign \ val->a.count = n; \ val->a.v = malloc(sizeof(val->a.v[0])*n); \ + if (n > (total - (*offset))/sizeof(val->a.v[0]))\ + return 0; \ if (!val->a.v) return 0; \ for (j=0;j<n;j++) \ CTVAL(val->a.v[j].member, func); \ @@ -646,6 +694,9 @@ ptp_unpack_DPV ( PTPParams *params, unsigned char* data, int *offset, int total, PTPPropertyValue* value, uint16_t datatype ) { + if (*offset >= total) /* we are at the end or over the end of the buffer */ + return 0; + switch (datatype) { case PTP_DTC_INT8: CTVAL(value->i8,dtoh8a); @@ -712,7 +763,11 @@ ptp_unpack_DPV ( case PTP_DTC_STR: { uint8_t len; /* XXX: max size */ - value->str = ptp_unpack_string(params,data,*offset,&len); + + if (*offset >= total+1) + return 0; + + value->str = ptp_unpack_string(params,data,*offset,total,&len); *offset += len*2+1; if (!value->str) return 1; @@ -737,6 +792,8 @@ ptp_unpack_DPD (PTPParams *params, unsig int offset=0, ret; memset (dpd, 0, sizeof(*dpd)); + if (dpdlen <= 5) + return 0; dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]); dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]); dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]); @@ -1062,8 +1119,11 @@ ptp_unpack_OPL (PTPParams *params, unsig MTPProperties *props = NULL; int offset = 0, i; - if (prop_count == 0) { - *pprops = NULL; + *pprops = NULL; + if (prop_count == 0) + return 0; + if (prop_count >= INT_MAX/sizeof(MTPProperties)) { + ptp_debug (params ,"prop_count %d is too large", prop_count); return 0; } ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count); @@ -1074,7 +1134,7 @@ ptp_unpack_OPL (PTPParams *params, unsig for (i = 0; i < prop_count; i++) { if (len <= 0) { ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count); - ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i); + ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL"); ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i); qsort (props, i, sizeof(MTPProperties),_compare_func); *pprops = props; @@ -1093,7 +1153,12 @@ ptp_unpack_OPL (PTPParams *params, unsig len -= sizeof(uint16_t); offset = 0; - ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype); + if (!ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype)) { + ptp_debug (params ,"unpacking DPV of property %d encountered insufficient buffer. attack?", i); + qsort (props, i, sizeof(MTPProperties),_compare_func); + *pprops = props; + return i; + } data += offset; len -= offset; } @@ -1352,14 +1417,19 @@ ptp_unpack_EOS_CustomFuncEx (PTPParams* { uint32_t s = dtoh32a( *data ); uint32_t n = s/4, i; - char* str = (char*)malloc( s ); // n is size in uint32, average len(itoa(i)) < 4 -> alloc n chars + char *str, *p; + + if (s > 1024) { + ptp_debug (params, "customfuncex data is larger than 1k / %d... unexpected?", s); + return strdup("bad length"); + } + str = (char*)malloc( s*2+s/4+1 ); /* n is size in uint32, maximum %x len is 8 chars and \0*/ if (!str) - return str; - char* p = str; + return strdup("malloc failed"); + p = str; for (i=0; i < n; ++i) p += sprintf(p, "%x,", dtoh32a( *data + 4*i )); - return str; } @@ -1416,27 +1486,60 @@ ptp_unpack_CANON_changes (PTPParams *par if (data==NULL) return 0; - while (curdata - data < datasize) { + while (curdata - data + 8 < datasize) { uint32_t size = dtoh32a(&curdata[PTP_ece_Size]); uint32_t type = dtoh32a(&curdata[PTP_ece_Type]); - curdata += size; + if (size > datasize) { + ptp_debug (params, "size %d is larger than datasize %d", size, datasize); + break; + } + if (size < 8) { + ptp_debug (params, "size %d is smaller than 8.", size); + break; + } if ((size == 8) && (type == 0)) break; + if ((curdata - data) + size >= datasize) { + ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries"); + break; + } + curdata += size; entries++; } *ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1)); if (!*ce) return 0; curdata = data; - while (curdata - data < datasize) { + while (curdata - data + 8 < datasize) { uint32_t size = dtoh32a(&curdata[PTP_ece_Size]); uint32_t type = dtoh32a(&curdata[PTP_ece_Type]); + if (size > datasize) { + ptp_debug (params, "size %d is larger than datasize %d", size, datasize); + break; + } + if (size < 8) { + ptp_debug (params, "size %d is smaller than 8.", size); + break; + } + + if ((size == 8) && (type == 0)) + break; + + if ((curdata - data) + size >= datasize) { + ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries"); + break; + } + (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN; (*ce)[i].u.info = NULL; switch (type) { - case PTP_EC_CANON_EOS_ObjectAddedEx: + case PTP_EC_CANON_EOS_ObjectAddedEx: + if (size < PTP_ece_OA_Name+1) { + ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OA_Name+1); + break; + } (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO; (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]); (*ce)[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]); @@ -1446,7 +1549,11 @@ ptp_unpack_CANON_changes (PTPParams *par (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name])); ptp_debug (params, "event %d: objectinfo added oid %08lx, parent %08lx, ofc %04x, size %d, filename %s", i, (*ce)[i].u.object.oid, (*ce)[i].u.object.oi.ParentObject, (*ce)[i].u.object.oi.ObjectFormat, (*ce)[i].u.object.oi.ObjectCompressedSize, (*ce)[i].u.object.oi.Filename); break; - case PTP_EC_CANON_EOS_RequestObjectTransfer: + case PTP_EC_CANON_EOS_RequestObjectTransfer: + if (size < PTP_ece_OI_Name+1) { + ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OI_Name+1); + break; + } (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER; (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]); (*ce)[i].u.object.oi.StorageID = 0; /* use as marker */ @@ -1465,6 +1572,11 @@ ptp_unpack_CANON_changes (PTPParams *par int j; PTPDevicePropDesc *dpd; + if (size < PTP_ece_Prop_Desc_Data) { + ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_Prop_Desc_Data); + break; + } + ptp_debug (params, "event %d: EOS prop %04x desc record, datasize %d, propxtype %d", i, proptype, size-PTP_ece_Prop_Desc_Data, propxtype); for (j=0;j<params->nrofcanon_props;j++) if (params->canon_props[j].proptype == proptype) @@ -1479,7 +1591,7 @@ ptp_unpack_CANON_changes (PTPParams *par * 7 - string? */ if (propxtype != 3) { - ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype); + ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled, size %d.", i, propxtype, proptype, size); for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++) ptp_debug (params, " %d: %02x", j, xdata[j]); break; @@ -1510,8 +1622,12 @@ ptp_unpack_CANON_changes (PTPParams *par /* 'normal' enumerated types */ switch (dpd->DataType) { #define XX( TYPE, CONV )\ - for (j=0;j<propxcnt;j++) { \ - dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \ + if (sizeof(dpd->FORM.Enum.SupportedValue[j].TYPE)*propxcnt + PTP_ece_Prop_Desc_Data > size) { \ + ptp_debug (params, "size %d does not match needed %d", sizeof(dpd->FORM.Enum.SupportedValue[j].TYPE)*propxcnt + PTP_ece_Prop_Desc_Data, size); \ + break; \ + } \ + for (j=0;j<propxcnt;j++) { \ + dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \ ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, CONV(xdata)); \ xdata += 4; /* might only be for propxtype 3 */ \ } \ @@ -1523,7 +1639,10 @@ ptp_unpack_CANON_changes (PTPParams *par case PTP_DTC_UINT8: XX( u8, dtoh8a ); #undef XX default: - ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata)); + free (dpd->FORM.Enum.SupportedValue); + dpd->FORM.Enum.SupportedValue = NULL; + dpd->FORM.Enum.NumberOfValues = 0; + ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, size %d, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata), size); for (j=0;j<(size-PTP_ece_Prop_Desc_Data)/4;j++, xdata+=4) /* 4 is good for propxtype 3 */ ptp_debug (params, " %3d: 0x%8x", j, dtoh32a(xdata)); break; @@ -1538,6 +1657,10 @@ ptp_unpack_CANON_changes (PTPParams *par unsigned char *xdata = &curdata[PTP_ece_Prop_Val_Data]; PTPDevicePropDesc *dpd; + if (size < PTP_ece_Prop_Val_Data) { + ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_Prop_Val_Data); + break; + } ptp_debug (params, "event %d: EOS prop %04x info record, datasize is %d", i, proptype, size-PTP_ece_Prop_Val_Data); for (j=0;j<params->nrofcanon_props;j++) if (params->canon_props[j].proptype == proptype) @@ -1546,6 +1669,7 @@ ptp_unpack_CANON_changes (PTPParams *par if ( (params->canon_props[j].size != size) || (memcmp(params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data))) { params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data); + params->canon_props[j].size = size; memcpy (params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data); } } else { @@ -1794,7 +1918,7 @@ ptp_unpack_CANON_changes (PTPParams *par break; case PTP_EC_CANON_EOS_BulbExposureTime: (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN; - (*ce)[i].u.info = malloc(strlen("BulbExposureTime 123456789")); + (*ce)[i].u.info = malloc(strlen("BulbExposureTime 123456789012345678")); sprintf ((*ce)[i].u.info, "BulbExposureTime %d", dtoh32a(curdata+8)); break; default: @@ -1837,8 +1961,9 @@ ptp_unpack_CANON_changes (PTPParams *par } curdata += size; i++; - if ((size == 8) && (type == 0)) - break; + if (i >= entries) { + ptp_debug (params, "BAD: i %d, entries %d", i, entries); + } } if (!entries) { free (*ce); @@ -1865,8 +1990,10 @@ ptp_unpack_Nikon_EC (PTPParams *params, if (len < PTP_nikon_ec_Code) return; *cnt = dtoh16a(&data[PTP_nikon_ec_Length]); - if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */ + if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) { /* broken cnt? */ + *cnt = 0; return; + } if (!*cnt) return; --- a/src/ptp.c +++ b/src/ptp.c @@ -1,7 +1,7 @@ /* ptp.c * * Copyright (C) 2001-2004 Mariusz Woloszyn <[email protected]> - * Copyright (C) 2003-2012 Marcus Meissner <[email protected]> + * Copyright (C) 2003-2016 Marcus Meissner <[email protected]> * Copyright (C) 2006-2008 Linus Walleij <[email protected]> * Copyright (C) 2007 Tero Saarni <[email protected]> * Copyright (C) 2009 Axel Waggershauser <[email protected]> @@ -215,7 +215,9 @@ ptp_transaction_new (PTPParams* params, "PTP: Sequence number mismatch %d vs expected %d.", ptp->Transaction_ID, params->transaction_id-1 ); +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION return PTP_ERROR_BADPARAM; +#endif } break; } @@ -446,9 +448,15 @@ ptp_getdeviceinfo (PTPParams* params, PT ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler); ptp_exit_recv_memory_handler (&handler, &di, &len); if (!di) ret = PTP_RC_GeneralError; - if (ret == PTP_RC_OK) ptp_unpack_DI(params, di, deviceinfo, len); + if (ret != PTP_RC_OK) { + return ret; + } + ret = ptp_unpack_DI(params, di, deviceinfo, len); free(di); - return ret; + if (ret) + return PTP_RC_OK; + else + return PTP_ERROR_IO; } uint16_t @@ -468,9 +476,15 @@ ptp_canon_eos_getdeviceinfo (PTPParams* data=NULL; ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler); ptp_exit_recv_memory_handler (&handler, &data, &len); - if (ret == PTP_RC_OK) ptp_unpack_EOS_DI(params, data, di, len); - free (data); - return ret; + if (ret != PTP_RC_OK) { + return ret; + } + ret = ptp_unpack_EOS_DI(params, data, di, len); + free(di); + if (ret) + return PTP_RC_OK; + else + return PTP_ERROR_IO; } /** @@ -622,7 +636,15 @@ ptp_getstorageinfo (PTPParams* params, u ptp.Nparam=1; len=0; ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &si, &len); - if (ret == PTP_RC_OK) ptp_unpack_SI(params, si, storageinfo, len); + if (ret != PTP_RC_OK) + return ret; + if (!si || !len) + return PTP_RC_GeneralError; + memset(storageinfo, 0, sizeof(*storageinfo)); + if (!ptp_unpack_SI(params, si, storageinfo, len)) { + free(si); + return PTP_RC_GeneralError; + } free(si); return ret; } @@ -651,6 +673,9 @@ ptp_getobjecthandles (PTPParams* params, unsigned char* oh=NULL; unsigned int len; + objecthandles->Handler = NULL; + objecthandles->n = 0; + PTP_CNT_INIT(ptp); ptp.Code=PTP_OC_GetObjectHandles; ptp.Param1=storage; @@ -1112,6 +1137,10 @@ ptp_getdevicepropdesc (PTPParams* params ptp.Nparam=1; len=0; ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpd, &len); + if (!dpd) { + ptp_debug (params, "no data received for getdevicepropdesc"); + return PTP_RC_InvalidDevicePropFormat; + } if (ret == PTP_RC_OK) ptp_unpack_DPD(params, dpd, devicepropertydesc, len); free(dpd); return ret; @@ -1555,7 +1584,7 @@ ptp_canon_gettreesize (PTPParams* params for (i=0;i<*cnt;i++) { unsigned char len; (*entries)[i].oid = dtoh32a(cur); - (*entries)[i].str = ptp_unpack_string(params, cur, 4, &len); + (*entries)[i].str = ptp_unpack_string(params, cur, 4, size-(cur-out-4), &len); cur += 4+(cur[4]*2+1); } free (out); @@ -1855,6 +1884,16 @@ ptp_canon_eos_getobjectinfoex ( if (ret != PTP_RC_OK) return ret; + if (size < 4) { + ret = PTP_RC_GeneralError; + goto exit; + } + /* check for integer overflow */ + if (dtoh32a(data) >= INT_MAX/sizeof(PTPCANONFolderEntry)) { + ret = PTP_RC_GeneralError; + goto exit; + } + *nrofentries = dtoh32a(data); *entries = malloc(*nrofentries * sizeof(PTPCANONFolderEntry)); if (!*entries) @@ -1862,10 +1901,20 @@ ptp_canon_eos_getobjectinfoex ( xdata = data+sizeof(uint32_t); for (i=0;i<*nrofentries;i++) { + if ((dtoh32a(xdata) + (xdata-data)) > size) { + ptp_debug (params, "reading canon FEs run over read data size?\n"); + free (*entries); + *entries = NULL; + *nrofentries = 0; + ret = PTP_RC_GeneralError; + goto exit; + } ptp_unpack_Canon_EOS_FE (params, &xdata[4], &((*entries)[i])); xdata += dtoh32a(xdata); } - return PTP_RC_OK; +exit: + free(data); + return ret; } /** @@ -2140,6 +2189,7 @@ ptp_canon_getobjectinfo (PTPParams* para PTPContainer ptp; unsigned char *data = NULL; unsigned int len; + unsigned int i, size; PTP_CNT_INIT(ptp); ptp.Code=PTP_OC_CANON_GetObjectInfoEx; @@ -2150,19 +2200,28 @@ ptp_canon_getobjectinfo (PTPParams* para ptp.Nparam=4; len=0; ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &len); - if (ret == PTP_RC_OK) { - int i; - *entnum=ptp.Param1; - *entries=calloc(*entnum, sizeof(PTPCANONFolderEntry)); - if (*entries!=NULL) { - for(i=0; i<(*entnum); i++) - ptp_unpack_Canon_FE(params, - data+i*PTP_CANON_FolderEntryLen, - &((*entries)[i]) ); - } else { - ret=PTP_ERROR_IO; /* Cannot allocate memory */ - } + if (ret != PTP_RC_OK) + goto exit; + if (!data) + return ret; + if (ptp.Param1 > size/PTP_CANON_FolderEntryLen) { + ptp_debug (params, "param1 is %d, size is only %d", ptp.Param1, size); + ret = PTP_RC_GeneralError; + goto exit; + } + *entnum=ptp.Param1; + *entries=calloc(*entnum, sizeof(PTPCANONFolderEntry)); + if (*entries==NULL) { + ret=PTP_ERROR_IO; /* Cannot allocate memory */ + goto exit; + } + for(i=0; i<(*entnum); i++) { + if (size < i*PTP_CANON_FolderEntryLen) break; + ptp_unpack_Canon_FE(params, + data+i*PTP_CANON_FolderEntryLen, + &((*entries)[i]) ); } +exit: free(data); return ret; } @@ -2489,13 +2548,13 @@ ptp_nikon_getwifiprofilelist (PTPParams* params->wifi_profiles[profn].device_type = data[pos++]; params->wifi_profiles[profn].icon_type = data[pos++]; - buffer = ptp_unpack_string(params, data, pos, &len); + buffer = ptp_unpack_string(params, data, pos, size, &len); strncpy(params->wifi_profiles[profn].creation_date, buffer, sizeof(params->wifi_profiles[profn].creation_date)); free (buffer); pos += (len*2+1); if (pos+1 >= size) return PTP_RC_Undefined; /* FIXME: check if it is really last usage date */ - buffer = ptp_unpack_string(params, data, pos, &len); + buffer = ptp_unpack_string(params, data, pos, size, &len); strncpy(params->wifi_profiles[profn].lastusage_date, buffer, sizeof(params->wifi_profiles[profn].lastusage_date)); free (buffer); pos += (len*2+1); @@ -2657,6 +2716,7 @@ ptp_mtp_getobjectpropssupported (PTPPara ptp.Nparam = 1; ptp.Param1 = ofc; ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size); + if (!data) return PTP_RC_GeneralError; if (ret == PTP_RC_OK) *propnum=ptp_unpack_uint16_t_array(params,data,0,props); free(data); @@ -3159,6 +3219,10 @@ struct fileinfo* ptp_chdk_readdir(PTPPar ptp.Nparam=1; ptp.Param1=PTP_CHDK_ReadDir; ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); + if (!data) { + ptp_error(params,"no data received"); + return PTP_ERROR_BADPARAM; + } if ( ret != 0x2001 ) { ptp_error(params,"unexpected return code 0x%x",ret); @@ -4779,9 +4843,14 @@ ptp_render_property_value(PTPParams* par switch (dpc) { case PTP_DPC_MTP_SynchronizationPartner: case PTP_DPC_MTP_DeviceFriendlyName: - return snprintf(out, length, "%s", dpd->CurrentValue.str); + if (dpd->DataType == PTP_DTC_STR) + return snprintf(out, length, "%s", dpd->CurrentValue.str); + else + return snprintf(out, length, "invalid type, expected STR"); case PTP_DPC_MTP_SecureTime: case PTP_DPC_MTP_DeviceCertificate: { + if (dpd->DataType != PTP_DTC_AUINT16) + return snprintf(out, length, "invalid type, expected AUINT16"); /* FIXME: Convert to use unicode demux functions */ for (i=0;(i<dpd->CurrentValue.a.count) && (i<length);i++) out[i] = dpd->CurrentValue.a.v[i].u16; @@ -5344,7 +5413,12 @@ static int _cmp_ob (const void *a, const PTPObject *oa = (PTPObject*)a; PTPObject *ob = (PTPObject*)b; - return oa->oid - ob->oid; + /* Do not subtract the oids and return ... + * the unsigned int -> int conversion will overflow in cases + * like 0xfffc0000 vs 0x0004000. */ + if (oa->oid > ob->oid) return 1; + if (oa->oid < ob->oid) return -1; + return 0; } void
