From a4dcb0ecf632832258ebb523c6bc39b7b94f8775 Mon Sep 17 00:00:00 2001 From: Daniel Brahneborg Date: Sun, 3 Mar 2002 22:02:40 +0000 Subject: Add buffer overflow checks to handle truncated and corrupted sis files. --- lib/siscomponentrecord.cpp | 23 ++++++++++++++++---- lib/siscomponentrecord.h | 4 +++- lib/sisfile.cpp | 52 +++++++++++++++++++++++++++++++++++++++------- lib/sisfile.h | 4 +++- lib/sisfileheader.cpp | 21 ++++++++++++++----- lib/sisfileheader.h | 4 +++- lib/sisfilerecord.cpp | 22 ++++++++++++++------ lib/sisfilerecord.h | 4 +++- lib/sislangrecord.cpp | 9 ++++++-- lib/sislangrecord.h | 4 +++- lib/sisreqrecord.cpp | 15 ++++++++++--- lib/sisreqrecord.h | 4 +++- lib/sistypes.h | 9 ++++++++ 13 files changed, 142 insertions(+), 33 deletions(-) (limited to 'lib') diff --git a/lib/siscomponentrecord.cpp b/lib/siscomponentrecord.cpp index 7ec468d..8078886 100644 --- a/lib/siscomponentrecord.cpp +++ b/lib/siscomponentrecord.cpp @@ -31,30 +31,44 @@ SISComponentNameRecord::~SISComponentNameRecord() delete[] m_names; } -void -SISComponentNameRecord::fillFrom(uchar* buf, int base, SISFile* sisFile) +SisRC +SISComponentNameRecord::fillFrom(uchar* buf, int base, off_t len, + SISFile* sisFile) { + int n = sisFile->m_header.m_nlangs; + if (base + 8 + n * 4 * 2) + return SIS_TRUNCATED; + uchar* p = buf + base; int size = 0; - int n = sisFile->m_header.m_nlangs; m_nameLengths = new uint32[n]; m_namePtrs = new uint32[n]; - m_names = new uchar*[n]; // First read lengths. // for (int i = 0; i < n; ++i) { m_nameLengths[i] = read32(p + size); + if (m_nameLengths[i] > len) + { + printf("Length too large for name record %d.\n", i); + return SIS_TRUNCATED; + } size += 4; } // Then read ptrs. // + m_names = new uchar*[n]; for (int i = 0; i < n; ++i) { m_namePtrs[i] = read32(p + size); + if (m_namePtrs[i] + m_nameLengths[i] > len) + { + printf("Position/length too large for name record %d.\n", i); + return SIS_TRUNCATED; + } size += 4; if (logLevel >= 2) printf("Name %d (for %s) is %.*s\n", @@ -69,6 +83,7 @@ SISComponentNameRecord::fillFrom(uchar* buf, int base, SISFile* sisFile) } if (logLevel >= 1) printf("%d .. %d (%d bytes): Name records\n", base, base + size, size); + return SIS_OK; } uchar* diff --git a/lib/siscomponentrecord.h b/lib/siscomponentrecord.h index 4b03793..f2a85da 100644 --- a/lib/siscomponentrecord.h +++ b/lib/siscomponentrecord.h @@ -25,6 +25,8 @@ #include "sistypes.h" +#include + class SISFile; /** @@ -40,7 +42,7 @@ public: /** * Populate the fields. */ - void fillFrom(uchar* buf, int base, SISFile* sisFile); + SisRC fillFrom(uchar* buf, int base, off_t len, SISFile* sisFile); /** * Return the name for the given language. diff --git a/lib/sisfile.cpp b/lib/sisfile.cpp index 05551b9..f9a19fb 100644 --- a/lib/sisfile.cpp +++ b/lib/sisfile.cpp @@ -27,11 +27,16 @@ #include -void -SISFile::fillFrom(uchar* buf) +SisRC +SISFile::fillFrom(uchar* buf, off_t len) { int ix = 0; - m_header.fillFrom(buf, &ix); + SisRC rc = m_header.fillFrom(buf, &ix, len); + if (rc != SIS_OK) + { + printf("Could not read header, rc = %d\n", rc); + return rc; + } if (logLevel >= 2) printf("Ate header, got ix = %d\n", ix); int n; @@ -42,7 +47,16 @@ SISFile::fillFrom(uchar* buf) m_langRecords = new SISLangRecord[n]; ix = m_header.m_languagePtr; for (int i = 0; i < n; ++i) - m_langRecords[i].fillFrom(buf, &ix); + { + if (ix >= len) + return SIS_TRUNCATED; + rc = m_langRecords[i].fillFrom(buf, &ix, len); + if (rc != SIS_OK) + { + printf("Problem reading language record %d, rc = %d.\n", i, rc); + return rc; + } + } // Read requisites. // @@ -50,12 +64,26 @@ SISFile::fillFrom(uchar* buf) m_reqRecords = new SISReqRecord[n]; ix = m_header.m_reqPtr; for (int i = 0; i < n; ++i) - m_reqRecords[i].fillFrom(buf, &ix, this); + { + if (ix >= len) + return SIS_TRUNCATED; + rc = m_reqRecords[i].fillFrom(buf, &ix, len, this); + if (rc != SIS_OK) + { + printf("Problem reading requisite record %d, rc = %d.\n", i, rc); + return rc; + } + } // Read component names, by language. // ix = m_header.m_componentPtr; - m_componentRecord.fillFrom(buf, ix, this); + rc = m_componentRecord.fillFrom(buf, ix, len, this); + if (rc != SIS_OK) + { + printf("Problem reading the name record, rc = %d.\n", rc); + return rc; + } // Read files. // @@ -63,8 +91,18 @@ SISFile::fillFrom(uchar* buf) m_fileRecords = new SISFileRecord[n]; ix = m_header.m_filesPtr; for (int i = 0; i < n; ++i) - m_fileRecords[i].fillFrom(buf, &ix, this); + { + if (ix >= len) + return SIS_TRUNCATED; + rc = m_fileRecords[i].fillFrom(buf, &ix, len, this); + if (rc != SIS_OK) + { + printf("Problem reading file record %d, rc = %d.\n", i, rc); + return rc; + } + } + return SIS_OK; } int diff --git a/lib/sisfile.h b/lib/sisfile.h index 0bfa000..45490da 100644 --- a/lib/sisfile.h +++ b/lib/sisfile.h @@ -27,6 +27,8 @@ #include "sisfileheader.h" #include "siscomponentrecord.h" +#include + class SISLangRecord; class SISFileRecord; class SISReqRecord; @@ -41,7 +43,7 @@ public: /** * Populate the fields. */ - void fillFrom(uchar* buf); + SisRC fillFrom(uchar* buf, off_t len); /** * Return the currently selected installation language. diff --git a/lib/sisfileheader.cpp b/lib/sisfileheader.cpp index f8b88d0..3279c38 100644 --- a/lib/sisfileheader.cpp +++ b/lib/sisfileheader.cpp @@ -28,9 +28,11 @@ const int OFF_NUMBER_OF_FILES = 26; const int OFF_INSTALLATION_DRIVE = 28; -void -SISFileHeader::fillFrom(uchar* buf, int* base) +SisRC +SISFileHeader::fillFrom(uchar* buf, int* base, off_t len) { + if (*base + 68 > len) + return SIS_TRUNCATED; uchar* start = buf + *base; m_buf = buf; m_uid1 = read32(start); @@ -40,7 +42,7 @@ SISFileHeader::fillFrom(uchar* buf, int* base) if (m_uid2 != 0x1000006d) { printf("Got bad uid2.\n"); - exit(1); + return SIS_CORRUPTED; } if (logLevel >= 2) printf("Got uid2 = %08x\n", m_uid2); @@ -48,7 +50,7 @@ SISFileHeader::fillFrom(uchar* buf, int* base) if (m_uid3 != 0x10000419) { printf("Got bad uid3.\n"); - exit(1); + return SIS_CORRUPTED; } if (logLevel >= 2) printf("Got uid3 = %08x\n", m_uid3); @@ -66,7 +68,7 @@ SISFileHeader::fillFrom(uchar* buf, int* base) if ((crc2 << 16 | crc1) != m_uid4) { printf("Got bad crc.\n"); - exit(1); + return SIS_CORRUPTED; } m_crc = read16(start + 16); m_nlangs = read16(start + 18); @@ -108,17 +110,26 @@ SISFileHeader::fillFrom(uchar* buf, int* base) m_languagePtr = read32(start + 48); if (logLevel >= 2) printf("Languages begin at %d\n", m_languagePtr); + if (m_languagePtr >= len) + return SIS_TRUNCATED; m_filesPtr = read32(start + 52); if (logLevel >= 2) printf("Files begin at %d\n", m_filesPtr); + if (m_filesPtr >= len) + return SIS_TRUNCATED; m_reqPtr = read32(start + 56); if (logLevel >= 2) printf("Requisites begin at %d\n", m_reqPtr); + if (m_reqPtr >= len) + return SIS_TRUNCATED; m_unknown = read32(start + 60); m_componentPtr = read32(start + 64); if (logLevel >= 2) printf("Components begin at %d\n", m_componentPtr); + if (m_componentPtr >= len) + return SIS_TRUNCATED; *base += 68; + return SIS_OK; } void diff --git a/lib/sisfileheader.h b/lib/sisfileheader.h index 6f22c59..8c90511 100644 --- a/lib/sisfileheader.h +++ b/lib/sisfileheader.h @@ -23,6 +23,8 @@ #ifndef _SISFILEHEADER_H #define _SISFILEHEADER_H +#include + #include "sistypes.h" /** @@ -35,7 +37,7 @@ public: /** * Populate the fields. */ - void fillFrom(uchar* buf, int* base); + SisRC fillFrom(uchar* buf, int* base, off_t len); /** * Update the drive letter, and patch the parsed buffer. diff --git a/lib/sisfilerecord.cpp b/lib/sisfilerecord.cpp index cb2665c..baa5776 100644 --- a/lib/sisfilerecord.cpp +++ b/lib/sisfilerecord.cpp @@ -25,9 +25,12 @@ #include -void -SISFileRecord::fillFrom(uchar* buf, int* base, SISFile* sisFile) +SisRC +SISFileRecord::fillFrom(uchar* buf, int* base, off_t len, SISFile* sisFile) { + if (*base + 28 + 4 * 2 > len) + return SIS_TRUNCATED; + uchar* p = buf + *base; int size = 0; m_flags = read32(p); @@ -79,27 +82,33 @@ SISFileRecord::fillFrom(uchar* buf, int* base, SISFile* sisFile) int n = sisFile->m_header.m_nlangs; m_fileLengths = new uint32[n]; m_filePtrs = new uint32[n]; + if (*base + size + n * 8 > len) + return SIS_TRUNCATED; for (int i = 0; i < n; ++i) { m_fileLengths[i] = read32(p + size); + if (m_fileLengths[i] > len) + return SIS_TRUNCATED; size += 4; } for (int i = 0; i < n; ++i) { m_filePtrs[i] = read32(p + size); + int fileLen = m_fileLengths[i]; + if (m_filePtrs[i] + fileLen > len) + return SIS_TRUNCATED; size += 4; - int len = m_fileLengths[i]; if (logLevel >= 2) printf("File %d (for %s) is %d bytes long (at %d)\n", i, sisFile->getLanguage(i)->m_name, - len, + fileLen, m_filePtrs[i]); if (logLevel >= 1) printf("%d .. %d (%d bytes): File record (%s) for %.*s\n", m_filePtrs[i], - m_filePtrs[i] + len, - len, + m_filePtrs[i] + fileLen, + fileLen, sisFile->getLanguage(i)->m_name, m_destLength, buf + m_destPtr); } @@ -111,5 +120,6 @@ SISFileRecord::fillFrom(uchar* buf, int* base, SISFile* sisFile) printf("Unknown file flags %d\n", m_flags); } *base += size; + return SIS_OK; } diff --git a/lib/sisfilerecord.h b/lib/sisfilerecord.h index d37d64e..ae99836 100644 --- a/lib/sisfilerecord.h +++ b/lib/sisfilerecord.h @@ -25,6 +25,8 @@ #include "sistypes.h" +#include + class SISFile; /** @@ -40,7 +42,7 @@ public: /** * Populate the fields. */ - void fillFrom(uchar* buf, int* base, SISFile* sisFile); + SisRC fillFrom(uchar* buf, int* base, off_t len, SISFile* sisFile); /** * 1 if multiple language versions, otherwise 0. diff --git a/lib/sislangrecord.cpp b/lib/sislangrecord.cpp index 5540e6e..2b6afc4 100644 --- a/lib/sislangrecord.cpp +++ b/lib/sislangrecord.cpp @@ -24,15 +24,20 @@ #include -void -SISLangRecord::fillFrom(uchar* buf, int* base) +SisRC +SISLangRecord::fillFrom(uchar* buf, int* base, off_t len) { + if (*base + 2 > len) + return SIS_TRUNCATED; m_lang = read16(buf + *base); + if (m_lang > 33) // Thai, last language + return SIS_CORRUPTED; if (logLevel >= 2) printf("Got language %d (%s)\n", m_lang, langTable[m_lang].m_name); if (logLevel >= 1) printf("%d .. %d (%d bytes): Language record for %s\n", *base, *base + 2, 2, langTable[m_lang].m_name); *base += 2; + return SIS_OK; } diff --git a/lib/sislangrecord.h b/lib/sislangrecord.h index e8dbd06..9a2b5e9 100644 --- a/lib/sislangrecord.h +++ b/lib/sislangrecord.h @@ -23,6 +23,8 @@ #ifndef _SISLANGRECORD_H #define _SISLANGRECORD_H +#include + #include "sistypes.h" /** @@ -36,7 +38,7 @@ public: /** * Populate the fields. */ - void fillFrom(uchar* buf, int* base); + SisRC fillFrom(uchar* buf, int* base, off_t len); uint16 m_lang; }; diff --git a/lib/sisreqrecord.cpp b/lib/sisreqrecord.cpp index 75d9e51..c13308e 100644 --- a/lib/sisreqrecord.cpp +++ b/lib/sisreqrecord.cpp @@ -25,9 +25,13 @@ #include -void -SISReqRecord::fillFrom(uchar* buf, int* base, SISFile* sisFile) +SisRC +SISReqRecord::fillFrom(uchar* buf, int* base, off_t len, SISFile* sisFile) { + int n = sisFile->m_header.m_nreqs; + if (*base + 12 + n * 4 * 2) + return SIS_TRUNCATED; + uchar* p = buf + *base; int size = 0; @@ -35,7 +39,6 @@ SISReqRecord::fillFrom(uchar* buf, int* base, SISFile* sisFile) m_major = read16(p + 4); m_minor = read16(p + 6); m_variant = read32(p + 8); - int n = sisFile->m_header.m_nreqs; m_nameLengths = new uint32[n]; m_namePtrs = new uint32[n]; @@ -53,6 +56,11 @@ SISReqRecord::fillFrom(uchar* buf, int* base, SISFile* sisFile) for (int i = 0; i < n; ++i) { m_namePtrs[i] = read32(p + size); + if (m_namePtrs[i] + m_nameLengths[i] > len) + { + printf("Position/length too large for req record %d.\n", i); + return SIS_CORRUPTED; + } size += 4; if (logLevel >= 2) printf("Name %d (for %s) is %.*s\n", @@ -65,5 +73,6 @@ SISReqRecord::fillFrom(uchar* buf, int* base, SISFile* sisFile) printf("%d .. %d (%d bytes): Req record\n", *base, *base + size, size); *base += size; + return SIS_OK; } diff --git a/lib/sisreqrecord.h b/lib/sisreqrecord.h index 80481be..44206a1 100644 --- a/lib/sisreqrecord.h +++ b/lib/sisreqrecord.h @@ -25,6 +25,8 @@ #include "sistypes.h" +#include + class SISFile; /** @@ -38,7 +40,7 @@ public: /** * Populate the fields. */ - void fillFrom(uchar* buf, int* base, SISFile* file); + SisRC fillFrom(uchar* buf, int* base, off_t len, SISFile* file); uint32 m_uid; uint16 m_major; diff --git a/lib/sistypes.h b/lib/sistypes.h index ce8b441..c763c4f 100644 --- a/lib/sistypes.h +++ b/lib/sistypes.h @@ -27,6 +27,15 @@ typedef unsigned short uint16; typedef unsigned int uint32; typedef unsigned char uchar; +/** + * Return Codes. + */ +enum SisRC { + SIS_OK = 0, + SIS_TRUNCATED, + SIS_CORRUPTED, +}; + extern uint16 read16(uchar* p); extern uint32 read32(uchar* p); -- cgit v1.2.3