From 256da5a361104276b01ad2834f9929bc8ed457f7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 13 Oct 2020 09:40:52 -0600 Subject: Add fuzzer for rewritten CursorWindow. We recently rewrote CursorWindow, so let's get a fuzzer wired up to see if it has any bugs. This change creates a separate "libandroidfw_fuzz" library, since we can't link to libbinder when building Windows host-side binaries; the fuzzer doesn't need Window support. And fix our first vulnerability where getFieldSlot() could be tricked into reading out of bounds data. The included corpus seed was generated using this example code: CursorWindow* w = nullptr; CursorWindow::create(android::String8("test"), 1 << 21, &w); w->setNumColumns(3); w->allocRow(); w->putLong(0,0,0xcafe); w->putLong(0,1,0xcafe); w->putLong(0,2,0xcafe); // Row purposefully left empty w->allocRow(); w->allocRow(); w->putNull(2,0); w->putNull(2,1); w->putNull(2,2); w->allocRow(); w->putString(3,0,"cafe",5); w->putString(3,1,"cafe",5); w->putString(3,2,"cafe",5); w->allocRow(); w->putDouble(4,0,3.14159f); w->putDouble(4,1,3.14159f); w->putDouble(4,2,3.14159f); Parcel p; w->writeToParcel(&p); Bug: 169251528 Test: atest libandroidfw_tests:CursorWindowTest Test: SANITIZE_HOST=address make ${FUZZER_NAME} && ${ANDROID_HOST_OUT}/fuzz/$(get_build_var HOST_ARCH)/${FUZZER_NAME}/${FUZZER_NAME} Change-Id: I405d377900943de0ad732d3f1a1a0970e17d5140 --- libs/androidfw/CursorWindow.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'libs/androidfw/CursorWindow.cpp') diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp index 1e6de67a40ba..915c0d75a280 100644 --- a/libs/androidfw/CursorWindow.cpp +++ b/libs/androidfw/CursorWindow.cpp @@ -251,7 +251,8 @@ status_t CursorWindow::clear() { } void CursorWindow::updateSlotsData() { - mSlotsData = static_cast(mData) + mSize - kSlotSizeBytes; + mSlotsStart = static_cast(mData) + mSize - kSlotSizeBytes; + mSlotsEnd = static_cast(mData) + mSlotsOffset; } void* CursorWindow::offsetToPtr(uint32_t offset, uint32_t bufferSize = 0) { @@ -300,6 +301,7 @@ status_t CursorWindow::allocRow() { } memset(offsetToPtr(newOffset), 0, size); mSlotsOffset = newOffset; + updateSlotsData(); mNumRows++; return OK; } @@ -314,6 +316,7 @@ status_t CursorWindow::freeLastRow() { return NO_MEMORY; } mSlotsOffset = newOffset; + updateSlotsData(); mNumRows--; return OK; } @@ -337,18 +340,18 @@ status_t CursorWindow::alloc(size_t size, uint32_t* outOffset) { } CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) { - if (row >= mNumRows || column >= mNumColumns) { - LOG(ERROR) << "Failed to read row " << row << ", column " << column - << " from a window with " << mNumRows << " rows, " << mNumColumns << " columns"; - return nullptr; - } - // This is carefully tuned to use as few cycles as // possible, since this is an extremely hot code path; // see CursorWindow_bench.cpp for more details - void *result = static_cast(mSlotsData) + void *result = static_cast(mSlotsStart) - (((row * mNumColumns) + column) << kSlotShift); - return static_cast(result); + if (result < mSlotsEnd || column >= mNumColumns) { + LOG(ERROR) << "Failed to read row " << row << ", column " << column + << " from a window with " << mNumRows << " rows, " << mNumColumns << " columns"; + return nullptr; + } else { + return static_cast(result); + } } status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) { -- cgit v1.2.3