diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp index a3beca5f809..90916c28b4b 100644 --- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -27,6 +27,8 @@ #include "nsIChromeRegistry.h" #include "nsISimpleEnumerator.h" #include "nsISubstitutingProtocolHandler.h" +#include "zlib.h" +#include "nsZipArchive.h" #endif using namespace mozilla; @@ -469,6 +471,30 @@ nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, } #ifdef MOZ_CRASHREPORTER +static inline nsresult +ComputeCRC32(nsIFile* aFile, uint32_t* aResult) +{ + PRFileDesc* fd; + nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t crc = crc32(0, nullptr, 0); + + unsigned char buf[512]; + int32_t n; + while ((n = PR_Read(fd, buf, sizeof(buf))) > 0) { + crc = crc32(crc, buf, n); + } + PR_Close(fd); + + if (n < 0) { + return NS_ERROR_FAILURE; + } + + *aResult = crc; + return NS_OK; +} + static void ListInterestingFiles(nsString& aAnnotation, nsIFile* aFile, const nsTArray& aInterestingFilenames) @@ -488,7 +514,14 @@ ListInterestingFiles(nsString& aAnnotation, nsIFile* aFile, } else { aAnnotation.AppendLiteral("???"); } - aAnnotation.AppendLiteral(" bytes)\n"); + aAnnotation.AppendLiteral(" bytes, crc32 = "); + uint32_t crc; + nsresult rv = ComputeCRC32(aFile, &crc); + if (NS_SUCCEEDED(rv)) { + aAnnotation.AppendPrintf("0x%08x)\n", crc); + } else { + aAnnotation.AppendPrintf("error 0x%08x)\n", uint32_t(rv)); + } return; } } @@ -553,6 +586,14 @@ AnnotateCrashReport(nsIURI* aURI) annotation.Append(NS_ConvertUTF8toUTF16(spec).get()); annotation.Append('\n'); + annotation.AppendLiteral("NS_ERROR_FILE_CORRUPTION reason: "); + if (nsZipArchive::sFileCorruptedReason) { + annotation.Append(NS_ConvertUTF8toUTF16(nsZipArchive::sFileCorruptedReason).get()); + annotation.Append('\n'); + } else { + annotation.AppendLiteral("(none)\n"); + } + // The jar: or file: URL that the sheet's resource: or chrome: URL // resolves to. if (scheme.EqualsLiteral("resource")) { @@ -739,6 +780,9 @@ nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI, } +#ifdef MOZ_CRASHREPORTER + nsZipArchive::sFileCorruptedReason = nullptr; +#endif nsresult rv = gCSSLoader->LoadSheetSync(aURI, aParsingMode, true, getter_AddRefs(aSheet)); if (NS_FAILED(rv)) { diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index 8ea93e7a5d6..b50289124a3 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -446,14 +446,19 @@ nsJAR::LoadEntry(const nsACString &aFilename, char** aBuf, uint32_t* aBufLen) uint64_t len64; rv = manifestStream->Available(&len64); if (NS_FAILED(rv)) return rv; - NS_ENSURE_TRUE(len64 < UINT32_MAX, NS_ERROR_FILE_CORRUPTED); // bug 164695 + if (len64 >= UINT32_MAX) { // bug 164695 + nsZipArchive::sFileCorruptedReason = "nsJAR: invalid manifest size"; + return NS_ERROR_FILE_CORRUPTED; + } uint32_t len = (uint32_t)len64; buf = (char*)malloc(len+1); if (!buf) return NS_ERROR_OUT_OF_MEMORY; uint32_t bytesRead; rv = manifestStream->Read(buf, len, &bytesRead); - if (bytesRead != len) + if (bytesRead != len) { + nsZipArchive::sFileCorruptedReason = "nsJAR: manifest too small"; rv = NS_ERROR_FILE_CORRUPTED; + } if (NS_FAILED(rv)) { free(buf); return rv; @@ -539,6 +544,7 @@ nsJAR::ParseManifest() if (more) { mParsedManifest = true; + nsZipArchive::sFileCorruptedReason = "nsJAR: duplicate manifests"; return NS_ERROR_FILE_CORRUPTED; // More than one MF file } @@ -638,8 +644,10 @@ nsJAR::ParseOneFile(const char* filebuf, int16_t aFileType) curLine.Assign(filebuf, linelen); if ( ((aFileType == JAR_MF) && !curLine.Equals(JAR_MF_HEADER) ) || - ((aFileType == JAR_SF) && !curLine.Equals(JAR_SF_HEADER) ) ) + ((aFileType == JAR_SF) && !curLine.Equals(JAR_SF_HEADER) ) ) { + nsZipArchive::sFileCorruptedReason = "nsJAR: invalid manifest header"; return NS_ERROR_FILE_CORRUPTED; + } //-- Skip header section do { diff --git a/modules/libjar/nsJARInputStream.cpp b/modules/libjar/nsJARInputStream.cpp index 4a4c1d64cf3..4df5d7a0495 100644 --- a/modules/libjar/nsJARInputStream.cpp +++ b/modules/libjar/nsJARInputStream.cpp @@ -58,8 +58,10 @@ nsJARInputStream::InitFile(nsJAR *aJar, nsZipItem *item) // Must keep handle to filepointer and mmap structure as long as we need access to the mmapped data mFd = aJar->mZip->GetFD(); mZs.next_in = (Bytef *)aJar->mZip->GetData(item); - if (!mZs.next_in) + if (!mZs.next_in) { + nsZipArchive::sFileCorruptedReason = "nsJARInputStream: !mZs.next_in"; return NS_ERROR_FILE_CORRUPTED; + } mZs.avail_in = item->Size(); mOutSize = item->RealSize(); mZs.total_out = 0; @@ -266,8 +268,10 @@ nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount, // now inflate int zerr = inflate(&mZs, Z_SYNC_FLUSH); - if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) + if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) { + nsZipArchive::sFileCorruptedReason = "nsJARInputStream: error while inflating"; return NS_ERROR_FILE_CORRUPTED; + } *aBytesRead = (mZs.total_out - oldTotalOut); @@ -280,8 +284,10 @@ nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount, inflateEnd(&mZs); // stop returning valid data as soon as we know we have a bad CRC - if (mOutCrc != mInCrc) + if (mOutCrc != mInCrc) { + nsZipArchive::sFileCorruptedReason = "nsJARInputStream: crc mismatch"; return NS_ERROR_FILE_CORRUPTED; + } } return NS_OK; diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 508319b5e75..568d0b68eab 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -444,6 +444,7 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname, uint32_t count = 0; uint8_t* buf = cursor.Read(&count); if (!buf) { + nsZipArchive::sFileCorruptedReason = "nsZipArchive: Read() failed to return a buffer"; rv = NS_ERROR_FILE_CORRUPTED; break; } else if (count == 0) { @@ -644,22 +645,28 @@ MOZ_WIN_MEM_TRY_BEGIN } } - if (!centralOffset) + if (!centralOffset) { + nsZipArchive::sFileCorruptedReason = "nsZipArchive: no central offset"; return NS_ERROR_FILE_CORRUPTED; + } buf = startp + centralOffset; // avoid overflow of startp + centralOffset. - if (buf < startp) + if (buf < startp) { + nsZipArchive::sFileCorruptedReason = "nsZipArchive: overflow looking for central directory"; return NS_ERROR_FILE_CORRUPTED; + } //-- Read the central directory headers uint32_t sig = 0; while (buf + int32_t(sizeof(uint32_t)) <= endp && (sig = xtolong(buf)) == CENTRALSIG) { // Make sure there is enough data available. - if (endp - buf < ZIPCENTRAL_SIZE) + if (endp - buf < ZIPCENTRAL_SIZE) { + nsZipArchive::sFileCorruptedReason = "nsZipArchive: central directory too small"; return NS_ERROR_FILE_CORRUPTED; + } // Read the fixed-size data. ZipCentral* central = (ZipCentral*)buf; @@ -672,9 +679,13 @@ MOZ_WIN_MEM_TRY_BEGIN // Sanity check variable sizes and refuse to deal with // anything too big: it's likely a corrupt archive. if (namelen < 1 || - namelen > kMaxNameLength || - buf >= buf + diff || // No overflow + namelen > kMaxNameLength) { + nsZipArchive::sFileCorruptedReason = "nsZipArchive: namelen out of range"; + return NS_ERROR_FILE_CORRUPTED; + } + if (buf >= buf + diff || // No overflow buf >= endp - diff) { + nsZipArchive::sFileCorruptedReason = "nsZipArchive: overflow looking for next item"; return NS_ERROR_FILE_CORRUPTED; } @@ -697,8 +708,10 @@ MOZ_WIN_MEM_TRY_BEGIN sig = 0; } /* while reading central directory records */ - if (sig != ENDSIG) + if (sig != ENDSIG) { + nsZipArchive::sFileCorruptedReason = "nsZipArchive: unexpected sig"; return NS_ERROR_FILE_CORRUPTED; + } // Make the comment available for consumers. if (endp - buf >= ZIPEND_SIZE) { @@ -1213,3 +1226,6 @@ nsZipItemPtr_base::nsZipItemPtr_base(nsZipArchive *aZip, return; } } + +/* static */ const char* +nsZipArchive::sFileCorruptedReason = nullptr; diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h index 242ee4a3c8b..73a524e9918 100644 --- a/modules/libjar/nsZipArchive.h +++ b/modules/libjar/nsZipArchive.h @@ -102,6 +102,8 @@ class nsZipArchive final ~nsZipArchive(); public: + static const char* sFileCorruptedReason; + /** constructing does not open the archive. See OpenArchive() */ nsZipArchive(); diff --git a/xpcom/build/FileLocation.cpp b/xpcom/build/FileLocation.cpp index 67a558b4b10..73ea5c57852 100644 --- a/xpcom/build/FileLocation.cpp +++ b/xpcom/build/FileLocation.cpp @@ -233,7 +233,11 @@ FileLocation::Data::Copy(char* aBuf, uint32_t aLen) aLen, true); uint32_t readLen; cursor.Copy(&readLen); - return (readLen == aLen) ? NS_OK : NS_ERROR_FILE_CORRUPTED; + if (readLen != aLen) { + nsZipArchive::sFileCorruptedReason = "FileLocation::Data: insufficient data"; + return NS_ERROR_FILE_CORRUPTED; + } + return NS_OK; } #endif // !defined(MOZILLA_XPCOMRT_API) return NS_ERROR_NOT_INITIALIZED;