[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: