summaryrefslogtreecommitdiff
path: root/test/http/http_connection_fuzzer.cpp
blob: d339bd5055a235868d3cd261e00ba0414cf18589 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright OpenBMC Authors

#include "app.hpp"
#include "async_resp.hpp"
#include "http/http_connection.hpp"
#include "http/http_request.hpp"
#include "http/http_response.hpp"
#include "http_connect_types.hpp"
#include "logging.hpp"
#include "redfish.hpp"
#include "test_stream.hpp"

#include <boost/asio/buffer.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/steady_timer.hpp>

#include <csignal>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <memory>
#include <string>
#include <utility>

struct FuzzHandler
{
    App app;
    redfish::RedfishService redfishService;
    FuzzHandler() : redfishService(app)
    {
        redfishService.validate();
    }

    template <typename Adaptor>
    void handleUpgrade(const std::shared_ptr<crow::Request>& /*req*/,
                       const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
                       Adaptor&& /*adaptor*/)
    {}

    void handle(const std::shared_ptr<crow::Request>& req,
                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
    {
        app.handle(req, asyncResp);
    }
};

std::string fuzzDateStr()
{
    return "FuzzTime";
}

extern "C"
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreserved-identifier"
// This is a hack to workaround profiler data not being written on shutdown,
// because libfuzzer steals the signal handler.
int __llvm_profile_write_file(void) __attribute__((weak));
#pragma clang diagnostic pop

[[noreturn]] void flushCoverageAndExit(int /*signum*/)
{
    __llvm_profile_write_file();
    std::_Exit(0);
}

void installCoverageSignalHandlers()
{
    if (__llvm_profile_write_file != nullptr)
    {
        std::signal(SIGINT, flushCoverageAndExit);
        std::signal(SIGTERM, flushCoverageAndExit);
    }
}

int LLVMFuzzerInitialize(int* /*argc*/, char*** /*argv*/)
{
    installCoverageSignalHandlers();
    return 0;
}

void runUntilDone(boost::asio::io_context& io, crow::TestStream& clientSide)
{
    bool closed = false;
    while (true)
    {
        size_t numberRun = io.poll_one();
        if (numberRun > 0)
        {
            continue;
        }
        // If we've run out of work to do, close the connection and see if more
        // work happens before we consider this done.
        if (!closed)
        {
            clientSide.close();
            closed = true;
            continue;
        }

        break;
    }
}

int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    // Set the logging level to error. If the code is correct, this should never
    // log anything, although we don't test that at this moment.
    crow::getBmcwebCurrentLoggingLevel() = crow::LogLevel::Error;
    boost::asio::io_context io;

    crow::TestStream serverSide(io);
    crow::TestStream clientSide(io);
    serverSide.connect(clientSide);

    if (size == 0)
    {
        return 0;
    }
    clientSide.write_some(boost::asio::buffer(data, size));

    FuzzHandler handler;
    boost::asio::steady_timer timer(io);
    std::function<std::string()> date(&fuzzDateStr);

    boost::asio::ssl::context ctx{boost::asio::ssl::context::tls};

    auto conn =
        std::make_shared<crow::Connection<crow::TestStream, FuzzHandler>>(
            &handler, crow::HttpType::BOTH, std::move(timer), date,
            boost::asio::ssl::stream<crow::TestStream>(std::move(serverSide),
                                                       ctx));
    conn->disableAuth();
    conn->start();

    runUntilDone(io, clientSide);

    return 0;
}

} // extern "C"