TestJARFuzzing.cpp (5095B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #include <iostream> 8 9 #include "FuzzingInterface.h" 10 #include "nsComponentManagerUtils.h" 11 #include "nsCOMPtr.h" 12 #include "nsIZipReader.h" 13 #include "nsNetUtil.h" 14 #include "nsNetCID.h" 15 #include "nsPrintfCString.h" 16 #include "nsString.h" 17 #include "nsIInputStream.h" 18 #include "nsIStringEnumerator.h" 19 20 enum FuzzMethodType { 21 eTest = 0, 22 eGetEntry, 23 eHasEntry, 24 eFindEntries, 25 eInputStream, 26 eOpenInner, 27 eLastMethod, 28 }; 29 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID); 30 31 template <typename T> 32 T jar_get_num(char** buf, size_t* size) { 33 if (sizeof(T) > *size) { 34 return 0; 35 } 36 37 T* iptr = reinterpret_cast<T*>(*buf); 38 *buf += sizeof(T); 39 *size -= sizeof(T); 40 return *iptr; 41 } 42 43 nsAutoCString jar_get_string(char** buf, size_t* size) { 44 uint8_t len = jar_get_num<uint8_t>(buf, size); 45 if (len > *size) { 46 len = static_cast<uint8_t>(*size); 47 } 48 nsAutoCString str(*buf, len); 49 50 *buf += len; 51 *size -= len; 52 return str; 53 } 54 55 nsresult FuzzEntries(char** buf, size_t* size, nsIZipReader* aReader, 56 const nsACString& aName) { 57 uint8_t iters = jar_get_num<uint8_t>(buf, size); 58 nsresult rv; 59 for (uint8_t i = 0; i < iters; ++i) { 60 nsAutoCString out; 61 uint64_t written; 62 nsCOMPtr<nsIZipEntry> entry; 63 nsCOMPtr<nsIInputStream> stream; 64 65 switch (jar_get_num<uint8_t>(buf, size) % eLastMethod) { 66 case eTest: { 67 rv = aReader->Test(aName); 68 NS_ENSURE_SUCCESS(rv, rv); 69 break; 70 } 71 case eGetEntry: { 72 rv = aReader->GetEntry(aName, getter_AddRefs(entry)); 73 NS_ENSURE_SUCCESS(rv, rv); 74 break; 75 } 76 case eHasEntry: { 77 bool has = false; 78 rv = aReader->HasEntry(aName, &has); 79 NS_ENSURE_SUCCESS(rv, rv); 80 break; 81 } 82 case eInputStream: 83 rv = aReader->GetInputStream(aName, getter_AddRefs(stream)); 84 NS_ENSURE_SUCCESS(rv, rv); 85 if (NS_FAILED(rv)) { 86 break; 87 } 88 rv = NS_ReadInputStreamToString(stream, out, -1, &written); 89 NS_ENSURE_SUCCESS(rv, rv); 90 break; 91 default: 92 break; 93 } 94 } 95 return NS_OK; 96 } 97 98 nsresult FuzzReader(char** buf, size_t* size, nsIZipReader* aReader) { 99 nsresult rv; 100 nsAutoCString name; 101 nsCOMPtr<nsIZipEntry> entry; 102 bool has = false; 103 nsAutoCString pattern; 104 nsCOMPtr<nsIUTF8StringEnumerator> enumerator; 105 nsCOMPtr<nsIInputStream> stream; 106 bool hasMore; 107 nsAutoCString out; 108 uint64_t written; 109 nsCOMPtr<nsIZipReader> newReader = do_CreateInstance(kZipReaderCID, &rv); 110 switch (jar_get_num<uint8_t>(buf, size) % eLastMethod) { 111 case eTest: 112 rv = aReader->Test(""_ns); 113 NS_ENSURE_SUCCESS(rv, rv); 114 break; 115 case eGetEntry: 116 name = jar_get_string(buf, size); 117 rv = aReader->GetEntry(name, getter_AddRefs(entry)); 118 NS_ENSURE_SUCCESS(rv, rv); 119 break; 120 case eHasEntry: 121 name = jar_get_string(buf, size); 122 rv = aReader->HasEntry(name, &has); 123 NS_ENSURE_SUCCESS(rv, rv); 124 break; 125 case eFindEntries: 126 pattern = jar_get_string(buf, size); 127 rv = aReader->FindEntries(pattern, getter_AddRefs(enumerator)); 128 NS_ENSURE_SUCCESS(rv, rv); 129 while (NS_SUCCEEDED(enumerator->HasMore(&hasMore)) && hasMore) { 130 if (NS_FAILED(enumerator->GetNext(name))) { 131 break; 132 } 133 rv = FuzzEntries(buf, size, aReader, name); 134 NS_ENSURE_SUCCESS(rv, rv); 135 } 136 137 break; 138 case eInputStream: 139 name = jar_get_string(buf, size); 140 rv = aReader->GetInputStream(name, getter_AddRefs(stream)); 141 NS_ENSURE_SUCCESS(rv, rv); 142 rv = NS_ReadInputStreamToString(stream, out, -1, &written); 143 NS_ENSURE_SUCCESS(rv, rv); 144 break; 145 case eOpenInner: 146 name = jar_get_string(buf, size); 147 rv = newReader->OpenInner(aReader, name); 148 NS_ENSURE_SUCCESS(rv, rv); 149 rv = FuzzReader(buf, size, newReader); 150 NS_ENSURE_SUCCESS(rv, rv); 151 break; 152 default: 153 break; 154 } 155 return rv; 156 } 157 158 static int FuzzingRunJARParser(const uint8_t* data, size_t size) { 159 char* buf = (char*)data; 160 nsresult rv; 161 162 nsCOMPtr<nsIURI> uri; 163 nsAutoCString jardata = jar_get_string(&buf, &size); 164 165 nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv); 166 rv = reader->OpenMemory((void*)jardata.get(), jardata.Length()); 167 NS_ENSURE_SUCCESS(rv, 0); 168 169 #if 0 170 // For easily exporting the last test case that triggered a crash. 171 FILE * f = fopen("/tmp/input.jar", "wb"); 172 fwrite((void*)jardata.get(), 1, jardata.Length(), f); 173 fclose(f); 174 #endif 175 176 uint8_t iters = jar_get_num<uint8_t>(&buf, &size); 177 for (uint8_t i = 0; i < iters; ++i) { 178 rv = FuzzReader(&buf, &size, reader); 179 NS_ENSURE_SUCCESS(rv, 0); 180 } 181 182 return 0; 183 } 184 185 MOZ_FUZZING_INTERFACE_RAW(nullptr, FuzzingRunJARParser, JARParser);