libmtp LTS update ready for testing
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é <anarcat@debian.org> 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 <marcus@jet.franken.de>
+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 <emsi@ipartners.pl>
+- * Copyright (C) 2003-2012 Marcus Meissner <marcus@jet.franken.de>
++ * Copyright (C) 2003-2016 Marcus Meissner <marcus@jet.franken.de>
+ * Copyright (C) 2006-2008 Linus Walleij <triad@df.lth.se>
+ * Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
+ * Copyright (C) 2009 Axel Waggershauser <awagger@web.de>
+@@ -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 <marcus@jet.franken.de>
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 <emsi@ipartners.pl>
- * Copyright (C) 2003-2012 Marcus Meissner <marcus@jet.franken.de>
+ * Copyright (C) 2003-2016 Marcus Meissner <marcus@jet.franken.de>
* Copyright (C) 2006-2008 Linus Walleij <triad@df.lth.se>
* Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
* Copyright (C) 2009 Axel Waggershauser <awagger@web.de>
@@ -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
Reply to: