mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Add plain JSON metadata fuzzing
This commit is contained in:
committed by
Milan Broz
parent
99e8ee6b7e
commit
2f4267ba81
190
tests/fuzz/LUKS2_plain_JSON.proto
Normal file
190
tests/fuzz/LUKS2_plain_JSON.proto
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* cryptsetup LUKS2 custom mutator
|
||||
*
|
||||
* Copyright (C) 2022 Daniel Zatovic <daniel.zatovic@gmail.com>
|
||||
* 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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
71
tests/fuzz/crypt2_load_proto_plain_json_fuzz.cc
Normal file
71
tests/fuzz/crypt2_load_proto_plain_json_fuzz.cc
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* cryptsetup LUKS2 custom mutator fuzz target
|
||||
*
|
||||
* Copyright (C) 2022 Daniel Zatovic <daniel.zatovic@gmail.com>
|
||||
* 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 <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "LUKS2_plain_JSON.pb.h"
|
||||
#include "plain_json_proto_to_luks2_converter.h"
|
||||
#include "libfuzzer/libfuzzer_macro.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libcryptsetup.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
87
tests/fuzz/json_proto_converter.cc
Normal file
87
tests/fuzz/json_proto_converter.cc
Normal file
@@ -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
|
||||
43
tests/fuzz/json_proto_converter.h
Normal file
43
tests/fuzz/json_proto_converter.h
Normal file
@@ -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 <sstream>
|
||||
#include <string>
|
||||
|
||||
#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_
|
||||
77
tests/fuzz/plain_json_proto_to_luks2.cc
Normal file
77
tests/fuzz/plain_json_proto_to_luks2.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* cryptsetup LUKS2 protobuf to image converter
|
||||
*
|
||||
* Copyright (C) 2022 Daniel Zatovic <daniel.zatovic@gmail.com>
|
||||
* 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 <iostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <google/protobuf/text_format.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
#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] << " <LUKS2 proto>\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;
|
||||
}
|
||||
168
tests/fuzz/plain_json_proto_to_luks2_converter.cc
Normal file
168
tests/fuzz/plain_json_proto_to_luks2_converter.cc
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* cryptsetup LUKS2 custom mutator fuzz target
|
||||
*
|
||||
* Copyright (C) 2022 Daniel Zatovic <daniel.zatovic@gmail.com>
|
||||
* 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 <exception>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
extern "C" {
|
||||
#include <json-c/json.h>
|
||||
#include <src/cryptsetup.h>
|
||||
#include <luks2/luks2.h>
|
||||
#include <libcryptsetup.h>
|
||||
#include <err.h>
|
||||
|
||||
#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
|
||||
58
tests/fuzz/plain_json_proto_to_luks2_converter.h
Normal file
58
tests/fuzz/plain_json_proto_to_luks2_converter.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* cryptsetup LUKS2 custom mutator fuzz target
|
||||
*
|
||||
* Copyright (C) 2022 Daniel Zatovic <daniel.zatovic@gmail.com>
|
||||
* 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 <sstream>
|
||||
#include <string>
|
||||
#include <json-c/json.h>
|
||||
|
||||
#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_
|
||||
Reference in New Issue
Block a user