From 35944cbfc1c8e2b8845bf3e38afedf326e2b9ae6 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Fri, 8 May 2015 18:32:42 -0700 Subject: [PATCH] Validate fat_head; CERT-FI id:000000,sig:06,src:000000,op:flip1,pos:7 --- src/file.cpp | 5 +++++ src/file.h | 3 +++ src/p_mach.cpp | 44 +++++++++++++++++++++++++++++++++++--------- src/p_mach.h | 1 + 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/file.cpp b/src/file.cpp index 53a749fe..c5a2387c 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -243,6 +243,7 @@ void InputFile::sopen(const char *name, int flags, int shflags) else throwIOException(_name, errno); } + _length_orig = _length; } @@ -294,6 +295,10 @@ off_t InputFile::tell() const return super::tell(); } +off_t InputFile::st_size_orig() const +{ + return _length_orig; +} /************************************************************************* // diff --git a/src/file.h b/src/file.h index 7a8811a2..a481671e 100644 --- a/src/file.h +++ b/src/file.h @@ -108,6 +108,9 @@ public: virtual void seek(off_t off, int whence); virtual off_t tell() const; + virtual off_t st_size_orig() const; +protected: + off_t _length_orig; }; diff --git a/src/p_mach.cpp b/src/p_mach.cpp index 3337d6e8..18542310 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -1443,6 +1443,34 @@ PackMachFat::~PackMachFat() { } +unsigned PackMachFat::check_fat_head() +{ + struct Mach_fat_arch const *const arch = &fat_head.arch[0]; + unsigned nfat = fat_head.fat.nfat_arch; + if (Mach_fat_header::FAT_MAGIC!=fat_head.fat.magic + || N_FAT_ARCH < nfat) { + return 0; + } + for (unsigned j=0; j < nfat; ++j) { + unsigned const align = arch[j].align; + unsigned const mask = ~(~0u< 24) { // heuristic + throwUnknownExecutableFormat("align", 0); + } + if (mask > size) { + throwUnknownExecutableFormat("size", 0); + } + if (mask & offset + || fi->st_size_orig() < (size + offset) + || fi->st_size_orig() <= offset) { // redundant unless overflow + throwUnknownExecutableFormat("offset", 0); + } + } + return nfat; +} + const int *PackMachFat::getCompressionMethods(int /*method*/, int /*level*/) const { static const int m_nrv2e[] = { M_NRV2E_LE32, M_END }; @@ -1549,8 +1577,9 @@ void PackMachFat::unpack(OutputFile *fo) fo->write(&fat_head, sizeof(fat_head.fat) + fat_head.fat.nfat_arch * sizeof(fat_head.arch[0])); } + unsigned const nfat = check_fat_head(); unsigned length; - for (unsigned j=0; j < fat_head.fat.nfat_arch; ++j) { + for (unsigned j=0; j < nfat; ++j) { unsigned base = (fo ? fo->unset_extent() : 0); // actual length base += ~(~0u<readx(&fat_head, sizeof(fat_head)); - if (Mach_fat_header::FAT_MAGIC!=fat_head.fat.magic - || N_FAT_ARCH < fat_head.fat.nfat_arch) { - return false; - } - for (unsigned j=0; j < fat_head.fat.nfat_arch; ++j) { + unsigned const nfat = check_fat_head(); + for (unsigned j=0; j < nfat; ++j) { fi->set_extent(fat_head.arch[j].offset, fat_head.arch[j].size); fi->seek(0, SEEK_SET); switch (arch[j].cputype) { @@ -1684,11 +1710,11 @@ int PackMachFat::canUnpack() struct Mach_fat_arch *arch = &fat_head.arch[0]; fi->readx(&fat_head, sizeof(fat_head)); - if (Mach_fat_header::FAT_MAGIC!=fat_head.fat.magic - || N_FAT_ARCH < fat_head.fat.nfat_arch) { + unsigned const nfat = check_fat_head(); + if (0 == nfat) { return false; } - for (unsigned j=0; j < fat_head.fat.nfat_arch; ++j) { + for (unsigned j=0; j < nfat; ++j) { fi->set_extent(fat_head.arch[j].offset, fat_head.arch[j].size); fi->seek(0, SEEK_SET); switch (arch[j].cputype) { diff --git a/src/p_mach.h b/src/p_mach.h index 0570d067..79da8416 100644 --- a/src/p_mach.h +++ b/src/p_mach.h @@ -855,6 +855,7 @@ public: protected: // implementation + virtual unsigned check_fat_head(); // number of architectures virtual void pack(OutputFile *fo); virtual void unpack(OutputFile *fo); virtual void list();