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 146 147
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* cryptsetup LUKS2 custom mutator fuzz target
*
* Copyright (C) 2022-2024 Daniel Zatovic <daniel.zatovic@gmail.com>
* Copyright (C) 2022-2024 Red Hat, Inc. All rights reserved.
*/
#include "plain_json_proto_to_luks2_converter.h"
#include "json_proto_converter.h"
extern "C" {
#include "src/cryptsetup.h"
#include "luks2/luks2.h"
#include <err.h>
}
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 = {};
size_t hdr_json_area_len, write_size;
uint8_t csum[LUKS2_CHECKSUM_L];
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_buffer(fd, &hdr, LUKS2_HDR_BIN_LEN) != LUKS2_HDR_BIN_LEN)
err(EXIT_FAILURE, "write_buffer failed");
if (crypt_hash_write(hd, (char*)&hdr, LUKS2_HDR_BIN_LEN))
err(EXIT_FAILURE, "crypt_hash_write failed");
if (header_proto.hdr_size() <= LUKS2_HDR_BIN_LEN ||
header_proto.hdr_size() > LUKS2_DEFAULT_HDR_SIZE)
hdr_json_area_len = LUKS2_DEFAULT_HDR_SIZE - LUKS2_HDR_BIN_LEN;
else
hdr_json_area_len = header_proto.hdr_size() - LUKS2_HDR_BIN_LEN;
write_size = json_text.length() > hdr_json_area_len - 1 ? hdr_json_area_len - 1 : json_text.length();
if (write_buffer(fd, json_text.c_str(), write_size) != (ssize_t)write_size)
err(EXIT_FAILURE, "write_buffer 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 - write_size); 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 + offsetof(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_buffer(fd, csum, hash_size) != hash_size)
err(EXIT_FAILURE, "write_buffer 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;
int result;
size_t out_size = headers.primary_header().hdr_size() + headers.secondary_header().hdr_size();
if (out_size < 4096 || out_size > 2 * LUKS2_DEFAULT_HDR_SIZE)
out_size = LUKS2_DEFAULT_HDR_SIZE;
if (!write_headers_only)
out_size += KEYSLOTS_SIZE + DATA_SIZE;
result = ftruncate(fd, out_size);
if (result == -1)
err(EXIT_FAILURE, "truncate 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
|