/* * Copyright (C) 2024 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. */ // To access constructor of CursorWindow along with its fields #define private public #include <androidfw/CursorWindow.h> #include <binder/Parcel.h> #include <utils/String8.h> #include "../includes/common.h" #include "../includes/memutils_track.h" using namespace android; char enable_selective_overload = ENABLE_NONE; bool is_tracking_required(size_t size) { return (size != 0); } constexpr int kSize = 0; String8 kEmptyString = String8(""); int main() { // Create CursorWindow object to invoke CursorWindow::create() to get the CursorWindow class's // constructor CursorWindow* window; CursorWindow::create(kEmptyString, kSize, &window); // Create parcel object Parcel parcelObj; Parcel* parcel = &parcelObj; // Assign values to window object to hit the vulnerability from CursorWindow.h window->mAllocOffset = 1; window->mName = kEmptyString; window->mNumColumns = kSize; window->mNumRows = kSize; window->mSize = kSize; window->mSlotsOffset = kSize; // Invoke vulnerable function enable_selective_overload = ENABLE_MALLOC_CHECK; window->writeToParcel(parcel); enable_selective_overload = ENABLE_NONE; // Set data position of parcel to 0 parcel->setDataPosition(0); // Since writes were made on parcel object in source code, hence the exact same reads have to // be made and checked accordingly to access the correct index of parcel FAIL_CHECK(parcel->readString8().string() == kEmptyString); FAIL_CHECK(parcel->readUint32(&window->mNumRows) == kSize); FAIL_CHECK(parcel->readUint32(&window->mNumColumns) == kSize); size_t compactSize = parcel->readUint32(); /* value is different with and without fix */ parcel->readBool(); // Create pointer dest using compactSize const void* dest = parcel->readInplace(compactSize); FAIL_CHECK(dest); const uint8_t* leakedBytes = static_cast<const uint8_t*>(dest) + compactSize; FAIL_CHECK(leakedBytes); // Check if any leaks are present in leakedBytes // The fix removes the code that CursorWindow::writeToParcel() uses to ensure slot data is // 4-byte aligned because 'mAllocOffset' and 'mSlotsOffset' are already 4-byte aligned, // alignment step here is unnecessary which causes leak of uninitialized heap content // INITIAL_VAL = 0xBE bool isVulnerable = false; if (leakedBytes[0] == INITIAL_VAL && leakedBytes[1] == INITIAL_VAL && leakedBytes[2] == INITIAL_VAL) { isVulnerable = true; } return isVulnerable ? EXIT_VULNERABLE : EXIT_SUCCESS; }