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 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
|
/*
* zgetdump - Tool for copying and converting System z dumps
*
* Utilities to decrypt secure execution guest dumps.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_UTILS_H
#define PV_UTILS_H
#include <stdbool.h>
#include <openssl/evp.h>
#include "lib/util_log.h"
#include "libpv/crypto.h"
#include "df_elf.h"
#include "dfi.h"
#include "pv_defs.h"
#include <stdint.h>
#define PV_INVAL_PAGE_STATE 0UL
#define PV_ENCRYPTED_PAGE (1UL << 0)
#define PV_SHARED_PAGE (1UL << 1)
#define PV_ZERO_PAGE (1UL << 2)
#define PV_MAPPED_PAGE (1UL << 3)
#define FUNC_NAME_FLAT_STRUCT_CLEANSE_FREE(type) type##_flat_struct_cleanse_free
#define DEFINE_FLAT_STRUCT_CLEANSE_FREE(type, free_func) \
static void FUNC_NAME_FLAT_STRUCT_CLEANSE_FREE(type)(type * obj) \
{ \
if (!obj) \
return; \
OPENSSL_cleanse(obj, sizeof(type)); \
free_func(obj); \
}
/* The typedef is required to be able to define a autoptr cleanup
* function using glib2.
*/
typedef struct dfi_cpu dfi_cpu_t;
DEFINE_FLAT_STRUCT_CLEANSE_FREE(dfi_cpu_t, dfi_cpu_free)
DEFINE_FLAT_STRUCT_CLEANSE_FREE(pv_dump_completion_data_v1_t, g_free)
DEFINE_FLAT_STRUCT_CLEANSE_FREE(pv_dump_completion_confidential_area_v1_t, g_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(dfi_cpu_t, FUNC_NAME_FLAT_STRUCT_CLEANSE_FREE(dfi_cpu_t))
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(
pv_dump_completion_data_v1_t,
FUNC_NAME_FLAT_STRUCT_CLEANSE_FREE(pv_dump_completion_data_v1_t))
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(
pv_dump_completion_confidential_area_v1_t,
FUNC_NAME_FLAT_STRUCT_CLEANSE_FREE(pv_dump_completion_confidential_area_v1_t))
typedef struct _pv_crypto_ctx pv_crypto_ctx_t;
typedef struct _storage_state_mmap storage_state_mmap_t;
struct _pv_elf_ctx {
BIO *output;
u64 elf_load_off;
pv_crypto_ctx_t *pv_ctx;
storage_state_mmap_t *storage_state_data;
};
typedef struct _pv_elf_ctx pv_elf_ctx_t;
void pv_dump_completion_free(pv_dump_completion_t *cpl);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(pv_dump_completion_t, pv_dump_completion_free)
/**
* pv_derive_dump_key_v1:
* @cpl_data: v1 dump completion data
* @cck: Customer communication key
* @error: return location for a #GError
*
* Derives an 32 byte AES-256-GCM key using the key derivation function HDKF
* together with the customer communication key (CCK) @cck as input keying
* material, and the seed from the completion configuration dump @cpl_data as salt.
*
* Returns: 32 byte AES-256-GCM key on success, %NULL if an error occurred
*/
GBytes *pv_derive_dump_key_v1(const pv_dump_completion_data_v1_t *cpl_data, GBytes *cck,
GError **error);
/**
* pv_decrypt_dump_completion_v1:
* @cpl_data: v1 dump completion data
* @dump_key: Dump key
* @error: return location for a #GError
*
* Decrypts and authenticates the completion configuration dump data @cpl_data
* using the AES-256-GCM @dump_key.
*
* Returns: Decrypted confidential area of the completion configuration dump on success,
* %NULL if an error occurred
*/
pv_dump_completion_v1_t *pv_decrypt_dump_completion_v1(const pv_dump_completion_data_v1_t *cpl_data,
GBytes *dump_key, GError **error);
dfi_cpu_t *pv_decrypt_cpu_note_data(const unsigned int expected_version, GBytes *cpu_note,
GBytes *dump_key, GError **error);
/**
* pv_decrypt_cpu_dump_area_v1:
* @cpu_dump_area: a v1 CPU dump area
* @dump_key: Dump key
* @error: return location for a #GError
*
* Decrypts and authenticates a secure CPU dump using AES-256-GCM with specified
* dump_key.
*
* Returns: Decrypted part of the CPU dump on success, %NULL if an error occurred
*/
GBytes *pv_decrypt_cpu_dump_area_v1(const pv_cpu_dump_v1_t *cpu_dump_area, GBytes *dump_key,
GError **error);
/**
* pv_dfi_cpu_from_pv_cpu:
* @pv_cpu: PV CPU data
*
* Convert PV CPU data to internal dfi_cpu struct.
*
* Returns: #dfi_cpu struct
*/
dfi_cpu_t *pv_dfi_cpu_from_pv_cpu(const pv_cpu_dump_confidential_area_v1_t *pv_cpu);
/**
* pv_crypto_ctx_new:
* @input: a #BIO input
* @key: (array length=key_size): byte data of the key
* @key_size: size of @key in bytes
* @nonce: The PV tweak nonce
* @mode: encrypt or decrypt mode
* @error: return location for a #GError
*
* Create a PV crypto context using @input as the input, @key as the cipher key
* and @nonce as the nonce for deriving the tweaks.
*
* Returns: a new #pv_crypto_ctx_t
*/
pv_crypto_ctx_t *pv_crypto_ctx_new(BIO *input, const unsigned char *key, size_t key_size,
const pv_tweak_nonce_t *nonce, enum PvCryptoMode mode,
GError **error);
/**
* pv_crypto_ctx_free:
* @ctx: a #pv_crypto_ctx_t
*
* Free all resources and the memory allocated for the #pv_crypto_ctx_t
*/
void pv_crypto_ctx_free(pv_crypto_ctx_t *ctx);
/**
* pv_process_pglist:
* @ctx: a #pv_crypto_ctx_t context
* @output: Output
* @tweaks_components: (array length=tweaks_len) (element-type pv_tweak_component_t): tweaks
* components to be used for the decryption
* @tweaks_components_len: the length of @tweaks and the length of the page list to be processed
* @input_off: the file offset of the encrypted memory passed in @ctx to decrypt
* @error: return location for a #GError
*
* Decrypts a page block (e.g. 256 pages).
*
* Returns: number of processed pages on success, -1 if an error occurred
*/
ssize_t pv_process_pglist(pv_crypto_ctx_t *ctx, BIO *output,
const pv_tweak_component_t *tweak_components, size_t tweak_components_len,
long input_off, GError **error);
/**
* calculate_tweak:
*
* calculates the bitwise or of tweak component and nonce.
*/
void calculate_tweak(const pv_tweak_component_t *tweak, const pv_tweak_nonce_t *nonce,
pv_tweak_t *out);
/**
* pv_read_page:
* @output: Input
* @output: Output
*
* Read one page data from @input and write it to @output.
*
* Returns: The number of bytes read for success, -1 if an error occurred
*/
int pv_read_page(BIO *input, BIO *output, GError **error);
/**
* pv_page_state:
*
* Get the page state of the tweak component.
*/
unsigned long pv_page_state(const pv_tweak_component_t *comp);
/**
* pv_get_tweak_components:
* @storage_state_data: input data
* @page_idx: Page index of the fist page
* @page_cnt: number of tweak components that can be at least accessed
*
* get a pointer to the page states of the given pages.
*
* Returns: pointer to page states or NULL in case of an error
*
*/
const pv_tweak_component_t *pv_get_tweak_components(storage_state_mmap_t *storage_state_data,
u64 page_idx, u64 page_cnt);
/**
* pv_elf_ctx_new:
* fd: file descriptor of elf file
* @completion_confidential_decr: content of ection pv_meta size must be
* sizeof(pv_dump_completion_confidential_area_t)
* @storage_state_data: mmap to pv_mem_meta
* @load_offset: offset of LOAD segment in fd
* @error: return value for GError
*
* creates a new elf context for processing the elf file
*
* Returns: new elf context or NULL in case of error
*/
pv_elf_ctx_t *
pv_elf_ctx_new(const int fd,
const pv_dump_completion_confidential_area_v1_t *completion_confidential_decr,
storage_state_mmap_t *storage_state_data, const u64 load_offset, GError **error);
/**
* pv_info_free:
* frees the elf context
*/
void pv_elf_ctx_free(pv_elf_ctx_t *p);
/**
* pv_is_pv_elf:
* @shdrs: list of section headers
* @shnum: size of shdrs list
* @shstrtab: content of shstrtab (section hdr string table)
* @shstrtab_size: size of shstrtab
*
* Returns: true in case it is a PV ELF vmcore dump, false otherwise.
*/
bool pv_is_pv_elf(const Elf64_Shdr *shdrs, const unsigned int shnum, const char *shstrtab,
const size_t shstrtab_size);
/**
* pv_process_section_data:
*
* Uses the ELF sections data to derive dump key, using the provided
* customer-communication-key. It copies the decrypted completion
* data into @completion_decr and mmaps storage state tweaks to storage
* state data.
*
* The caller is responsible for cleanup and overwriting.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_process_section_data(const int fd, const size_t file_size, GBytes *completion_sec,
const u64 storage_state_offset, const size_t storage_state_size,
GBytes *cck, pv_dump_completion_t **completion_decr, GBytes **dump_key,
storage_state_mmap_t **storage_state_data, GError **error);
/**
* pv_elf_read:
*
* elf_ctx: elf context
* @start_addr: first address to read from
* @dst: target
* @size: num bytes to read
* @error: return value for GError
*
* Read size bytes from start addr in elf_ctx and save it into dest.
* Will decrypt pages if defined by page state.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_elf_read(const pv_elf_ctx_t *elf_ctx, const u64 start_addr, void *dst, const u64 size,
GError **error);
/**
* storage_state_mmap_new:
* @fd: file descriptor for which to create the mapping
* @file_size: file size in bytes
* @offset: offset in fd to pv_mem_meta section
* @size: size of mapping (and pv_mem_meta section)
* @error: return value for GError
*
* Returns: new storage_state_mmap context
*/
storage_state_mmap_t *storage_state_mmap_new(const int fd, const size_t file_size, const u64 offset,
const u64 size, GError **error);
/**
* storage_state_ref:
*
* increase the reference counter by one.
*
* Returns: pointer to storage_state
*/
storage_state_mmap_t *storage_state_mmap_ref(storage_state_mmap_t *storage_state);
/**
* storage_state_unref:
*
* Decreases the reference counter by one.
* If the counter is now zero storage_state will be unmapped and freed.
* If the munmap fails, an error will be logged.
*/
void storage_state_mmap_unref(storage_state_mmap_t *storage_state);
#define ZDUMP_PV_UTILS_ERROR g_quark_from_static_string("zdump-pv-utils")
typedef enum {
ZDUMP_ERR_BIO,
ZDUMP_ERR_BIO_FAIL,
ZDUMP_ERR_BIO_KEY,
ZDUMP_ERR_CORRUPTED_COMPL_DATA,
ZDUMP_ERR_CORRUPTED_NOTE,
ZDUMP_ERR_CRYPTO_CTX,
ZDUMP_ERR_ELF_CTX,
ZDUMP_ERR_ELF_CTX_BIO,
ZDUMP_ERR_ELF_READ,
ZDUMP_ERR_ELF_READ_END_ADDR_OVERFLOW,
ZDUMP_ERR_MMAP,
ZDUMP_ERR_PAGELIST_ELF_OFFSET_TOO_LARGE,
ZDUMP_ERR_PAGE_END_ADDR_OVERFLOW,
ZDUMP_ERR_PAGE_START_ADDR_OVERFLOW,
ZDUMP_ERR_PGLIST_BIO,
ZDUMP_ERR_PGLIST_INVAL,
ZDUMP_ERR_PGLIST_INVAL_STATE,
ZDUMP_ERR_PROC_SECT,
ZDUMP_ERR_TWEAK,
ZDUMP_ERR_UNSUPP_COMPL_VER,
ZDUMP_ERR_UNSUPP_SEC_CPU_VER,
ZDUMP_ERR_WRONG_AAD_SIZE,
ZDUMP_ERR_WRONG_CCK_SIZE,
ZDUMP_ERR_WRONG_CONFIDENTIAL_SIZE,
ZDUMP_ERR_WRONG_NOTE_SIZE,
ZDUMP_ERR_WRONG_TAG_SIZE,
} zdump_pv_utils_error_e;
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(pv_crypto_ctx_t, pv_crypto_ctx_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(pv_elf_ctx_t, pv_elf_ctx_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(storage_state_mmap_t, storage_state_mmap_unref)
#endif /* PV_UTILS_H */
|