/*
 * Copyright (C) 2023 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 <MtpFfsCompatHandle.h>
#include "../includes/common.h"
#include "../includes/memutils.h"

using namespace android;
char enable_selective_overload = ENABLE_NONE;

int main(int argc, char* argv[]) {
    FAIL_CHECK(argc == 2);
    int32_t controlFd;
    const char* descriptorFilePath = argv[1];
    controlFd = open(descriptorFilePath, O_RDWR | O_NONBLOCK | O_CLOEXEC);
    FAIL_CHECK(controlFd >= 0);
    struct mtp_event event;
    event.data = const_cast<char*>("");
    event.length = 0;
    {
        // Memory for handle is being allocated here
        enable_selective_overload = ENABLE_ALL;
        std::unique_ptr<IMtpHandle> handle(new MtpFfsCompatHandle(controlFd));
        enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;

        // handle->sendEvent() internally calls handle->doSendEvent() in a detached thread.
        // This will cause an use-after-free if handle goes out of scope before the thread completes
        // its execution. The fix adds a wait in handle->close() to wait till the detached thread is
        // fully executed.
        handle->sendEvent(event);
        handle->close();
    }
    // Sleep is added here to make sure program does not exit before use after free occurs in
    // detached thread.
    // It is observed that 200 ms is required for UAF to get triggered. But to detect the
    // vulnerability in other slow devices, sleep of 1 second (1000 ms) is used here
    sleep(1);
    return EXIT_SUCCESS;
}
