aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Brahneborg <basic@chello.se>2002-03-03 22:02:40 +0000
committerDaniel Brahneborg <basic@chello.se>2002-03-03 22:02:40 +0000
commita4dcb0ecf632832258ebb523c6bc39b7b94f8775 (patch)
tree18cf38bb6ecd95671401414c2ba8381b6c90132f
parentd92c2abcca7d9270f49cbfb09a27bfda86642c31 (diff)
downloadplptools-a4dcb0ecf632832258ebb523c6bc39b7b94f8775.tar.gz
plptools-a4dcb0ecf632832258ebb523c6bc39b7b94f8775.tar.bz2
plptools-a4dcb0ecf632832258ebb523c6bc39b7b94f8775.zip
Add buffer overflow checks to handle truncated and corrupted sis files.
-rw-r--r--lib/siscomponentrecord.cpp23
-rw-r--r--lib/siscomponentrecord.h4
-rw-r--r--lib/sisfile.cpp52
-rw-r--r--lib/sisfile.h4
-rw-r--r--lib/sisfileheader.cpp21
-rw-r--r--lib/sisfileheader.h4
-rw-r--r--lib/sisfilerecord.cpp22
-rw-r--r--lib/sisfilerecord.h4
-rw-r--r--lib/sislangrecord.cpp9
-rw-r--r--lib/sislangrecord.h4
-rw-r--r--lib/sisreqrecord.cpp15
-rw-r--r--lib/sisreqrecord.h4
-rw-r--r--lib/sistypes.h9
-rw-r--r--sisinstall/Makefile.am3
-rw-r--r--sisinstall/sisinstaller.cpp21
-rw-r--r--sisinstall/sisinstaller.h6
-rw-r--r--sisinstall/sismain.cpp17
17 files changed, 173 insertions, 49 deletions
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 <sys/types.h>
+
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 <stdio.h>
-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 <sys/types.h>
+
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 <sys/types.h>
+
#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 <stdio.h>
-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 <sys/types.h>
+
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 <stdio.h>
-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 <sys/types.h>
+
#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 <stdio.h>
-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 <sys/types.h>
+
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);
diff --git a/sisinstall/Makefile.am b/sisinstall/Makefile.am
index 67c990d..09c2620 100644
--- a/sisinstall/Makefile.am
+++ b/sisinstall/Makefile.am
@@ -5,8 +5,7 @@ INCLUDES=-I$(top_srcdir)/lib
bin_PROGRAMS = sisinstall
sisinstall_LDADD = $(top_srcdir)/lib/libplp.la
sisinstall_SOURCES = psion.cpp sisinstaller.cpp sismain.cpp \
- fakepsion.cpp
-sisinstall_HEADERS = fakepsion.h
+ fakepsion.cpp fakepsion.h
EXTRA_DIST = psion.h sisinstaller.h
maintainer-clean-local:
diff --git a/sisinstall/sisinstaller.cpp b/sisinstall/sisinstaller.cpp
index db58720..a82c9a2 100644
--- a/sisinstall/sisinstaller.cpp
+++ b/sisinstall/sisinstaller.cpp
@@ -152,10 +152,16 @@ SISInstaller::installFile(SISFileRecord* fileRecord)
printf("Recursive sis file...\n");
SISFile sisFile;
uchar* buf2 = m_buf + fileRecord->m_filePtrs[m_fileNo];
- sisFile.fillFrom(buf2);
+ off_t len = fileRecord->m_fileLengths[m_fileNo];
+ SisRC rc = sisFile.fillFrom(buf2, len);
+ if (rc != SIS_OK)
+ {
+ printf("Could not read contained sis file, rc = %d\n", rc);
+ break;
+ }
SISInstaller installer;
installer.setPsion(m_psion);
- installer.run(&sisFile, buf2, m_file);
+ rc = installer.run(&sisFile, buf2, len, m_file);
if (0 == m_drive)
{
m_drive = sisFile.m_header.m_installationDrive;
@@ -186,14 +192,14 @@ SISInstaller::setPsion(Psion* psion)
m_psion = psion;
}
-void
-SISInstaller::run(SISFile* file, uchar* buf)
+SisRC
+SISInstaller::run(SISFile* file, uchar* buf, off_t len)
{
- run(file, buf, 0);
+ return run(file, buf, len, 0);
}
-void
-SISInstaller::run(SISFile* file, uchar* buf, SISFile* parent)
+SisRC
+SISInstaller::run(SISFile* file, uchar* buf, off_t len, SISFile* parent)
{
int n;
int lang;
@@ -318,6 +324,7 @@ SISInstaller::run(SISFile* file, uchar* buf, SISFile* parent)
printf("Creating residual sis file %s\n", resname);
copyBuf(buf, firstFile, resname);
delete[] resname;
+ return SIS_OK;
}
void
diff --git a/sisinstall/sisinstaller.h b/sisinstall/sisinstaller.h
index 6bc6c18..00077f3 100644
--- a/sisinstall/sisinstaller.h
+++ b/sisinstall/sisinstaller.h
@@ -3,6 +3,8 @@
#include "sistypes.h"
+#include <sys/types.h>
+
class Psion;
class SISFile;
class SISFileRecord;
@@ -15,9 +17,9 @@ class SISInstaller
{
public:
- void run(SISFile* file, uchar* buf);
+ SisRC run(SISFile* file, uchar* buf, off_t len);
- void run(SISFile* file, uchar* buf, SISFile* parent);
+ SisRC run(SISFile* file, uchar* buf, off_t len, SISFile* parent);
/**
* Ask the user which drive to install to.
diff --git a/sisinstall/sismain.cpp b/sisinstall/sismain.cpp
index 8516b0f..5a5b640 100644
--- a/sisinstall/sismain.cpp
+++ b/sisinstall/sismain.cpp
@@ -67,12 +67,19 @@ void main(int argc, char* argv[])
}
createCRCTable();
SISFile sisFile;
- sisFile.fillFrom(buf);
- if (!dryrun)
+ SisRC rc = sisFile.fillFrom(buf, len);
+ if (rc == SIS_OK)
{
- SISInstaller installer;
- installer.setPsion(psion);
- installer.run(&sisFile, buf);
+ if (!dryrun)
+ {
+ SISInstaller installer;
+ installer.setPsion(psion);
+ installer.run(&sisFile, buf, len);
+ }
+ }
+ else
+ {
+ printf("Could not parse the sis file.\n");
}
psion->disconnect();