diff options
-rw-r--r-- | libs/androidfw/Android.bp | 18 | ||||
-rw-r--r-- | libs/androidfw/CursorWindow.cpp | 21 | ||||
-rw-r--r-- | libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp | 31 | ||||
-rw-r--r-- | libs/androidfw/fuzz/cursorwindow_fuzzer/corpus/typical.bin | bin | 0 -> 292 bytes | |||
-rw-r--r-- | libs/androidfw/fuzz/cursorwindow_fuzzer/cursorwindow_fuzzer.cpp | 78 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/CursorWindow.h | 3 |
6 files changed, 141 insertions, 10 deletions
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index 45ad94fdb75a..903ca2aa0783 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -193,3 +193,21 @@ cc_benchmark { shared_libs: common_test_libs, data: ["tests/data/**/*.apk"], } + +cc_library { + name: "libandroidfw_fuzzer_lib", + defaults: ["libandroidfw_defaults"], + host_supported: true, + srcs: [ + "CursorWindow.cpp", + ], + export_include_dirs: ["include"], + target: { + android: { + shared_libs: common_test_libs + ["libbinder", "liblog"], + }, + host: { + static_libs: common_test_libs + ["libbinder", "liblog"], + }, + }, +} 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<uint8_t*>(mData) + mSize - kSlotSizeBytes; + mSlotsStart = static_cast<uint8_t*>(mData) + mSize - kSlotSizeBytes; + mSlotsEnd = static_cast<uint8_t*>(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<uint8_t*>(mSlotsData) + void *result = static_cast<uint8_t*>(mSlotsStart) - (((row * mNumColumns) + column) << kSlotShift); - return static_cast<FieldSlot*>(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<FieldSlot*>(result); + } } status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) { diff --git a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp new file mode 100644 index 000000000000..2dac47b0dac6 --- /dev/null +++ b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp @@ -0,0 +1,31 @@ +cc_fuzz { + name: "cursorwindow_fuzzer", + srcs: [ + "cursorwindow_fuzzer.cpp", + ], + host_supported: true, + corpus: ["corpus/*"], + static_libs: ["libgmock"], + target: { + android: { + shared_libs: [ + "libandroidfw_fuzzer_lib", + "libbase", + "libbinder", + "libcutils", + "liblog", + "libutils", + ], + }, + host: { + static_libs: [ + "libandroidfw_fuzzer_lib", + "libbase", + "libbinder", + "libcutils", + "liblog", + "libutils", + ], + }, + }, +} diff --git a/libs/androidfw/fuzz/cursorwindow_fuzzer/corpus/typical.bin b/libs/androidfw/fuzz/cursorwindow_fuzzer/corpus/typical.bin Binary files differnew file mode 100644 index 000000000000..c7e22dd26ea7 --- /dev/null +++ b/libs/androidfw/fuzz/cursorwindow_fuzzer/corpus/typical.bin diff --git a/libs/androidfw/fuzz/cursorwindow_fuzzer/cursorwindow_fuzzer.cpp b/libs/androidfw/fuzz/cursorwindow_fuzzer/cursorwindow_fuzzer.cpp new file mode 100644 index 000000000000..8dce21220199 --- /dev/null +++ b/libs/androidfw/fuzz/cursorwindow_fuzzer/cursorwindow_fuzzer.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <string> +#include <memory> + +#include "android-base/logging.h" +#include "androidfw/CursorWindow.h" +#include "binder/Parcel.h" + +#include <fuzzer/FuzzedDataProvider.h> + +using android::CursorWindow; +using android::Parcel; + +extern "C" int LLVMFuzzerInitialize(int *, char ***) { + setenv("ANDROID_LOG_TAGS", "*:s", 1); + android::base::InitLogging(nullptr, &android::base::StderrLogger); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + Parcel p; + p.setData(data, size); + + CursorWindow* w = nullptr; + if (!CursorWindow::createFromParcel(&p, &w)) { + LOG(WARNING) << "Valid cursor with " << w->getNumRows() << " rows, " + << w->getNumColumns() << " cols"; + + // Try obtaining heap allocations for most items; we trim the + // search space to speed things up + auto rows = std::min(w->getNumRows(), static_cast<uint32_t>(128)); + auto cols = std::min(w->getNumColumns(), static_cast<uint32_t>(128)); + for (auto row = 0; row < rows; row++) { + for (auto col = 0; col < cols; col++) { + auto field = w->getFieldSlot(row, col); + if (!field) continue; + switch (w->getFieldSlotType(field)) { + case CursorWindow::FIELD_TYPE_STRING: { + size_t size; + w->getFieldSlotValueString(field, &size); + break; + } + case CursorWindow::FIELD_TYPE_BLOB: { + size_t size; + w->getFieldSlotValueBlob(field, &size); + break; + } + } + } + } + + // Finally, try obtaining the furthest valid field + if (rows > 0 && cols > 0) { + w->getFieldSlot(w->getNumRows() - 1, w->getNumColumns() - 1); + } + } + delete w; + + return 0; +} diff --git a/libs/androidfw/include/androidfw/CursorWindow.h b/libs/androidfw/include/androidfw/CursorWindow.h index 4c4f7335008d..6e55a9a0eb8b 100644 --- a/libs/androidfw/include/androidfw/CursorWindow.h +++ b/libs/androidfw/include/androidfw/CursorWindow.h @@ -150,7 +150,8 @@ private: * Pointer to the first FieldSlot, used to optimize the extremely * hot code path of getFieldSlot(). */ - void* mSlotsData = nullptr; + void* mSlotsStart = nullptr; + void* mSlotsEnd = nullptr; uint32_t mSize = 0; /** * When a window starts as lightweight inline allocation, this value |