/*
 * Copyright (C) 2025 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.
 */

#define private public

#include <binder/Parcel.h>
#include <linux/android/binder.h>

#include "../includes/common.h"
#include "binary_loader.h"
using namespace android;

typedef status_t (*grow_data_func)(void*, size_t);

int main(int /* argc */, char* argv[]) {
    // Get the path to the shared library.
    BinaryLoader binaryLoader(argv[1]);

    // Get the function address of 'Parcel::growData()' from loaded library.
    const uintptr_t functionOffset = strtoul(argv[2], nullptr, 0);
    const uintptr_t grow_data_addr = binaryLoader.getFunctionAddress(functionOffset);
    FAIL_CHECK(grow_data_addr);

    // Create the function pointer to 'Parcel::growData()'.
    grow_data_func grow_data_ptr = (grow_data_func)grow_data_addr;

    // Create an object for Parcel to call the vulnerable function.
    Parcel data;

    // Set 'Parcel::mDataPos' > 'Parcel::mDataSize' to meet the fix condition.
    data.mDataSize = 1;
    data.mDataPos = data.mDataSize + 1;

    // Call the vulnerable function 'Parcel::growData()'.
    // 'Parcel::growData()' expects a size_t type argument to create/increase the array length by
    // size of a structure - 'struct flat_binder_object'.
    status_t status = grow_data_ptr(&data, sizeof(struct flat_binder_object) /* len */);

    // Check the return value of 'Parcel::growData()'. If 'Parcel::growData()' returns 'NO_ERROR'
    // and if 'Parcel::mDataPos', 'Parcel::mDataSize' properties are modified, it indicates the
    // vulnerability.
    if (status == NO_ERROR && (data.mDataSize == 0 && data.mDataPos == 0)) {
        exit(EXIT_VULNERABLE);
    }
    return EXIT_SUCCESS;
}
