Commit 9be5f7d5 authored by Olivier Dion's avatar Olivier Dion Committed by Adrien Béraud
Browse files

fuzzing/gnutls: Add GNU TLS wrapper

Change-Id: Ide37f73f142cb1cfa86b86c6ddbc76ce80e9414d
parent 445fe312
......@@ -7,5 +7,5 @@ check_PROGRAMS =
lib_LTLIBRARIES = libfuzz.la
libfuzz_la_SOURCES = lib/utils.cpp lib/supervisor.cpp
libfuzz_la_SOURCES = lib/utils.cpp lib/supervisor.cpp lib/gnutls.cpp
endif
/*
* Copyright (C) 2021 Savoir-faire Linux Inc.
*
* Author: Olivier Dion <olivier.dion>@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <cstdlib>
#include <cinttypes>
#include "lib/gnutls.h"
#include "lib/supervisor.h"
static FILE* redirect_to = nullptr;
static std::atomic<size_t> packet_ID = 0;
static void
open_redirection(void)
{
const char* supervisor_says = std::getenv(supervisor::env::tls_out);
if (nullptr == supervisor_says) {
redirect_to = stderr;
} else {
redirect_to = fopen(supervisor_says, "w");
assert(redirect_to);
}
}
static void
print_channel_msg(const ChanneledMessage& msg, const char* direction, bool mutated, size_t packed_id)
{
if (nullptr == redirect_to) {
open_redirection();
}
fprintf(redirect_to,
"\n"
"================================================================================\n"
"#:direction %s #:mut %d #:transport TLS #:channel %" PRIu16 " #:ID %" PRIu64 "\n"
"--------------------------------------------------------------------------------\n"
"%.*s\n"
"================================================================================\n",
direction,
mutated,
msg.channel,
packed_id,
static_cast<int>(msg.data.size()),
msg.data.data());
fflush(redirect_to);
}
#if 0
static std::map<std::string;
static void
register_channel(const std::string& name, uint16_t channel)
{
}
#endif
__weak
bool
mutate_gnutls_record_send(ChanneledMessage& msg)
{
(void) msg;
return false;
}
__weak
bool
mutate_gnutls_record_recv(ChanneledMessage& msg)
{
(void) msg;
return false;
}
__weak
void
pack_gnutls_record_recv(msgpack::sbuffer& buf, const ChanneledMessage& msg)
{
msgpack::packer<msgpack::sbuffer> pk(&buf);
pk.pack_array(2);
pk.pack(msg.channel);
pk.pack_bin(msg.data.size());
pk.pack_bin_body((const char*) msg.data.data(), msg.data.size());
}
__weak
void
pack_gnutls_record_send(msgpack::sbuffer& buf, const ChanneledMessage& msg)
{
msgpack::packer<msgpack::sbuffer> pk(&buf);
pk.pack_array(2);
pk.pack(msg.channel);
pk.pack_bin(msg.data.size());
pk.pack_bin_body((const char*) msg.data.data(), msg.data.size());
}
BEGIN_WRAPPER(ssize_t, gnutls_record_send, gnutls_session_t session, const void* data, size_t data_size)
{
if (data_size > 0) {
msgpack::unpacker pac {};
msgpack::object_handle oh;
pac.reserve_buffer(data_size);
memcpy(pac.buffer(), data, data_size);
pac.buffer_consumed(data_size);
if (pac.next(oh)) {
try {
auto msg = oh.get().as<ChanneledMessage>();
size_t ID = packet_ID++;
bool mutated;
print_channel_msg(msg, "TX", false, ID);
mutated = mutate_gnutls_record_send(msg);
if (not mutated) {
goto no_mut;
}
print_channel_msg(msg, "TX", true, ID);
msgpack::sbuffer buf(16 +msg.data.size());
pack_gnutls_record_send(buf, msg);
return this_func(session, buf.data(), buf.size());
} catch (...) { }
}
}
no_mut:
return this_func(session, data, data_size);
}
END_WRAPPER();
BEGIN_WRAPPER(ssize_t, gnutls_record_recv, gnutls_session_t session, void* data, size_t data_size)
{
ssize_t ret = this_func(session, data, data_size);
if (ret > 0) {
msgpack::unpacker pac {};
msgpack::object_handle oh;
pac.reserve_buffer(ret);
memcpy(pac.buffer(), data, ret);
pac.buffer_consumed(ret);
if (pac.next(oh)) {
auto msg = oh.get().as<ChanneledMessage>();
size_t ID = packet_ID++;
bool mutated;
#if 0
if (CONTROL_CHANNEL == msg.channel) {
try {
msgpack::unpacked result;
msgpack::unpack(result, (const char*) msg.data.data(), msg.data.size(), 0);
auto obj = result.get();
auto req = obj.as<ChannelRequest>();
if (ChannelRequestState::ACCEPT == req.state) {
register_channel(req.name, req.channel);
}
} catch (...) {
}
}
#endif
print_channel_msg(msg, "RX", false, ID);
mutated = mutate_gnutls_record_recv(msg);
if (not mutated) {
goto no_mut;
}
print_channel_msg(msg, "RX", true, ID);
msgpack::sbuffer buf(16 + msg.data.size());
pack_gnutls_record_recv(buf, msg);
memcpy(data, buf.data(), buf.size());
/* Respect GNU TLS API! */
assert(buf.size() <= data_size);
ret = buf.size();
}
}
no_mut:
return ret;
}
END_WRAPPER();
__weak
void
post_gnutls_init_hook(gnutls_session_t session)
{
(void)session;
}
__weak
void
pre_gnutls_deinit_hook(gnutls_session_t session)
{
(void)session;
}
BEGIN_WRAPPER(int, gnutls_init, gnutls_session_t * session, unsigned int flags)
{
int ret;
ret = this_func(session, flags);
post_gnutls_init_hook(*session);
return ret;
}
END_WRAPPER();
BEGIN_WRAPPER(ssize_t, gnutls_record_recv_seq, gnutls_session_t session, void * data, size_t data_size, unsigned char * seq)
{
ssize_t ret = this_func(session, data, data_size, seq);
if (ret > 0) {
msgpack::unpacker pac {};
msgpack::object_handle oh;
pac.reserve_buffer(ret);
memcpy(pac.buffer(), data, ret);
pac.buffer_consumed(ret);
if (pac.next(oh)) {
auto msg = oh.get().as<ChanneledMessage>();
size_t ID = packet_ID++;
bool mutated;
print_channel_msg(msg, "RX", false, ID);
mutated = mutate_gnutls_record_recv(msg);
if (not mutated) {
goto no_mut;
}
print_channel_msg(msg, "RX", true, ID);
msgpack::sbuffer buf(16 + msg.data.size());
pack_gnutls_record_recv(buf, msg);
memcpy(data, buf.data(), buf.size());
/* Respect GNU TLS API! */
assert(buf.size() <= data_size);
ret = buf.size();
}
}
no_mut:
return ret;
}
END_WRAPPER();
/*
* Copyright (C) 2021 Savoir-faire Linux Inc.
*
* Author: Olivier Dion <olivier.dion>@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <gnutls/gnutls.h>
#include <gnutls/dtls.h>
#include <msgpack.hpp>
/* TODO - Import this from jami */
struct ChanneledMessage
{
uint16_t channel;
std::vector<uint8_t> data;
MSGPACK_DEFINE(channel, data)
};
extern "C" {
extern void inject_into_gnutls(const ChanneledMessage& msg);
extern void post_gnutls_init_hook(gnutls_session_t session);
extern void pre_gnutls_deinit_hook(gnutls_session_t session);
extern void pre_mutate_gnutls_record_send_hook(const ChanneledMessage& msg);
extern void post_mutate_gnutls_record_send_hook(const ChanneledMessage& msg, bool hasMutated);
extern bool mutate_gnutls_record_send(ChanneledMessage& msg);
extern void pre_mutate_gnutls_record_recv_hook(const ChanneledMessage& msg);
extern void post_mutate_gnutls_record_recv_hook(const ChanneledMessage& msg, bool hasMutated);
extern bool mutate_gnutls_record_recv(ChanneledMessage& msg);
};
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment