Bug 1391268 - 1. Add call to verify CRC; r?glandium
To reliably detect corrupt APK, this patch adds a GeckoLoader.verifyCRC
call to enable verification of CRC before extracting libs.
MozReview-Commit-ID: 5EpIfwREGIv
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
@@ -486,16 +486,17 @@ public final class GeckoLoader {
thread.getUncaughtExceptionHandler();
if (uncaughtHandler != null) {
uncaughtHandler.uncaughtException(thread, new AbortException(msg));
}
}
// These methods are implemented in mozglue/android/nsGeckoUtils.cpp
private static native void putenv(String map);
+ public static native boolean verifyCRC(String apkName);
// These methods are implemented in mozglue/android/APKOpen.cpp
public static native void nativeRun(String[] args, int crashFd, int ipcFd);
private static native void loadGeckoLibsNative(String apkName);
private static native void loadSQLiteLibsNative(String apkName);
private static native void loadNSSLibsNative(String apkName);
public static native boolean neonCompatible();
public static native void suppressCrashDialog();
--- a/mozglue/android/nsGeckoUtils.cpp
+++ b/mozglue/android/nsGeckoUtils.cpp
@@ -21,16 +21,32 @@ Java_org_mozilla_gecko_mozglue_GeckoLoad
// better to do here
str = jenv->GetStringUTFChars(map, nullptr);
if (str == nullptr)
return;
putenv(strdup(str));
jenv->ReleaseStringUTFChars(map, str);
}
+extern "C" APKOPEN_EXPORT jboolean MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_verifyCRC(JNIEnv *jenv, jclass, jstring jApkName) {
+ const char* str;
+ // XXX: java doesn't give us true UTF8, we should figure out something
+ // better to do here
+ str = jenv->GetStringUTFChars(jApkName, nullptr);
+ if (str == nullptr) {
+ return false;
+ }
+
+ RefPtr<Zip> zip = Zip::Create(str);
+ const bool valid = zip->VerifyCRC();
+ jenv->ReleaseStringUTFChars(jApkName, str);
+ return jboolean(valid);
+}
+
extern "C"
__attribute__ ((visibility("default")))
jobject MOZ_JNICALL
Java_org_mozilla_gecko_mozglue_DirectBufferAllocator_nativeAllocateDirectBuffer(JNIEnv *jenv, jclass, jlong size)
{
jobject buffer = nullptr;
void* mem = malloc(size);
if (mem) {
--- a/mozglue/linker/Zip.cpp
+++ b/mozglue/linker/Zip.cpp
@@ -179,16 +179,76 @@ Zip::GetFirstEntry() const
entries = DirectoryEntry::validate(static_cast<const char *>(mapped)
+ end->offset);
if (!entries) {
ERROR("%s - Couldn't find central directory record", name);
}
return entries;
}
+bool
+Zip::VerifyCRC() const
+{
+ AutoLock lock(&mutex);
+
+ for (const DirectoryEntry *entry = GetFirstEntry();
+ entry; entry = entry->GetNext()) {
+ const LocalFile *file = LocalFile::validate(
+ static_cast<const char *>(mapped) + entry->offset);
+ uint32_t crc = crc32(0, nullptr, 0);
+
+ DEBUG_LOG("%.*s: crc=%08x", int(entry->filenameSize),
+ reinterpret_cast<const char *>(entry) + sizeof(*entry),
+ uint32_t(entry->CRC32));
+
+ if (entry->compression == Stream::Type::STORE) {
+ crc = crc32(crc, static_cast<const uint8_t*>(file->GetData()),
+ entry->compressedSize);
+ DEBUG_LOG(" STORE size=%d crc=%08x", int(entry->compressedSize), crc);
+
+ } else if (entry->compression == Stream::Type::DEFLATE) {
+ zxx_stream zstream;
+ Bytef buffer[1024];
+ zstream.avail_in = entry->compressedSize;
+ zstream.next_in = reinterpret_cast<Bytef *>(
+ const_cast<void *>(file->GetData()));
+
+ if (inflateInit2(&zstream, -MAX_WBITS) != Z_OK) {
+ return false;
+ }
+
+ for (;;) {
+ zstream.avail_out = sizeof(buffer);
+ zstream.next_out = buffer;
+
+ int ret = inflate(&zstream, Z_SYNC_FLUSH);
+ crc = crc32(crc, buffer, sizeof(buffer) - zstream.avail_out);
+
+ if (ret == Z_STREAM_END) {
+ break;
+ } else if (ret != Z_OK) {
+ return false;
+ }
+ }
+
+ inflateEnd(&zstream);
+ DEBUG_LOG(" DEFLATE size=%d crc=%08x", int(zstream.total_out), crc);
+
+ } else {
+ continue;
+ }
+
+ if (entry->CRC32 != crc) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
ZipCollection ZipCollection::Singleton;
static pthread_mutex_t sZipCollectionMutex = PTHREAD_MUTEX_INITIALIZER;
already_AddRefed<Zip>
ZipCollection::GetZip(const char *path)
{
{
--- a/mozglue/linker/Zip.h
+++ b/mozglue/linker/Zip.h
@@ -258,16 +258,21 @@ public:
/**
* Returns the file name of the archive
*/
const char *GetName() const
{
return name;
}
+ /**
+ * Returns whether all files have correct CRC checksum.
+ */
+ bool VerifyCRC() const;
+
private:
/* File name of the archive */
char *name;
/* Address where the Zip archive is mapped */
void *mapped;
/* Size of the archive */
size_t size;