/*
 * 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 <dlfcn.h>
#include <sys/mman.h>

#include "../includes/common.h"
#include "androidfw/CursorWindow.h"

using namespace android;

static void* (*real_malloc)(size_t) = nullptr;

const char* kVulnMarker = "Vulnerable to CVE_2025_26448";
size_t bufferSize = getpagesize();
void* buffer = nullptr;

// Override malloc
void* malloc(size_t size) {
    if (!real_malloc) {
        real_malloc = (void* (*)(size_t))dlsym(RTLD_NEXT, "malloc");
        FAIL_CHECK(real_malloc);
    }

    if (size == bufferSize) {
        // Fill buffer with kVulnMarker
        buffer = memalign(size, size);
        memset(buffer, 0, bufferSize);
        memcpy(buffer, kVulnMarker, strlen(kVulnMarker));
        return buffer;
    }
    return real_malloc(size);
}

void cleanUp() {
    if (buffer != nullptr) {
        free(buffer);
        buffer = nullptr;
    }
}

int main() {
    atexit(cleanUp);

    // Without fix, CursorWindow::create() should invoke malloc(bufferSize)
    // With fix, CursorWindow::create() should invoke calloc(bufferSize, 1)
    CursorWindow* cursorWindow;
    CursorWindow::create(String8("cve_2025_26448"), bufferSize, &cursorWindow);

    // Fail the test if malloc was called and the mData contains kVulnMarker
    bool isVulnerable = false;
    if (buffer != nullptr && cursorWindow->mData == buffer) {
        if (memcmp(cursorWindow->mData, kVulnMarker, strlen(kVulnMarker)) == 0) {
            isVulnerable = true;
        }
    }
    return isVulnerable ? EXIT_VULNERABLE : EXIT_SUCCESS;
}
