Added len argument and boundary checks to various read functions

v0.27.3
Andreas Huggel 21 years ago
parent 41dc298854
commit cc827d59a8

@ -20,14 +20,14 @@
*/ */
/* /*
File: ifd.cpp File: ifd.cpp
Version: $Name: $ $Revision: 1.17 $ Version: $Name: $ $Revision: 1.18 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 26-Jan-04, ahu: created History: 26-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component 11-Feb-04, ahu: isolated as a component
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.17 $ $RCSfile: ifd.cpp,v $") EXIV2_RCSID("@(#) $Name: $ $Revision: 1.18 $ $RCSfile: ifd.cpp,v $")
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -197,40 +197,54 @@ namespace Exiv2 {
} }
} }
int Ifd::read(const char* buf, ByteOrder byteOrder, long offset) int Ifd::read(const char* buf, long len, ByteOrder byteOrder, long offset)
{ {
offset_ = offset; int rc = 0;
long o = 0;
Ifd::PreEntries preEntries; Ifd::PreEntries preEntries;
int n = getUShort(buf, byteOrder); if (len < 2) rc = 6;
long o = 2; if (rc == 0) {
offset_ = offset;
int n = getUShort(buf, byteOrder);
o = 2;
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
Ifd::PreEntry pe; if (len < o + 12) {
pe.tag_ = getUShort(buf+o, byteOrder); rc = 6;
pe.type_ = getUShort(buf+o+2, byteOrder); break;
pe.count_ = getULong(buf+o+4, byteOrder); }
pe.size_ = pe.count_ * TypeInfo::typeSize(TypeId(pe.type_)); Ifd::PreEntry pe;
pe.offsetLoc_ = o + 8; pe.tag_ = getUShort(buf + o, byteOrder);
pe.offset_ = pe.size_ > 4 ? getULong(buf+o+8, byteOrder) : 0; pe.type_ = getUShort(buf + o + 2, byteOrder);
preEntries.push_back(pe); pe.count_ = getULong(buf + o + 4, byteOrder);
o += 12; pe.size_ = pe.count_ * TypeInfo::typeSize(TypeId(pe.type_));
} pe.offsetLoc_ = o + 8;
if (alloc_) { pe.offset_ = pe.size_ > 4 ? getULong(buf + o + 8, byteOrder) : 0;
memcpy(pNext_, buf + o, 4); preEntries.push_back(pe);
o += 12;
}
} }
else { if (rc == 0) {
pNext_ = const_cast<char*>(buf + o); if (len < o + 4) {
rc = 6;
}
else {
if (alloc_) {
memcpy(pNext_, buf + o, 4);
}
else {
pNext_ = const_cast<char*>(buf + o);
}
next_ = getULong(buf + o, byteOrder);
}
} }
next_ = getULong(buf+o, byteOrder);
// Set the offset of the first data entry outside of the IFD. // Set the offset of the first data entry outside of the IFD.
// At the same time we guess the offset of the IFD, if it was not // At the same time we guess the offset of the IFD, if it was not
// given. The guess is based on the assumption that the smallest offset // given. The guess is based on the assumption that the smallest offset
// points to a data buffer directly following the IFD. Subsequently all // points to a data buffer directly following the IFD. Subsequently all
// offsets of IFD entries will need to be recalculated. // offsets of IFD entries will need to be recalculated.
if (preEntries.size() > 0) { if (rc == 0 && preEntries.size() > 0) {
// Find the entry with the smallest offset // Find the entry with the smallest offset
Ifd::PreEntries::const_iterator i = std::min_element( Ifd::PreEntries::const_iterator i = std::min_element(
preEntries.begin(), preEntries.end(), cmpPreEntriesByOffset); preEntries.begin(), preEntries.end(), cmpPreEntriesByOffset);
@ -242,31 +256,42 @@ namespace Exiv2 {
offset_ = i->offset_ - size(); offset_ = i->offset_ - size();
} }
// Set the offset of the first data entry outside of the IFD // Set the offset of the first data entry outside of the IFD
dataOffset_ = i->offset_; if (static_cast<unsigned long>(len) < i->offset_ - offset_) {
rc = 6;
}
else {
dataOffset_ = i->offset_;
}
} }
} }
// Convert the pre-IFD entries to the actual entries, assign the data // Convert the pre-IFD entries to the actual entries, assign the data
// to each IFD entry and calculate relative offsets, relative to the // to each IFD entry and calculate relative offsets, relative to the
// start of the IFD // start of the IFD
entries_.clear(); if (rc == 0) {
int idx = 0; entries_.clear();
const Ifd::PreEntries::iterator begin = preEntries.begin(); int idx = 0;
const Ifd::PreEntries::iterator end = preEntries.end(); const Ifd::PreEntries::iterator begin = preEntries.begin();
for (Ifd::PreEntries::iterator i = begin; i != end; ++i) { const Ifd::PreEntries::iterator end = preEntries.end();
Entry e(alloc_); for (Ifd::PreEntries::iterator i = begin; i != end; ++i) {
e.setIfdId(ifdId_); Entry e(alloc_);
e.setIdx(++idx); e.setIfdId(ifdId_);
e.setTag(i->tag_); e.setIdx(++idx);
// Set the offset to the data, relative to start of IFD e.setTag(i->tag_);
e.setOffset(i->size_ > 4 ? i->offset_ - offset_ : i->offsetLoc_); // Set the offset to the data, relative to start of IFD
// Set the size to at least for bytes to accomodate offset-data e.setOffset(i->size_ > 4 ? i->offset_ - offset_ : i->offsetLoc_);
e.setValue(i->type_, i->count_, buf + e.offset(), if (static_cast<unsigned long>(len) < e.offset() + i->size_) {
std::max(long(4), i->size_)); rc = 6;
this->add(e); break;
}
// Set the size to at least for bytes to accomodate offset-data
e.setValue(i->type_, i->count_, buf + e.offset(),
std::max(long(4), i->size_));
this->add(e);
}
} }
if (rc) this->clear();
return 0; return rc;
} // Ifd::read } // Ifd::read
Ifd::const_iterator Ifd::findIdx(int idx) const Ifd::const_iterator Ifd::findIdx(int idx) const
@ -299,14 +324,19 @@ namespace Exiv2 {
} }
int Ifd::readSubIfd( int Ifd::readSubIfd(
Ifd& dest, const char* buf, ByteOrder byteOrder, uint16 tag Ifd& dest, const char* buf, long len, ByteOrder byteOrder, uint16 tag
) const ) const
{ {
int rc = 0; int rc = 0;
const_iterator pos = findTag(tag); const_iterator pos = findTag(tag);
if (pos != entries_.end()) { if (pos != entries_.end()) {
uint32 offset = getULong(pos->data(), byteOrder); long offset = getULong(pos->data(), byteOrder);
rc = dest.read(buf + offset, byteOrder, offset); if (len < offset) {
rc = 6;
}
else {
rc = dest.read(buf + offset, len - offset, byteOrder, offset);
}
} }
return rc; return rc;
} // Ifd::readSubIfd } // Ifd::readSubIfd
@ -371,6 +401,7 @@ namespace Exiv2 {
else { else {
pNext_ = 0; pNext_ = 0;
} }
next_ = 0;
offset_ = 0; offset_ = 0;
dataOffset_ = 0; dataOffset_ = 0;
} // Ifd::clear } // Ifd::clear

@ -21,7 +21,7 @@
/*! /*!
@file ifd.hpp @file ifd.hpp
@brief Encoding and decoding of IFD (Image File Directory) data @brief Encoding and decoding of IFD (Image File Directory) data
@version $Name: $ $Revision: 1.16 $ @version $Name: $ $Revision: 1.17 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 09-Jan-04, ahu: created @date 09-Jan-04, ahu: created
@ -310,6 +310,7 @@ namespace Exiv2 {
@param buf Pointer to the data to decode. The buffer must start with the @param buf Pointer to the data to decode. The buffer must start with the
IFD data (unlike the readSubIfd() method). IFD data (unlike the readSubIfd() method).
@param len Number of bytes in the data buffer
@param byteOrder Applicable byte order (little or big endian). @param byteOrder Applicable byte order (little or big endian).
@param offset (Optional) offset of the IFD from the start of the TIFF @param offset (Optional) offset of the IFD from the start of the TIFF
header, if known. If not given, the offset will be guessed header, if known. If not given, the offset will be guessed
@ -317,9 +318,12 @@ namespace Exiv2 {
directory entries points to a data buffer immediately follwing directory entries points to a data buffer immediately follwing
the IFD. the IFD.
@return 0 if successful @return 0 if successful;<BR>
6 if the data buffer is too small, e.g., if an offset points
beyond the provided buffer. The IFD is cleared in this
case.
*/ */
int read(const char* buf, ByteOrder byteOrder, long offset =0); int read(const char* buf, long len, ByteOrder byteOrder, long offset =0);
/*! /*!
@brief Read a sub-IFD from the location pointed to by the directory entry @brief Read a sub-IFD from the location pointed to by the directory entry
with the given tag. with the given tag.
@ -327,13 +331,20 @@ namespace Exiv2 {
@param dest References the destination IFD. @param dest References the destination IFD.
@param buf The data buffer to read from. The buffer must contain all Exif @param buf The data buffer to read from. The buffer must contain all Exif
data starting from the TIFF header (unlike the read() method). data starting from the TIFF header (unlike the read() method).
@param len Number of bytes in the data buffer
@param byteOrder Applicable byte order (little or big endian). @param byteOrder Applicable byte order (little or big endian).
@param tag Tag to look for. @param tag Tag to look for.
@return 0 if successful @return 0 if successful;<BR>
6 if reading the sub-IFD failed (see read() above) or
the location pointed to by the directory entry with the
given tag is outside of the data buffer.
@note It is not considered an error if the tag cannot be found in the
IFD. 0 is returned and no action is taken in this case.
*/ */
int readSubIfd( int readSubIfd(
Ifd& dest, const char* buf, ByteOrder byteOrder, uint16 tag Ifd& dest, const char* buf, long len, ByteOrder byteOrder, uint16 tag
) const; ) const;
/*! /*!
@brief Copy the IFD to a data array, update the offsets of the IFD and @brief Copy the IFD to a data array, update the offsets of the IFD and

@ -20,13 +20,13 @@
*/ */
/* /*
File: makernote.cpp File: makernote.cpp
Version: $Name: $ $Revision: 1.17 $ Version: $Name: $ $Revision: 1.18 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 18-Feb-04, ahu: created History: 18-Feb-04, ahu: created
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.17 $ $RCSfile: makernote.cpp,v $") EXIV2_RCSID("@(#) $Name: $ $Revision: 1.18 $ $RCSfile: makernote.cpp,v $")
// Define DEBUG_MAKERNOTE to output debug information to std::cerr // Define DEBUG_MAKERNOTE to output debug information to std::cerr
#undef DEBUG_MAKERNOTE #undef DEBUG_MAKERNOTE
@ -162,7 +162,7 @@ namespace Exiv2 {
int rc = 0; int rc = 0;
if (!prefix_.empty()) { if (!prefix_.empty()) {
// Check if makernote is long enough and starts with prefix // Check if makernote is long enough and starts with prefix
if ( len <= static_cast<long>(prefix_.size()) if ( len < static_cast<long>(prefix_.size())
|| prefix_ != std::string(buf, prefix_.size())) rc = 2; || prefix_ != std::string(buf, prefix_.size())) rc = 2;
} }
if (!absOffset_) { if (!absOffset_) {
@ -171,6 +171,7 @@ namespace Exiv2 {
} }
if (rc == 0) { if (rc == 0) {
rc = ifd_.read(buf + prefix_.size(), rc = ifd_.read(buf + prefix_.size(),
len - prefix_.size(),
byteOrder_, byteOrder_,
offset + prefix_.size()); offset + prefix_.size());
} }

Loading…
Cancel
Save