Bug 1798631 - Add zip reader fuzzer r=decoder,necko-reviewers,kershaw

Add back nsIZipReader.openMemory - Backed out changeset 1b442368d567

Differential Revision: https://phabricator.services.mozilla.com/D162239
This commit is contained in:
Valentin Gosu 2023-08-10 12:42:00 +00:00
parent bc10fd3dc9
commit bc75bd4701
7 changed files with 229 additions and 0 deletions

View File

@ -43,5 +43,6 @@ XPCOM_MANIFESTS += [
]
include("/ipc/chromium/chromium-config.mozbuild")
include("/tools/fuzzing/libfuzzer-config.mozbuild")
FINAL_LIBRARY = "xul"

View File

@ -77,6 +77,16 @@ interface nsIZipReader : nsISupports
*/
void openInner(in nsIZipReader zipReader, in AUTF8String zipEntry);
/**
* Opens a zip file stored in memory; the file attribute will be null.
*
* The ZipReader does not copy or take ownership of this memory; the
* caller must ensure that it is valid and unmodified until the
* ZipReader is closed or destroyed, and must free the memory as
* appropriate afterwards.
*/
void openMemory(in voidPtr aData, in unsigned long aLength);
/**
* The file that represents the zip with which this zip reader was
* initialized. This will be null if there is no underlying file.

View File

@ -149,6 +149,21 @@ nsJAR::OpenInner(nsIZipReader* aZipReader, const nsACString& aZipEntry) {
return mZip ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsJAR::OpenMemory(void* aData, uint32_t aLength) {
NS_ENSURE_ARG_POINTER(aData);
RecursiveMutexAutoLock lock(mLock);
if (mZip) return NS_ERROR_FAILURE; // Already open!
RefPtr<nsZipHandle> handle;
nsresult rv = nsZipHandle::Init(static_cast<uint8_t*>(aData), aLength,
getter_AddRefs(handle));
if (NS_FAILED(rv)) return rv;
mZip = nsZipArchive::OpenArchive(handle);
return mZip ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsJAR::GetFile(nsIFile** result) {
RecursiveMutexAutoLock lock(mLock);

View File

@ -259,6 +259,20 @@ nsresult nsZipHandle::Init(nsZipArchive* zip, const char* entry,
return NS_OK;
}
nsresult nsZipHandle::Init(const uint8_t* aData, uint32_t aLen,
nsZipHandle** aRet) {
RefPtr<nsZipHandle> handle = new nsZipHandle();
handle->mFileStart = aData;
handle->mTotalLen = aLen;
nsresult rv = handle->findDataStart();
if (NS_FAILED(rv)) {
return rv;
}
handle.forget(aRet);
return NS_OK;
}
// This function finds the start of the ZIP data. If the file is a regular ZIP,
// this is just the start of the file. If the file is a CRX file, the start of
// the data is after the CRX header.

View File

@ -364,6 +364,7 @@ class nsZipHandle final {
static nsresult Init(nsIFile* file, nsZipHandle** ret,
PRFileDesc** aFd = nullptr);
static nsresult Init(nsZipArchive* zip, const char* entry, nsZipHandle** ret);
static nsresult Init(const uint8_t* aData, uint32_t aLen, nsZipHandle** aRet);
NS_METHOD_(MozExternalRefCountType) AddRef(void);
NS_METHOD_(MozExternalRefCountType) Release(void);

View File

@ -0,0 +1,187 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include <iostream>
#include "FuzzingInterface.h"
#include "nsComponentManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsIZipReader.h"
#include "nsNetUtil.h"
#include "nsNetCID.h"
#include "nsPrintfCString.h"
#include "nsString.h"
#include "mozilla/Span.h"
#include "mozilla/Unused.h"
#include "nsIInputStream.h"
#include "nsIStringEnumerator.h"
enum FuzzMethodType {
eTest = 0,
eGetEntry,
eHasEntry,
eFindEntries,
eInputStream,
eOpenInner,
eLastMethod,
};
static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
template <typename T>
T jar_get_num(char** buf, size_t* size) {
if (sizeof(T) > *size) {
return 0;
}
T* iptr = reinterpret_cast<T*>(*buf);
*buf += sizeof(T);
*size -= sizeof(T);
return *iptr;
}
nsAutoCString jar_get_string(char** buf, size_t* size) {
uint8_t len = jar_get_num<uint8_t>(buf, size);
if (len > *size) {
len = static_cast<uint8_t>(*size);
}
nsAutoCString str(*buf, len);
*buf += len;
*size -= len;
return str;
}
nsresult FuzzEntries(char** buf, size_t* size, nsIZipReader* aReader,
const nsACString& aName) {
uint8_t iters = jar_get_num<uint8_t>(buf, size);
nsresult rv;
for (uint8_t i = 0; i < iters; ++i) {
nsAutoCString out;
uint64_t written;
nsCOMPtr<nsIZipEntry> entry;
nsCOMPtr<nsIInputStream> stream;
switch (jar_get_num<uint8_t>(buf, size) % eLastMethod) {
case eTest: {
rv = aReader->Test(aName);
NS_ENSURE_SUCCESS(rv, rv);
break;
}
case eGetEntry: {
rv = aReader->GetEntry(aName, getter_AddRefs(entry));
NS_ENSURE_SUCCESS(rv, rv);
break;
}
case eHasEntry: {
bool has = false;
rv = aReader->HasEntry(aName, &has);
NS_ENSURE_SUCCESS(rv, rv);
break;
}
case eInputStream:
rv = aReader->GetInputStream(aName, getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
break;
}
rv = NS_ReadInputStreamToString(stream, out, -1, &written);
NS_ENSURE_SUCCESS(rv, rv);
break;
default:
break;
}
}
return NS_OK;
}
nsresult FuzzReader(char** buf, size_t* size, nsIZipReader* aReader) {
nsresult rv;
nsAutoCString name;
nsCOMPtr<nsIZipEntry> entry;
bool has = false;
nsAutoCString pattern;
nsCOMPtr<nsIUTF8StringEnumerator> enumerator;
nsCOMPtr<nsIInputStream> stream;
bool hasMore;
nsAutoCString out;
uint64_t written;
nsCOMPtr<nsIZipReader> newReader = do_CreateInstance(kZipReaderCID, &rv);
switch (jar_get_num<uint8_t>(buf, size) % eLastMethod) {
case eTest:
rv = aReader->Test(""_ns);
NS_ENSURE_SUCCESS(rv, rv);
break;
case eGetEntry:
name = jar_get_string(buf, size);
rv = aReader->GetEntry(name, getter_AddRefs(entry));
NS_ENSURE_SUCCESS(rv, rv);
break;
case eHasEntry:
name = jar_get_string(buf, size);
rv = aReader->HasEntry(name, &has);
NS_ENSURE_SUCCESS(rv, rv);
break;
case eFindEntries:
pattern = jar_get_string(buf, size);
rv = aReader->FindEntries(pattern, getter_AddRefs(enumerator));
NS_ENSURE_SUCCESS(rv, rv);
while (NS_SUCCEEDED(enumerator->HasMore(&hasMore)) && hasMore) {
if (NS_FAILED(enumerator->GetNext(name))) {
break;
}
rv = FuzzEntries(buf, size, aReader, name);
NS_ENSURE_SUCCESS(rv, rv);
}
break;
case eInputStream:
name = jar_get_string(buf, size);
rv = aReader->GetInputStream(name, getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_ReadInputStreamToString(stream, out, -1, &written);
NS_ENSURE_SUCCESS(rv, rv);
break;
case eOpenInner:
name = jar_get_string(buf, size);
rv = newReader->OpenInner(aReader, name);
NS_ENSURE_SUCCESS(rv, rv);
rv = FuzzReader(buf, size, newReader);
NS_ENSURE_SUCCESS(rv, rv);
break;
default:
break;
}
return rv;
}
static int FuzzingRunJARParser(const uint8_t* data, size_t size) {
char* buf = (char*)data;
nsresult rv;
nsCOMPtr<nsIURI> uri;
nsAutoCString jardata = jar_get_string(&buf, &size);
nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv);
rv = reader->OpenMemory((void*)jardata.get(), jardata.Length());
NS_ENSURE_SUCCESS(rv, 0);
#if 0
// For easily exporting the last test case that triggered a crash.
FILE * f = fopen("/tmp/input.jar", "wb");
fwrite((void*)jardata.get(), 1, jardata.Length(), f);
fclose(f);
#endif
uint8_t iters = jar_get_num<uint8_t>(&buf, &size);
for (uint8_t i = 0; i < iters; ++i) {
rv = FuzzReader(&buf, &size, reader);
NS_ENSURE_SUCCESS(rv, 0);
}
return 0;
}
MOZ_FUZZING_INTERFACE_RAW(nullptr, FuzzingRunJARParser, JARParser);

View File

@ -7,6 +7,7 @@
UNIFIED_SOURCES += [
"FuzzingStreamListener.cpp",
"TestHttpFuzzing.cpp",
"TestJARFuzzing.cpp",
"TestURIFuzzing.cpp",
"TestWebsocketFuzzing.cpp",
]