From 065f58af22ddc1b061656b633cf0186b8bff6999 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Sat, 26 Aug 2017 10:44:13 -0500 Subject: [PATCH] app/blk_shred: fill a block device with noise The blk_shred utitity write over an entire Block session region with noise suitable as a ciphertext background. See the 'sequence' utility for making multiple write passes. Fix #81 --- run/blk_shred.run | 75 ++++++++++ src/app/blk_shred/main.cc | 277 ++++++++++++++++++++++++++++++++++++ src/app/blk_shred/target.mk | 3 + 3 files changed, 355 insertions(+) create mode 100644 run/blk_shred.run create mode 100644 src/app/blk_shred/main.cc create mode 100644 src/app/blk_shred/target.mk diff --git a/run/blk_shred.run b/run/blk_shred.run new file mode 100644 index 0000000..c203eb0 --- /dev/null +++ b/run/blk_shred.run @@ -0,0 +1,75 @@ +# +# \brief Scenario to wipe hard drive in target machine +# \author Emery Hemingway +# \date 2017-08-26 +# + + +# +# Build +# +set build_components { app/blk_shred } + +source ${genode_dir}/repos/base/run/platform_drv.inc +append_platform_drv_build_components + +build $build_components + +create_boot_directory + +import_from_depot \ + genodelabs/src/[base_src] \ + genodelabs/src/init \ + genodelabs/src/ahci_drv \ + +# +# Generate config +# +set config { + + + + + + + + + + + + + + + + + + + } + +append_platform_drv_config + +append config { + + + + + + + + + + + } + +install_config $config + +# +# Boot modules +# +set boot_modules { blk_shred } + +append_platform_drv_boot_modules + +build_boot_image $boot_modules + +run_genode_until forever diff --git a/src/app/blk_shred/main.cc b/src/app/blk_shred/main.cc new file mode 100644 index 0000000..2846884 --- /dev/null +++ b/src/app/blk_shred/main.cc @@ -0,0 +1,277 @@ +/* + * \brief Block shredder + * \author Emery Hemingway + * \date 2017-08-26 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/** + * TODO: + * - Progress report + */ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* Jitterentropy includes */ +#include + +/* PCG includes */ +#include + + +namespace Blk_shred { + using namespace Genode; + using namespace Block; + struct Main; + + enum { + /* XXX: part_blk has a fixed backend buffer that limits our packet size */ + PKT_SIZE = 1 << 20, + PKT_BUF_SIZE = PKT_SIZE*2 + (32<<10) + }; + + uint64_t pcg_init[2] = PCG32_INITIALIZER; +} + + +struct Blk_shred::Main +{ + Genode::Env &env; + + Timer::Connection timer { env }; + + Heap heap { env.pd(), env.rm() }; + + Allocator_avl packet_alloc { &heap }; + + Block::Connection blk { + env, &packet_alloc, PKT_BUF_SIZE }; + + Block::Session::Tx::Source &pkt_source = *blk.tx(); + + size_t blk_size = 0; + Block::sector_t blk_total= 0; + + rand_data *jent; + pcg32_random_t pcg; + + template + void die(ARGS &&... args) + { + /* wipe noise state */ + seed_noise(); + + error(args...); + env.parent().exit(~0); + sleep_forever(); + } + + void seed_noise() + { + /* read entropy into initialization variables */ + jent_read_entropy(jent, (char*)&pcg_init, sizeof(pcg_init)); + pcg_init[1] |= 1; + + pcg32_srandom_r(&pcg, pcg_init[0], pcg_init[1]); + } + + Main(Genode::Env &env) : env(env) + { + /*********************** + ** Seed noise source ** + ***********************/ + + jitterentropy_init(heap); + if (jent_entropy_init() != 0) + die("jitterentropy library could not be initialized!"); + + jent = jent_entropy_collector_alloc(0, 0); + if (!jent) + die("jitterentropy could not allocate entropy collector!"); + + seed_noise(); + + + /**************************************** + ** Initialize block device parameters ** + ****************************************/ + + { + Block::Session::Operations ops; + blk.info(&blk_total, &blk_size, &ops); + + if (!ops.supported(Block::Packet_descriptor::WRITE)) + die("block device not writeable!"); + } + } + + ~Main() + { + /* wipe noise state */ + seed_noise(); + + jent_entropy_collector_free(jent); + } + + void submit_noise(Block::Packet_descriptor const &pkt) + { + uint32_t *buffer = (uint32_t*)pkt_source.packet_content(pkt); + for (size_t i = 0; i < ((pkt.block_count()*blk_size) / sizeof(uint32_t)); ++i) + buffer[i] = pcg32_random_r(&pcg); + pkt_source.submit_packet(pkt); + } + + void shred() + { + float const mbytes = (float(blk_total) * float(blk_size)) / (1<<20); + log("shredding ", mbytes/(1<<10), " GiB..."); + auto start_ms = timer.elapsed_ms(); + + size_t const blk_per_pkt = PKT_SIZE / blk_size; + size_t const bytes_per_pkt = blk_per_pkt * blk_size; + + /* + * send two packets in succession, the first write + * aligns those that follow with end of the device + */ + Block::sector_t blk_offset = blk_total % blk_per_pkt; + if (blk_offset == 0) + blk_offset = blk_per_pkt; + + { + Block::Packet_descriptor pkt( + pkt_source.alloc_packet(bytes_per_pkt), + Block::Packet_descriptor::WRITE, + 0, blk_offset); + submit_noise(pkt); + } + + { + Block::Packet_descriptor pkt( + pkt_source.alloc_packet(bytes_per_pkt), + Block::Packet_descriptor::WRITE, + blk_offset, blk_per_pkt); + submit_noise(pkt); + blk_offset += blk_per_pkt; + } + + while (true) { + Block::Packet_descriptor const ack = pkt_source.get_acked_packet(); + if (!ack.succeeded()) + error("ack indicates failure ", ack.block_number(),"/",blk_total); + + pkt_source.release_packet(ack); + + if (blk_offset >= blk_total) break; + + /* reuse packet buffer region */ + Block::Packet_descriptor const pkt( + ack, Block::Packet_descriptor::WRITE, + blk_offset, blk_per_pkt); + submit_noise(pkt); + blk_offset += blk_per_pkt; + } + + Block::Packet_descriptor const ack = pkt_source.get_acked_packet(); + if (!ack.succeeded()) + error("ack indicates failure ", ack.block_number(),"/",blk_total); + + float seconds = (timer.elapsed_ms() - start_ms) / 1000; + log("shred complete, ", mbytes / seconds, " MiB/s"); + } + + /** + * Verify a block, PCG must first be seeked into position + */ + bool verify_block(Block::sector_t sector) + { + Block::Packet_descriptor pkt( + pkt_source.alloc_packet(blk_size), + Block::Packet_descriptor::READ, sector, 1); + + pkt_source.submit_packet(pkt); + pkt = pkt_source.get_acked_packet(); + pkt_source.release_packet(pkt); + + if (!pkt.succeeded()) + die("error while reading back sector ", sector); + + uint32_t *buffer = (uint32_t*)pkt_source.packet_content(pkt); + for (size_t i = 0; i < (blk_size / sizeof(uint32_t)); ++i) { + if (buffer[i] != pcg32_random_r(&pcg)) + die("sector ", sector, " is invalid"); + } + return true; + } + + /** + * Verify random blocks + */ + void verify() + { + /* a weak RNG to generate skips */ + pcg32_random_t skip_gen; + pcg32_srandom_r(&skip_gen, pcg32_random_r(&pcg), pcg32_random_r(&pcg)); + + /* reset the noise generator */ + pcg32_srandom_r(&pcg, pcg_init[0], pcg_init[1]); + + /* make jumps of approximately 1 Mib */ + int const max_jump = (2<<20) / blk_size; + int const step = blk_size / sizeof(uint32_t); + Block::sector_t sector_offset = 0; + unsigned long count = 0; + + /* verify the first block and loop */ + if (!verify_block(sector_offset)) return; + ++count; + + /* random jump loop */ + while (true) { + /* make a bounded random jumps */ + Block::sector_t skip = + pcg32_boundedrand_r(&skip_gen, max_jump)+1; + + if (sector_offset+skip >= blk_total) + break; + + /* move the sector offset ahead */ + sector_offset += skip; + + /* seek the noise source ahead for the next read */ + pcg32_advance_r(&pcg, (skip-1)*step); + + if (!verify_block(sector_offset)) return; + ++count; + } + + /* verify the last block */ + pcg32_advance_r(&pcg, (blk_total-(sector_offset+2))*step); + if (!verify_block(blk_total-1)) return; + ++count; + + log(count, " blocks passed random spot check"); + } +}; + + +void Component::construct(Genode::Env &env) +{ + Blk_shred::Main main(env); + + main.shred(); + main.verify(); + + env.parent().exit(0); +} diff --git a/src/app/blk_shred/target.mk b/src/app/blk_shred/target.mk new file mode 100644 index 0000000..37f2c66 --- /dev/null +++ b/src/app/blk_shred/target.mk @@ -0,0 +1,3 @@ +TARGET = blk_shred +LIBS = base jitterentropy libpcg_random +SRC_CC = main.cc