From 2f4267ba81f2d352af998da5ed7c8575ed692f09 Mon Sep 17 00:00:00 2001 From: "daniel.zatovic" Date: Wed, 14 Sep 2022 13:17:23 +0200 Subject: [PATCH] Add plain JSON metadata fuzzing --- tests/fuzz/LUKS2_plain_JSON.proto | 190 ++++++++++++++++++ tests/fuzz/Makefile.am | 28 ++- .../fuzz/crypt2_load_proto_plain_json_fuzz.cc | 71 +++++++ tests/fuzz/json_proto_converter.cc | 87 ++++++++ tests/fuzz/json_proto_converter.h | 43 ++++ tests/fuzz/plain_json_proto_to_luks2.cc | 77 +++++++ .../plain_json_proto_to_luks2_converter.cc | 168 ++++++++++++++++ .../plain_json_proto_to_luks2_converter.h | 58 ++++++ 8 files changed, 720 insertions(+), 2 deletions(-) create mode 100644 tests/fuzz/LUKS2_plain_JSON.proto create mode 100644 tests/fuzz/crypt2_load_proto_plain_json_fuzz.cc create mode 100644 tests/fuzz/json_proto_converter.cc create mode 100644 tests/fuzz/json_proto_converter.h create mode 100644 tests/fuzz/plain_json_proto_to_luks2.cc create mode 100644 tests/fuzz/plain_json_proto_to_luks2_converter.cc create mode 100644 tests/fuzz/plain_json_proto_to_luks2_converter.h diff --git a/tests/fuzz/LUKS2_plain_JSON.proto b/tests/fuzz/LUKS2_plain_JSON.proto new file mode 100644 index 00000000..da4e92b9 --- /dev/null +++ b/tests/fuzz/LUKS2_plain_JSON.proto @@ -0,0 +1,190 @@ +/* + * cryptsetup LUKS2 custom mutator + * + * Copyright (C) 2022 Daniel Zatovic + * Copyright (C) 2022 Red Hat, Inc. All rights reserved. + * + * 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 2 + * 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. + */ + +syntax = "proto2"; + +package json_proto; + +// --------------------------------------------------------------------------- +// ----------------------------- GENERIC OBJECTS ----------------------------- +// --------------------------------------------------------------------------- + +message object_id { + oneof id { + // int_id will be mapped to range -16 to 16 (mod 33) + // this way iy should be easier to generate valid + // object cross-references + uint32 int_id = 1; + string string_id = 2; + } +} + +message string_uint64 { + required bool negative = 1; + oneof number { + uint32 uint_num = 2; + string string_num = 3; + } +} + +enum hash_algorithm { + HASH_ALG_SHA1 = 1; + HASH_ALG_SHA256 = 2; +} + + +// --------------------------------------------------------------------------- +// ----------------------------- BINARY HEADER ------------------------------- +// --------------------------------------------------------------------------- + +enum luks2_magic { + INVALID = 0; + FIRST = 1; + SECOND = 2; +} + +enum luks_version { + ONE = 1; + TWO = 2; + THREE = 3; +} + +// we limit the size to 64KiB to make the fuzzing faster +// because the checksum needs to be calculated for the whole image +enum hdr_size { + size_16_KB = 16384; + size_32_KB = 32768; + size_64_KB = 65536; +// size_128_KB = 131072; +// size_256_KB = 262144; +// size_512_KB = 524288; +// size_1_MB = 1048576; +// size_2_MB = 2097152; +// size_4_MB = 4194304; +} + +enum seqid_description { + PRIMARY_GREATER = 0; + SECONDARY_GREATER = 1; + EQUAL = 2; +} + +// message luks2_hdr_disk { +// char magic[LUKS2_MAGIC_L]; +// //uint16_t version; /* Version 2 */ +// uint64_t hdr_size; /* in bytes, including JSON area */ +// uint64_t seqid; /* increased on every update */ +// char label[LUKS2_LABEL_L]; +// char checksum_alg[LUKS2_CHECKSUM_ALG_L]; +// uint8_t salt[LUKS2_SALT_L]; /* unique for every header/offset */ +// char uuid[LUKS2_UUID_L]; +// char subsystem[LUKS2_LABEL_L]; /* owner subsystem label */ +// uint64_t hdr_offset; /* offset from device start in bytes */ +// char _padding[184]; +// uint8_t csum[LUKS2_CHECKSUM_L]; +// } +message LUKS2_header { + required luks_version version = 1; + required luks2_magic magic = 2; + required hdr_size hdr_size = 3; + required bool use_correct_checksum = 4; + + optional uint64 selected_offset = 5; +} + +message LUKS2_both_headers { + required LUKS2_header primary_header = 1; + required LUKS2_header secondary_header = 2; + + required seqid_description seqid = 3; + required JsonObject json_area = 4; +} + +message JsonObject { + required string name = 1; + required JsonValue value = 2; +} + +message JsonValue { + oneof value { + // Json value types: + + // null: null, will be used when 'oneof' contains nothing + + // object: another json object of any type + JsonObject object_value = 1; + + // array: an array of values + ArrayValue array_value = 2; + + // number: can be an integer, a float, an exponent + NumberValue number_value = 3; + + // string: unicode string + StringValue string_value = 4; + + // boolean: true or talse + BooleanValue boolean_value = 5; + } +} + +message ArrayValue { + repeated JsonValue value = 1; +} + +message NumberInteger { + required int64 value = 1; +} + +message NumberFloat { + required double value = 1; +} + +message NumberExponent { + required int32 base = 1; + required int32 exponent = 2; + required bool use_uppercase = 3; +} + +message NumberExponentFrac { + required float base = 1; + required int32 exponent = 2; + required bool use_uppercase = 3; +} + +message NumberValue { + required NumberInteger integer_value = 1; + + // integer_value is used when oneof field below has nothing. + oneof value { + NumberFloat float_value = 2; + NumberExponent exponent_value = 3; + NumberExponentFrac exponent_frac_value = 4; + } +} + +message StringValue { + required string value = 1; +} + +message BooleanValue { + required bool value = 1; +} diff --git a/tests/fuzz/Makefile.am b/tests/fuzz/Makefile.am index 141ddebb..70784561 100644 --- a/tests/fuzz/Makefile.am +++ b/tests/fuzz/Makefile.am @@ -15,10 +15,13 @@ crypt2_load_fuzz_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir)/lib -I$(top_srcdir)/t generate_proto: LUKS2.proto @protoc LUKS2.proto --cpp_out=. + @protoc LUKS2_plain_JSON.proto --cpp_out=. LUKS2.pb.h: generate_proto LUKS2.pb.cc: generate_proto +LUKS2_plain_JSON.pb.cc: generate_proto +LUKS2_plain_JSON.pb.h: generate_proto -BUILT_SOURCES = LUKS2.pb.h LUKS2.pb.cc +BUILT_SOURCES = LUKS2.pb.h LUKS2.pb.cc LUKS2_plain_JSON.pb.h LUKS2_plain_JSON.pb.cc crypt2_load_proto_fuzz_SOURCES = crypt2_load_proto_fuzz.cc common.c LUKS2.pb.cc proto_to_luks2_converter.cc crypt2_load_proto_fuzz_LDADD = \ @@ -35,13 +38,34 @@ crypt2_load_proto_fuzz_CXXFLAGS = \ -fsanitize=fuzzer-no-link \ @LIBPROTOBUF_MUTATOR_CFLAGS@ +crypt2_load_proto_plain_json_fuzz_SOURCES = crypt2_load_proto_plain_json_fuzz.cc common.c LUKS2_plain_JSON.pb.cc json_proto_converter.cc plain_json_proto_to_luks2_converter.cc +crypt2_load_proto_plain_json_fuzz_LDADD = \ + ../../libcryptsetup.la \ + ../../libcrypto_backend.la \ + @LIBPROTOBUF_MUTATOR_LIBS@ \ + @PROTOBUF_LIBS@ +crypt2_load_proto_plain_json_fuzz_LDFLAGS = $(AM_LDFLAGS) $(LIB_FUZZING_ENGINE) -static +crypt2_load_proto_plain_json_fuzz_CFLAGS = -fsanitize=fuzzer-no-link +crypt2_load_proto_plain_json_fuzz_CXXFLAGS = \ + $(AM_CXXFLAGS) \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/tests/fuzz \ + -fsanitize=fuzzer-no-link \ + @LIBPROTOBUF_MUTATOR_CFLAGS@ + proto_to_luks2_SOURCES = proto_to_luks2.cc common.c LUKS2.pb.cc proto_to_luks2_converter.cc proto_to_luks2_LDADD = ../../libcryptsetup.la ../../libcrypto_backend.la @PROTOBUF_LIBS@ proto_to_luks2_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer-no-link -static proto_to_luks2_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/lib -I$(top_srcdir)/tests/fuzz proto_to_luks2_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir)/lib -I$(top_srcdir)/tests/fuzz -check_PROGRAMS = crypt2_load_fuzz crypt2_load_proto_fuzz proto_to_luks2 +plain_json_proto_to_luks2_SOURCES = plain_json_proto_to_luks2.cc common.c LUKS2_plain_JSON.pb.cc plain_json_proto_to_luks2_converter.cc json_proto_converter.cc +plain_json_proto_to_luks2_LDADD = ../../libcryptsetup.la ../../libcrypto_backend.la @PROTOBUF_LIBS@ +plain_json_proto_to_luks2_LDFLAGS = $(AM_LDFLAGS) -fsanitize=fuzzer-no-link -static +plain_json_proto_to_luks2_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/lib -I$(top_srcdir)/tests/fuzz +plain_json_proto_to_luks2_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir)/lib -I$(top_srcdir)/tests/fuzz + +check_PROGRAMS = crypt2_load_fuzz crypt2_load_proto_fuzz crypt2_load_proto_plain_json_fuzz proto_to_luks2 plain_json_proto_to_luks2 clang-only: @test "$(CC)" == "clang" || (echo "Building fuzz targets is only supported using clang. Please set CC=clang CXX=clang++" && exit 1) diff --git a/tests/fuzz/crypt2_load_proto_plain_json_fuzz.cc b/tests/fuzz/crypt2_load_proto_plain_json_fuzz.cc new file mode 100644 index 00000000..71f9d9d6 --- /dev/null +++ b/tests/fuzz/crypt2_load_proto_plain_json_fuzz.cc @@ -0,0 +1,71 @@ +/* + * cryptsetup LUKS2 custom mutator fuzz target + * + * Copyright (C) 2022 Daniel Zatovic + * Copyright (C) 2022 Red Hat, Inc. All rights reserved. + * + * 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 2 + * 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 +#include +#include +#include + +#include "LUKS2_plain_JSON.pb.h" +#include "plain_json_proto_to_luks2_converter.h" +#include "libfuzzer/libfuzzer_macro.h" + +extern "C" { +#include +#include +#include +#include + +#include "common.h" +} + +DEFINE_PROTO_FUZZER(const json_proto::LUKS2_both_headers &headers) { + int result; + struct crypt_device *cd; + uint8_t *map; + int r = 0; + + char name[] = "/tmp/test-proto-fuzz.XXXXXX"; + int fd = mkostemp(name, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC); + if (fd < 0) + err(EXIT_FAILURE, "mkostemp() failed"); + + json_proto::LUKS2ProtoConverter converter; + converter.convert(headers, fd); + + r = crypt_init(&cd, name); + if (r < 0 ) { + r = 0; + goto out; + } + + r = crypt_load(cd, CRYPT_LUKS2, NULL); + crypt_free(cd); + if (r < 0) { + r = 0; + goto out; + } + +out: + if (fd >= 0) + close(fd); + unlink(name); +} diff --git a/tests/fuzz/json_proto_converter.cc b/tests/fuzz/json_proto_converter.cc new file mode 100644 index 00000000..ed453be9 --- /dev/null +++ b/tests/fuzz/json_proto_converter.cc @@ -0,0 +1,87 @@ +// Copyright 2020 Google Inc. +// +// 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 "json_proto_converter.h" + +namespace json_proto { + +void JsonProtoConverter::AppendArray(const ArrayValue& array_value) { + data_ << '['; + bool need_comma = false; + for (const auto& value : array_value.value()) { + // Trailing comma inside of an array makes JSON invalid, avoid adding that. + if (need_comma) + data_ << ','; + else + need_comma = true; + + AppendValue(value); + } + data_ << ']'; +} + +void JsonProtoConverter::AppendNumber(const NumberValue& number_value) { + if (number_value.has_float_value()) { + data_ << number_value.float_value().value(); + } else if (number_value.has_exponent_value()) { + auto value = number_value.exponent_value(); + data_ << value.base(); + data_ << (value.use_uppercase() ? 'E' : 'e'); + data_ << value.exponent(); + } else if (number_value.has_exponent_frac_value()) { + auto value = number_value.exponent_value(); + data_ << value.base(); + data_ << (value.use_uppercase() ? 'E' : 'e'); + data_ << value.exponent(); + } else { + data_ << number_value.integer_value().value(); + } +} + +void JsonProtoConverter::AppendObject(const JsonObject& json_object) { + data_ << '{' << '"' << json_object.name() << '"' << ':'; + AppendValue(json_object.value()); + data_ << '}'; +} + +void JsonProtoConverter::AppendValue(const JsonValue& json_value) { + if (json_value.has_object_value()) { + AppendObject(json_value.object_value()); + } else if (json_value.has_array_value()) { + AppendArray(json_value.array_value()); + } else if (json_value.has_number_value()) { + AppendNumber(json_value.number_value()); + } else if (json_value.has_string_value()) { + data_ << '"' << json_value.string_value().value() << '"'; + } else if (json_value.has_boolean_value()) { + data_ << (json_value.boolean_value().value() ? "true" : "false"); + } else { + data_ << "null"; + } +} + +std::string JsonProtoConverter::Convert(const JsonObject& json_object) { + AppendObject(json_object); + return data_.str(); +} + +std::string JsonProtoConverter::Convert( + const json_proto::ArrayValue& json_array) { + AppendArray(json_array); + return data_.str(); +} + +} // namespace json_proto diff --git a/tests/fuzz/json_proto_converter.h b/tests/fuzz/json_proto_converter.h new file mode 100644 index 00000000..ca52d675 --- /dev/null +++ b/tests/fuzz/json_proto_converter.h @@ -0,0 +1,43 @@ +// Copyright 2020 Google Inc. +// +// 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. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef JSON_PROTO_CONVERTER_H_ +#define JSON_PROTO_CONVERTER_H_ + +#include +#include + +#include "LUKS2_plain_JSON.pb.h" + +namespace json_proto { + +class JsonProtoConverter { + public: + std::string Convert(const json_proto::JsonObject&); + std::string Convert(const json_proto::ArrayValue&); + + private: + std::stringstream data_; + + void AppendArray(const json_proto::ArrayValue&); + void AppendNumber(const json_proto::NumberValue&); + void AppendObject(const json_proto::JsonObject&); + void AppendValue(const json_proto::JsonValue&); +}; + +} // namespace json_proto + +#endif // TESTING_LIBFUZZER_PROTO_JSON_PROTO_CONVERTER_H_ diff --git a/tests/fuzz/plain_json_proto_to_luks2.cc b/tests/fuzz/plain_json_proto_to_luks2.cc new file mode 100644 index 00000000..2f718b08 --- /dev/null +++ b/tests/fuzz/plain_json_proto_to_luks2.cc @@ -0,0 +1,77 @@ +/* + * cryptsetup LUKS2 protobuf to image converter + * + * Copyright (C) 2022 Daniel Zatovic + * Copyright (C) 2022 Red Hat, Inc. All rights reserved. + * + * 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 2 + * 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 +#include +#include + +#include +#include +#include + +#include +#include + +#include "plain_json_proto_to_luks2_converter.h" + +using namespace json_proto; + +int main(int argc, char *argv[]) { + LUKS2_both_headers headers; + LUKS2ProtoConverter converter; + + std::string out_img_name; + + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + int fd = open(argv[1], O_RDONLY); + if (fd < 0) { + std::cerr << "Failed to open " << argv[1] << std::endl; + return 1; + } + + google::protobuf::io::FileInputStream fileInput(fd); + + if (!google::protobuf::TextFormat::Parse(&fileInput, &headers)) { + std::cerr << "Failed to parse protobuf " << argv[1] << std::endl; + goto out; + } + close(fd); + + out_img_name = argv[1]; + out_img_name += ".img"; + + fd = open(out_img_name.c_str(), O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC|O_TRUNC, 0644); + if (fd < 0) { + std::cerr << "Failed to open output file " << out_img_name << std::endl; + goto out; + } + converter.set_write_headers_only(false); + converter.convert(headers, fd); + +out: + if (fd >= 0) + close(fd); + return 0; +} diff --git a/tests/fuzz/plain_json_proto_to_luks2_converter.cc b/tests/fuzz/plain_json_proto_to_luks2_converter.cc new file mode 100644 index 00000000..01c7cd3c --- /dev/null +++ b/tests/fuzz/plain_json_proto_to_luks2_converter.cc @@ -0,0 +1,168 @@ +/* + * cryptsetup LUKS2 custom mutator fuzz target + * + * Copyright (C) 2022 Daniel Zatovic + * Copyright (C) 2022 Red Hat, Inc. All rights reserved. + * + * 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 2 + * 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 "plain_json_proto_to_luks2_converter.h" +#include "json_proto_converter.h" +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +#include + +#include "common.h" +} + +#define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0) + +namespace json_proto { + +void LUKS2ProtoConverter::emit_luks2_binary_header(const LUKS2_header &header_proto, int fd, uint64_t offset, uint64_t seqid, const std::string &json_text) { + struct luks2_hdr_disk hdr = {}; + char *json_area = NULL; + int r; + + if (hd) + crypt_hash_destroy(hd); + if (crypt_hash_init(&hd, "sha256")) + err(EXIT_FAILURE, "crypt_hash_init failed"); + + + r = lseek(fd, offset, SEEK_SET); + if (r == -1) + err(EXIT_FAILURE, "lseek failed"); + + switch (header_proto.magic()) { + case INVALID: + memset(&hdr.magic, 0, LUKS2_MAGIC_L); + break; + case FIRST: + memcpy(&hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L); + break; + case SECOND: + memcpy(&hdr.magic, LUKS2_MAGIC_2ND, LUKS2_MAGIC_L); + break; + } + hdr.version = cpu_to_be16(header_proto.version()); + hdr.hdr_size = cpu_to_be64(header_proto.hdr_size()); + hdr.seqid = cpu_to_be64(seqid); + strncpy(hdr.checksum_alg, "sha256", LUKS2_CHECKSUM_ALG_L); + hdr.checksum_alg[LUKS2_CHECKSUM_ALG_L - 1] = '\0'; + strncpy(hdr.uuid, "af7f64ea-3233-4581-946b-6187d812841e", LUKS2_UUID_L); + memset(hdr.salt, 1, LUKS2_SALT_L); + + + if (header_proto.has_selected_offset()) + hdr.hdr_offset = cpu_to_be64(header_proto.selected_offset()); + else + hdr.hdr_offset = cpu_to_be64(offset); + + if (write_all(fd, &hdr, LUKS2_HDR_BIN_LEN) != 0) + err(EXIT_FAILURE, "write_all failed"); + if (crypt_hash_write(hd, (char*)&hdr, LUKS2_HDR_BIN_LEN)) + err(EXIT_FAILURE, "crypt_hash_write failed"); + + size_t hdr_json_area_len = header_proto.hdr_size() - LUKS2_HDR_BIN_LEN; + uint8_t csum[LUKS2_CHECKSUM_L]; + + size_t write_size = json_text.length() > hdr_json_area_len - 1 ? hdr_json_area_len - 1 : json_text.length(); + if (write_all(fd, json_text.c_str(), write_size) != 0) + err(EXIT_FAILURE, "write_all failed"); + if (crypt_hash_write(hd, json_text.c_str(), write_size)) + err(EXIT_FAILURE, "crypt_hash_write failed"); + + for (size_t i = 0; i < (hdr_json_area_len - json_text.length()); i++) { + if (crypt_hash_write(hd, "\0", 1)) + err(EXIT_FAILURE, "crypt_hash_write failed"); + } + + if (header_proto.use_correct_checksum()) { + if (lseek(fd, offset + OFFSET_OF(luks2_hdr_disk, csum), SEEK_SET) == -1) + err(EXIT_FAILURE, "lseek failed"); + + int hash_size = crypt_hash_size("sha256"); + if (hash_size <= 0) + err(EXIT_FAILURE, "crypt_hash_size failed"); + + if (crypt_hash_final(hd, (char*)csum, (size_t)hash_size)) + err(EXIT_FAILURE, "crypt_hash_final failed"); + if (write_all(fd, csum, hash_size) != 0) + err(EXIT_FAILURE, "write_all failed"); + } +} + +void LUKS2ProtoConverter::set_write_headers_only(bool headers_only) { + write_headers_only = headers_only; +} + +void LUKS2ProtoConverter::convert(const LUKS2_both_headers &headers, int fd) { + uint64_t primary_seqid, secondary_seqid; + const char name_pattern[] = "/tmp/test-proto-fuzz.XXXXXX"; + int result; + + size_t out_size = headers.primary_header().hdr_size() + headers.secondary_header().hdr_size(); + + if (!write_headers_only) + out_size += KEYSLOTS_SIZE + DATA_SIZE; + + result = lseek(fd, out_size - 1, SEEK_SET); + if (result == -1) + err(EXIT_FAILURE, "lseek failed"); + + result = write(fd, "\0", 1); + if (result != 1) + err(EXIT_FAILURE, "write failed"); + + result = lseek(fd, 0, SEEK_SET); + if (result == -1) + err(EXIT_FAILURE, "lseek failed"); + + switch (headers.seqid()) { + case EQUAL: + primary_seqid = 1; + secondary_seqid = 1; + break; + case PRIMARY_GREATER: + primary_seqid = 2; + secondary_seqid = 1; + break; + case SECONDARY_GREATER: + primary_seqid = 1; + secondary_seqid = 2; + break; + } + + JsonProtoConverter converter; + std::string json_text = converter.Convert(headers.json_area()); + + emit_luks2_binary_header(headers.primary_header(), fd, 0, primary_seqid, json_text); + emit_luks2_binary_header(headers.secondary_header(), fd, headers.primary_header().hdr_size(), secondary_seqid, json_text); +} + +LUKS2ProtoConverter::~LUKS2ProtoConverter() { + if (hd) + crypt_hash_destroy(hd); +} +} // namespace LUKS2_proto diff --git a/tests/fuzz/plain_json_proto_to_luks2_converter.h b/tests/fuzz/plain_json_proto_to_luks2_converter.h new file mode 100644 index 00000000..013fdb71 --- /dev/null +++ b/tests/fuzz/plain_json_proto_to_luks2_converter.h @@ -0,0 +1,58 @@ +/* + * cryptsetup LUKS2 custom mutator fuzz target + * + * Copyright (C) 2022 Daniel Zatovic + * Copyright (C) 2022 Red Hat, Inc. All rights reserved. + * + * 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 2 + * 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. + */ + +#ifndef LUKS2_PROTO_CONVERTER_H_ +#define LUKS2_PROTO_CONVERTER_H_ + +#include +#include +#include + +#include "LUKS2_plain_JSON.pb.h" +extern "C" { +#include "crypto_backend/crypto_backend.h" +} + +namespace json_proto { + +class LUKS2ProtoConverter { + public: + ~LUKS2ProtoConverter(); + void create_jobj(const LUKS2_both_headers &headers, uint64_t hdr_size); + void convert(const LUKS2_both_headers &headers, int fd); + void create_jobj(const LUKS2_both_headers &headers); + void emit_luks2_binary_header(const LUKS2_header &header_proto, int fd, uint64_t offset, uint64_t seqid, const std::string &json_text); + + void set_write_headers_only(bool headers_only); + + const uint8_t *get_out_buffer(); + const size_t get_out_size(); + + static const uint64_t KEYSLOTS_SIZE = 3 * 1024 * 1024; + static const uint64_t DATA_SIZE = 16 * 1024 * 1024; + private: + bool write_headers_only = false; + struct crypt_hash *hd = NULL; +}; + +} // namespace LUKS2_proto + +#endif // LUKS2_PROTO_CONVERTER_H_