tresor: streamline design further

* differentiates request types that where merged formerly per module;
  e.g. instead of type Superblock_control::Request, there are now types
  * Superblock_control::Read_vbas
  * Superblock_control::Write_vbas
  * Superblock_control::Rekey
  * Superblock_control::Initialize
  * ...
  each holding only the state and functionality that is required for exactly
  that request

* removes all classes of the Tresor module framework and adapts all
  Tresor- and File-Vault- related libs, apps, and tests accordingly
  * the former "channel" state is merged into the new request types, meaning, a
    request manages no longer only the "call" to a functionality but
    also the execution of that functionality; every request has a lifetime
    equal to the "call" and an execute method to be driven forward
  * state that is used by a request but has a longer lifetime (e.g. VFS file
    handles in Tresor::Crypto) is managed by the top level
    of the user and handed over via the execute arguments; however, the
    synchronization of multiple requests on this state is done by the module
    (e.g. Tresor::Crypto)
  * requests are now driven explicitly as first argument of the (overloaded)
    execute method of their module; the module can, however, stall a request
    by returning false without doing anything (used for synchronization on
    resources)

* introduces Request_helper, Generated_request and Generatable_request in the
  Tresor namespace in order to avoid the redundancy of sub-request generation
  and execution

* moves access to Client-Data pointers up to Tresor::Virtual_block_device in
  order to simplify Tresor::Block_io and Tresor::Crypto

* removes Tresor::Client_data and introduces pure interface
  Client_data_interface in order to remove  Tresor::Client_data and
  move management of Client Data to the top level of a Tresor user

* introduces pure interface Crypto_files_interface in order to move management
  of Crypto files to the top level of a Tresor user

* moves management of Block-IO and Trust-Anchor files to the top level of a
  Tresor user

* adapts all execute methods, so, that they return the progress state
  instead of modifying a reference argument

* removes Tresor::Request_and Tresor:Request and instead implements
  scheduling at the top level of the Tresor user
  * the Tresor Tester uses a list as schedule that holds Command objects; this
    list ensures, that commands are started in the order of configuration
    the Command type is a merge of the state of all possible commands that can
    be configured at the Tresor Tester; the actual Tresor requests (if any) are
    then allocated on-demand only
  * the Tresor VFS plugin does not use a dynamic data structure for scheduling;
    the plugin has 5 members that each reflect a distinct type of operation:
    * initialize operation
    * deinitialize operation
    * data operation
    * extend operation
    * rekey operation
    consequently, of each type, there can be only one operation in-flight at a
    time; at the user front-end each operation (except "initialize") can be
    controlled through a dedicated VFS file; for each of these files, the VFS
    expects only one handle to be open at a time and only one file operation
    (read, write, sync) active at a time; once an operation gets started it is
    finished without preemtion (except of the interleaving at rekey and
    extend); when multiple operations are waiting to be started the plugin
    follows a static priority scheme:

      init op > deinit op > data op > extend op > rekey op

    there are some operation-specific details
    * the initialize operation is started only by the plugin itself on startup
      and will be driven as side effect by subsequent user calls to file
      operations
    * the data file is the only contiguous file in the front end and the file
      operations work as on usual data files
    * the other 3 files are transactional files and the user is expected to
      follow this scheme when operating on them
      1) stat (to determine file size)
      2) seek to offset 0
      3) read entire file once (this will be queued until there is no operation
         of this type pending anymore and return the last result:
         "none" | "failed" | "succeeded"; used primarily for synchronization)
      4) write operation parameters (this returns immediately and marks the
         operation as "requested")
      5) read entire file once (the same as above but this time in order to
         determine the operation result)
    * the rekey op and deinitialize op are requested by writing "true"
    * the extend op is requested by writing "tree=[TREE], blocks=[BLOCKS]"
      where TREE is either "vbd" or "ft" and BLOCKS is the number of physical
      4K blocks by which the physical range of the tresor container expands
      (the physical range always starts at block address 0 and is always
      expanded upwards)

* replaces the former <trust-anchor op="initialize"> command at the Tresor
  Tester with <initialize-trust-achor> as there are no other trust anchor
  operations that can be requested through the Tester config anyway

* removes the "sync" attribute from all commands at the Tresor Tester except
  from <request op="rekey">, <request "extend_ft">, <request op="extend_vbd">;
  as the Tester controls scheduling now, requests are generally synchronous;
  at the rekeying and extension commands, the "sync" attribute determines
  wether subsequent commands are interleaved with the execution of these
  commands (if possible)

* removes "debug" config attribute from Tresor VFS plugin and reworks "verbose"
  attribute to generate more sensible output

* removes NONCOPYABLE macro and instead uses Genode::Noncopyable and in-place
  Constructors deletion

* introduces types Attr and Execute_attr where a constructor or execute method
  have many arguments in order to raise readability

* renames the "hashsum" file that is provided by the Tresor Trust-Anchor VFS
  plugin to "hash" in order to become conformant with the wording in the Tresor
  lib

* makes the VFS Tresor test an automated test by merging in the functionality
  of vfs_tresor_init.run and removing the interactive front end; removes
  vfs_tresor_init.run as it is not needed anymore; adds consideration for
  autopilot file structure in the Test and adds it to autopilot.list

* removes all snapshot controls and the progress files for rekeying and
  extending from the Tresor VFS plugin; both functionalities were tested
  only rudimentary by the VFS Tresor test and are not supported with the only
  real user, the File Vault

* use /* .. */ instead of // ..
* use (..) instead of { .. } in init lists

Ref #5148
This commit is contained in:
Martin Stein 2023-12-14 13:54:57 +01:00 committed by Christian Helmuth
parent 14f4aa6e05
commit b4c4681733
55 changed files with 7098 additions and 9859 deletions

View File

@ -1,7 +1,6 @@
TRESOR_DIR := $(REP_DIR)/src/lib/tresor
SRC_CC += crypto.cc
SRC_CC += request_pool.cc
SRC_CC += hash.cc
SRC_CC += trust_anchor.cc
SRC_CC += block_io.cc
@ -9,7 +8,6 @@ SRC_CC += meta_tree.cc
SRC_CC += virtual_block_device.cc
SRC_CC += superblock_control.cc
SRC_CC += free_tree.cc
SRC_CC += module.cc
SRC_CC += vbd_initializer.cc
SRC_CC += ft_initializer.cc
SRC_CC += sb_initializer.cc

View File

@ -1,6 +1,6 @@
LIB_DIR := $(REP_DIR)/src/lib/vfs/tresor
SRC_CC := vfs.cc splitter.cc
SRC_CC := vfs.cc
INC_DIR += $(LIB_DIR)

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,26 @@
assert_spec linux
set dd [installed_command dd]
create_boot_directory
proc tresor_image_file { } {
return "vfs_tresor_block.img"
}
proc tresor_image_name { } { return "vfs_tresor_block.img" }
set use_interactively [expr ![get_cmd_switch --autopilot]]
proc tresor_image_size_mb { } { return 4 }
import_from_depot [depot_user]/pkg/[drivers_interactive_pkg] \
[depot_user]/pkg/terminal \
[depot_user]/src/ncurses \
proc local_tresor_image { } { return bin/[tresor_image_name] }
proc autopilot_tresor_image { } { return /tmp/[tresor_image_name].[exec id -un] }
import_from_depot [depot_user]/src/ncurses \
[depot_user]/src/bash \
[depot_user]/src/coreutils \
[depot_user]/src/nitpicker
[depot_user]/src/coreutils
build {
core lib/ld timer init
server/lx_fs
core
timer
init
lib/ld
lib/vfs_tresor
lib/vfs_tresor_crypto_aes_cbc
lib/vfs_tresor_crypto_memcopy
@ -26,17 +28,24 @@ build {
lib/vfs_import
lib/vfs_jitterentropy
lib/vfs_pipe
lib/vfs lib/libc lib/posix lib/libcrypto
lib/vfs
lib/libc
lib/libm
lib/posix
lib/libcrypto
test/vfs_stress
test/libc
server/log_terminal
server/report_rom
server/fs_rom
server/lx_fs
server/vfs
app/tresor_init_trust_anchor
app/tresor_init
app/sequence
}
set config {
append config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
@ -54,64 +63,20 @@ set config {
</default-route>
<default caps="100"/>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="drivers" caps="1000" managing_system="yes">
<resource name="RAM" quantum="32M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config"> <parent label="drivers.config"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="Capture"> <child name="nitpicker"/> </service>
<service name="Event"> <child name="nitpicker"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="nitpicker">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Gui"/>
<service name="Capture"/>
<service name="Event"/>
</provides>
<config focus="rom" request_framebuffer="no" request_input="no">
<capture/> <event/>
<domain name="default" layer="2" content="client" label="no" hover="always"/>
<default-policy domain="default"/>
</config>
<route>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
append_if $use_interactively config {
<start name="terminal_service" caps="110">
<binary name="terminal"/>
<resource name="RAM" quantum="12M"/>
<provides><service name="Terminal"/></provides>
<route>
<service name="ROM" label="config"> <parent label="terminal.config"/> </service>
<service name="Gui"> <child name="nitpicker"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
append_if [expr !$use_interactively] config {
<start name="terminal_service" caps="110">
<binary name="log_terminal"/>
<start name="log_terminal" caps="110">
<resource name="RAM" quantum="2M"/>
<provides><service name="Terminal"/></provides>
<route>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
</start>
append config {
<start name="lx_fs" ld="no">
<resource name="RAM" quantum="4M"/>
<provides> <service name="File_system"/> </provides>
@ -127,15 +92,9 @@ append config {
<config>
<vfs>
<ram/>
<import>
<rom name="encrypted_private_key"/>
<rom name="superblock_hash"/>
</import>
<dir name="dev">
<jitterentropy/>
<tresor_trust_anchor name="tresor_trust_anchor"
storage_dir="/"/>
<tresor_trust_anchor name="tresor_trust_anchor" storage_dir="/"/>
</dir>
</vfs>
@ -146,8 +105,7 @@ append config {
</route>
</start>
<start name="initialize_tresor" caps="3000">
<binary name="sequence"/>
<start name="sequence" caps="3000">
<resource name="RAM" quantum="300M"/>
<config>
@ -156,12 +114,37 @@ append config {
<config passphrase="foobar" trust_anchor_dir="/trust_anchor">
<vfs>
<dir name="trust_anchor">
<fs label="ta"/>
<fs label="tresor_trust_anchor"/>
</dir>
</vfs>
</config>
</start>
<start name="tresor_init">
<resource name="RAM" quantum="4M"/>
<config>
<block-io type="vfs" path="/} [tresor_image_name] {"/>
<crypto path="/crypto"/>
<trust-anchor path="/trust_anchor"/>
<vfs>
<fs label="tresor_block_io" buffer_size="1M"/>
<tresor_crypto_aes_cbc name="crypto"/>
<dir name="trust_anchor">
<fs label="tresor_trust_anchor"/>
</dir>
</vfs>
<virtual-block-device nr_of_levels="3" nr_of_children="64" nr_of_leafs="512" />
<free-tree nr_of_levels="3" nr_of_children="64" nr_of_leafs="2048" />
</config>
<route>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="init" caps="1600">
<resource name="RAM" quantum="256M"/>
<config verbose="yes">
@ -188,12 +171,12 @@ append config {
<provides><service name="File_system"/></provides>
<config>
<vfs>
<fs buffer_size="1M" label="fs_backend"/>
<fs buffer_size="1M" label="tresor_block_io"/>
<tresor_crypto_aes_cbc name="tresor_crypto"/>
<dir name="ta"> <fs buffer_size="1M" label="ta"/> </dir>
<dir name="ta"> <fs buffer_size="1M" label="tresor_trust_anchor"/> </dir>
<dir name="dev">
<tresor name="tresor" debug="no" verbose="yes"
block="/} [tresor_image_file] {"
block="/} [tresor_image_name] {"
crypto="/tresor_crypto"
trust_anchor="/ta"/>
</dir>
@ -202,8 +185,6 @@ append config {
<default-policy root="/dev" writeable="yes"/>
</config>
<route>
<service name="File_system" label="fs_backend"> <parent label="fs"/> </service>
<service name="File_system" label="ta"> <parent label="ta"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
@ -230,7 +211,7 @@ append config {
<default-policy root="/" writeable="yes"/>
</config>
<route>
<service name="Terminal"> <parent label="terminal_service"/> </service>
<service name="Terminal"> <parent label="log_terminal"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<any-service> <parent/> </any-service>
</route>
@ -266,21 +247,23 @@ append config {
<env key="PATH" value="/bin"/>
</config>
<route>
<service name="File_system" label="shell"> <child name="vfs"/> </service>
<service name="File_system" label="tresor"> <child name="vfs_tresor"/> </service>
<service name="File_system" label="shell"> <child name="vfs"/> </service>
<service name="File_system" label="tresor"> <child name="vfs_tresor"/> </service>
<service name="ROM" label_suffix=".lib.so"> <parent/> </service>
<service name="ROM" label_last="/bin/bash"> <child name="vfs_rom"/> </service>
<service name="ROM" label_prefix="/bin"> <child name="vfs_rom"/> </service>
<service name="ROM" label_prefix="/bin"> <child name="vfs_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>
</start>
</config>
<route>
<service name="Terminal"> <child name="terminal_service"/> </service>
<service name="File_system" label_last="fs"> <child name="lx_fs"/> </service>
<service name="File_system" label_last="ta"> <child name="vfs_tresor_trust_anchor"/> </service>
<service name="Terminal"> <child name="log_terminal"/> </service>
<service name="File_system" label_suffix="tresor_block_io"> <child name="lx_fs"/> </service>
<service name="File_system" label_suffix="tresor_trust_anchor"> <child name="vfs_tresor_trust_anchor"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<any-service> <parent/> </any-service>
</route>
@ -294,19 +277,28 @@ set shell_script "run/vfs_tresor.sh"
set repo "[repository_contains $shell_script]"
exec cp $repo/$shell_script bin/
exec rm -rf [local_tresor_image]
if { [get_cmd_switch --autopilot] } {
exec rm -rf [autopilot_tresor_image]
catch { exec $dd if=/dev/urandom of=[autopilot_tresor_image] bs=1M count=[tresor_image_size_mb] }
exec ln -sf -T [autopilot_tresor_image] [local_tresor_image]
} else {
catch { exec $dd if=/dev/urandom of=[local_tresor_image] bs=1M count=[tresor_image_size_mb] }
}
set boot_modules [build_artifacts]
append boot_modules { vfs_tresor.sh encrypted_private_key superblock_hash }
lappend boot_modules [tresor_image_file]
set fd [open [run_dir]/genode/focus w]
puts $fd "<focus label=\"terminal_service -> \" domain=\"default\"/>"
close $fd
append boot_modules { vfs_tresor.sh }
lappend boot_modules [tresor_image_name]
build_boot_image $boot_modules
if {$use_interactively} {
run_genode_until forever
} else {
run_genode_until {.*--- Automated Tresor testing finished.*} 1800
run_genode_until {.*"/bin/bash".* exited with exit value 0.*\n} 120
if { [get_cmd_switch --autopilot] } {
exec rm -rf [local_tresor_image]
exec rm -rf [autopilot_tresor_image]
}

View File

@ -55,33 +55,25 @@ test_read_compare_1() {
fi
}
test_create_snapshot() {
test_deinitialize() {
local tresor_dir="$1"
echo "Create snapshot"
echo true > $tresor_dir/control/create_snapshot
echo "Deinitialize"
local state="$(< $tresor_dir/control/deinitialize)"
echo true > $tresor_dir/control/deinitialize
}
test_list_snapshots() {
wait_for_deinitialize() {
local tresor_dir="$1"
echo "List content of '$tresor_dir'"
ls -l $tresor_dir/snapshots
}
test_discard_snapshot() {
local tresor_dir="$1"
local snap_id=$2
echo "Discard snapshot with id: $snap_id"
echo $snap_id > $tresor_dir/control/discard_snapshot
echo "Wait for deinitialize"
local state="$(< $tresor_dir/control/deinitialize)"
}
test_rekey_start() {
local tresor_dir="$1"
echo "Start rekeying"
echo on > $tresor_dir/control/rekey
local state="$(< $tresor_dir/control/rekey)"
echo true > $tresor_dir/control/rekey
echo "Reykeying started"
}
@ -137,16 +129,14 @@ wait_for_rekeying() {
echo "Wait for rekeying to finish..."
while : ; do
local done=0
local file_content="$(< $tresor_dir/control/rekey_progress)"
local file_content="$(< $tresor_dir/control/rekey)"
# XXX remove later
echo "file_content: ${file_content}"
case "$file_content" in
*at*)
if [ "$verbose" = "yes" ]; then
echo "Rekeying: $file_content"
fi
*failed*)
done=1;
;;
*idle*)
*succeeded*)
done=1;
;;
esac
@ -163,16 +153,14 @@ wait_for_vbd_extension() {
echo "Wait for VBD extension to finish..."
while : ; do
local done=0
local file_content="$(< $tresor_dir/control/extend_progress)"
local file_content="$(< $tresor_dir/control/extend)"
# XXX remove later
echo "file_content: ${file_content}"
case "$file_content" in
*at*)
if [ "$verbose" = "yes" ]; then
echo "Extending VBD: $file_content"
fi
*failed*)
done=1;
;;
*idle*)
*succeeded*)
done=1;
;;
esac
@ -189,16 +177,14 @@ wait_for_ft_extension() {
echo "Wait for FT extension to finish..."
while : ; do
local done=0
local file_content="$(< $tresor_dir/control/extend_progress)"
local file_content="$(< $tresor_dir/control/extend)"
# XXX remove later
echo "file_content: ${file_content}"
case "$file_content" in
*at*)
if [ "$verbose" = "yes" ]; then
echo "Extending FT: $file_content"
fi
*failed*)
done=1;
;;
*idle*)
*succeeded*)
done=1;
;;
esac
@ -212,95 +198,37 @@ wait_for_ft_extension() {
main() {
local tresor_dir="/dev/tresor"
local data_file="$tresor_dir/current/data"
echo "list files..."
ls -l $tresor_dir
for i in $(seq 3); do
echo "--> Run $i:"
test_read_seq_unaligned_512 "$data_file" "1048576"
local pattern_file="/tmp/pattern"
produce_pattern "$i" "4096" > $pattern_file
test_write_1 "$data_file" "419"
test_write_1 "$data_file" "63"
test_write_1 "$data_file" "333"
test_vbd_extension "$tresor_dir" "1000"
test_read_compare_1 "$data_file" "63"
test_write_1 "$data_file" "175"
test_read_compare_1 "$data_file" "419"
test_write_1 "$data_file" "91"
test_read_compare_1 "$data_file" "175"
test_read_compare_1 "$data_file" "91"
test_read_compare_1 "$data_file" "333"
wait_for_vbd_extension "$tresor_dir"
test_write_1 "$data_file" "32"
test_write_1 "$data_file" "77"
test_write_1 "$data_file" "199"
#test_ft_extension "$tresor_dir" "1000"
test_read_compare_1 "$data_file" "32"
test_write_1 "$data_file" "211"
test_read_compare_1 "$data_file" "77"
test_write_1 "$data_file" "278"
test_read_compare_1 "$data_file" "199"
test_read_compare_1 "$data_file" "278"
test_read_compare_1 "$data_file" "211"
#wait_for_ft_extension "$tresor_dir"
test_write_1 "$data_file" "0"
test_write_1 "$data_file" "8"
test_write_1 "$data_file" "16"
test_write_1 "$data_file" "490"
test_write_1 "$data_file" "468"
test_read_compare_1 "$data_file" "0"
test_read_compare_1 "$data_file" "8"
test_read_compare_1 "$data_file" "16"
test_read_compare_1 "$data_file" "490"
#test_rekey "$tresor_dir"
test_rekey_start "$tresor_dir"
test_write_1 "$data_file" "0"
test_rekey_state "$tresor_dir"
test_read_compare_1 "$data_file" "490"
test_rekey_state "$tresor_dir"
test_write_1 "$data_file" "16"
test_rekey_state "$tresor_dir"
test_read_compare_1 "$data_file" "468"
test_rekey_state "$tresor_dir"
test_read_compare_1 "$data_file" "8"
test_rekey_state "$tresor_dir"
test_read_compare_1 "$data_file" "16"
test_rekey_state "$tresor_dir"
test_read_compare_1 "$data_file" "0"
test_write_1 "$data_file" "300"
test_write_1 "$data_file" "240"
test_write_1 "$data_file" "201"
test_write_1 "$data_file" "328"
wait_for_rekeying "$tresor_dir" "yes"
echo "--> Run $i done"
done
echo "--> Read/Compare test"
test_read_compare_1 "$data_file" "0"
test_read_compare_1 "$data_file" "490"
test_read_compare_1 "$data_file" "468"
test_read_compare_1 "$data_file" "8"
test_read_compare_1 "$data_file" "16"
echo "--> Read/Compare test done"
echo "--- Automated Tresor testing finished, shell is yours ---"
echo "produce pattern..."
local pattern_file="/tmp/pattern"
produce_pattern "1" "4096" > $pattern_file
echo "write..."
test_write_1 "$data_file" "20"
echo "read..."
test_read_compare_1 "$data_file" "20"
test_write_1 "$data_file" "20"
echo "extend VBD..."
test_vbd_extension "$tresor_dir" "100"
test_write_1 "$data_file" "2"
test_read_compare_1 "$data_file" "2"
wait_for_vbd_extension "$tresor_dir"
echo "extend FT..."
test_ft_extension "$tresor_dir" "100"
test_write_1 "$data_file" "2"
test_read_compare_1 "$data_file" "2"
wait_for_ft_extension "$tresor_dir"
echo "rekey..."
test_rekey_start "$tresor_dir"
test_write_1 "$data_file" "2"
test_read_compare_1 "$data_file" "2"
wait_for_rekeying "$tresor_dir" "no"
test_deinitialize "$tresor_dir"
wait_for_deinitialize "$tresor_dir"
echo "done!"
}
main "$@"
# just drop into shell
# exit 0
exit 0

View File

@ -1,153 +0,0 @@
assert_spec linux
proc tresor_image_file { } {
return "vfs_tresor_block.img"
}
set image_size 32
proc tresor_image_size_mb { } {
global image_size
return $image_size
}
build {
core lib/ld init timer
server/lx_block
server/lx_fs
server/vfs lib/vfs
app/sequence
app/tresor_init_trust_anchor
app/tresor_init
lib/vfs_tresor_crypto_aes_cbc
lib/vfs_tresor_trust_anchor
lib/vfs_jitterentropy
lib/libc
lib/libcrypto
}
create_boot_directory
append config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="lx_fs" ld="no">
<resource name="RAM" quantum="2M"/>
<provides> <service name="File_system"/> </provides>
<config>
<default-policy root="/" writeable="yes"/>
</config>
</start>
<start name="vfs_trust_anchor" caps="120">
<binary name="vfs"/>
<resource name="RAM" quantum="16M"/>
<provides><service name="File_system"/></provides>
<config>
<vfs>
<dir name="ta_storage">
<fs/>
</dir>
<dir name="dev">
<jitterentropy/>
<tresor_trust_anchor name="tresor_trust_anchor"
storage_dir="/ta_storage"/>
</dir>
</vfs>
<default-policy root="/dev/tresor_trust_anchor" writeable="yes"/>
</config>
<route>
<service name="File_system"> <child name="lx_fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="initialize_tresor" caps="200">
<binary name="sequence"/>
<resource name="RAM" quantum="128M"/>
<config>
<start name="tresor_init_trust_anchor">
<resource name="RAM" quantum="4M"/>
<config passphrase="foobar" trust_anchor_dir="/trust_anchor">
<vfs>
<dir name="trust_anchor">
<fs label="ta"/>
</dir>
</vfs>
</config>
</start>
<start name="tresor_init">
<resource name="RAM" quantum="4M"/>
<config>
<block-io type="vfs" path="/} [tresor_image_file] {"/>
<crypto path="/crypto"/>
<trust-anchor path="/trust_anchor"/>
<vfs>
<fs buffer_size="1M"/>
<tresor_crypto_aes_cbc name="crypto"/>
<dir name="trust_anchor">
<fs label="ta"/>
</dir>
</vfs>
<virtual-block-device
nr_of_levels="3"
nr_of_children="64"
nr_of_leafs="512" />
<free-tree
nr_of_levels="3"
nr_of_children="64"
nr_of_leafs="2048" />
</config>
</start>
</config>
<route>
<service name="File_system" label_last="ta">
<child name="vfs_trust_anchor"/>
</service>
<service name="File_system"> <child name="lx_fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>}
install_config $config
exec rm -rf bin/[tresor_image_file]
exec truncate -s [tresor_image_size_mb]M bin/[tresor_image_file]
build_boot_image [list {*}[build_artifacts] [tresor_image_file]]
run_genode_until {.*child "initialize_tresor" exited with exit value 0.*\n} 240
exec cp [run_dir]/genode/encrypted_private_key bin
exec cp [run_dir]/genode/superblock_hash bin

View File

@ -641,8 +641,28 @@ class File_vault::Main
size_t nr_of_ft_children,
size_t nr_of_ft_leafs);
static bool tresor_control_file_yields_state_idle(Xml_node const &fs_query_listing,
char const *file_name);
template <size_t N>
static bool listing_file_starts_with(Xml_node const &fs_query_listing,
char const *file_name,
String<N> const &str)
{
bool result { false };
bool done { false };
fs_query_listing.with_optional_sub_node("dir", [&] (Xml_node const &node_0) {
node_0.for_each_sub_node("file", [&] (Xml_node const &node_1) {
if (done) {
return;
}
if (node_1.attribute_value("name", String<16>()) == file_name) {
node_1.with_raw_content([&] (char const *base, size_t size) {
result = String<N> { Cstring {base, size} } == str;
done = true;
});
}
});
});
return result;
}
/***************************************************
@ -699,28 +719,6 @@ void Main::_handle_ui_config()
}
bool Main::tresor_control_file_yields_state_idle(Xml_node const &fs_query_listing,
char const *file_name)
{
bool result { false };
bool done { false };
fs_query_listing.with_optional_sub_node("dir", [&] (Xml_node const &node_0) {
node_0.for_each_sub_node("file", [&] (Xml_node const &node_1) {
if (done) {
return;
}
if (node_1.attribute_value("name", String<16>()) == file_name) {
node_1.with_raw_content([&] (char const *base, size_t size) {
result = String<5> { Cstring {base, size} } == "idle";
done = true;
});
}
});
});
return result;
}
void Main::_update_sandbox_config()
{
Buffered_xml const config { _heap, "config", [&] (Xml_generator &xml) {
@ -940,16 +938,20 @@ void Main::_handle_resizing_fs_query_listing(Xml_node const &node)
switch (_resizing_state) {
case Resizing_state::WAIT_TILL_DEVICE_IS_READY:
if (tresor_control_file_yields_state_idle(node, "extend_progress")) {
if (listing_file_starts_with(node, "extend", String<10>("succeeded")) ||
listing_file_starts_with(node, "extend", String<5>("none"))) {
_resizing_state = Resizing_state::ISSUE_REQUEST_AT_DEVICE;
Signal_transmitter(_state_handler).submit();
}
} else
error("failed to extend: tresor not ready");
break;
case Resizing_state::IN_PROGRESS_AT_DEVICE:
if (tresor_control_file_yields_state_idle(node, "extend_progress")) {
if (listing_file_starts_with(node, "extend", String<10>("succeeded"))) {
switch (_resizing_type) {
case Resizing_type::EXPAND_CLIENT_FS:
@ -972,7 +974,10 @@ void Main::_handle_resizing_fs_query_listing(Xml_node const &node)
}
_resizing_state = Resizing_state::DETERMINE_CLIENT_FS_SIZE;
Signal_transmitter(_state_handler).submit();
}
} else
error("failed to extend: operation failed at tresor");
break;
default:
@ -992,13 +997,16 @@ void Main::_handle_lock_fs_query_listing(Xml_node const &node)
switch (_state) {
case State::LOCK_WAIT_TILL_DEINIT_REQUEST_IS_DONE:
if (tresor_control_file_yields_state_idle(node, "deinitialize")) {
if (listing_file_starts_with(node, "deinitialize", String<10>("succeeded"))) {
_set_state(State::UNLOCK_OBTAIN_PARAMETERS);
_setup_obtain_params_passphrase = Input_passphrase { };
_setup_obtain_params_select = Setup_obtain_params_select::PASSPHRASE_INPUT;
Signal_transmitter(_state_handler).submit();
}
} else
error("failed to deinitialize: operation failed at tresor");
break;
default:
@ -1024,20 +1032,27 @@ void Main::_handle_rekeying_fs_query_listing(Xml_node const &node)
switch (_rekeying_state) {
case Rekeying_state::WAIT_TILL_DEVICE_IS_READY:
if (tresor_control_file_yields_state_idle(node, "rekey_progress")) {
if (listing_file_starts_with(node, "rekey", String<10>("succeeded")) ||
listing_file_starts_with(node, "rekey", String<5>("none"))) {
_rekeying_state = Rekeying_state::ISSUE_REQUEST_AT_DEVICE;
Signal_transmitter(_state_handler).submit();
}
} else
error("failed to rekey: tresor not ready");
break;
case Rekeying_state::IN_PROGRESS_AT_DEVICE:
if (tresor_control_file_yields_state_idle(node, "rekey_progress")) {
if (listing_file_starts_with(node, "rekey", String<10>("succeeded"))) {
_rekeying_state = Rekeying_state::INACTIVE;
Signal_transmitter(_state_handler).submit();
}
} else
error("failed to rekey: operation failed at tresor");
break;
default:
@ -1465,10 +1480,8 @@ void File_vault::Main::handle_sandbox_state()
update_dialog = true;
update_sandbox = true;
} else {
} else
_unlock_retry_delay.schedule(Microseconds { 3000000 });
}
});
break;

View File

@ -299,7 +299,6 @@ namespace File_vault {
xml.node("tresor", [&] () {
xml.attribute("name", "tresor");
xml.attribute("verbose", "no");
xml.attribute("debug", "no");
xml.attribute("block", File_path { "/", tresor_img_file_name });
xml.attribute("crypto", "/crypto");
xml.attribute("trust_anchor", "/trust_anchor");
@ -531,7 +530,7 @@ namespace File_vault {
}
void gen_tresor_vfs_block_start_node(Xml_generator &xml,
Child_state const &child)
Child_state const &child)
{
child.gen_start_node(xml, [&] () {

View File

@ -31,76 +31,44 @@ using namespace Tresor;
namespace Tresor_check { class Main; }
class Tresor_check::Main : private Vfs::Env::User, private Tresor::Module_composition, public Tresor::Module, public Module_channel
class Tresor_check::Main : private Vfs::Env::User
{
private:
enum State { INIT, REQ_GENERATED, CHECK_SBS_SUCCEEDED };
enum State { INIT, CHECK_SB, CHECK_SB_SUCCEEDED };
Env &_env;
Heap _heap { _env.ram(), _env.rm() };
Attached_rom_dataspace _config_rom { _env, "config" };
Vfs::Simple_env _vfs_env { _env, _heap, _config_rom.xml().sub_node("vfs"), *this };
Signal_handler<Main> _sigh { _env.ep(), *this, &Main::_handle_signal };
Trust_anchor _trust_anchor { _vfs_env, _config_rom.xml().sub_node("trust-anchor") };
Crypto _crypto { _vfs_env, _config_rom.xml().sub_node("crypto") };
Block_io _block_io { _vfs_env, _config_rom.xml().sub_node("block-io") };
Tresor::Path const _block_io_path { _config_rom.xml().sub_node("block-io").attribute_value("path", Tresor::Path()) };
Vfs::Vfs_handle &_block_io_file { open_file(_vfs_env, _block_io_path, Vfs::Directory_service::OPEN_MODE_RDWR) };
Block_io _block_io { _block_io_file };
Vbd_check _vbd_check { };
Ft_check _ft_check { };
Sb_check _sb_check { };
bool _generated_req_success { };
State _state { INIT };
NONCOPYABLE(Main);
void _generated_req_completed(State_uint state_uint) override
{
if (!_generated_req_success) {
error("command pool: request failed because generated request failed)");
_env.parent().exit(-1);
return;
}
_state = (State)state_uint;
}
void wakeup_vfs_user() override { _sigh.local_submit(); }
Sb_check::Check _check_superblocks { };
void _wakeup_back_end_services() { _vfs_env.io().commit(); }
void _handle_signal()
{
execute_modules();
while(_sb_check.execute(_check_superblocks, _vbd_check, _ft_check, _block_io));
if (_check_superblocks.complete())
_env.parent().exit(_check_superblocks.success() ? 0 : -1);
_wakeup_back_end_services();
}
/********************
** Vfs::Env::User **
********************/
void wakeup_vfs_user() override { _sigh.local_submit(); }
public:
Main(Env &env) : Module_channel { COMMAND_POOL, 0 }, _env { env }
{
add_module(COMMAND_POOL, *this);
add_module(CRYPTO, _crypto);
add_module(TRUST_ANCHOR, _trust_anchor);
add_module(BLOCK_IO, _block_io);
add_module(VBD_CHECK, _vbd_check);
add_module(FT_CHECK, _ft_check);
add_module(SB_CHECK, _sb_check);
add_channel(*this);
_handle_signal();
}
void execute(bool &progress) override
{
switch(_state) {
case INIT:
generate_req<Sb_check_request>(CHECK_SBS_SUCCEEDED, progress, _generated_req_success);
_state = REQ_GENERATED;
break;
case CHECK_SBS_SUCCEEDED: _env.parent().exit(0); break;
default: break;
}
}
Main(Env &env) : _env(env) { _handle_signal(); }
};
void Component::construct(Genode::Env &env) { static Tresor_check::Main main { env }; }

View File

@ -34,86 +34,116 @@ using namespace Tresor;
namespace Tresor_init { class Main; }
class Tresor_init::Main : private Vfs::Env::User, private Tresor::Module_composition, public Tresor::Module, public Module_channel
class Tresor_init::Main : private Vfs::Env::User, private Crypto_key_files_interface
{
private:
enum State { INIT, REQ_GENERATED, INIT_SBS_SUCCEEDED };
struct Crypto_key
{
Key_id const key_id;
Vfs::Vfs_handle &encrypt_file;
Vfs::Vfs_handle &decrypt_file;
};
Env &_env;
Heap _heap { _env.ram(), _env.rm() };
Attached_rom_dataspace _config_rom { _env, "config" };
Vfs::Simple_env _vfs_env { _env, _heap, _config_rom.xml().sub_node("vfs"), *this };
Signal_handler<Main> _sigh { _env.ep(), *this, &Main::_handle_signal };
Constructible<Configuration> _cfg { };
Trust_anchor _trust_anchor { _vfs_env, _config_rom.xml().sub_node("trust-anchor") };
Crypto _crypto { _vfs_env, _config_rom.xml().sub_node("crypto") };
Block_io _block_io { _vfs_env, _config_rom.xml().sub_node("block-io") };
Configuration _cfg { _config_rom.xml() };
Tresor::Path const _crypto_path { _config_rom.xml().sub_node("crypto").attribute_value("path", Tresor::Path()) };
Tresor::Path const _block_io_path { _config_rom.xml().sub_node("block-io").attribute_value("path", Tresor::Path()) };
Tresor::Path const _trust_anchor_path { _config_rom.xml().sub_node("trust-anchor").attribute_value("path", Tresor::Path()) };
Vfs::Vfs_handle &_block_io_file { open_file(_vfs_env, _block_io_path, Vfs::Directory_service::OPEN_MODE_RDWR) };
Vfs::Vfs_handle &_crypto_add_key_file { open_file(_vfs_env, { _crypto_path, "/add_key" }, Vfs::Directory_service::OPEN_MODE_WRONLY) };
Vfs::Vfs_handle &_crypto_remove_key_file { open_file(_vfs_env, { _crypto_path, "/remove_key" }, Vfs::Directory_service::OPEN_MODE_WRONLY) };
Vfs::Vfs_handle &_ta_decrypt_file { open_file(_vfs_env, { _trust_anchor_path, "/decrypt" }, Vfs::Directory_service::OPEN_MODE_RDWR) };
Vfs::Vfs_handle &_ta_encrypt_file { open_file(_vfs_env, { _trust_anchor_path, "/encrypt" }, Vfs::Directory_service::OPEN_MODE_RDWR) };
Vfs::Vfs_handle &_ta_generate_key_file { open_file(_vfs_env, { _trust_anchor_path, "/generate_key" }, Vfs::Directory_service::OPEN_MODE_RDWR) };
Vfs::Vfs_handle &_ta_initialize_file { open_file(_vfs_env, { _trust_anchor_path, "/initialize" }, Vfs::Directory_service::OPEN_MODE_RDWR) };
Vfs::Vfs_handle &_ta_hash_file { open_file(_vfs_env, { _trust_anchor_path, "/hash" }, Vfs::Directory_service::OPEN_MODE_RDWR) };
Trust_anchor _trust_anchor { { _ta_decrypt_file, _ta_encrypt_file, _ta_generate_key_file, _ta_initialize_file, _ta_hash_file } };
Crypto _crypto { {*this, _crypto_add_key_file, _crypto_remove_key_file} };
Block_io _block_io { _block_io_file };
Constructible<Crypto_key> _crypto_keys[2] { };
Pba_allocator _pba_alloc { NR_OF_SUPERBLOCK_SLOTS };
Vbd_initializer _vbd_initializer { };
Ft_initializer _ft_initializer { };
Sb_initializer _sb_initializer { };
bool _generated_req_success { };
State _state { INIT };
Sb_initializer::Initialize _init_superblocks {{
Tree_configuration {
(Tree_level_index)(_cfg.vbd_nr_of_lvls() - 1),
(Tree_degree)_cfg.vbd_nr_of_children(),
_cfg.vbd_nr_of_leafs()
},
Tree_configuration {
(Tree_level_index)_cfg.ft_nr_of_lvls() - 1,
(Tree_degree)_cfg.ft_nr_of_children(),
_cfg.ft_nr_of_leafs()
},
Tree_configuration {
(Tree_level_index)_cfg.ft_nr_of_lvls() - 1,
(Tree_degree)_cfg.ft_nr_of_children(),
_cfg.ft_nr_of_leafs()
},
_pba_alloc
}};
NONCOPYABLE(Main);
void _generated_req_completed(State_uint state_uint) override
Constructible<Crypto_key> &_crypto_key(Key_id key_id)
{
if (!_generated_req_success) {
error("command pool: request failed because generated request failed)");
_env.parent().exit(-1);
return;
}
_state = (State)state_uint;
for (Constructible<Crypto_key> &key : _crypto_keys)
if (key.constructed() && key->key_id == key_id)
return key;
ASSERT_NEVER_REACHED;
}
void wakeup_vfs_user() override { _sigh.local_submit(); }
void _wakeup_back_end_services() { _vfs_env.io().commit(); }
void _handle_signal()
{
execute_modules();
while(_sb_initializer.execute(_init_superblocks, _block_io, _trust_anchor, _vbd_initializer, _ft_initializer));
if (_init_superblocks.complete())
_env.parent().exit(_init_superblocks.success() ? 0 : -1);
_wakeup_back_end_services();
}
/********************************
** Crypto_key_files_interface **
********************************/
void add_crypto_key(Key_id key_id) override
{
for (Constructible<Crypto_key> &key : _crypto_keys)
if (!key.constructed()) {
key.construct(key_id,
open_file(_vfs_env, { _crypto_path, "/keys/", key_id, "/encrypt" }, Vfs::Directory_service::OPEN_MODE_RDWR),
open_file(_vfs_env, { _crypto_path, "/keys/", key_id, "/decrypt" }, Vfs::Directory_service::OPEN_MODE_RDWR)
);
return;
}
ASSERT_NEVER_REACHED;
}
void remove_crypto_key(Key_id key_id) override
{
Constructible<Crypto_key> &crypto_key = _crypto_key(key_id);
_vfs_env.root_dir().close(&crypto_key->encrypt_file);
_vfs_env.root_dir().close(&crypto_key->decrypt_file);
crypto_key.destruct();
}
Vfs::Vfs_handle &encrypt_file(Key_id key_id) override { return _crypto_key(key_id)->encrypt_file; }
Vfs::Vfs_handle &decrypt_file(Key_id key_id) override { return _crypto_key(key_id)->decrypt_file; }
/********************
** Vfs::Env::User **
********************/
void wakeup_vfs_user() override { _sigh.local_submit(); }
public:
Main(Env &env) : Module_channel { COMMAND_POOL, 0 }, _env { env }
{
add_module(COMMAND_POOL, *this);
add_module(CRYPTO, _crypto);
add_module(TRUST_ANCHOR, _trust_anchor);
add_module(BLOCK_IO, _block_io);
add_module(VBD_INITIALIZER, _vbd_initializer);
add_module(FT_INITIALIZER, _ft_initializer);
add_module(SB_INITIALIZER, _sb_initializer);
add_channel(*this);
_cfg.construct(_config_rom.xml());
_handle_signal();
}
void execute(bool &progress) override
{
switch(_state) {
case INIT:
generate_req<Sb_initializer_request>(
INIT_SBS_SUCCEEDED, progress, (Tree_level_index)_cfg->vbd_nr_of_lvls() - 1,
(Tree_degree)_cfg->vbd_nr_of_children(), _cfg->vbd_nr_of_leafs(),
(Tree_level_index)_cfg->ft_nr_of_lvls() - 1,
(Tree_degree)_cfg->ft_nr_of_children(), _cfg->ft_nr_of_leafs(),
(Tree_level_index)_cfg->ft_nr_of_lvls() - 1,
(Tree_degree)_cfg->ft_nr_of_children(), _cfg->ft_nr_of_leafs(), _pba_alloc,
_generated_req_success);
_state = REQ_GENERATED;
break;
case INIT_SBS_SUCCEEDED: _env.parent().exit(0); break;
default: break;
}
}
Main(Env &env) : _env(env) { _handle_signal(); }
};
void Component::construct(Genode::Env &env) { static Tresor_init::Main main { env }; }

View File

@ -89,9 +89,8 @@ class Main : Vfs::Env::User
char const *name,
Vfs::File_system &vfs,
Genode::Allocator &alloc)
:
_vfs { vfs },
_vfs_handle { nullptr }
:
_vfs(vfs), _vfs_handle(nullptr)
{
using Result = Vfs::Directory_service::Open_result;
@ -207,9 +206,7 @@ class Main : Vfs::Env::User
public:
Main(Env &env)
:
_env { env }
Main(Env &env) : _env(env)
{
Xml_node const &config { _config_rom.xml() };

File diff suppressed because it is too large Load Diff

View File

@ -12,199 +12,79 @@
*/
/* tresor includes */
#include <tresor/crypto.h>
#include <tresor/block_io.h>
#include <tresor/hash.h>
using namespace Tresor;
Block_io_request::Block_io_request(Module_id src_module_id, Module_channel_id src_chan_id, Type type,
Request_offset client_req_offset, Request_tag client_req_tag, Key_id key_id,
Physical_block_address pba, Virtual_block_address vba, Block &blk, Hash &hash,
bool &success)
:
Module_request { src_module_id, src_chan_id, BLOCK_IO }, _type { type },
_client_req_offset { client_req_offset }, _client_req_tag { client_req_tag },
_key_id { key_id }, _pba { pba }, _vba { vba }, _blk { blk }, _hash { hash }, _success { success }
{ }
char const *Block_io_request::type_to_string(Type type)
bool Block_io::Sync::execute(Vfs::Vfs_handle &file)
{
switch (type) {
case READ: return "read";
case WRITE: return "write";
case SYNC: return "sync";
case READ_CLIENT_DATA: return "read_client_data";
case WRITE_CLIENT_DATA: return "write_client_data";
}
ASSERT_NEVER_REACHED;
}
bool progress = false;
switch (_helper.state) {
case INIT:
_file.construct(_helper.state, file);
_helper.state = SYNC;
progress = true;
break;
void Block_io_channel::_generated_req_completed(State_uint state_uint)
{
if (!_generated_req_success) {
error("block io: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
void Block_io_channel::_mark_req_failed(bool &progress, Error_string str)
{
error("request failed: failed to ", str);
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Block_io_channel::_mark_req_successful(bool &progress)
{
Request &req { *_req_ptr };
req._success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
if (VERBOSE_BLOCK_IO && (!VERBOSE_BLOCK_IO_PBA_FILTER || VERBOSE_BLOCK_IO_PBA == req._pba)) {
switch (req._type) {
case Request::READ:
case Request::WRITE:
log("block_io: ", req.type_to_string(req._type), " pba ", req._pba, " hash ", hash(req._blk));
break;
default: break;
}
}
}
void Block_io_channel::_read(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _file.read(READ_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&req._blk, BLOCK_SIZE }, progress); break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
case SYNC: _file->sync(SYNC_OK, FILE_ERR, progress); break;
case SYNC_OK: _helper.mark_succeeded(progress); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
void Block_io_channel::_read_client_data(bool &progress)
bool Block_io::Read::execute(Vfs::Vfs_handle &file)
{
bool progress = false;
switch (_helper.state) {
case INIT:
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _file.read(READ_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&_blk, BLOCK_SIZE }, progress); break;
_file.construct(_helper.state, file);
_helper.state = READ;
progress = true;
break;
case READ: _file->read(READ_OK, FILE_ERR, _attr.in_pba * BLOCK_SIZE, { (char *)&_attr.out_block, BLOCK_SIZE }, progress); break;
case READ_OK:
calc_hash(_blk, req._hash);
_generate_req<Crypto_request>(
PLAINTEXT_BLK_SUPPLIED, progress, Crypto_request::DECRYPT_CLIENT_DATA, req._client_req_offset,
req._client_req_tag, req._key_id, *(Key_value *)0, req._pba, req._vba, _blk);
return;
case PLAINTEXT_BLK_SUPPLIED: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
default: break;
}
}
void Block_io_channel::_write_client_data(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
_generate_req<Crypto_request>(
CIPHERTEXT_BLK_OBTAINED, progress, Crypto_request::ENCRYPT_CLIENT_DATA, req._client_req_offset,
req._client_req_tag, req._key_id, *(Key_value *)0, req._pba, req._vba, _blk);
_helper.mark_succeeded(progress);
if (VERBOSE_BLOCK_IO && (!VERBOSE_BLOCK_IO_PBA_FILTER || VERBOSE_BLOCK_IO_PBA == _attr.in_pba))
log("block_io: ", *this, " hash ", hash(_attr.out_block));
break;
case CIPHERTEXT_BLK_OBTAINED:
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
calc_hash(_blk, req._hash);
_file.write(WRITE_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&_blk, BLOCK_SIZE }, progress); break;
bool Block_io::Write::execute(Vfs::Vfs_handle &file)
{
bool progress = false;
switch (_helper.state) {
case INIT:
_file.construct(_helper.state, file);
_helper.state = WRITE;
progress = true;
break;
case WRITE_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, _attr.in_pba * BLOCK_SIZE, { (char *)&_attr.in_block, BLOCK_SIZE }, progress); break;
case WRITE_OK:
_helper.mark_succeeded(progress);
if (VERBOSE_BLOCK_IO && (!VERBOSE_BLOCK_IO_PBA_FILTER || VERBOSE_BLOCK_IO_PBA == _attr.in_pba))
log("block_io: ", *this, " hash ", hash(_attr.in_block));
break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
}
void Block_io_channel::_write(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _file.write(WRITE_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&req._blk, BLOCK_SIZE }, progress); break;
case WRITE_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
default: break;
}
}
void Block_io_channel::_sync(bool &progress)
{
switch (_state) {
case REQ_SUBMITTED: _file.sync(SYNC_OK, FILE_ERR, progress); break;
case SYNC_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
default: break;
}
}
void Block_io_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
switch (_req_ptr->_type) {
case Request::READ: _read(progress); break;
case Request::WRITE: _write(progress); break;
case Request::SYNC: _sync(progress); break;
case Request::READ_CLIENT_DATA: _read_client_data(progress); break;
case Request::WRITE_CLIENT_DATA: _write_client_data(progress); break;
}
}
void Block_io::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
}
void Block_io_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
Block_io_channel::Block_io_channel(Module_channel_id id, Vfs::Env &vfs_env, Xml_node const &xml_node)
:
Module_channel { BLOCK_IO, id }, _vfs_env { vfs_env }, _path { xml_node.attribute_value("path", Tresor::Path()) }
{ }
Block_io::Block_io(Vfs::Env &vfs_env, Xml_node const &xml_node)
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++, vfs_env, xml_node);
add_channel(*chan);
}
return progress;
}

View File

@ -13,317 +13,101 @@
/* tresor includes */
#include <tresor/crypto.h>
#include <tresor/client_data.h>
#include <tresor/hash.h>
using namespace Tresor;
Crypto_request::Crypto_request(Module_id src_module_id, Module_channel_id src_chan_id, Type type,
Request_offset client_req_offset, Request_tag client_req_tag, Key_id key_id,
Key_value const &key_plaintext, Physical_block_address pba, Virtual_block_address vba,
Block &blk, bool &success)
:
Module_request { src_module_id, src_chan_id, CRYPTO }, _type { type }, _client_req_offset { client_req_offset },
_client_req_tag { client_req_tag }, _pba { pba }, _vba { vba }, _key_id { key_id }, _key_plaintext { key_plaintext },
_blk { blk }, _success { success }
{ }
void Crypto_request::print(Output &out) const
bool Crypto::Add_key::execute(Crypto::Attr const &crypto_attr)
{
Genode::print(out, type_to_string(_type));
switch (_type) {
case ADD_KEY:
case REMOVE_KEY: Genode::print(out, " ", _key_id); break;
case DECRYPT:
case ENCRYPT:
case DECRYPT_CLIENT_DATA:
case ENCRYPT_CLIENT_DATA: Genode::print(out, " pba ", _pba); break;
default: break;
}
}
bool progress { false };
switch (_helper.state) {
case INIT:
char const *Crypto_request::type_to_string(Type type)
{
switch (type) {
case ADD_KEY: return "add_key";
case REMOVE_KEY: return "remove_key";
case ENCRYPT_CLIENT_DATA: return "encrypt_client_data";
case DECRYPT_CLIENT_DATA: return "decrypt_client_data";
case ENCRYPT: return "encrypt";
case DECRYPT: return "decrypt";
}
ASSERT_NEVER_REACHED;
}
void Crypto_channel::_generated_req_completed(State_uint state_uint)
{
if (!_generated_req_success) {
error("crypto: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
Constructible<Crypto_channel::Key_directory> &Crypto_channel::_key_dir(Key_id key_id)
{
for (Constructible<Key_directory> &key_dir : _key_dirs)
if (key_dir.constructed() && key_dir->key_id == key_id)
return key_dir;
ASSERT_NEVER_REACHED;
}
void Crypto_channel::_mark_req_failed(bool &progress, char const *str)
{
error("crypto: request (", *_req_ptr, ") failed at step \"", str, "\"");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Crypto_channel::_mark_req_successful(bool &progress)
{
Request &req { *_req_ptr };
req._success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
if (VERBOSE_WRITE_VBA && req._type == Request::ENCRYPT_CLIENT_DATA)
log(" encrypt leaf data: plaintext ", _blk, " hash ", hash(_blk),
"\n update branch:\n ", Branch_lvl_prefix("leaf data: "), req._blk);
if (VERBOSE_READ_VBA && req._type == Request::DECRYPT_CLIENT_DATA)
log(" ", Branch_lvl_prefix("leaf data: "), req._blk,
"\n decrypt leaf data: plaintext ", _blk, " hash ", hash(_blk));
if (VERBOSE_CRYPTO) {
switch (req._type) {
case Request::DECRYPT_CLIENT_DATA:
case Request::ENCRYPT_CLIENT_DATA:
log("crypto: ", req.type_to_string(req._type), " pba ", req._pba, " vba ", req._vba,
" plain ", _blk, " cipher ", req._blk);
break;
default: break;
}
}
if (VERBOSE_BLOCK_IO && (!VERBOSE_BLOCK_IO_PBA_FILTER || VERBOSE_BLOCK_IO_PBA == req._pba)) {
switch (req._type) {
case Request::DECRYPT_CLIENT_DATA:
log("block_io: read pba ", req._pba, " hash ", hash(req._blk), " (plaintext hash ", hash(_blk), ")");
break;
case Request::ENCRYPT_CLIENT_DATA:
log("block_io: write pba ", req._pba, " hash ", hash(req._blk), " (plaintext hash ", hash(_blk), ")");
break;
default: break;
}
}
}
void Crypto_channel::_add_key(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
memcpy(_add_key_buf, &req._key_id, sizeof(Key_id));
memcpy(_add_key_buf + sizeof(Key_id), &req._key_plaintext, KEY_SIZE);
_add_key_file.write(WRITE_OK, FILE_ERR, 0, { _add_key_buf, sizeof(_add_key_buf) }, progress);
_file.construct(_helper.state, crypto_attr.add_key_file);
memcpy(_write_buf, &_attr.in_key.id, sizeof(Key_id));
memcpy(_write_buf + sizeof(Key_id), &_attr.in_key.value, sizeof(Key_value));
_helper.state = WRITE;
progress = true;
break;
case WRITE_OK:
{
Constructible<Key_directory> *key_dir_ptr { nullptr };
for (Constructible<Key_directory> &key_dir : _key_dirs)
if (!key_dir.constructed())
key_dir_ptr = &key_dir;
if (!key_dir_ptr) {
_mark_req_failed(progress, "find unused key dir");
break;
}
key_dir_ptr->construct(*this, req._key_id);
_mark_req_successful(progress);
break;
}
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
default: break;
}
}
void Crypto_channel::_remove_key(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _remove_key_file.write(WRITE_OK, FILE_ERR, 0, { (char *)&req._key_id, sizeof(Key_id) }, progress); break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, 0, { _write_buf, sizeof(_write_buf) }, progress); break;
case WRITE_OK:
_key_dir(req._key_id).destruct();
_mark_req_successful(progress);
crypto_attr.key_files.add_crypto_key(_attr.in_key.id);
_helper.mark_succeeded(progress);
break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
default: return;
}
}
void Crypto_channel::_encrypt_client_data(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
_generate_req<Client_data_request>(
PLAINTEXT_BLK_OBTAINED, progress, Client_data_request::OBTAIN_PLAINTEXT_BLK,
req._client_req_offset, req._client_req_tag, req._pba, req._vba, _blk);;
break;
case PLAINTEXT_BLK_OBTAINED:
_key_dir(req._key_id)->encrypt_file.write(
WRITE_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&_blk, BLOCK_SIZE }, progress);
break;
case WRITE_OK:
_key_dir(req._key_id)->encrypt_file.read(
READ_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&req._blk, BLOCK_SIZE }, progress);
break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation"); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
void Crypto_channel::_encrypt(bool &progress)
bool Crypto::Remove_key::execute(Crypto::Attr const &crypto_attr)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
bool progress { false };
switch (_helper.state) {
case INIT:
_key_dir(req._key_id)->encrypt_file.write(
WRITE_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&req._blk, BLOCK_SIZE }, progress);
_file.construct(_helper.state, crypto_attr.remove_key_file);
_helper.state = WRITE;
progress = true;
break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, 0, { (char *)&_attr.in_key_id, sizeof(Key_id) }, progress); break;
case WRITE_OK:
_key_dir(req._key_id)->encrypt_file.read(
READ_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&req._blk, BLOCK_SIZE }, progress);
crypto_attr.key_files.remove_crypto_key(_attr.in_key_id);
_helper.mark_succeeded(progress);
break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation"); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
void Crypto_channel::_decrypt(bool &progress)
bool Crypto::Encrypt::execute(Crypto::Attr const &crypto_attr)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
bool progress { false };
switch (_helper.state) {
case INIT:
_key_dir(req._key_id)->decrypt_file.write(
WRITE_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&req._blk, BLOCK_SIZE }, progress);
_file.construct(_helper.state, crypto_attr.key_files.encrypt_file(_attr.in_key_id));
_offset = _attr.in_pba * BLOCK_SIZE;
_helper.state = WRITE;
progress = true;
break;
case WRITE_OK:
_key_dir(req._key_id)->decrypt_file.read(
READ_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&req._blk, BLOCK_SIZE }, progress);
break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation"); break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, _offset, { (char *)&_attr.in_out_blk, BLOCK_SIZE }, progress); break;
case WRITE_OK: _file->read(READ_OK, FILE_ERR, _offset, { (char *)&_attr.in_out_blk, BLOCK_SIZE }, progress); break;
case READ_OK: _helper.mark_succeeded(progress); break;
case FILE_ERR: _helper.mark_failed(progress, "file-operation error"); break;
default: break;
}
return progress;
}
void Crypto_channel::_decrypt_client_data(bool &progress)
bool Crypto::Decrypt::execute(Crypto::Attr const &crypto_attr)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
bool progress { false };
switch (_helper.state) {
case INIT:
_key_dir(req._key_id)->decrypt_file.write(
WRITE_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&req._blk, BLOCK_SIZE }, progress);
_file.construct(_helper.state, crypto_attr.key_files.decrypt_file(_attr.in_key_id));
_offset = _attr.in_pba * BLOCK_SIZE;
_helper.state = WRITE;
progress = true;
break;
case WRITE_OK:
_key_dir(req._key_id)->decrypt_file.read(
READ_OK, FILE_ERR, req._pba * BLOCK_SIZE, { (char *)&_blk, BLOCK_SIZE }, progress);
break;
case READ_OK:
_generate_req<Client_data_request>(
PLAINTEXT_BLK_SUPPLIED, progress, Client_data_request::SUPPLY_PLAINTEXT_BLK,
req._client_req_offset, req._client_req_tag, req._pba, req._vba, _blk);;
break;
case PLAINTEXT_BLK_SUPPLIED: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, _offset, { (char *)&_attr.in_out_blk, BLOCK_SIZE }, progress); break;
case WRITE_OK: _file->read(READ_OK, FILE_ERR, _offset, { (char *)&_attr.in_out_blk, BLOCK_SIZE }, progress); break;
case READ_OK: _helper.mark_succeeded(progress); break;
case FILE_ERR: _helper.mark_failed(progress, "file-operation error"); break;
default: break;
}
}
void Crypto_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
void Crypto_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
switch (_req_ptr->_type) {
case Request::ADD_KEY: _add_key(progress); break;
case Request::REMOVE_KEY: _remove_key(progress); break;
case Request::DECRYPT: _decrypt(progress); break;
case Request::ENCRYPT: _encrypt(progress); break;
case Request::DECRYPT_CLIENT_DATA: _decrypt_client_data(progress); break;
case Request::ENCRYPT_CLIENT_DATA: _encrypt_client_data(progress); break;
}
}
void Crypto::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
}
Crypto_channel::Crypto_channel(Module_channel_id id, Vfs::Env &vfs_env, Xml_node const &xml_node)
:
Module_channel { CRYPTO, id }, _vfs_env { vfs_env }, _path { xml_node.attribute_value("path", Tresor::Path()) }
{ }
Crypto::Crypto(Vfs::Env &vfs_env, Xml_node const &xml_node)
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++, vfs_env, xml_node);
add_channel(*chan);
}
return progress;
}

View File

@ -13,62 +13,22 @@
/* tresor includes */
#include <tresor/free_tree.h>
#include <tresor/meta_tree.h>
#include <tresor/block_io.h>
#include <tresor/hash.h>
using namespace Tresor;
char const *Free_tree_request::type_to_string(Type type)
bool Free_tree::Allocate_pbas::_can_alloc_pba_of(Type_2_node &node)
{
switch (type) {
case ALLOC_FOR_NON_RKG: return "alloc_for_non_rkg";
case ALLOC_FOR_RKG_CURR_GEN_BLKS: return "alloc_for_rkg_curr_gen_blks";
case ALLOC_FOR_RKG_OLD_GEN_BLKS: return "alloc_for_rkg_old_gen_blks";
case EXTENSION_STEP: return "extension_step";
}
ASSERT_NEVER_REACHED;
}
Free_tree_request::Free_tree_request(Module_id src_module_id, Module_channel_id src_chan_id, Type type,
Tree_root &ft, Tree_root &mt, Snapshots const &snapshots, Generation last_secured_gen,
Generation curr_gen, Generation free_gen, Number_of_blocks num_required_pbas,
Tree_walk_pbas &new_blocks, Type_1_node_walk const &old_blocks,
Tree_level_index max_lvl, Virtual_block_address vba, Tree_degree vbd_degree,
Virtual_block_address vbd_max_vba, bool rekeying, Key_id prev_key_id,
Key_id curr_key_id, Virtual_block_address rekeying_vba, Physical_block_address &pba,
Number_of_blocks &num_pbas, bool &success)
:
Module_request { src_module_id, src_chan_id, FREE_TREE }, _type { type }, _ft { ft }, _mt { mt },
_curr_gen { curr_gen }, _free_gen { free_gen }, _num_required_pbas { num_required_pbas }, _new_blocks { new_blocks },
_old_blocks { old_blocks }, _max_lvl { max_lvl }, _vba { vba }, _vbd_degree { vbd_degree }, _vbd_max_vba { vbd_max_vba },
_rekeying { rekeying }, _prev_key_id { prev_key_id }, _curr_key_id { curr_key_id }, _rekeying_vba { rekeying_vba },
_success { success }, _snapshots { snapshots }, _last_secured_gen { last_secured_gen }, _pba { pba }, _num_pbas { num_pbas }
{ }
void Free_tree::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
}
bool Free_tree_channel::_can_alloc_pba_of(Type_2_node &node)
{
Request &req { *_req_ptr };
if (node.pba == 0 || node.pba == INVALID_PBA || node.free_gen > req._last_secured_gen)
if (node.pba == 0 || node.pba == INVALID_PBA || node.free_gen > _attr.in_last_secured_gen)
return false;
if (!node.reserved)
return true;
if (req._rekeying && node.last_key_id == req._prev_key_id && node.last_vba < req._rekeying_vba)
if (_attr.in_rekeying && node.last_key_id == _attr.in_prev_key_id && node.last_vba < _attr.in_rekeying_vba)
return true;
for (Snapshot const &snap : req._snapshots.items)
for (Snapshot const &snap : _attr.in_snapshots.items)
if (snap.valid && node.free_gen > snap.gen && node.alloc_gen < snap.gen + 1)
return false;
@ -76,62 +36,48 @@ bool Free_tree_channel::_can_alloc_pba_of(Type_2_node &node)
}
void Free_tree_channel::_generated_req_completed(State_uint state_uint)
void Free_tree::Allocate_pbas::_alloc_pba_of(Type_2_node &t2_node)
{
if (!_generated_req_success) {
error("free tree: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
void Free_tree_channel::_alloc_pba_of(Type_2_node &t2_node)
{
Request &req { *_req_ptr };
Tree_level_index vbd_lvl { 0 };
for (; vbd_lvl <= req._max_lvl && req._new_blocks.pbas[vbd_lvl]; vbd_lvl++);
for (; vbd_lvl <= _attr.in_max_lvl && _attr.in_out_new_blocks.pbas[vbd_lvl]; vbd_lvl++);
Virtual_block_address node_min_vba { vbd_node_min_vba(_vbd_degree_log_2, vbd_lvl, req._vba) };
req._new_blocks.pbas[vbd_lvl] = t2_node.pba;
t2_node.alloc_gen = req._old_blocks.nodes[vbd_lvl].gen;
t2_node.free_gen = req._free_gen;
Virtual_block_address rkg_vba { req._rekeying_vba };
switch (req._type) {
case Request::ALLOC_FOR_NON_RKG:
Virtual_block_address node_min_vba { vbd_node_min_vba(_vbd_degree_log_2, vbd_lvl, _attr.in_vba) };
_attr.in_out_new_blocks.pbas[vbd_lvl] = t2_node.pba;
t2_node.alloc_gen = _attr.in_old_blocks.nodes[vbd_lvl].gen;
t2_node.free_gen = _attr.in_free_gen;
Virtual_block_address rkg_vba { _attr.in_rekeying_vba };
switch (_attr.in_application) {
case NON_REKEYING:
t2_node.reserved = true;
t2_node.pba = req._old_blocks.nodes[vbd_lvl].pba;
t2_node.pba = _attr.in_old_blocks.nodes[vbd_lvl].pba;
t2_node.last_vba = node_min_vba;
if (req._rekeying) {
if (req._vba < rkg_vba)
t2_node.last_key_id = req._curr_key_id;
if (_attr.in_rekeying) {
if (_attr.in_vba < rkg_vba)
t2_node.last_key_id = _attr.in_curr_key_id;
else
t2_node.last_key_id = req._prev_key_id;
t2_node.last_key_id = _attr.in_prev_key_id;
} else
t2_node.last_key_id = req._curr_key_id;
t2_node.last_key_id = _attr.in_curr_key_id;
break;
case Request::ALLOC_FOR_RKG_CURR_GEN_BLKS:
case REKEYING_IN_CURRENT_GENERATION:
t2_node.reserved = false;
t2_node.pba = req._old_blocks.nodes[vbd_lvl].pba;
t2_node.pba = _attr.in_old_blocks.nodes[vbd_lvl].pba;
t2_node.last_vba = node_min_vba;
t2_node.last_key_id = req._prev_key_id;
t2_node.last_key_id = _attr.in_prev_key_id;
break;
case Request::ALLOC_FOR_RKG_OLD_GEN_BLKS:
case REKEYING_IN_OLDER_GENERATION:
{
t2_node.reserved = true;
Virtual_block_address node_max_vba { vbd_node_max_vba(_vbd_degree_log_2, vbd_lvl, req._vba) };
if (rkg_vba < node_max_vba && rkg_vba < req._vbd_max_vba) {
t2_node.last_key_id = req._prev_key_id;
Virtual_block_address node_max_vba { vbd_node_max_vba(_vbd_degree_log_2, vbd_lvl, _attr.in_vba) };
if (rkg_vba < node_max_vba && rkg_vba < _attr.in_vbd_max_vba) {
t2_node.last_key_id = _attr.in_prev_key_id;
t2_node.last_vba = rkg_vba + 1;
} else if (rkg_vba == node_max_vba || rkg_vba == req._vbd_max_vba) {
t2_node.last_key_id = req._curr_key_id;
} else if (rkg_vba == node_max_vba || rkg_vba == _attr.in_vbd_max_vba) {
t2_node.last_key_id = _attr.in_curr_key_id;
t2_node.last_vba = node_min_vba;
} else
ASSERT_NEVER_REACHED;
@ -142,78 +88,59 @@ void Free_tree_channel::_alloc_pba_of(Type_2_node &t2_node)
}
void Free_tree_channel::_mark_req_failed(bool &progress, char const *str)
{
error(Request::type_to_string(_req_ptr->_type), " request failed, reason: \"", str, "\"");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Free_tree_channel::_mark_req_successful(bool &progress)
{
_req_ptr->_success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Free_tree_channel::_start_tree_traversal(bool &progress)
{
Request &req { *_req_ptr };
_num_pbas = 0;
_lvl = req._ft.max_lvl;
_node_idx[_lvl] = 0;
_t1_blks[_lvl].nodes[_node_idx[_lvl]] = req._ft.t1_node();
_generate_req<Block_io::Read>(SEEK_DOWN, progress, req._ft.pba, _blk);
}
void Free_tree_channel::_traverse_curr_node(bool &progress)
void Free_tree::Allocate_pbas::_traverse_curr_node(bool &progress)
{
if (_lvl) {
Type_1_node &t1_node { _t1_blks[_lvl].nodes[_node_idx[_lvl]] };
if (t1_node.pba)
_generate_req<Block_io::Read>(SEEK_DOWN, progress, t1_node.pba, _blk);
_read_block.generate(_helper, READ_BLK, SEEK_DOWN, progress, t1_node.pba, _blk);
else {
_state = SEEK_LEFT_OR_UP;
_helper.state = SEEK_LEFT_OR_UP;
progress = true;
}
} else {
Type_2_node &t2_node { _t2_blk.nodes[_node_idx[_lvl]] };
if (_num_pbas < _req_ptr->_num_required_pbas && _can_alloc_pba_of(t2_node)) {
if (_num_pbas < _attr.in_num_required_pbas && _can_alloc_pba_of(t2_node)) {
if (_apply_allocation)
_alloc_pba_of(t2_node);
_num_pbas++;
}
_state = SEEK_LEFT_OR_UP;
_helper.state = SEEK_LEFT_OR_UP;
progress = true;
}
}
void Free_tree_channel::_alloc_pbas(bool &progress)
void Free_tree::Allocate_pbas::_start_tree_traversal(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
_num_pbas = 0;
_lvl = _attr.in_out_ft.max_lvl;
_node_idx[_lvl] = 0;
_t1_blks[_lvl].nodes[_node_idx[_lvl]] = _attr.in_out_ft.t1_node();
_read_block.generate(_helper, READ_BLK, SEEK_DOWN, progress, _attr.in_out_ft.pba, _blk);
}
_vbd_degree_log_2 = log2<Tree_degree_log_2>(req._vbd_degree);
bool Free_tree::Allocate_pbas::execute(Block_io &block_io, Meta_tree &meta_tree)
{
bool progress = false;
switch (_helper.state) {
case INIT:
_vbd_degree_log_2 = log2<Tree_degree_log_2>(_attr.in_vbd_degree);
_apply_allocation = false;
_start_tree_traversal(progress);
break;
case READ_BLK: progress |= _read_block.execute(block_io); break;
case SEEK_DOWN:
{
if (!check_hash(_blk, _t1_blks[_lvl].nodes[_node_idx[_lvl]].hash)) {
_mark_req_failed(progress, "hash mismatch");
_helper.mark_failed(progress, "hash mismatch");
break;
}
_lvl--;
_node_idx[_lvl] = req._ft.degree - 1;
_node_idx[_lvl] = _attr.in_out_ft.degree - 1;
if (_lvl)
_t1_blks[_lvl].decode_from_blk(_blk);
else
@ -223,31 +150,31 @@ void Free_tree_channel::_alloc_pbas(bool &progress)
}
case SEEK_LEFT_OR_UP:
if (_lvl < req._ft.max_lvl) {
if (_node_idx[_lvl] && _num_pbas < _req_ptr->_num_required_pbas) {
if (_lvl < _attr.in_out_ft.max_lvl) {
if (_node_idx[_lvl] && _num_pbas < _attr.in_num_required_pbas) {
_node_idx[_lvl]--;
_traverse_curr_node(progress);
} else {
_lvl++;
Type_1_node &t1_node { _t1_blks[_lvl].nodes[_node_idx[_lvl]] };
if (_apply_allocation)
if (t1_node.is_volatile(req._curr_gen)) {
_state = WRITE_BLK;
if (t1_node.is_volatile(_attr.in_curr_gen)) {
_helper.state = ALLOC_PBA_SUCCEEDED;
progress = true;
} else
_generate_req<Meta_tree::Alloc_pba>(WRITE_BLK, progress, req._mt, req._curr_gen, t1_node.pba);
_allocate_pba.generate(_helper, ALLOC_PBA, ALLOC_PBA_SUCCEEDED, progress, _attr.in_out_mt, _attr.in_curr_gen, t1_node.pba);
else {
_state = SEEK_LEFT_OR_UP;
_helper.state = SEEK_LEFT_OR_UP;
progress = true;
}
}
} else {
if (_apply_allocation) {
req._ft.t1_node(_t1_blks[_lvl].nodes[_node_idx[_lvl]]);
_mark_req_successful(progress);
_attr.in_out_ft.t1_node(_t1_blks[_lvl].nodes[_node_idx[_lvl]]);
_helper.mark_succeeded(progress);
} else {
if (_num_pbas < req._num_required_pbas)
_mark_req_failed(progress, "not enough free pbas");
if (_num_pbas < _attr.in_num_required_pbas)
_helper.mark_failed(progress, "not enough free pbas");
else {
_apply_allocation = true;
_start_tree_traversal(progress);
@ -256,68 +183,55 @@ void Free_tree_channel::_alloc_pbas(bool &progress)
}
break;
case WRITE_BLK:
case ALLOC_PBA: progress |= _allocate_pba.execute(meta_tree, block_io); break;
case ALLOC_PBA_SUCCEEDED:
{
if (_lvl > 1)
_t1_blks[_lvl - 1].encode_to_blk(_blk);
else
_t2_blk.encode_to_blk(_blk);
Type_1_node &t1_node { _t1_blks[_lvl].nodes[_node_idx[_lvl]] };
t1_node.gen = req._curr_gen;
t1_node.gen = _attr.in_curr_gen;
calc_hash(_blk, t1_node.hash);
_generate_req<Block_io::Write>(SEEK_LEFT_OR_UP, progress, t1_node.pba, _blk);
_write_block.generate(_helper, WRITE_BLK, SEEK_LEFT_OR_UP, progress, t1_node.pba, _blk);
break;
}
case WRITE_BLK: progress |= _write_block.execute(block_io); break;
default: break;
}
return progress;
}
void Free_tree_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
switch(_req_ptr->_type) {
case Request::ALLOC_FOR_NON_RKG:
case Request::ALLOC_FOR_RKG_CURR_GEN_BLKS:
case Request::ALLOC_FOR_RKG_OLD_GEN_BLKS: _alloc_pbas(progress); break;
case Request::EXTENSION_STEP: _extension_step(progress); break;
}
}
void Free_tree_channel::_generate_write_blk_req(bool &progress)
void Free_tree::Extend_tree::_generate_write_blk_req(bool &progress)
{
if (_lvl > 1)
_t1_blks[_lvl].encode_to_blk(_blk);
else
_t2_blk.encode_to_blk(_blk);
_generate_req<Block_io::Write>(WRITE_BLK_SUCCEEDED, progress, _new_pbas.pbas[_lvl], _blk);
_write_block.generate(_helper, WRITE_BLK, WRITE_BLK_SUCCEEDED, progress, _new_pbas.pbas[_lvl], _blk);
if (VERBOSE_FT_EXTENSION)
log(" lvl ", _lvl, " write to pba ", _new_pbas.pbas[_lvl]);
}
void Free_tree_channel::_add_new_root_lvl()
void Free_tree::Extend_tree::_add_new_root_lvl()
{
Request &req { *_req_ptr };
ASSERT(req._ft.max_lvl < TREE_MAX_LEVEL);
req._ft.max_lvl++;
_t1_blks[req._ft.max_lvl] = { };
_t1_blks[req._ft.max_lvl].nodes[0] = req._ft.t1_node();
_new_pbas.pbas[req._ft.max_lvl] = alloc_pba_from_range(req._pba, req._num_pbas);
req._ft.t1_node({ _new_pbas.pbas[req._ft.max_lvl], req._curr_gen });
ASSERT(_attr.in_out_ft.max_lvl < TREE_MAX_LEVEL);
_attr.in_out_ft.max_lvl++;
_t1_blks[_attr.in_out_ft.max_lvl] = { };
_t1_blks[_attr.in_out_ft.max_lvl].nodes[0] = _attr.in_out_ft.t1_node();
_new_pbas.pbas[_attr.in_out_ft.max_lvl] = alloc_pba_from_range(_attr.in_out_first_pba, _attr.in_out_num_pbas);
_attr.in_out_ft.t1_node({ _new_pbas.pbas[_attr.in_out_ft.max_lvl], _attr.in_curr_gen });
if (VERBOSE_FT_EXTENSION)
log(" set root: ", req._ft, "\n set lvl ", req._ft.max_lvl, " node 0: ",
_t1_blks[req._ft.max_lvl].nodes[0]);
log(" set root: ", _attr.in_out_ft, "\n set lvl ", _attr.in_out_ft.max_lvl, " node 0: ",
_t1_blks[_attr.in_out_ft.max_lvl].nodes[0]);
}
void Free_tree_channel::_add_new_branch_at(Tree_level_index dst_lvl, Tree_node_index dst_node_idx)
void Free_tree::Extend_tree::_add_new_branch_at(Tree_level_index dst_lvl, Tree_node_index dst_node_idx)
{
Request &req { *_req_ptr };
_num_leaves = 0;
_lvl = dst_lvl;
if (dst_lvl > 1) {
@ -331,17 +245,17 @@ void Free_tree_channel::_add_new_branch_at(Tree_level_index dst_lvl, Tree_node_i
log(" reset lvl ", lvl);
}
}
for (; _lvl && req._num_pbas; _lvl--) {
for (; _lvl && _attr.in_out_num_pbas; _lvl--) {
Tree_node_index node_idx = (_lvl == dst_lvl) ? dst_node_idx : 0;
if (_lvl > 1) {
_new_pbas.pbas[_lvl - 1] = alloc_pba_from_range(req._pba, req._num_pbas);
_t1_blks[_lvl].nodes[node_idx] = { _new_pbas.pbas[_lvl - 1], req._curr_gen };
_new_pbas.pbas[_lvl - 1] = alloc_pba_from_range(_attr.in_out_first_pba, _attr.in_out_num_pbas);
_t1_blks[_lvl].nodes[node_idx] = { _new_pbas.pbas[_lvl - 1], _attr.in_curr_gen };
if (VERBOSE_FT_EXTENSION)
log(" set _lvl d ", _lvl, " node ", node_idx, ": ", _t1_blks[_lvl].nodes[node_idx]);
} else {
for (; node_idx < req._ft.degree && req._num_pbas; node_idx++) {
_t2_blk.nodes[node_idx] = { alloc_pba_from_range(req._pba, req._num_pbas) };
for (; node_idx < _attr.in_out_ft.degree && _attr.in_out_num_pbas; node_idx++) {
_t2_blk.nodes[node_idx] = { alloc_pba_from_range(_attr.in_out_first_pba, _attr.in_out_num_pbas) };
_num_leaves++;
if (VERBOSE_FT_EXTENSION)
log(" set _lvl e ", _lvl, " node ", node_idx, ": ", _t2_blk.nodes[node_idx]);
@ -353,80 +267,80 @@ void Free_tree_channel::_add_new_branch_at(Tree_level_index dst_lvl, Tree_node_i
}
void Free_tree_channel::_extension_step(bool &progress)
bool Free_tree::Extend_tree::execute(Block_io &block_io, Meta_tree &meta_tree)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
bool progress = false;
switch (_helper.state) {
case INIT:
_num_leaves = 0;
_vba = req._ft.num_leaves;
_vba = _attr.in_out_ft.num_leaves;
_old_pbas = { };
_old_generations = { };
_new_pbas = { };
_lvl = req._ft.max_lvl;
_old_pbas.pbas[_lvl] = req._ft.pba;
_old_generations.items[_lvl] = req._ft.gen;
if (_vba <= tree_max_max_vba(req._ft.degree, req._ft.max_lvl)) {
_lvl = _attr.in_out_ft.max_lvl;
_old_pbas.pbas[_lvl] = _attr.in_out_ft.pba;
_old_generations.items[_lvl] = _attr.in_out_ft.gen;
if (_vba <= tree_max_max_vba(_attr.in_out_ft.degree, _attr.in_out_ft.max_lvl)) {
_generate_req<Block_io::Read>(READ_BLK_SUCCEEDED, progress, req._ft.pba, _blk);
_read_block.generate(_helper, READ_BLK, READ_BLK_SUCCEEDED, progress, _attr.in_out_ft.pba, _blk);
if (VERBOSE_FT_EXTENSION)
log(" root (", req._ft, "): load to lvl ", _lvl);
log(" root (", _attr.in_out_ft, "): load to lvl ", _lvl);
} else {
_add_new_root_lvl();
_add_new_branch_at(req._ft.max_lvl, 1);
_add_new_branch_at(_attr.in_out_ft.max_lvl, 1);
_generate_write_blk_req(progress);
if (VERBOSE_FT_EXTENSION)
log(" pbas allocated: curr gen ", req._curr_gen);
log(" pbas allocated: curr gen ", _attr.in_curr_gen);
}
break;
case READ_BLK: progress |= _read_block.execute(block_io); break;
case READ_BLK_SUCCEEDED:
if (_lvl > 1) {
_t1_blks[_lvl].decode_from_blk(_blk);
if (_lvl < req._ft.max_lvl) {
Tree_node_index node_idx = t1_node_idx_for_vba(_vba, _lvl + 1, req._ft.degree);
if (_lvl < _attr.in_out_ft.max_lvl) {
Tree_node_index node_idx = tree_node_index(_vba, _lvl + 1, _attr.in_out_ft.degree);
if (!check_hash(_blk, _t1_blks[_lvl + 1].nodes[node_idx].hash))
_mark_req_failed(progress, "hash mismatch");
_helper.mark_failed(progress, "hash mismatch");
} else
if (!check_hash(_blk, req._ft.hash))
_mark_req_failed(progress, "hash mismatch");
if (!check_hash(_blk, _attr.in_out_ft.hash))
_helper.mark_failed(progress, "hash mismatch");
Tree_node_index node_idx = t1_node_idx_for_vba(_vba, _lvl, req._ft.degree);
Tree_node_index node_idx = tree_node_index(_vba, _lvl, _attr.in_out_ft.degree);
Type_1_node &t1_node = _t1_blks[_lvl].nodes[node_idx];
if (t1_node.valid()) {
_lvl--;
_old_pbas.pbas [_lvl] = t1_node.pba;
_old_generations.items[_lvl] = t1_node.gen;
_generate_req<Block_io::Read>(READ_BLK_SUCCEEDED, progress, t1_node.pba, _blk);
_read_block.generate(_helper, READ_BLK, READ_BLK_SUCCEEDED, progress, t1_node.pba, _blk);
if (VERBOSE_FT_EXTENSION)
log(" lvl ", _lvl + 1, " node ", node_idx, " (", t1_node, "): load to lvl ", _lvl);
} else {
_alloc_lvl = _lvl;
_add_new_branch_at(_lvl, node_idx);
if (_old_generations.items[_alloc_lvl] == req._curr_gen) {
if (_old_generations.items[_alloc_lvl] == _attr.in_curr_gen) {
_alloc_pba = _old_pbas.pbas[_alloc_lvl];
_state = ALLOC_PBA_SUCCEEDED;
_helper.state = ALLOC_PBA_SUCCEEDED;
progress = true;
} else {
_alloc_pba = _old_pbas.pbas[_alloc_lvl];
_generate_req<Meta_tree_request>(
ALLOC_PBA_SUCCEEDED, progress, Meta_tree_request::ALLOC_PBA, req._mt, req._curr_gen, _alloc_pba);
_allocate_pba.generate(_helper, ALLOC_PBA, ALLOC_PBA_SUCCEEDED, progress, _attr.in_out_mt, _attr.in_curr_gen, _alloc_pba);
}
}
} else {
_t2_blk.decode_from_blk(_blk);
Tree_node_index t1_node_idx = t1_node_idx_for_vba(_vba, _lvl + 1, req._ft.degree);
Tree_node_index t1_node_idx = tree_node_index(_vba, _lvl + 1, _attr.in_out_ft.degree);
if (!check_hash(_blk, _t1_blks[_lvl + 1].nodes[t1_node_idx].hash))
_mark_req_failed(progress, "hash mismatch");
_helper.mark_failed(progress, "hash mismatch");
Tree_node_index t2_node_idx = t2_node_idx_for_vba(_vba, req._ft.degree);
Tree_node_index t2_node_idx = tree_node_index(_vba, _lvl, _attr.in_out_ft.degree);
if (_t2_blk.nodes[t2_node_idx].valid())
_mark_req_failed(progress, "t2 node valid");
_helper.mark_failed(progress, "t2 node valid");
_add_new_branch_at(_lvl, t2_node_idx);
_alloc_lvl = _lvl;
@ -434,41 +348,41 @@ void Free_tree_channel::_extension_step(bool &progress)
log(" alloc lvl ", _alloc_lvl);
_alloc_pba = _old_pbas.pbas[_alloc_lvl];
_generate_req<Meta_tree_request>(
ALLOC_PBA_SUCCEEDED, progress, Meta_tree_request::ALLOC_PBA, req._mt, req._curr_gen, _alloc_pba);
_allocate_pba.generate(_helper, ALLOC_PBA, ALLOC_PBA_SUCCEEDED, progress, _attr.in_out_mt, _attr.in_curr_gen, _alloc_pba);
}
break;
case ALLOC_PBA: progress |= _allocate_pba.execute(meta_tree, block_io); break;
case ALLOC_PBA_SUCCEEDED:
_new_pbas.pbas[_alloc_lvl] = _alloc_pba;
if (_alloc_lvl < req._ft.max_lvl) {
if (_alloc_lvl < _attr.in_out_ft.max_lvl) {
_alloc_lvl++;
if (_old_generations.items[_alloc_lvl] == req._curr_gen) {
if (_old_generations.items[_alloc_lvl] == _attr.in_curr_gen) {
_alloc_pba = _old_pbas.pbas[_alloc_lvl];
_state = ALLOC_PBA_SUCCEEDED;
_helper.state = ALLOC_PBA_SUCCEEDED;
progress = true;
} else {
_alloc_pba = _old_pbas.pbas[_alloc_lvl];
_generate_req<Meta_tree_request>(
ALLOC_PBA_SUCCEEDED, progress, Meta_tree_request::ALLOC_PBA, req._mt, req._curr_gen, _alloc_pba);
_allocate_pba.generate(_helper, ALLOC_PBA, ALLOC_PBA_SUCCEEDED, progress, _attr.in_out_mt, _attr.in_curr_gen, _alloc_pba);
}
} else {
_generate_write_blk_req(progress);
if (VERBOSE_FT_EXTENSION)
log(" pbas allocated: curr gen ", req._curr_gen);
log(" pbas allocated: curr gen ", _attr.in_curr_gen);
}
break;
case WRITE_BLK: progress |= _write_block.execute(block_io); break;
case WRITE_BLK_SUCCEEDED:
if (_lvl < req._ft.max_lvl) {
if (_lvl < _attr.in_out_ft.max_lvl) {
if (_lvl > 1) {
Tree_node_index node_idx = t1_node_idx_for_vba(_vba, _lvl + 1, req._ft.degree);
Tree_node_index node_idx = tree_node_index(_vba, _lvl + 1, _attr.in_out_ft.degree);
Type_1_node &t1_node { _t1_blks[_lvl + 1].nodes[node_idx] };
t1_node = { _new_pbas.pbas[_lvl], req._curr_gen };
t1_node = { _new_pbas.pbas[_lvl], _attr.in_curr_gen };
calc_hash(_blk, t1_node.hash);
if (VERBOSE_FT_EXTENSION)
log(" set lvl ", _lvl + 1, " node ", node_idx, ": ", t1_node);
@ -476,9 +390,9 @@ void Free_tree_channel::_extension_step(bool &progress)
_lvl++;
_generate_write_blk_req(progress);
} else {
Tree_node_index node_idx = t1_node_idx_for_vba(_vba, _lvl + 1, req._ft.degree);
Tree_node_index node_idx = tree_node_index(_vba, _lvl + 1, _attr.in_out_ft.degree);
Type_1_node &t1_node = _t1_blks[_lvl + 1].nodes[node_idx];
t1_node = { _new_pbas.pbas[_lvl], req._curr_gen };
t1_node = { _new_pbas.pbas[_lvl], _attr.in_curr_gen };
calc_hash(_blk, t1_node.hash);
if (VERBOSE_FT_EXTENSION)
log(" set lvl ", _lvl + 1, " t1_node ", node_idx, ": ", t1_node);
@ -487,30 +401,14 @@ void Free_tree_channel::_extension_step(bool &progress)
_generate_write_blk_req(progress);
}
} else {
req._ft.t1_node({ _new_pbas.pbas[_lvl], req._curr_gen });
calc_hash(_blk, req._ft.hash);
req._ft.num_leaves += _num_leaves;
_mark_req_successful(progress);
_attr.in_out_ft.t1_node({ _new_pbas.pbas[_lvl], _attr.in_curr_gen });
calc_hash(_blk, _attr.in_out_ft.hash);
_attr.in_out_ft.num_leaves += _num_leaves;
_helper.mark_succeeded(progress);
}
break;
default: break;
}
}
void Free_tree_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
Free_tree::Free_tree()
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
}
return progress;
}

View File

@ -13,73 +13,66 @@
/* tresor includes */
#include <tresor/ft_check.h>
#include <tresor/block_io.h>
#include <tresor/hash.h>
using namespace Tresor;
Ft_check_request::Ft_check_request(Module_id src_mod, Module_channel_id src_chan, Tree_root const &ft, bool &success)
:
Module_request { src_mod, src_chan, FT_CHECK }, _ft { ft }, _success { success }
{ }
bool Ft_check_channel::_execute_node(Tree_level_index lvl, Tree_node_index node_idx, bool &progress)
bool Ft_check::Check::_execute_node(Block_io &block_io, Tree_level_index lvl, Tree_node_index node_idx, bool &progress)
{
bool &check_node { _check_node[lvl][node_idx] };
if (check_node == false)
return false;
Request &req { *_req_ptr };
switch (_state) {
case REQ_IN_PROGRESS:
switch (_helper.state) {
case IN_PROGRESS:
if (lvl == 1) {
Type_2_node const &node { _t2_blk.nodes[node_idx] };
if (!_num_remaining_leaves) {
if (node.valid()) {
_mark_req_failed(progress, { "lvl ", lvl, " node ", node_idx, " (", node,
") valid but no leaves remaining" });
_helper.mark_failed(progress, { "lvl ", lvl, " node ", node_idx, " (", node,
") valid but no leaves remaining" });
break;
}
check_node = false;
progress = true;
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._ft.max_lvl }, " lvl ", lvl, " node ", node_idx, " unused");
log(Level_indent { lvl, _attr.in_ft.max_lvl }, " lvl ", lvl, " node ", node_idx, " unused");
break;
}
_num_remaining_leaves--;
check_node = false;
progress = true;
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._ft.max_lvl }, " lvl ", lvl, " node ", node_idx, " done");
log(Level_indent { lvl, _attr.in_ft.max_lvl }, " lvl ", lvl, " node ", node_idx, " done");
} else {
Type_1_node const &node { _t1_blks.items[lvl].nodes[node_idx] };
if (!node.valid()) {
if (_num_remaining_leaves) {
_mark_req_failed(progress, { "lvl ", lvl, " node ", node_idx, " invalid but ",
_num_remaining_leaves, " leaves remaining" });
_helper.mark_failed(progress, { "lvl ", lvl, " node ", node_idx, " invalid but ",
_num_remaining_leaves, " leaves remaining" });
break;
}
check_node = false;
progress = true;
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._ft.max_lvl }, " lvl ", lvl, " node ", node_idx, " unused");
log(Level_indent { lvl, _attr.in_ft.max_lvl }, " lvl ", lvl, " node ", node_idx, " unused");
break;
}
_generate_req<Block_io::Read>(READ_BLK_SUCCEEDED, progress, node.pba, _blk);
_read_block.generate(_helper, READ_BLK, READ_BLK_SUCCEEDED, progress, node.pba, _blk);
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._ft.max_lvl }, " lvl ", lvl, " node ", node_idx,
log(Level_indent { lvl, _attr.in_ft.max_lvl }, " lvl ", lvl, " node ", node_idx,
" (", node, "): load to lvl ", lvl - 1);
}
break;
case READ_BLK: progress |= _read_block.execute(block_io); break;
case READ_BLK_SUCCEEDED:
{
Type_1_node const &node { _t1_blks.items[lvl].nodes[node_idx] };
if (node.gen != INITIAL_GENERATION && !check_hash(_blk, node.hash)) {
_mark_req_failed(progress, { "lvl ", lvl, " node ", node_idx, " (", node, ") has bad hash" });
_helper.mark_failed(progress, { "lvl ", lvl, " node ", node_idx, " (", node, ") has bad hash" });
break;
}
if (lvl == 2)
@ -89,11 +82,11 @@ bool Ft_check_channel::_execute_node(Tree_level_index lvl, Tree_node_index node_
for (bool &cn : _check_node[lvl - 1])
cn = true;
_state = REQ_IN_PROGRESS;
_helper.state = IN_PROGRESS;
check_node = false;
progress = true;
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._ft.max_lvl }, " lvl ", lvl, " node ", node_idx, " has good hash");
log(Level_indent { lvl, _attr.in_ft.max_lvl }, " lvl ", lvl, " node ", node_idx, " has good hash");
break;
}
default: break;
@ -102,81 +95,24 @@ bool Ft_check_channel::_execute_node(Tree_level_index lvl, Tree_node_index node_
}
void Ft_check_channel::execute(bool &progress)
bool Ft_check::Check::execute(Block_io &block_io)
{
if (!_req_ptr)
return;
if (_state == REQ_SUBMITTED) {
for (Tree_level_index lvl { 1 }; lvl <= _req_ptr->_ft.max_lvl + 1; lvl++)
for (Tree_node_index node_idx { 0 }; node_idx < _req_ptr->_ft.degree; node_idx++)
bool progress = false;
if (_helper.state == INIT) {
for (Tree_level_index lvl { 1 }; lvl <= _attr.in_ft.max_lvl + 1; lvl++)
for (Tree_node_index node_idx { 0 }; node_idx < _attr.in_ft.degree; node_idx++)
_check_node[lvl][node_idx] = false;
_num_remaining_leaves = _req_ptr->_ft.num_leaves;
_t1_blks.items[_req_ptr->_ft.max_lvl + 1].nodes[0] = _req_ptr->_ft.t1_node();
_check_node[_req_ptr->_ft.max_lvl + 1][0] = true;
_state = REQ_IN_PROGRESS;
_num_remaining_leaves = _attr.in_ft.num_leaves;
_t1_blks.items[_attr.in_ft.max_lvl + 1].nodes[0] = _attr.in_ft.t1_node();
_check_node[_attr.in_ft.max_lvl + 1][0] = true;
_helper.state = IN_PROGRESS;
}
for (Tree_level_index lvl { 1 }; lvl <= _req_ptr->_ft.max_lvl + 1; lvl++)
for (Tree_node_index node_idx { 0 }; node_idx < _req_ptr->_ft.degree; node_idx++)
if (_execute_node(lvl, node_idx, progress))
return;
for (Tree_level_index lvl { 1 }; lvl <= _attr.in_ft.max_lvl + 1; lvl++)
for (Tree_node_index node_idx { 0 }; node_idx < _attr.in_ft.degree; node_idx++)
if (_execute_node(block_io, lvl, node_idx, progress))
return progress;
_mark_req_successful(progress);
}
void Ft_check_channel::_generated_req_completed(State_uint state_uint)
{
if (!_generated_req_success) {
error("ft check: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
void Ft_check_channel::_mark_req_failed(bool &progress, Error_string str)
{
error("ft check request (", *_req_ptr, ") failed: ", str);
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Ft_check_channel::_mark_req_successful(bool &progress)
{
_req_ptr->_success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Ft_check_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
Ft_check::Ft_check()
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
}
}
void Ft_check::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
_helper.mark_succeeded(progress);
return progress;
}

View File

@ -13,20 +13,67 @@
*/
/* tresor includes */
#include <tresor/block_io.h>
#include <tresor/hash.h>
#include <tresor/ft_initializer.h>
using namespace Tresor;
Ft_initializer_request::Ft_initializer_request(Module_id src_mod, Module_channel_id src_chan,
Tree_root &ft, Pba_allocator &pba_alloc, bool &success)
:
Module_request { src_mod, src_chan, FT_INITIALIZER }, _ft { ft }, _pba_alloc { pba_alloc }, _success { success }
{ }
void Ft_initializer::Initialize::_reset_level(Tree_level_index lvl, Node_state node_state)
{
if (lvl == 1)
for (Tree_node_index idx = 0; idx < NUM_NODES_PER_BLK; idx++) {
_t2_blk.nodes[idx] = { };
_t2_node_states[idx] = node_state;
}
else
for (Tree_node_index idx = 0; idx < NUM_NODES_PER_BLK; idx++) {
_t1_blks.items[lvl].nodes[idx] = { };
_t1_node_states[lvl][idx] = node_state;
}
}
bool Ft_initializer_channel::_execute_t2_node(Tree_node_index node_idx, bool &progress)
bool Ft_initializer::Initialize::execute(Block_io &block_io)
{
bool progress = false;
switch (_helper.state) {
case INIT:
_num_remaining_leaves = _attr.in_tree_cfg.num_leaves;
for (Tree_level_index lvl = 0; lvl < TREE_MAX_LEVEL; lvl++)
_reset_level(lvl, DONE);
_t1_node_states[_attr.in_tree_cfg.max_lvl + 1][0] = INIT_BLOCK;
_helper.state = EXECUTE_NODES;
progress = true;
break;
case EXECUTE_NODES:
for (Tree_node_index node_idx = 0; node_idx < _attr.in_tree_cfg.degree; node_idx++)
if (_execute_t2_node(node_idx, progress))
return progress;
for (Tree_level_index lvl = 1; lvl <= _attr.in_tree_cfg.max_lvl + 1; lvl++)
for (Tree_node_index node_idx = 0; node_idx < _attr.in_tree_cfg.degree; node_idx++)
if (_execute_t1_node(lvl, node_idx, progress))
return progress;
if (_num_remaining_leaves)
_helper.mark_failed(progress, "leaves remaining");
else {
_attr.out_tree_root = _t1_blks.items[_attr.in_tree_cfg.max_lvl + 1].nodes[0];
_helper.mark_succeeded(progress);
}
break;
case WRITE_BLOCK: progress |= _write_block.execute(block_io); break;
default: break;;
}
return progress;
}
bool Ft_initializer::Initialize::_execute_t2_node(Tree_node_index node_idx, bool &progress)
{
Node_state &node_state { _t2_node_states[node_idx] };
Type_2_node &node { _t2_blk.nodes[node_idx] };
@ -42,8 +89,8 @@ bool Ft_initializer_channel::_execute_t2_node(Tree_node_index node_idx, bool &pr
if (_num_remaining_leaves) {
node = { };
if (!_req_ptr->_pba_alloc.alloc(node.pba)) {
_mark_req_failed(progress, "allocate pba");
if (!_attr.in_out_pba_alloc.alloc(node.pba)) {
_helper.mark_failed(progress, "allocate pba");
break;
}
node_state = DONE;
@ -60,13 +107,13 @@ bool Ft_initializer_channel::_execute_t2_node(Tree_node_index node_idx, bool &pr
}
break;
case WRITE_BLK: ASSERT_NEVER_REACHED;
case WRITING_BLOCK: ASSERT_NEVER_REACHED;
}
return true;
}
bool Ft_initializer_channel::_execute_t1_node(Tree_level_index lvl, Tree_node_index node_idx, bool &progress)
bool Ft_initializer::Initialize::_execute_t1_node(Tree_level_index lvl, Tree_node_index node_idx, bool &progress)
{
Type_1_node &node { _t1_blks.items[lvl].nodes[node_idx] };
Node_state &node_state { _t1_node_states[lvl][node_idx] };
@ -92,8 +139,8 @@ bool Ft_initializer_channel::_execute_t1_node(Tree_level_index lvl, Tree_node_in
case INIT_NODE:
{
node = { };
if (!_req_ptr->_pba_alloc.alloc(node.pba)) {
_mark_req_failed(progress, "allocate pba");
if (!_attr.in_out_pba_alloc.alloc(node.pba)) {
_helper.mark_failed(progress, "allocate pba");
break;
}
if (lvl == 2)
@ -101,15 +148,13 @@ bool Ft_initializer_channel::_execute_t1_node(Tree_level_index lvl, Tree_node_in
else
_t1_blks.items[lvl - 1].encode_to_blk(_blk);
calc_hash(_blk, node.hash);
generate_req<Block_io::Write>(EXECUTE_NODES, progress, node.pba, _blk, _generated_req_success);
_state = REQ_GENERATED;
node_state = WRITE_BLK;
progress = true;
_write_block.generate(_helper, WRITE_BLOCK, EXECUTE_NODES, progress, node.pba, _blk);
node_state = WRITING_BLOCK;
if (VERBOSE_FT_INIT)
log("[ft_init] node: ", lvl, " ", node_idx, " assign pba: ", node.pba);
break;
}
case WRITE_BLK:
case WRITING_BLOCK:
node_state = DONE;
progress = true;
@ -119,115 +164,3 @@ bool Ft_initializer_channel::_execute_t1_node(Tree_level_index lvl, Tree_node_in
}
return true;
}
void Ft_initializer_channel::_generated_req_completed(State_uint state_uint)
{
if (!_generated_req_success) {
error("ft initializer request (", *_req_ptr, ") failed because generated request failed");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
void Ft_initializer_channel::_mark_req_failed(bool &progress, char const *str)
{
error("ft initializer request (", *_req_ptr, ") failed because: ", str);
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Ft_initializer_channel::_mark_req_successful(bool &progress)
{
_req_ptr->_ft.t1_node(_t1_blks.items[_req_ptr->_ft.max_lvl + 1].nodes[0]);
_req_ptr->_success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Ft_initializer_channel::_reset_level(Tree_level_index lvl, Node_state node_state)
{
if (lvl == 1)
for (Tree_node_index idx = 0; idx < NUM_NODES_PER_BLK; idx++) {
_t2_blk.nodes[idx] = { };
_t2_node_states[idx] = node_state;
}
else
for (Tree_node_index idx = 0; idx < NUM_NODES_PER_BLK; idx++) {
_t1_blks.items[lvl].nodes[idx] = { };
_t1_node_states[lvl][idx] = node_state;
}
}
void Ft_initializer_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
_num_remaining_leaves = req._ft.num_leaves;
for (Tree_level_index lvl = 0; lvl < TREE_MAX_LEVEL; lvl++)
_reset_level(lvl, DONE);
_t1_node_states[req._ft.max_lvl + 1][0] = INIT_BLOCK;
_state = EXECUTE_NODES;
progress = true;
return;
case EXECUTE_NODES:
for (Tree_node_index node_idx = 0; node_idx < req._ft.degree; node_idx++)
if (_execute_t2_node(node_idx, progress))
return;
for (Tree_level_index lvl = 1; lvl <= req._ft.max_lvl + 1; lvl++)
for (Tree_node_index node_idx = 0; node_idx < req._ft.degree; node_idx++)
if (_execute_t1_node(lvl, node_idx, progress))
return;
if (_num_remaining_leaves)
_mark_req_failed(progress, "leaves remaining");
else
_mark_req_successful(progress);
return;
default: return;
}
}
void Ft_initializer_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
Ft_initializer::Ft_initializer()
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
}
}
void Ft_initializer::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
}

View File

@ -18,147 +18,132 @@
#include <tresor/types.h>
#include <tresor/file.h>
namespace Tresor {
namespace Tresor { class Block_io; }
class Block_io;
class Block_io_request;
class Block_io_channel;
}
class Tresor::Block_io_request : public Module_request
{
friend class Block_io_channel;
public:
enum Type { READ, WRITE, SYNC, READ_CLIENT_DATA, WRITE_CLIENT_DATA };
private:
Type const _type;
Request_offset const _client_req_offset;
Request_tag const _client_req_tag;
Key_id const _key_id;
Physical_block_address const _pba;
Virtual_block_address const _vba;
Block &_blk;
Hash &_hash;
bool &_success;
NONCOPYABLE(Block_io_request);
public:
Block_io_request(Module_id, Module_channel_id, Type, Request_offset, Request_tag, Key_id,
Physical_block_address, Virtual_block_address, Block &, Hash &, bool &);
static char const *type_to_string(Type);
void print(Output &out) const override { Genode::print(out, type_to_string(_type), " pba ", _pba); }
};
class Tresor::Block_io_channel : public Module_channel
class Tresor::Block_io : Noncopyable
{
private:
using Request = Block_io_request;
Vfs::Vfs_handle &_file;
addr_t _user { };
enum State {
REQ_SUBMITTED, REQ_COMPLETE, CIPHERTEXT_BLK_OBTAINED, PLAINTEXT_BLK_SUPPLIED, REQ_GENERATED,
READ_OK, WRITE_OK, SYNC_OK, FILE_ERR };
public:
State _state { REQ_COMPLETE };
Block _blk { };
bool _generated_req_success { false };
Block_io_request *_req_ptr { };
Vfs::Env &_vfs_env;
Tresor::Path const _path;
Read_write_file<State> _file { _state, _vfs_env, _path };
class Read;
class Write;
class Sync;
NONCOPYABLE(Block_io_channel);
Block_io(Vfs::Vfs_handle &file) : _file(file) { }
void _generated_req_completed(State_uint) override;
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
template <typename REQ>
bool execute(REQ &req)
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
if (!_user)
_user = (addr_t)&req;
if (_user != (addr_t)&req)
return false;
bool progress = req.execute(_file);
if (req.complete())
_user = 0;
return progress;
}
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
void _read(bool &);
void _write(bool &);
void _read_client_data(bool &);
void _write_client_data(bool &);
void _sync(bool &);
void _mark_req_failed(bool &, Error_string);
void _mark_req_successful(bool &);
public:
Block_io_channel(Module_channel_id, Vfs::Env &, Xml_node const &);
void execute(bool &);
static constexpr char const *name() { return "block_io"; }
};
class Tresor::Block_io : public Module
class Tresor::Block_io::Read : Noncopyable
{
public:
using Module = Block_io;
struct Attr
{
Physical_block_address const in_pba;
Block &out_block;
};
private:
using Request = Block_io_request;
using Channel = Block_io_channel;
enum State { INIT, COMPLETE, READ, READ_OK, FILE_ERR };
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Block_io);
Request_helper<Read, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
public:
struct Read : Request
Read(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "read pba ", _attr.in_pba); }
bool execute(Vfs::Vfs_handle &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Block_io::Write : Noncopyable
{
public:
using Module = Block_io;
struct Attr
{
Read(Module_id m, Module_channel_id c, Physical_block_address a, Block &b, bool &s)
: Request(m, c, Request::READ, 0, 0, 0, a, 0, b, *(Hash*)0, s) { }
Physical_block_address const in_pba;
Block const &in_block;
};
struct Write : Request
{
Write(Module_id m, Module_channel_id c, Physical_block_address a, Block const &b, bool &s)
: Request(m, c, Request::WRITE, 0, 0, 0, a, 0, *const_cast<Block*>(&b), *(Hash*)0, s) { }
};
private:
struct Sync : Request
{
Sync(Module_id m, Module_channel_id c, bool &s)
: Request(m, c, Request::SYNC, 0, 0, 0, 0, 0, *(Block*)0, *(Hash*)0, s) { }
};
enum State { INIT, COMPLETE, WRITE, WRITE_OK, FILE_ERR };
struct Write_client_data : Request
{
Write_client_data(Module_id m, Module_channel_id c, Physical_block_address p, Virtual_block_address v,
Key_id k, Request_tag t, Request_offset o, Hash &h, bool &s)
: Request(m, c, Request::WRITE_CLIENT_DATA, o, t, k, p, v, *(Block*)0, h, s) { }
};
Request_helper<Write, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
struct Read_client_data : Request
{
Read_client_data(Module_id m, Module_channel_id c, Physical_block_address p, Virtual_block_address v,
Key_id k, Request_tag t, Request_offset o, Hash &h, bool &s)
: Request(m, c, Request::READ_CLIENT_DATA, o, t, k, p, v, *(Block*)0, h, s) { }
};
public:
Block_io(Vfs::Env &, Xml_node const &);
Write(Attr const &attr) : _helper(*this), _attr(attr) { }
void execute(bool &) override;
void print(Output &out) const { Genode::print(out, "write pba ", _attr.in_pba); }
bool execute(Vfs::Vfs_handle &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Block_io::Sync : Noncopyable
{
public:
using Module = Block_io;
struct Attr { };
private:
enum State { INIT, COMPLETE, SYNC, SYNC_OK, FILE_ERR };
Request_helper<Sync, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
public:
Sync(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "sync"); }
bool execute(Vfs::Vfs_handle &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
#endif /* _TRESOR__BLOCK_IO_H_ */

View File

@ -1,69 +0,0 @@
/*
* \brief Module that provides access to the client request data
* \author Martin Stein
* \date 2023-02-13
*/
/*
* Copyright (C) 2023 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.
*/
#ifndef _TRESOR__CLIENT_DATA_H_
#define _TRESOR__CLIENT_DATA_H_
/* tresor includes */
#include <tresor/types.h>
namespace Tresor { class Client_data_request; }
namespace Vfs_tresor { class Client_data; }
namespace Tresor_tester { class Client_data; }
class Tresor::Client_data_request : public Module_request
{
friend class ::Vfs_tresor::Client_data;
friend class ::Tresor_tester::Client_data;
public:
enum Type { OBTAIN_PLAINTEXT_BLK, SUPPLY_PLAINTEXT_BLK };
private:
Type const _type;
Request_offset const _req_off;
Request_tag const _req_tag;
Physical_block_address const _pba;
Virtual_block_address const _vba;
Block &_blk;
bool &_success;
NONCOPYABLE(Client_data_request);
public:
Client_data_request(Module_id src_mod_id, Module_channel_id src_chan_id, Type type,
Request_offset req_off, Request_tag req_tag, Physical_block_address pba,
Virtual_block_address vba, Block &blk, bool &success)
:
Module_request { src_mod_id, src_chan_id, CLIENT_DATA }, _type { type }, _req_off { req_off },
_req_tag { req_tag }, _pba { pba }, _vba { vba }, _blk { blk }, _success { success }
{ }
static char const *type_to_string(Type type)
{
switch (type) {
case OBTAIN_PLAINTEXT_BLK: return "obtain_plaintext_blk";
case SUPPLY_PLAINTEXT_BLK: return "supply_plaintext_blk";
}
ASSERT_NEVER_REACHED;
}
void print(Output &out) const override { Genode::print(out, type_to_string(_type)); }
};
#endif /* _TRESOR__CLIENT_DATA_H_ */

View File

@ -0,0 +1,47 @@
/*
* \brief Interface for providing access to the client request data
* \author Martin Stein
* \date 2023-02-13
*/
/*
* Copyright (C) 2023 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.
*/
#ifndef _TRESOR__CLIENT_DATA_INTERFACE_H_
#define _TRESOR__CLIENT_DATA_INTERFACE_H_
/* tresor includes */
#include <tresor/types.h>
namespace Tresor { class Client_data_interface; }
struct Tresor::Client_data_interface : Interface
{
struct Obtain_data_attr
{
Request_offset const in_req_off;
Request_tag const in_req_tag;
Physical_block_address const in_pba;
Virtual_block_address const in_vba;
Block &out_blk;
};
virtual void obtain_data(Obtain_data_attr const &) = 0;
struct Supply_data_attr
{
Request_offset const in_req_off;
Request_tag const in_req_tag;
Physical_block_address const in_pba;
Virtual_block_address const in_vba;
Block const &in_blk;
};
virtual void supply_data(Supply_data_attr const &) = 0;
};
#endif /* _TRESOR__CLIENT_DATA_INTERFACE_H_ */

View File

@ -21,155 +21,187 @@
namespace Tresor {
class Crypto;
class Crypto_request;
class Crypto_channel;
class Crypto_key_files_interface;
}
class Tresor::Crypto_request : public Module_request
struct Tresor::Crypto_key_files_interface : Interface
{
friend class Crypto_channel;
virtual void add_crypto_key(Key_id) = 0;
public:
virtual void remove_crypto_key(Key_id) = 0;
enum Type { ADD_KEY, REMOVE_KEY, DECRYPT, ENCRYPT, DECRYPT_CLIENT_DATA, ENCRYPT_CLIENT_DATA };
virtual Vfs::Vfs_handle &encrypt_file(Key_id) = 0;
private:
Type const _type;
Request_offset const _client_req_offset;
Request_tag const _client_req_tag;
Physical_block_address const _pba;
Virtual_block_address const _vba;
Key_id const _key_id;
Key_value const &_key_plaintext;
Block &_blk;
bool &_success;
NONCOPYABLE(Crypto_request);
public:
Crypto_request(Module_id, Module_channel_id, Type, Request_offset, Request_tag, Key_id,
Key_value const &, Physical_block_address, Virtual_block_address, Block &, bool &);
static const char *type_to_string(Type);
void print(Output &) const override;
virtual Vfs::Vfs_handle &decrypt_file(Key_id) = 0;
};
class Tresor::Crypto_channel : public Module_channel
class Tresor::Crypto : Noncopyable
{
private:
public:
using Request = Crypto_request;
enum State {
REQ_SUBMITTED, REQ_COMPLETE, PLAINTEXT_BLK_OBTAINED, PLAINTEXT_BLK_SUPPLIED, REQ_GENERATED,
READ_OK, WRITE_OK, FILE_ERR };
struct Key_directory
struct Attr
{
Crypto_channel &chan;
Key_id key_id;
Read_write_file<State> encrypt_file { chan._state, chan._vfs_env, { chan._path, "/keys/", key_id, "/encrypt" } };
Read_write_file<State> decrypt_file { chan._state, chan._vfs_env, { chan._path, "/keys/", key_id, "/decrypt" } };
NONCOPYABLE(Key_directory);
Key_directory(Crypto_channel &chan, Key_id key_id) : chan { chan }, key_id { key_id } { }
Crypto_key_files_interface &key_files;
Vfs::Vfs_handle &add_key_file;
Vfs::Vfs_handle &remove_key_file;
};
Vfs::Env &_vfs_env;
Tresor::Path const _path;
char _add_key_buf[sizeof(Key_id) + KEY_SIZE] { };
Write_only_file<State> _add_key_file { _state, _vfs_env, { _path, "/add_key" } };
Write_only_file<State> _remove_key_file { _state, _vfs_env, { _path, "/remove_key" } };
Constructible<Key_directory> _key_dirs[2] { };
State _state { REQ_COMPLETE };
bool _generated_req_success { false };
Block _blk { };
Request *_req_ptr { };
private:
NONCOPYABLE(Crypto_channel);
Attr const _attr;
addr_t _user { };
void _generated_req_completed(State_uint) override;
public:
void _request_submitted(Module_request &) override;
class Encrypt;
class Decrypt;
class Add_key;
class Remove_key;
bool _request_complete() override { return _state == REQ_COMPLETE; }
Crypto(Attr const &attr) : _attr(attr) { }
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
template <typename REQ>
bool execute(REQ &req)
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
if (!_user)
_user = (addr_t)&req;
if (_user != (addr_t)&req)
return false;
bool progress = req.execute(_attr);
if (req.complete())
_user = 0;
return progress;
}
void _add_key(bool &);
void _remove_key(bool &);
void _decrypt(bool &);
void _encrypt(bool &);
void _encrypt_client_data(bool &);
void _decrypt_client_data(bool &);
void _mark_req_failed(bool &, char const *);
void _mark_req_successful(bool &);
Constructible<Key_directory> &_key_dir(Key_id key_id);
public:
Crypto_channel(Module_channel_id, Vfs::Env &, Xml_node const &);
void execute(bool &);
static constexpr char const *name() { return "crypto"; }
};
class Tresor::Crypto : public Module
class Tresor::Crypto::Encrypt : Noncopyable
{
public:
using Module = Crypto;
struct Attr
{
Key_id const in_key_id;
Physical_block_address const in_pba;
Block &in_out_blk;
};
private:
using Request = Crypto_request;
using Channel = Crypto_channel;
enum State { INIT, COMPLETE, WRITE, WRITE_OK, READ_OK, FILE_ERR };
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Crypto);
Request_helper<Encrypt, State> _helper;
Attr const _attr;
off_t _offset { };
Constructible<File<State> > _file { };
public:
struct Add_key : Request
Encrypt(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "encrypt pba ", _attr.in_pba); }
bool execute(Crypto::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Crypto::Decrypt : Noncopyable
{
public:
using Module = Crypto;
struct Attr
{
Add_key(Module_id src_mod, Module_channel_id src_chan, Key &key, bool &succ)
: Request(src_mod, src_chan, Request::ADD_KEY, 0, 0, key.id, key.value, 0, 0, *(Block*)0, succ) { }
Key_id const in_key_id;
Physical_block_address const in_pba;
Block &in_out_blk;
};
struct Remove_key : Request
{
Remove_key(Module_id src_mod, Module_channel_id src_chan, Key_id key, bool &succ)
: Request(src_mod, src_chan, Request::REMOVE_KEY, 0, 0, key, *(Key_value*)0, 0, 0, *(Block*)0, succ) { }
};
private:
struct Decrypt : Request
{
Decrypt(Module_id src_mod, Module_channel_id src_chan, Key_id key, Physical_block_address pba, Block &blk, bool &succ)
: Request(src_mod, src_chan, Request::DECRYPT, 0, 0, key, *(Key_value*)0, pba, 0, blk, succ) { }
};
enum State { INIT, COMPLETE, WRITE, WRITE_OK, READ_OK, FILE_ERR };
struct Encrypt : Request
{
Encrypt(Module_id src_mod, Module_channel_id src_chan, Key_id key, Physical_block_address pba, Block &blk, bool &succ)
: Request(src_mod, src_chan, Request::ENCRYPT, 0, 0, key, *(Key_value*)0, pba, 0, blk, succ) { }
};
Request_helper<Decrypt, State> _helper;
Attr const _attr;
off_t _offset { };
Constructible<File<State> > _file { };
Crypto(Vfs::Env &, Xml_node const &);
public:
void execute(bool &) override;
Decrypt(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "decrypt pba ", _attr.in_pba); }
bool execute(Crypto::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Crypto::Add_key : Noncopyable
{
public:
using Module = Crypto;
struct Attr { Key const &in_key; };
private:
enum State { INIT, COMPLETE, WRITE, WRITE_OK, FILE_ERR };
Request_helper<Add_key, State> _helper;
Attr const _attr;
char _write_buf[sizeof(Key_id) + sizeof(Key_value)] { };
Constructible<File<State> > _file { };
public:
Add_key(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "add key id ", _attr.in_key.id); }
bool execute(Crypto::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Crypto::Remove_key : Noncopyable
{
public:
using Module = Crypto;
struct Attr { Key_id const in_key_id; };
private:
enum State { INIT, COMPLETE, WRITE, WRITE_OK, FILE_ERR };
Request_helper<Remove_key, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
public:
Remove_key(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "remove key id ", _attr.in_key_id); }
bool execute(Crypto::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
#endif /* _TRESOR__CRYPTO_H_ */

View File

@ -33,8 +33,17 @@ namespace Tresor {
template <typename> class File;
template <typename> class Read_write_file;
template <typename> class Write_only_file;
inline Vfs::Vfs_handle &open_file(Vfs::Env &env, Tresor::Path const &path, Vfs::Directory_service::Open_mode mode)
{
using Open_result = Vfs::Directory_service::Open_result;
Vfs::Vfs_handle *handle { nullptr };
ASSERT(env.root_dir().open(path.string(), mode, &handle, env.alloc()) == Open_result::OPEN_OK);
return *handle;
}
}
template <typename HOST_STATE>
class Tresor::File
{
@ -43,34 +52,34 @@ class Tresor::File
using Read_result = Vfs::File_io_service::Read_result;
using Write_result = Vfs::File_io_service::Write_result;
using Sync_result = Vfs::File_io_service::Sync_result;
using Open_result = Vfs::Directory_service::Open_result;
enum State { IDLE, SYNC_QUEUED, READ_QUEUED, READ_INITIALIZED, WRITE_INITIALIZED, WRITE_OFFSET_APPLIED };
Vfs::Env &_env;
Vfs::Env *_env { };
Tresor::Path const *_path { };
HOST_STATE &_host_state;
State _state { IDLE };
Vfs::Vfs_handle &_handle;
Vfs::file_size _num_processed_bytes { 0 };
Vfs::Vfs_handle &_open(Tresor::Path path, Vfs::Directory_service::Open_mode mode)
{
Vfs::Vfs_handle *handle { nullptr };
ASSERT(_env.root_dir().open(path.string(), mode, &handle, _env.alloc()) == Open_result::OPEN_OK);
return *handle;
}
/*
* Noncopyable
*/
File(File const &) = delete;
File &operator = (File const &) = delete;
public:
File(HOST_STATE &host_state, Vfs::Vfs_handle &handle) : _host_state { host_state }, _handle { handle } { }
File(HOST_STATE &host_state, Vfs::Vfs_handle &handle) : _host_state(host_state), _handle(handle) { }
File(HOST_STATE &host_state, Vfs::Env &env, Tresor::Path path, Vfs::Directory_service::Open_mode mode)
: _env { env }, _host_state { host_state }, _handle { _open(path, mode) } { }
File(HOST_STATE &host_state, Vfs::Env &env, Tresor::Path const &path, Vfs::Directory_service::Open_mode mode)
: _env(&env), _path(&path), _host_state(host_state), _handle(open_file(*_env, *_path, mode)) { }
~File()
{
ASSERT(_state == IDLE);
_env.root_dir().close(&_handle);
if (_env)
_env->root_dir().close(&_handle);
}
void read(HOST_STATE succeeded, HOST_STATE failed, Vfs::file_offset off, Byte_range_ptr dst, bool &progress)
@ -116,7 +125,7 @@ class Tresor::File
default:
error("read failed");
error("file: read failed");
_host_state = failed;
_state = IDLE;
progress = true;
@ -167,7 +176,7 @@ class Tresor::File
default:
error("write failed");
error("file: write failed");
_host_state = failed;
_state = IDLE;
progress = true;
@ -204,7 +213,7 @@ class Tresor::File
default:
error("sync failed");
error("file: sync failed");
_host_state = failed;
_state = IDLE;
progress = true;
@ -218,15 +227,15 @@ class Tresor::File
template <typename HOST_STATE>
struct Tresor::Read_write_file : public File<HOST_STATE>
{
Read_write_file(HOST_STATE &host_state, Vfs::Env &env, Tresor::Path path)
: File<HOST_STATE> { host_state, env, path, Vfs::Directory_service::OPEN_MODE_RDWR } { }
Read_write_file(HOST_STATE &host_state, Vfs::Env &env, Tresor::Path const &path)
: File<HOST_STATE>(host_state, env, path, Vfs::Directory_service::OPEN_MODE_RDWR) { }
};
template <typename HOST_STATE>
struct Tresor::Write_only_file : public File<HOST_STATE>
{
Write_only_file(HOST_STATE &host_state, Vfs::Env &env, Tresor::Path path)
: File<HOST_STATE> { host_state, env, path, Vfs::Directory_service::OPEN_MODE_WRONLY } { }
Write_only_file(HOST_STATE &host_state, Vfs::Env &env, Tresor::Path const &path)
: File<HOST_STATE>(host_state, env, path, Vfs::Directory_service::OPEN_MODE_WRONLY) { }
};
#endif /* _TRESOR__FILE_H_ */

View File

@ -16,80 +16,68 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/block_io.h>
#include <tresor/meta_tree.h>
namespace Tresor {
namespace Tresor { class Free_tree; }
class Free_tree;
class Free_tree_request;
class Free_tree_channel;
}
class Tresor::Free_tree_request : public Module_request
class Tresor::Free_tree : Noncopyable
{
friend class Free_tree_channel;
public:
enum Type { ALLOC_FOR_NON_RKG, ALLOC_FOR_RKG_CURR_GEN_BLKS, ALLOC_FOR_RKG_OLD_GEN_BLKS, EXTENSION_STEP };
class Allocate_pbas;
class Extend_tree;
private:
template <typename REQUEST>
bool execute(REQUEST &req, Block_io &block_io, Meta_tree &meta_tree) { return req.execute(block_io, meta_tree); }
Type const _type;
Tree_root &_ft;
Tree_root &_mt;
Generation const _curr_gen;
Generation const _free_gen;
Number_of_blocks const _num_required_pbas;
Tree_walk_pbas &_new_blocks;
Type_1_node_walk const &_old_blocks;
Tree_level_index const _max_lvl;
Virtual_block_address const _vba;
Tree_degree const _vbd_degree;
Virtual_block_address const _vbd_max_vba;
bool const _rekeying;
Key_id const _prev_key_id;
Key_id const _curr_key_id;
Virtual_block_address const _rekeying_vba;
bool &_success;
Snapshots const &_snapshots;
Generation const _last_secured_gen;
Physical_block_address &_pba;
Number_of_blocks &_num_pbas;
NONCOPYABLE(Free_tree_request);
public:
Free_tree_request(Module_id, Module_channel_id, Type, Tree_root &, Tree_root &, Snapshots const &,
Generation, Generation, Generation, Number_of_blocks, Tree_walk_pbas &, Type_1_node_walk const &,
Tree_level_index, Virtual_block_address, Tree_degree, Virtual_block_address,
bool, Key_id, Key_id, Virtual_block_address, Physical_block_address &, Number_of_blocks &, bool &);
static char const *type_to_string(Type);
void print(Output &out) const override { Genode::print(out, type_to_string(_type)); }
static constexpr char const *name() { return "free_tree"; }
};
class Tresor::Free_tree_channel : public Module_channel
class Tresor::Free_tree::Allocate_pbas : Noncopyable
{
public:
using Module = Free_tree;
enum Application { NON_REKEYING, REKEYING_IN_CURRENT_GENERATION, REKEYING_IN_OLDER_GENERATION };
struct Attr
{
Tree_root &in_out_ft;
Tree_root &in_out_mt;
Snapshots const &in_snapshots;
Generation const in_last_secured_gen;
Generation const in_curr_gen;
Generation const in_free_gen;
Number_of_blocks const in_num_required_pbas;
Tree_walk_pbas &in_out_new_blocks;
Type_1_node_walk const &in_old_blocks;
Tree_level_index const in_max_lvl;
Virtual_block_address const in_vba;
Tree_degree const in_vbd_degree;
Virtual_block_address const in_vbd_max_vba;
bool const in_rekeying;
Key_id const in_prev_key_id;
Key_id const in_curr_key_id;
Virtual_block_address const in_rekeying_vba;
Application const in_application;
};
private:
using Request = Free_tree_request;
enum State {
REQ_SUBMITTED, REQ_GENERATED, SEEK_DOWN, SEEK_LEFT_OR_UP, WRITE_BLK, READ_BLK_SUCCEEDED,
ALLOC_PBA_SUCCEEDED, WRITE_BLK_SUCCEEDED, REQ_COMPLETE };
INIT, COMPLETE, SEEK_DOWN, SEEK_LEFT_OR_UP, READ_BLK, READ_BLK_SUCCEEDED,
ALLOC_PBA, ALLOC_PBA_SUCCEEDED, WRITE_BLK, WRITE_BLK_SUCCEEDED };
Request *_req_ptr { nullptr };
State _state { REQ_COMPLETE };
using Helper = Request_helper<Allocate_pbas, State>;
Helper _helper;
Attr const _attr;
Virtual_block_address _vba { };
Tree_walk_pbas _old_pbas { };
Tree_walk_pbas _new_pbas { };
Tree_walk_generations _old_generations { };
Number_of_leaves _num_leaves { 0 };
Physical_block_address _alloc_pba { 0 };
Tree_level_index _alloc_lvl { 0 };
Number_of_blocks _num_pbas { 0 };
Block _blk { };
Tree_node_index _node_idx[TREE_MAX_NR_OF_LEVELS] { };
@ -98,36 +86,71 @@ class Tresor::Free_tree_channel : public Module_channel
Type_2_node_block _t2_blk { };
Tree_degree_log_2 _vbd_degree_log_2 { 0 };
Tree_level_index _lvl { 0 };
bool _generated_req_success { false };
NONCOPYABLE(Free_tree_channel);
void _generated_req_completed(State_uint) override;
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
}
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
void _mark_req_failed(bool &, char const *);
bool _can_alloc_pba_of(Type_2_node &);
Generatable_request<Helper, State, Block_io::Read> _read_block { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
Generatable_request<Helper, State, Meta_tree::Allocate_pba> _allocate_pba { };
void _alloc_pba_of(Type_2_node &);
void _traverse_curr_node(bool &);
bool _can_alloc_pba_of(Type_2_node &);
void _mark_req_successful(bool &);
void _traverse_curr_node(bool &);
void _start_tree_traversal(bool &);
void _advance_to_next_node();
public:
Allocate_pbas(Attr const &attr) : _helper(*this), _attr(attr) { }
~Allocate_pbas() { }
void print(Output &out) const { Genode::print(out, "allocate pbas"); }
bool execute(Block_io &, Meta_tree &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Free_tree::Extend_tree : Noncopyable
{
public:
using Module = Free_tree;
struct Attr
{
Generation const in_curr_gen;
Tree_root &in_out_ft;
Tree_root &in_out_mt;
Physical_block_address &in_out_first_pba;
Number_of_blocks &in_out_num_pbas;
};
private:
enum State {
INIT, COMPLETE, READ_BLK, READ_BLK_SUCCEEDED, ALLOC_PBA, ALLOC_PBA_SUCCEEDED, WRITE_BLK,
WRITE_BLK_SUCCEEDED };
using Helper = Request_helper<Extend_tree, State>;
Helper _helper;
Attr const _attr;
Number_of_leaves _num_leaves { 0 };
Virtual_block_address _vba { };
Tree_walk_pbas _old_pbas { };
Tree_walk_generations _old_generations { };
Tree_walk_pbas _new_pbas { };
Tree_level_index _lvl { 0 };
Block _blk { };
Type_1_node_block _t1_blks[TREE_MAX_NR_OF_LEVELS] { };
Type_2_node_block _t2_blk { };
Tree_level_index _alloc_lvl { 0 };
Physical_block_address _alloc_pba { 0 };
Generatable_request<Helper, State, Block_io::Read> _read_block { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
Generatable_request<Helper, State, Meta_tree::Allocate_pba> _allocate_pba { };
void _add_new_branch_at(Tree_level_index, Tree_node_index);
@ -135,41 +158,18 @@ class Tresor::Free_tree_channel : public Module_channel
void _generate_write_blk_req(bool &);
void _extension_step(bool &);
void _alloc_pbas(bool &);
public:
Free_tree_channel(Module_channel_id id) : Module_channel { FREE_TREE, id } { }
Extend_tree(Attr const &attr) : _helper(*this), _attr(attr) { }
void execute(bool &);
};
~Extend_tree() { }
class Tresor::Free_tree : public Module
{
private:
void print(Output &out) const { Genode::print(out, "extend tree"); }
using Channel = Free_tree_channel;
using Request = Free_tree_request;
bool execute(Block_io &, Meta_tree &);
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Free_tree);
void execute(bool &) override;
public:
struct Extension_step : Request
{
Extension_step(Module_id mod_id, Module_channel_id chan_id, Generation curr_gen, Tree_root &ft, Tree_root &mt,
Physical_block_address &pba, Number_of_blocks &num_pbas, bool &succ)
: Request(mod_id, chan_id, Request::EXTENSION_STEP, ft, mt, *(Snapshots *)0, 0, curr_gen, 0, 0, *(Tree_walk_pbas*)0,
*(Type_1_node_walk*)0, 0, 0, 0, 0, 0, 0, 0, 0, pba, num_pbas, succ) { }
};
Free_tree();
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
#endif /* _TRESOR__FREE_TREE_H_ */

View File

@ -16,95 +16,54 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/block_io.h>
namespace Tresor {
namespace Tresor { class Ft_check; }
class Ft_check;
class Ft_check_request;
class Ft_check_channel;
}
class Tresor::Ft_check_request : public Module_request
struct Tresor::Ft_check : Noncopyable
{
friend class Ft_check_channel;
class Check : Noncopyable
{
public:
private:
using Module = Ft_check;
Tree_root const &_ft;
bool &_success;
struct Attr { Tree_root const &in_ft; };
NONCOPYABLE(Ft_check_request);
private:
public:
enum State { INIT, IN_PROGRESS, COMPLETE, READ_BLK, READ_BLK_SUCCEEDED };
Ft_check_request(Module_id, Module_channel_id, Tree_root const &, bool &);
using Helper = Request_helper<Check, State>;
void print(Output &out) const override { Genode::print(out, "check ", _ft); }
};
Helper _helper;
Attr const _attr;
Type_1_node_block_walk _t1_blks { };
Type_2_node_block _t2_blk { };
bool _check_node[TREE_MAX_NR_OF_LEVELS + 1][NUM_NODES_PER_BLK] { };
Number_of_leaves _num_remaining_leaves { 0 };
Block _blk { };
Generatable_request<Helper, State, Block_io::Read> _read_block { };
bool _execute_node(Block_io &, Tree_level_index, Tree_node_index, bool &);
class Tresor::Ft_check_channel : public Module_channel
{
private:
public:
using Request = Ft_check_request;
Check(Attr const &attr) : _helper(*this), _attr(attr) { }
enum State : State_uint { REQ_SUBMITTED, REQ_IN_PROGRESS, REQ_COMPLETE, REQ_GENERATED, READ_BLK_SUCCEEDED };
void print(Output &out) const { Genode::print(out, "check ", _attr.in_ft); }
State _state { REQ_COMPLETE };
Type_1_node_block_walk _t1_blks { };
Type_2_node_block _t2_blk { };
bool _check_node[TREE_MAX_NR_OF_LEVELS + 1][NUM_NODES_PER_BLK] { };
Number_of_leaves _num_remaining_leaves { 0 };
Request *_req_ptr { };
Block _blk { };
bool _generated_req_success { false };
bool execute(Block_io &);
NONCOPYABLE(Ft_check_channel);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
void _generated_req_completed(State_uint) override;
Ft_check() { }
void _request_submitted(Module_request &) override;
bool execute(Check &req, Block_io &block_io) { return req.execute(block_io); }
bool _request_complete() override { return _state == REQ_COMPLETE; }
void _mark_req_failed(bool &, Error_string);
void _mark_req_successful(bool &);
bool _execute_node(Tree_level_index, Tree_node_index, bool &);
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
}
public:
Ft_check_channel(Module_channel_id id) : Module_channel { FT_CHECK, id } { }
void execute(bool &);
};
class Tresor::Ft_check : public Module
{
private:
using Channel = Ft_check_channel;
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Ft_check);
public:
Ft_check();
void execute(bool &) override;
static constexpr char const *name() { return "ft_check"; }
};
#endif /* _TRESOR__FT_CHECK_H_ */

View File

@ -17,97 +17,68 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/block_io.h>
namespace Tresor {
namespace Tresor { class Ft_initializer; }
class Ft_initializer;
class Ft_initializer_request;
class Ft_initializer_channel;
}
class Tresor::Ft_initializer_request : public Module_request
class Tresor::Ft_initializer : Noncopyable
{
friend class Ft_initializer_channel;
private:
Tree_root &_ft;
Pba_allocator &_pba_alloc;
bool &_success;
NONCOPYABLE(Ft_initializer_request);
public:
Ft_initializer_request(Module_id, Module_channel_id, Tree_root &, Pba_allocator &, bool &);
class Initialize : Noncopyable
{
public:
void print(Output &out) const override { Genode::print(out, "init"); }
};
using Module = Ft_initializer;
struct Attr
{
Tree_configuration const in_tree_cfg;
Type_1_node &out_tree_root;
Pba_allocator &in_out_pba_alloc;
};
class Tresor::Ft_initializer_channel : public Module_channel
{
private:
private:
using Request = Ft_initializer_request;
enum Node_state { DONE, INIT_BLOCK, INIT_NODE, WRITING_BLOCK };
enum State { REQ_GENERATED, REQ_SUBMITTED, EXECUTE_NODES, REQ_COMPLETE };
enum State { INIT, COMPLETE, EXECUTE_NODES, WRITE_BLOCK };
enum Node_state { DONE, INIT_BLOCK, INIT_NODE, WRITE_BLK };
using Helper = Request_helper<Initialize, State>;
State _state { REQ_COMPLETE };
Request *_req_ptr { };
Type_2_node_block _t2_blk { };
Type_1_node_block_walk _t1_blks { };
Node_state _t1_node_states[TREE_MAX_NR_OF_LEVELS][NUM_NODES_PER_BLK] { };
Node_state _t2_node_states[NUM_NODES_PER_BLK] { };
Number_of_leaves _num_remaining_leaves { 0 };
bool _generated_req_success { false };
Block _blk { };
Helper _helper;
Attr const _attr;
Type_2_node_block _t2_blk { };
Type_1_node_block_walk _t1_blks { };
Node_state _t1_node_states[TREE_MAX_NR_OF_LEVELS][NUM_NODES_PER_BLK] { };
Node_state _t2_node_states[NUM_NODES_PER_BLK] { };
Number_of_leaves _num_remaining_leaves { 0 };
Block _blk { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
NONCOPYABLE(Ft_initializer_channel);
void _reset_level(Tree_level_index, Node_state);
void _reset_level(Tree_level_index, Node_state);
bool _execute_t2_node(Tree_node_index, bool &);
void _generated_req_completed(State_uint) override;
bool _execute_t1_node(Tree_level_index, Tree_node_index, bool &);
bool _request_complete() override { return _state == REQ_COMPLETE; }
public:
void _request_submitted(Module_request &) override;
Initialize(Attr const &attr) : _helper(*this), _attr(attr) { }
bool _execute_t2_node(Tree_node_index, bool &);
~Initialize() { }
bool _execute_t1_node(Tree_level_index, Tree_node_index, bool &);
void print(Output &out) const { Genode::print(out, "initialize"); }
void _mark_req_failed(bool &, char const *);
bool execute(Block_io &);
void _mark_req_successful(bool &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
public:
Ft_initializer_channel(Module_channel_id id) : Module_channel { FT_INITIALIZER, id } { }
void execute(bool &);
};
class Tresor::Ft_initializer : public Module
{
private:
using Channel = Ft_initializer_channel;
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Ft_initializer);
public:
Ft_initializer();
void execute(bool &) override;
bool execute(Initialize &req, Block_io &block_io) { return req.execute(block_io); }
static constexpr char const *name() { return "ft_initializer"; }
};
#endif /* _TRESOR__FT_INITIALIZER_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Module for doing VBD COW allocations on the meta tree
* \brief Module for doing PBA allocations for the Free Tree via the Meta Tree
* \author Martin Stein
* \date 2023-02-13
*/
@ -16,74 +16,49 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/block_io.h>
namespace Tresor {
namespace Tresor { class Meta_tree; }
class Meta_tree;
class Meta_tree_request;
class Meta_tree_channel;
}
class Tresor::Meta_tree_request : public Module_request
class Tresor::Meta_tree : Noncopyable
{
friend class Meta_tree_channel;
public:
enum Type { ALLOC_PBA };
class Allocate_pba;
private:
bool execute(Allocate_pba &, Block_io &);
Type const _type;
Tree_root &_mt;
Generation const _curr_gen;
Physical_block_address &_pba;
bool &_success;
NONCOPYABLE(Meta_tree_request);
public:
Meta_tree_request(Module_id, Module_channel_id, Type, Tree_root &, Generation, Physical_block_address &, bool &);
static char const *type_to_string(Type);
void print(Output &out) const override { Genode::print(out, type_to_string(_type)); }
static constexpr char const *name() { return "meta_tree"; }
};
class Tresor::Meta_tree_channel : public Module_channel
class Tresor::Meta_tree::Allocate_pba : Noncopyable
{
public:
using Module = Meta_tree;
struct Attr
{
Tree_root &in_out_mt;
Generation const in_curr_gen;
Physical_block_address &in_out_pba;
};
private:
using Request = Meta_tree_request;
enum State { INIT, COMPLETE, READ_BLK, SEEK_DOWN, SEEK_LEFT_OR_UP, WRITE_BLK, WRITE_BLK_SUCCEEDED };
enum State { REQ_SUBMITTED, REQ_GENERATED, SEEK_DOWN, SEEK_LEFT_OR_UP, WRITE_BLK, COMPLETE };
using Helper = Request_helper<Allocate_pba, State>;
State _state { COMPLETE };
Request *_req_ptr { nullptr };
Helper _helper;
Attr const _attr;
Block _blk { };
Tree_node_index _node_idx[TREE_MAX_NR_OF_LEVELS] { };
Type_1_node_block _t1_blks[TREE_MAX_NR_OF_LEVELS] { };
Type_2_node_block _t2_blk { };
Tree_level_index _lvl { 0 };
bool _generated_req_success { false };
NONCOPYABLE(Meta_tree_channel);
void _generated_req_completed(State_uint) override;
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
}
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == COMPLETE; }
void _mark_req_failed(bool &, char const *);
Generatable_request<Helper, State, Block_io::Read> _read_block { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
bool _can_alloc_pba_of(Type_2_node &);
@ -91,38 +66,20 @@ class Tresor::Meta_tree_channel : public Module_channel
void _traverse_curr_node(bool &);
void _mark_req_successful(bool &);
void _start_tree_traversal(bool &);
public:
Meta_tree_channel(Module_channel_id id) : Module_channel { META_TREE, id } { }
Allocate_pba(Attr const &attr) : _helper(*this), _attr(attr) { }
void execute(bool &);
};
~Allocate_pba() { }
class Tresor::Meta_tree : public Module
{
private:
void print(Output &out) const { Genode::print(out, "allocate pba"); }
using Channel = Meta_tree_channel;
bool execute(Block_io &);
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Meta_tree);
void execute(bool &) override;
public:
struct Alloc_pba : Meta_tree_request
{
Alloc_pba(Module_id src_mod, Module_channel_id src_chan, Tree_root &mt, Generation gen, Physical_block_address &pba, bool &succ)
: Meta_tree_request(src_mod, src_chan, Meta_tree_request::ALLOC_PBA, mt, gen, pba, succ) { }
};
Meta_tree();
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
#endif /* _TRESOR__META_TREE_H_ */

View File

@ -1,223 +0,0 @@
/*
* \brief Framework for component internal modularization
* \author Martin Stein
* \date 2023-02-13
*/
/*
* Copyright (C) 2023 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.
*/
#ifndef _TRESOR__MODULE_H_
#define _TRESOR__MODULE_H_
/* base includes */
#include <util/avl_tree.h>
/* tresor includes */
#include <tresor/verbosity.h>
#include <tresor/noncopyable.h>
#include <tresor/assertion.h>
namespace Tresor {
using namespace Genode;
using Module_id = uint64_t;
using Module_channel_id = uint64_t;
enum { INVALID_MODULE_ID = ~(Module_id)0, INVALID_MODULE_CHANNEL_ID = ~(Module_channel_id)0 };
enum Module_id_enum : Module_id {
CRYPTO = 0, CLIENT_DATA = 1, TRUST_ANCHOR = 2, COMMAND_POOL = 3, BLOCK_IO = 4, CACHE = 5, META_TREE = 6,
FREE_TREE = 7, VIRTUAL_BLOCK_DEVICE = 8, SUPERBLOCK_CONTROL = 9, VBD_INITIALIZER = 10, FT_INITIALIZER = 11,
SB_INITIALIZER = 12, REQUEST_POOL = 13, SB_CHECK = 14, VBD_CHECK = 15, FT_CHECK = 16, SPLITTER = 17, MAX_MODULE_ID = 17 };
char const *module_name(Module_id module_id);
class Module_request;
class Module_channel;
class Module;
class Module_composition;
}
class Tresor::Module_request : public Interface
{
private:
Module_id _src_module_id;
Module_channel_id _src_chan_id;
Module_id _dst_module_id;
Module_channel_id _dst_chan_id { INVALID_MODULE_CHANNEL_ID };
NONCOPYABLE(Module_request);
public:
Module_request(Module_id, Module_channel_id, Module_id);
void dst_chan_id(Module_channel_id id) { _dst_chan_id = id; }
Module_id src_module_id() const { return _src_module_id; }
Module_channel_id src_chan_id() const { return _src_chan_id; }
Module_id dst_module_id() const { return _dst_module_id; }
Module_channel_id dst_chan_id() const { return _dst_chan_id; }
virtual void print(Output &) const = 0;
virtual ~Module_request() { }
};
class Tresor::Module_channel : private Avl_node<Module_channel>
{
friend class Module;
friend class Avl_node<Module_channel>;
friend class Avl_tree<Module_channel>;
public:
using State_uint = uint64_t;
private:
enum { GEN_REQ_BUF_SIZE = 4000 };
enum Generated_request_state { NONE, PENDING, IN_PROGRESS };
Module_request *_req_ptr { nullptr };
Module_id _module_id;
Module_channel_id _id;
Generated_request_state _gen_req_state { NONE };
uint8_t _gen_req_buf[GEN_REQ_BUF_SIZE] { };
State_uint _gen_req_complete_state { 0 };
NONCOPYABLE(Module_channel);
bool higher(Module_channel *ptr) { return ptr->_id > _id; }
virtual void _generated_req_completed(State_uint) { ASSERT_NEVER_REACHED; }
virtual void _request_submitted(Module_request &) { ASSERT_NEVER_REACHED; }
virtual bool _request_complete() { ASSERT_NEVER_REACHED; }
public:
Module_channel(Module_id module_id, Module_channel_id id) : _module_id { module_id }, _id { id } { };
template <typename REQUEST, typename... ARGS>
void generate_req(State_uint complete_state, bool &progress, ARGS &&... args)
{
ASSERT(_gen_req_state == NONE);
static_assert(sizeof(REQUEST) <= GEN_REQ_BUF_SIZE);
construct_at<REQUEST>(_gen_req_buf, _module_id, _id, args...);
_gen_req_state = PENDING;
_gen_req_complete_state = complete_state;
progress = true;
}
template <typename CHAN, typename FUNC>
void with_channel(Module_channel_id id, FUNC && func)
{
if (id != _id) {
Module_channel *chan_ptr { Avl_node<Module_channel>::child(id > _id) };
ASSERT(chan_ptr);
chan_ptr->with_channel<CHAN>(id, func);
} else
func(*static_cast<CHAN *>(this));
}
void generated_req_completed();
bool try_submit_request(Module_request &);
Module_channel_id id() const { return _id; }
virtual ~Module_channel() { }
};
class Tresor::Module : public Interface
{
private:
Avl_tree<Module_channel> _channels { };
NONCOPYABLE(Module);
public:
template <typename CHAN = Module_channel, typename FUNC>
void with_channel(Module_channel_id id, FUNC && func)
{
ASSERT(_channels.first());
_channels.first()->with_channel<CHAN>(id, func);
}
template <typename CHAN = Module_channel, typename FUNC>
void for_each_channel(FUNC && func)
{
_channels.for_each([&] (Module_channel const &const_chan) {
func(*static_cast<CHAN *>(const_cast<Module_channel *>(&const_chan))); });
}
template <typename FUNC>
void for_each_generated_request(FUNC && handle_request)
{
for_each_channel([&] (Module_channel &chan) {
if (chan._gen_req_state != Module_channel::PENDING)
return;
Module_request &req = *(Module_request *)chan._gen_req_buf;
if (handle_request(req)) {
chan._gen_req_state = Module_channel::IN_PROGRESS;
return;
}
});
}
template <typename FUNC>
void for_each_completed_request(FUNC && handle_request)
{
for_each_channel([&] (Module_channel &chan) {
if (chan._req_ptr && chan._request_complete()) {
handle_request(*chan._req_ptr);
chan._req_ptr = nullptr;
}
});
return;
}
bool try_submit_request(Module_request &);
void add_channel(Module_channel &chan) { _channels.insert(&chan); }
Module() { }
virtual ~Module() { }
virtual void execute(bool &) { }
};
class Tresor::Module_composition
{
private:
Module *_module_ptrs[MAX_MODULE_ID + 1] { };
public:
void add_module(Module_id module_id, Module &mod);
void remove_module(Module_id module_id);
void execute_modules();
};
#endif /* _TRESOR__MODULE_H_ */

View File

@ -1,21 +0,0 @@
/*
* \brief Macro to make a class non-copyable
* \author Martin Stein
* \date 2023-06-09
*/
/*
* Copyright (C) 2023 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.
*/
#ifndef _TRESOR__NONCOPYABLE_H_
#define _TRESOR__NONCOPYABLE_H_
#define NONCOPYABLE(class_name) \
class_name(class_name const &) = delete; \
class_name &operator = (class_name const &) = delete; \
#endif /* _TRESOR__NONCOPYABLE_H_ */

View File

@ -1,180 +0,0 @@
/*
* \brief Module for scheduling requests for processing
* \author Martin Stein
* \date 2023-03-17
*/
/*
* Copyright (C) 2023 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.
*/
#ifndef _TRESOR__REQUEST_POOL_H_
#define _TRESOR__REQUEST_POOL_H_
/* tresor includes */
#include <tresor/types.h>
#include <tresor/superblock_control.h>
namespace Tresor {
class Request;
class Request_pool;
class Request_pool_channel;
class Request_pool_channel_queue;
}
class Tresor::Request : public Module_request
{
NONCOPYABLE(Request);
friend class Request_pool_channel;
public:
enum Operation {
READ, WRITE, SYNC, CREATE_SNAPSHOT, DISCARD_SNAPSHOT, REKEY, EXTEND_VBD,
EXTEND_FT, RESUME_REKEYING, DEINITIALIZE, INITIALIZE, };
private:
Operation _op;
Virtual_block_address const _vba;
Request_offset const _offset;
Number_of_blocks const _count;
Key_id const _key_id;
Request_tag const _tag;
Generation &_gen;
bool &_success;
public:
static char const *op_to_string(Operation);
Request(Module_id, Module_channel_id, Operation, Virtual_block_address, Request_offset,
Number_of_blocks, Key_id, Request_tag, Generation &, bool &);
void print(Output &) const override;
};
class Tresor::Request_pool_channel : public Module_channel
{
private:
enum State : State_uint {
INVALID, REQ_SUBMITTED, REQ_RESUMED, REQ_GENERATED, REKEY_INIT_SUCCEEDED, PREPONED_REQUESTS_COMPLETE,
TREE_EXTENSION_STEP_SUCCEEDED, FORWARD_TO_SB_CTRL_SUCCEEDED, ACCESS_VBA_AT_SB_CTRL_SUCCEEDED,
REKEY_VBA_SUCCEEDED, INITIALIZE_SB_CTRL_SUCCEEDED, DEINITIALIZE_SB_CTRL_SUCCEEDED, REQ_COMPLETE };
State _state { INVALID };
Number_of_blocks _num_blks { 0 };
Superblock::State _sb_state { Superblock::INVALID };
uint32_t _num_requests_preponed { 0 };
bool _request_finished { false };
bool _generated_req_success { false };
Request_pool_channel_queue &_chan_queue;
Request *_req_ptr { nullptr };
NONCOPYABLE(Request_pool_channel);
void _generated_req_completed(State_uint) override;
void _request_submitted(Module_request &req) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
void _access_vbas(bool &, Superblock_control_request::Type);
void _forward_to_sb_ctrl(bool &, Superblock_control_request::Type);
void _gen_sb_control_req(bool &, Superblock_control_request::Type, State, Virtual_block_address);
void _rekey(bool &);
void _mark_req_successful(bool &);
void _reset();
void _try_prepone_requests(bool &);
void _extend_tree(Superblock_control_request::Type, bool &);
void _initialize(bool &);
void _resume_request(bool &, Request::Operation);
public:
Request_pool_channel(Module_channel_id id, Request_pool_channel_queue &chan_queue) : Module_channel { REQUEST_POOL, id }, _chan_queue { chan_queue } { }
void execute(bool &);
};
class Tresor::Request_pool_channel_queue
{
NONCOPYABLE(Request_pool_channel_queue);
public:
enum { NUM_SLOTS = 16 };
private:
using Channel = Request_pool_channel;
using Slot_index = uint64_t;
using Number_of_slots = uint64_t;
Slot_index _head { 0 };
Slot_index _tail { 0 };
Number_of_slots _num_used_slots { 0 };
Channel *_slots[NUM_SLOTS] { 0 };
public:
Request_pool_channel_queue() { }
bool empty() const { return _num_used_slots == 0; }
bool full() const { return _num_used_slots >= NUM_SLOTS; }
Channel &head() const;
void enqueue(Channel &);
void move_one_slot_towards_tail(Channel const &);
bool is_tail(Channel const &) const;
Channel &next(Channel const &) const;
void dequeue(Channel const &);
};
class Tresor::Request_pool : public Module
{
NONCOPYABLE(Request_pool);
private:
using Channel = Request_pool_channel;
enum { NUM_CHANNELS = Request_pool_channel_queue::NUM_SLOTS };
bool _init_success { false };
Generation _init_gen { INVALID_GENERATION };
Request _init_req { INVALID_MODULE_ID, INVALID_MODULE_CHANNEL_ID, Request::INITIALIZE, 0, 0, 0, 0, 0, _init_gen, _init_success };
Constructible<Channel> _channels[NUM_CHANNELS] { };
Request_pool_channel_queue _chan_queue { };
public:
void execute(bool &) override;
Request_pool();
};
#endif /* _TRESOR__REQUEST_POOL_H_ */

View File

@ -16,95 +16,60 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/vbd_check.h>
#include <tresor/ft_check.h>
#include <tresor/block_io.h>
namespace Tresor {
namespace Tresor { class Sb_check; }
class Sb_check;
class Sb_check_request;
class Sb_check_channel;
}
class Tresor::Sb_check_request : public Module_request
struct Tresor::Sb_check : Noncopyable
{
friend class Sb_check_channel;
class Check : Noncopyable
{
public:
private:
using Module = Sb_check;
bool &_success;
private:
NONCOPYABLE(Sb_check_request);
enum State {
INIT, COMPLETE, READ_BLK, READ_BLK_SUCCEEDED, CHECK_VBD, CHECK_VBD_SUCCEEDED, CHECK_FT, CHECK_FT_SUCCEEDED,
CHECK_MT, CHECK_MT_SUCCEEDED};
public:
using Helper = Request_helper<Check, State>;
Sb_check_request(Module_id, Module_channel_id, bool &);
Helper _helper;
Generation _highest_gen { 0 };
Superblock_index _highest_gen_sb_idx { 0 };
bool _scan_for_highest_gen_sb_done { false };
Superblock_index _sb_idx { 0 };
Superblock _sb { };
Snapshot_index _snap_idx { 0 };
Constructible<Tree_root> _tree_root { };
Block _blk { };
Generatable_request<Helper, State, Vbd_check::Check> _check_vbd { };
Generatable_request<Helper, State, Ft_check::Check> _check_ft { };
Generatable_request<Helper, State, Block_io::Read> _read_block { };
void print(Output &out) const override { Genode::print(out, "check"); }
};
public:
Check() : _helper(*this) { }
class Tresor::Sb_check_channel : public Module_channel
{
private:
~Check() { }
using Request = Sb_check_request;
void print(Output &out) const { Genode::print(out, "check"); }
enum State { REQ_SUBMITTED, REQ_COMPLETE, READ_BLK_SUCCESSFUL, REQ_GENERATED, CHECK_VBD_SUCCESSFUL, CHECK_FT_SUCCESSFUL, CHECK_MT_SUCCESSFUL};
bool execute(Vbd_check &vbd_check, Ft_check &ft_check, Block_io &block_io);
State _state { REQ_COMPLETE };
Request *_req_ptr { };
Generation _highest_gen { 0 };
Superblock_index _highest_gen_sb_idx { 0 };
bool _scan_for_highest_gen_sb_done { false };
Superblock_index _sb_idx { 0 };
Superblock _sb { };
Snapshot_index _snap_idx { 0 };
Constructible<Tree_root> _tree_root { };
Block _blk { };
bool _generated_req_success { false };
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
NONCOPYABLE(Sb_check_channel);
Sb_check() { }
void _generated_req_completed(State_uint) override;
bool execute(Check &check, Vbd_check &vbd_check, Ft_check &ft_check, Block_io &block_io) { return check.execute(vbd_check, ft_check, block_io); };
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
}
void _mark_req_failed(bool &, char const *);
void _mark_req_successful(bool &);
public:
Sb_check_channel(Module_channel_id id) : Module_channel { SB_CHECK, id } { }
void execute(bool &);
};
class Tresor::Sb_check : public Module
{
private:
using Channel = Sb_check_channel;
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Sb_check);
public:
Sb_check();
void execute(bool &) override;
static constexpr char const *name() { return "sb_check"; }
};
#endif /* _TRESOR__SB_CHECK_H_ */

View File

@ -17,107 +17,78 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/block_io.h>
#include <tresor/vbd_initializer.h>
#include <tresor/ft_initializer.h>
#include <tresor/trust_anchor.h>
namespace Tresor {
namespace Tresor { class Sb_initializer; }
class Sb_initializer;
class Sb_initializer_request;
class Sb_initializer_channel;
}
class Tresor::Sb_initializer_request : public Module_request
class Tresor::Sb_initializer : Noncopyable
{
friend class Sb_initializer_channel;
private:
Tree_level_index _vbd_max_lvl;
Tree_degree _vbd_degree;
Number_of_leaves _vbd_num_leaves;
Tree_level_index _ft_max_lvl;
Tree_degree _ft_degree;
Number_of_leaves _ft_num_leaves;
Tree_level_index _mt_max_lvl;
Tree_degree _mt_degree;
Number_of_leaves _mt_num_leaves;
Pba_allocator &_pba_alloc;
bool &_success;
NONCOPYABLE(Sb_initializer_request);
public:
Sb_initializer_request(Module_id, Module_channel_id, Tree_level_index, Tree_degree, Number_of_leaves,
Tree_level_index, Tree_degree, Number_of_leaves, Tree_level_index, Tree_degree,
Number_of_leaves, Pba_allocator &, bool &);
void print(Output &out) const override { Genode::print(out, "init"); }
};
class Tresor::Sb_initializer_channel : public Module_channel
{
private:
using Request = Sb_initializer_request;
enum State {
REQ_SUBMITTED, START_NEXT_SB, SB_COMPLETE, REQ_COMPLETE, INIT_FT_SUCCEEDED, INIT_MT_SUCCEEDED,
WRITE_HASH_TO_TA, CREATE_KEY_SUCCEEDED, ENCRYPT_KEY_SUCCEEDED, SECURE_SB_SUCCEEDED, INIT_VBD_SUCCEEDED,
WRITE_BLK_SUCCEEDED, REQ_GENERATED };
State _state { REQ_COMPLETE };
Request *_req_ptr { };
Superblock_index _sb_idx { 0 };
Superblock _sb { };
Block _blk { };
Hash _hash { };
Constructible<Tree_root> _vbd { };
Constructible<Tree_root> _mt { };
Constructible<Tree_root> _ft { };
bool _generated_req_success { false };
NONCOPYABLE(Sb_initializer_channel);
void _generated_req_completed(State_uint) override;
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
class Initialize : Noncopyable
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
public:
using Module = Sb_initializer;
struct Attr
{
Tree_configuration const in_vbd_cfg;
Tree_configuration const in_ft_cfg;
Tree_configuration const in_mt_cfg;
Pba_allocator &in_out_pba_alloc;
};
private:
enum State {
INIT, COMPLETE, START_NEXT_SB, SB_COMPLETE, INIT_FT, INIT_FT_SUCCEEDED, INIT_MT_SUCCEEDED,
WRITE_HASH_TO_TA, GENERATE_KEY, GENERATE_KEY_SUCCEEDED, ENCRYPT_KEY, ENCRYPT_KEY_SUCCEEDED,
SECURE_SB_SUCCEEDED, INIT_VBD, INIT_VBD_SUCCEEDED, WRITE_BLK, WRITE_BLK_SUCCEEDED,
SYNC_BLOCK_IO, WRITE_SB_HASH };
using Helper = Request_helper<Initialize, State>;
Helper _helper;
Attr const _attr;
Superblock_index _sb_idx { 0 };
Superblock _sb { };
Block _blk { };
Hash _hash { };
Type_1_node _vbd_root { };
Type_1_node _ft_root { };
Type_1_node _mt_root { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
Generatable_request<Helper, State, Block_io::Sync> _sync_block_io { };
Generatable_request<Helper, State, Trust_anchor::Generate_key> _generate_key { };
Generatable_request<Helper, State, Trust_anchor::Write_hash> _write_sb_hash { };
Generatable_request<Helper, State, Trust_anchor::Encrypt_key> _encrypt_key { };
Generatable_request<Helper, State, Ft_initializer::Initialize> _init_ft { };
Generatable_request<Helper, State, Vbd_initializer::Initialize> _init_vbd { };
public:
Initialize(Attr const &attr) : _helper(*this), _attr(attr) { }
~Initialize() { }
void print(Output &out) const { Genode::print(out, "initialize"); }
bool execute(Block_io &, Trust_anchor &, Vbd_initializer &, Ft_initializer &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
bool execute(Initialize &req, Block_io &block_io, Trust_anchor &trust_anchor, Vbd_initializer &vbd_initializer, Ft_initializer &ft_initializer)
{
return req.execute(block_io, trust_anchor, vbd_initializer, ft_initializer);
}
void _mark_req_successful(bool &);
public:
Sb_initializer_channel(Module_channel_id id) : Module_channel { SB_INITIALIZER, id } { }
void execute(bool &);
};
class Tresor::Sb_initializer : public Module
{
private:
using Channel = Sb_initializer_channel;
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Sb_initializer);
public:
Sb_initializer();
void execute(bool &) override;
static constexpr char const *name() { return "sb_initializer"; }
};
#endif /* _TRESOR__SB_INITIALIZER_H_ */

View File

@ -20,153 +20,558 @@
#include <tresor/trust_anchor.h>
#include <tresor/block_io.h>
namespace Tresor {
namespace Tresor { class Superblock_control; }
class Superblock_control;
class Superblock_control_request;
class Superblock_control_channel;
}
class Tresor::Superblock_control_request : Module_request, Noncopyable
{
friend class Superblock_control_channel;
public:
enum Type {
READ_VBA, WRITE_VBA, SYNC, INITIALIZE, DEINITIALIZE, VBD_EXTENSION_STEP,
FT_EXTENSION_STEP, CREATE_SNAPSHOT, DISCARD_SNAPSHOT, INITIALIZE_REKEYING,
REKEY_VBA };
private:
Type const _type;
Request_offset const _client_req_offset;
Request_tag const _client_req_tag;
Number_of_blocks _nr_of_blks;
Virtual_block_address const _vba;
bool &_success;
bool &_client_req_finished;
Superblock::State &_sb_state;
Generation &_gen;
public:
Superblock_control_request(Module_id, Module_channel_id, Type, Request_offset,
Request_tag, Number_of_blocks, Virtual_block_address,
bool &, bool &, Superblock::State &, Generation &);
static char const *type_to_string(Type);
void print(Output &) const override;
};
class Tresor::Superblock_control_channel : public Module_channel
class Tresor::Superblock_control : Noncopyable
{
private:
using Request = Superblock_control_request;
enum State : State_uint {
INACTIVE, REQ_SUBMITTED, ACCESS_VBA_AT_VBD_SUCCEEDED,
REKEY_VBA_AT_VBD_SUCCEEDED, CREATE_KEY_SUCCEEDED,
TREE_EXT_STEP_IN_TREE_SUCCEEDED, DECRYPT_CURR_KEY_SUCCEEDED,
DECRYPT_PREV_KEY_SUCCEEDED, READ_SB_HASH_SUCCEEDED, ADD_PREV_KEY_SUCCEEDED,
ADD_CURR_KEY_SUCCEEDED, REMOVE_PREV_KEY_SUCCEEDED, REMOVE_CURR_KEY_SUCCEEDED,
READ_SB_SUCCEEDED, REQ_COMPLETE, REQ_GENERATED, SECURE_SB, SECURE_SB_SUCCEEDED };
enum Secure_sb_state : State_uint {
SECURE_SB_INACTIVE, STARTED, ENCRYPT_CURR_KEY_SUCCEEDED,
SECURE_SB_REQ_GENERATED, ENCRYPT_PREV_KEY_SUCCEEDED, SYNC_CACHE_SUCCEEDED,
WRITE_SB_SUCCEEDED, SYNC_BLK_IO_SUCCEEDED, WRITE_SB_HASH_SUCCEEDED };
State _state { INACTIVE };
Constructible<Tree_root> _ft { };
Constructible<Tree_root> _mt { };
Secure_sb_state _secure_sb_state { SECURE_SB_INACTIVE };
Superblock _sb_ciphertext { };
Block _blk { };
Generation _gen { INVALID_GENERATION };
Hash _hash { };
Physical_block_address _pba { INVALID_PBA };
Number_of_blocks _nr_of_leaves { 0 };
Request *_req_ptr { nullptr };
bool _gen_req_success { false };
Superblock &_sb;
Superblock_index &_sb_idx;
Generation &_curr_gen;
NONCOPYABLE(Superblock_control_channel);
void _generated_req_completed(State_uint) override;
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
void _mark_req_successful(bool &);
void _mark_req_failed(bool &, char const *);
void _access_vba(Virtual_block_device_request::Type, bool &);
void _generate_vbd_req(Virtual_block_device_request::Type, State_uint, bool &, Key_id, Virtual_block_address);
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint complete_state, bool &progress, ARGS &&... args)
class Secure_superblock : Noncopyable
{
generate_req<REQUEST>(complete_state, progress, args..., _gen_req_success);
if (_state == SECURE_SB)
_secure_sb_state = SECURE_SB_REQ_GENERATED;
else
_state = REQ_GENERATED;
}
public:
void _start_secure_sb(bool &);
using Module = Superblock_control;
void _secure_sb(bool &);
struct Attr { };
void _tree_ext_step(Superblock::State, bool, String<4>, bool &);
struct Execute_attr
{
Superblock &sb;
Superblock_index &sb_idx;
Generation &curr_gen;
Block_io &block_io;
Trust_anchor &trust_anchor;
};
void _rekey_vba(bool &);
private:
void _init_rekeying(bool &);
enum State {
INIT, COMPLETE, WRITE_BLOCK, WRITE_BLOCK_SUCCEEDED, SYNC_BLOCK_IO, SYNC_BLOCK_IO_SUCCEEDED,
ENCRYPT_KEY, ENCRYPT_CURR_KEY_SUCCEEDED, ENCRYPT_PREV_KEY_SUCCEEDED, WRITE_SB_HASH,
WRITE_SB_HASH_SUCCEEDED };
void _discard_snap(bool &);
using Helper = Request_helper<Secure_superblock, State>;
void _create_snap(bool &);
Helper _helper;
Attr const _attr;
Superblock _sb_ciphertext { };
Block _blk { };
Hash _hash { };
Generation _gen { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
Generatable_request<Helper, State, Block_io::Sync> _sync_block_io { };
Generatable_request<Helper, State, Trust_anchor::Encrypt_key> _encrypt_key { };
Generatable_request<Helper, State, Trust_anchor::Write_hash> _write_sb_hash { };
void _sync(bool &);
public:
void _initialize(bool &);
Secure_superblock(Attr const &attr) : _helper(*this), _attr(attr) { }
void _deinitialize(bool &);
~Secure_superblock() { }
public:
void print(Output &out) const { Genode::print(out, "secure sb"); }
void execute(bool &);
bool execute(Execute_attr const &);
Superblock_control_channel(Module_channel_id, Superblock &, Superblock_index &, Generation &);
};
class Tresor::Superblock_control : public Module
{
private:
using Channel = Superblock_control_channel;
enum { NUM_CHANNELS = 1 };
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
Superblock _sb { };
Superblock_index _sb_idx { INVALID_SB_IDX };
Generation _curr_gen { INVALID_GENERATION };
Constructible<Channel> _channels[NUM_CHANNELS] { };
void execute(bool &) override;
Superblock_index _sb_idx { };
Generation _curr_gen { };
public:
class Write_vbas : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr
{
Virtual_block_address const in_first_vba;
Number_of_blocks const in_num_vbas;
Request_offset const in_client_req_offset;
Request_tag const in_client_req_tag;
};
struct Execute_attr
{
Virtual_block_device &vbd;
Client_data_interface &client_data;
Block_io &block_io;
Free_tree &free_tree;
Meta_tree &meta_tree;
Crypto &crypto;
Superblock &sb;
Generation const &curr_gen;
};
private:
enum State { INIT, COMPLETE, WRITE_VBA, WRITE_VBA_SUCCEEDED };
using Helper = Request_helper<Write_vbas, State>;
Helper _helper;
Attr const _attr;
Number_of_blocks _num_written_vbas { };
Constructible<Tree_root> _ft { };
Constructible<Tree_root> _mt { };
Generatable_request<Helper, State, Virtual_block_device::Write_vba> _write_vba { };
void _start_write_vba(Execute_attr const &, bool &);
public:
Write_vbas(Attr const &attr) : _helper(*this), _attr(attr) { }
~Write_vbas() { }
void print(Output &out) const { Genode::print(out, "write vba"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Extend_free_tree : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr
{
Number_of_blocks const in_num_pbas;
bool &out_extension_finished;
};
struct Execute_attr
{
Superblock_control &sb_control;
Free_tree &free_tree;
Meta_tree &meta_tree;
Block_io &block_io;
Trust_anchor &trust_anchor;
Superblock &sb;
Generation const &curr_gen;
};
private:
enum State { INIT, COMPLETE, EXTEND_FREE_TREE, EXTEND_FREE_TREE_SUCCEEDED, SECURE_SB, SECURE_SB_SUCCEEDED };
using Helper = Request_helper<Extend_free_tree, State>;
Helper _helper;
Attr const _attr;
Number_of_blocks _num_pbas { };
Physical_block_address _pba { };
Number_of_blocks _nr_of_leaves { };
Constructible<Tree_root> _ft { };
Constructible<Tree_root> _mt { };
Generatable_request<Helper, State, Secure_superblock> _secure_sb { };
Generatable_request<Helper, State, Free_tree::Extend_tree> _extend_free_tree { };
public:
Extend_free_tree(Attr const &attr) : _helper(*this), _attr(attr) { }
~Extend_free_tree() { }
void print(Output &out) const { Genode::print(out, "rekey vba"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Extend_vbd : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr
{
Number_of_blocks const in_num_pbas;
bool &out_extension_finished;
};
struct Execute_attr
{
Superblock_control &sb_control;
Virtual_block_device &vbd;
Free_tree &free_tree;
Meta_tree &meta_tree;
Block_io &block_io;
Trust_anchor &trust_anchor;
Superblock &sb;
Generation const &curr_gen;
};
private:
enum State { INIT, COMPLETE, EXTEND_VBD, EXTEND_VBD_SUCCEEDED, SECURE_SB, SECURE_SB_SUCCEEDED };
using Helper = Request_helper<Extend_vbd, State>;
Helper _helper;
Attr const _attr;
Number_of_blocks _num_pbas { };
Physical_block_address _pba { };
Number_of_blocks _nr_of_leaves { };
Constructible<Tree_root> _ft { };
Constructible<Tree_root> _mt { };
Generatable_request<Helper, State, Secure_superblock> _secure_sb { };
Generatable_request<Helper, State, Virtual_block_device::Extend_tree> _extend_vbd { };
public:
Extend_vbd(Attr const &attr) : _helper(*this), _attr(attr) { }
~Extend_vbd() { }
void print(Output &out) const { Genode::print(out, "extend vbd"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Rekey : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr { bool &out_rekeying_finished; };
struct Execute_attr
{
Superblock &sb;
Generation const &curr_gen;
Block_io &block_io;
Crypto &crypto;
Trust_anchor &trust_anchor;
Free_tree &free_tree;
Meta_tree &meta_tree;
Virtual_block_device &vbd;
Superblock_control &sb_control;
};
private:
enum State {
INIT, COMPLETE, REKEY_VBA, REKEY_VBA_SUCCEEDED, SECURE_SB, SECURE_SB_SUCCEEDED, REMOVE_KEY,
REMOVE_KEY_SUCCEEDED, GENERATE_KEY, GENERATE_KEY_SUCCEEDED, ADD_KEY, ADD_KEY_SUCCEEDED };
using Helper = Request_helper<Rekey, State>;
Helper _helper;
Attr const _attr;
Constructible<Tree_root> _ft { };
Constructible<Tree_root> _mt { };
Generation _gen { };
Generatable_request<Helper, State, Virtual_block_device::Rekey_vba> _rekey_vba { };
Generatable_request<Helper, State, Crypto::Remove_key> _remove_key { };
Generatable_request<Helper, State, Secure_superblock> _secure_sb { };
Generatable_request<Helper, State, Crypto::Add_key> _add_key { };
Generatable_request<Helper, State, Trust_anchor::Generate_key> _generate_key { };
public:
Rekey(Attr const &attr) : _helper(*this), _attr(attr) { }
~Rekey() { }
void print(Output &out) const { Genode::print(out, "continue rekeying"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Read_vbas : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr
{
Virtual_block_address const in_first_vba;
Number_of_blocks const in_num_vbas;
Request_offset const in_client_req_offset;
Request_tag const in_client_req_tag;
};
struct Execute_attr
{
Virtual_block_device &vbd;
Client_data_interface &client_data;
Block_io &block_io;
Crypto &crypto;
Superblock const &sb;
Generation const &curr_gen;
};
private:
enum State { INIT, COMPLETE, READ_VBA, READ_VBA_SUCCEEDED };
using Helper = Request_helper<Read_vbas, State>;
Helper _helper;
Attr const _attr;
Number_of_blocks _num_read_vbas { };
Generatable_request<Helper, State, Virtual_block_device::Read_vba> _read_vba { };
void _start_read_vba(Execute_attr const &, bool &progress);
public:
Read_vbas(Attr const &attr) : _helper(*this), _attr(attr) { }
~Read_vbas() { }
void print(Output &out) const { Genode::print(out, "read vbas"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Create_snapshot : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr { Generation &out_gen; };
struct Execute_attr
{
Superblock &sb;
Generation &curr_gen;
Block_io &block_io;
Trust_anchor &trust_anchor;
Superblock_control &sb_control;
};
private:
enum State { INIT, COMPLETE, SECURE_SB, SECURE_SB_SUCCEEDED };
using Helper = Request_helper<Create_snapshot, State>;
Helper _helper;
Attr const _attr;
Generation _gen { };
Generatable_request<Helper, State, Secure_superblock> _secure_sb { };
public:
Create_snapshot(Attr const &attr) : _helper(*this), _attr(attr) { }
~Create_snapshot() { }
void print(Output &out) const { Genode::print(out, "create snapshot"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Synchronize : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr { };
struct Execute_attr
{
Superblock &sb;
Generation const &curr_gen;
Block_io &block_io;
Trust_anchor &trust_anchor;
Superblock_control &sb_control;
};
private:
enum State { INIT, COMPLETE, SECURE_SB, SECURE_SB_SUCCEEDED };
using Helper = Request_helper<Synchronize, State>;
Helper _helper;
Attr const _attr;
Generatable_request<Helper, State, Secure_superblock> _secure_sb { };
public:
Synchronize(Attr const &attr) : _helper(*this), _attr(attr) { }
~Synchronize() { }
void print(Output &out) const { Genode::print(out, "sync"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Deinitialize : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr { };
struct Execute_attr
{
Superblock &sb;
Generation const &curr_gen;
Block_io &block_io;
Crypto &crypto;
Trust_anchor &trust_anchor;
Superblock_control &sb_control;
};
private:
enum State {
INIT, COMPLETE, SECURE_SB, SECURE_SB_SUCCEEDED, REMOVE_KEY,
REMOVE_CURR_KEY_SUCCEEDED, REMOVE_PREV_KEY_SUCCEEDED };
using Helper = Request_helper<Deinitialize, State>;
Helper _helper;
Attr const _attr;
Generatable_request<Helper, State, Secure_superblock> _secure_sb { };
Generatable_request<Helper, State, Crypto::Remove_key> _remove_key { };
public:
Deinitialize(Attr const &attr) : _helper(*this), _attr(attr) { }
~Deinitialize() { }
void print(Output &out) const { Genode::print(out, "deinitialize"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Initialize : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr { Superblock::State &out_sb_state; };
struct Execute_attr
{
Superblock &sb;
Superblock_index &sb_idx;
Generation &curr_gen;
Block_io &block_io;
Crypto &crypto;
Trust_anchor &trust_anchor;
Superblock_control &sb_control;
};
private:
enum State {
INIT, COMPLETE, READ_SB_HASH, READ_SB_HASH_SUCCEEDED, READ_BLOCK, READ_BLOCK_SUCCEEDED,
DECRYPT_KEY, DECRYPT_CURR_KEY_SUCCEEDED, DECRYPT_PREV_KEY_SUCCEEDED, ADD_KEY,
ADD_CURR_KEY_SUCCEEDED, ADD_PREV_KEY_SUCCEEDED };
using Helper = Request_helper<Initialize, State>;
Helper _helper;
Attr const _attr;
Generation _gen { };
Hash _hash { };
Block _blk { };
Superblock _sb_ciphertext { };
Generatable_request<Helper, State, Block_io::Read> _read_block { };
Generatable_request<Helper, State, Trust_anchor::Read_hash> _read_sb_hash { };
Generatable_request<Helper, State, Trust_anchor::Decrypt_key> _decrypt_key { };
Generatable_request<Helper, State, Crypto::Add_key> _add_key { };
public:
Initialize(Attr const &attr) : _helper(*this), _attr(attr) { }
~Initialize() { }
void print(Output &out) const { Genode::print(out, "initialize"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Discard_snapshot : Noncopyable
{
public:
using Module = Superblock_control;
struct Attr { Generation const in_gen; };
struct Execute_attr
{
Superblock &sb;
Generation &curr_gen;
Block_io &block_io;
Trust_anchor &trust_anchor;
Superblock_control &sb_control;
};
private:
enum State { INIT, COMPLETE, SECURE_SB, SECURE_SB_SUCCEEDED };
using Helper = Request_helper<Discard_snapshot, State>;
Helper _helper;
Attr const _attr;
Generatable_request<Helper, State, Secure_superblock> _secure_sb { };
public:
Discard_snapshot(Attr const &attr) : _helper(*this), _attr(attr) { }
~Discard_snapshot() { }
void print(Output &out) const { Genode::print(out, "discard snapshot"); }
bool execute(Execute_attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
Virtual_block_address max_vba() const { return _sb.valid() ? _sb.max_vba() : 0; };
Virtual_block_address resizing_nr_of_pbas() const { return _sb.resizing_nr_of_pbas; }
@ -177,7 +582,62 @@ class Tresor::Superblock_control : public Module
Superblock_info sb_info() const;
Superblock_control();
bool execute(Extend_free_tree &req, Free_tree &free_tree, Meta_tree &meta_tree, Block_io &block_io, Trust_anchor &trust_anchor)
{
return req.execute({ *this, free_tree, meta_tree, block_io, trust_anchor, _sb, _curr_gen });
}
bool execute(Extend_vbd &req, Virtual_block_device &vbd, Free_tree &free_tree, Meta_tree &meta_tree, Block_io &block_io, Trust_anchor &trust_anchor)
{
return req.execute({ *this, vbd, free_tree, meta_tree, block_io, trust_anchor, _sb, _curr_gen });
}
bool execute(Rekey &req, Virtual_block_device &vbd, Free_tree &free_tree, Meta_tree &meta_tree, Block_io &block_io, Crypto &crypto, Trust_anchor &trust_anchor)
{
return req.execute({ _sb, _curr_gen, block_io, crypto, trust_anchor, free_tree, meta_tree, vbd, *this });
}
bool execute(Secure_superblock &req, Block_io &block_io, Trust_anchor &trust_anchor)
{
return req.execute({_sb, _sb_idx, _curr_gen, block_io, trust_anchor });
}
bool execute(Synchronize &req, Block_io &block_io, Trust_anchor &trust_anchor)
{
return req.execute({_sb, _curr_gen, block_io, trust_anchor, *this });
}
bool execute(Deinitialize &req, Block_io &block_io, Crypto &crypto, Trust_anchor &trust_anchor)
{
return req.execute({_sb, _curr_gen, block_io, crypto, trust_anchor, *this });
}
bool execute(Initialize &req, Block_io &block_io, Crypto &crypto, Trust_anchor &trust_anchor)
{
return req.execute({_sb, _sb_idx, _curr_gen, block_io, crypto, trust_anchor, *this });
}
bool execute(Create_snapshot &req, Block_io &block_io, Trust_anchor &trust_anchor)
{
return req.execute({_sb, _curr_gen, block_io, trust_anchor, *this });
}
bool execute(Discard_snapshot &req, Block_io &block_io, Trust_anchor &trust_anchor)
{
return req.execute({_sb, _curr_gen, block_io, trust_anchor, *this });
}
bool execute(Read_vbas &req, Virtual_block_device &vbd, Client_data_interface &client_data, Block_io &block_io, Crypto &crypto)
{
return req.execute({ vbd, client_data, block_io, crypto, _sb, _curr_gen });
}
bool execute(Write_vbas &req, Virtual_block_device &vbd, Client_data_interface &client_data, Block_io &block_io, Free_tree &free_tree, Meta_tree &meta_tree, Crypto &crypto)
{
return req.execute({ vbd, client_data, block_io, free_tree, meta_tree, crypto, _sb, _curr_gen });
}
static constexpr char const *name() { return "sb_control"; }
};
#endif /* _TRESOR__SUPERBLOCK_CONTROL_H_ */

View File

@ -18,141 +18,232 @@
#include <tresor/types.h>
#include <tresor/file.h>
namespace Tresor {
namespace Tresor { class Trust_anchor; }
class Trust_anchor;
class Trust_anchor_request;
class Trust_anchor_channel;
}
class Tresor::Trust_anchor_request : public Module_request
class Tresor::Trust_anchor : Noncopyable
{
friend class Trust_anchor_channel;
public:
enum Type { CREATE_KEY, ENCRYPT_KEY, DECRYPT_KEY, WRITE_HASH, READ_HASH, INITIALIZE };
struct Attr
{
Vfs::Vfs_handle &decrypt_file;
Vfs::Vfs_handle &encrypt_file;
Vfs::Vfs_handle &generate_key_file;
Vfs::Vfs_handle &initialize_file;
Vfs::Vfs_handle &hash_file;
};
private:
Type const _type;
Key_value &_key_plaintext;
Key_value &_key_ciphertext;
Hash &_hash;
Passphrase const _pass;
bool &_success;
NONCOPYABLE(Trust_anchor_request);
Attr const _attr;
addr_t _user { };
public:
Trust_anchor_request(Module_id src, Module_channel_id, Type, Key_value &, Key_value &, Hash &, Passphrase, bool &);
class Encrypt_key;
class Decrypt_key;
class Generate_key;
class Initialize;
class Read_hash;
class Write_hash;
static char const *type_to_string(Type);
Trust_anchor(Attr const &attr) : _attr(attr) { }
void print(Output &out) const override { Genode::print(out, type_to_string(_type)); }
template <typename REQ>
bool execute(REQ &req)
{
if (!_user)
_user = (addr_t)&req;
if (_user != (addr_t)&req)
return false;
bool progress = req.execute(_attr);
if (req.complete())
_user = 0;
return progress;
}
static constexpr char const *name() { return "trust_anchor"; }
};
class Tresor::Trust_anchor_channel : public Module_channel
class Tresor::Trust_anchor::Encrypt_key : Noncopyable
{
public:
using Module = Trust_anchor;
struct Attr
{
Key_value &out_key_ciphertext;
Key_value const &in_key_plaintext;
};
private:
using Request = Trust_anchor_request;
enum State { INIT, COMPLETE, WRITE, WRITE_OK, READ_OK, FILE_ERR };
enum State { REQ_SUBMITTED, REQ_COMPLETE, READ_OK, WRITE_OK, FILE_ERR };
Request_helper<Encrypt_key, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
State _state { REQ_COMPLETE };
Vfs::Env &_vfs_env;
public:
Encrypt_key(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "encrypt key"); }
bool execute(Trust_anchor::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Trust_anchor::Decrypt_key : Noncopyable
{
public:
using Module = Trust_anchor;
struct Attr
{
Key_value &out_key_plaintext;
Key_value const &in_key_ciphertext;
};
private:
enum State { INIT, COMPLETE, WRITE, WRITE_OK, READ_OK, FILE_ERR };
Request_helper<Decrypt_key, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
public:
Decrypt_key(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "decrypt key"); }
bool execute(Trust_anchor::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Trust_anchor::Initialize : Noncopyable
{
public:
using Module = Trust_anchor;
struct Attr { Passphrase const &in_passphrase; };
private:
enum State { INIT, COMPLETE, WRITE, WRITE_OK, READ_OK, FILE_ERR };
Request_helper<Initialize, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
char _result_buf[3];
Tresor::Path const _path;
Read_write_file<State> _decrypt_file { _state, _vfs_env, { _path, "/decrypt" } };
Read_write_file<State> _encrypt_file { _state, _vfs_env, { _path, "/encrypt" } };
Read_write_file<State> _generate_key_file { _state, _vfs_env, { _path, "/generate_key" } };
Read_write_file<State> _initialize_file { _state, _vfs_env, { _path, "/initialize" } };
Read_write_file<State> _hashsum_file { _state, _vfs_env, { _path, "/hashsum" } };
Trust_anchor_request *_req_ptr { nullptr };
NONCOPYABLE(Trust_anchor_channel);
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
void _create_key(bool &);
void _read_hash(bool &);
void _initialize(bool &);
void _write_hash(bool &);
void _encrypt_key(bool &);
void _decrypt_key(bool &);
void _mark_req_failed(bool &, Error_string);
void _mark_req_successful(bool &);
public:
void execute(bool &);
Initialize(Attr const &attr) : _helper(*this), _attr(attr) { }
Trust_anchor_channel(Module_channel_id, Vfs::Env &, Xml_node const &);
void print(Output &out) const { Genode::print(out, "initialize"); }
bool execute(Trust_anchor::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Trust_anchor : public Module
class Tresor::Trust_anchor::Generate_key : Noncopyable
{
public:
using Module = Trust_anchor;
struct Attr { Key_value &out_key_plaintext; };
private:
using Request = Trust_anchor_request;
using Channel = Trust_anchor_channel;
enum State { INIT, COMPLETE, READ, READ_OK, FILE_ERR };
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Trust_anchor);
Request_helper<Generate_key, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
public:
struct Create_key : Request
{
Create_key(Module_id m, Module_channel_id c, Key_value &k, bool &s)
: Request(m, c, Request::CREATE_KEY, k, *(Key_value*)0, *(Hash*)0, Passphrase(), s) { }
};
Generate_key(Attr const &attr) : _helper(*this), _attr(attr) { }
struct Encrypt_key : Request
{
Encrypt_key(Module_id m, Module_channel_id c, Key_value const &kp, Key_value &kc, bool &s)
: Request(m, c, Request::ENCRYPT_KEY, *const_cast<Key_value*>(&kp), kc, *(Hash*)0, Passphrase(), s) { }
};
void print(Output &out) const { Genode::print(out, "generate key"); }
struct Decrypt_key : Request
{
Decrypt_key(Module_id m, Module_channel_id c, Key_value &kp, Key_value const &kc, bool &s)
: Request(m, c, Request::DECRYPT_KEY, kp, *const_cast<Key_value*>(&kc), *(Hash*)0, Passphrase(), s) { }
};
bool execute(Trust_anchor::Attr const &);
struct Write_hash : Request
{
Write_hash(Module_id m, Module_channel_id c, Hash const &h, bool &s)
: Request(m, c, Request::WRITE_HASH, *(Key_value*)0, *(Key_value*)0, *const_cast<Hash*>(&h), Passphrase(), s) { }
};
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
struct Read_hash : Request
{
Read_hash(Module_id m, Module_channel_id c, Hash &h, bool &s)
: Request(m, c, Request::READ_HASH, *(Key_value*)0, *(Key_value*)0, h, Passphrase(), s) { }
};
class Tresor::Trust_anchor::Write_hash : Noncopyable
{
public:
struct Initialize : Request
{
Initialize(Module_id src_mod, Module_channel_id src_chan, Passphrase pass, bool &succ)
: Request(src_mod, src_chan, Request::INITIALIZE, *(Key_value*)0, *(Key_value*)0, *(Hash*)0, pass, succ) { }
};
using Module = Trust_anchor;
Trust_anchor(Vfs::Env &, Xml_node const &);
struct Attr { Hash const &in_hash; };
void execute(bool &) override;
private:
enum State { INIT, COMPLETE, WRITE, WRITE_OK, READ_OK, FILE_ERR };
Request_helper<Write_hash, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
char _result_buf[3];
public:
Write_hash(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "write hash"); }
bool execute(Trust_anchor::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Trust_anchor::Read_hash : Noncopyable
{
public:
using Module = Trust_anchor;
struct Attr { Hash &out_hash; };
private:
enum State { INIT, COMPLETE, READ, READ_OK, FILE_ERR };
Request_helper<Read_hash, State> _helper;
Attr const _attr;
Constructible<File<State> > _file { };
public:
Read_hash(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "read hash"); }
bool execute(Trust_anchor::Attr const &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
#endif /* _TRESOR__TRUST_ANCHOR_H_ */

View File

@ -23,7 +23,7 @@
/* tresor includes */
#include <tresor/math.h>
#include <tresor/module.h>
#include <tresor/verbosity.h>
namespace Tresor {
@ -101,8 +101,15 @@ namespace Tresor {
struct Tree_walk_generations;
struct Level_indent;
struct Tree_root;
struct Tree_configuration;
class Pba_allocator;
template <typename, typename>
class Request_helper;
template <typename, typename, typename>
class Generatable_request;
template <size_t LEN>
class Fixed_length;
@ -124,8 +131,7 @@ namespace Tresor {
return first_pba - 1;
}
inline Tree_node_index
t1_node_idx_for_vba_typed(Virtual_block_address vba, Tree_level_index lvl, Tree_degree degr)
inline Tree_node_index tree_node_index(Virtual_block_address vba, Tree_level_index lvl, Tree_degree degr)
{
uint64_t const degr_log_2 { log2(degr) };
uint64_t const degr_mask { ((uint64_t)1 << degr_log_2) - 1 };
@ -133,19 +139,6 @@ namespace Tresor {
return (Tree_node_index)(degr_mask & (vba >> vba_rshift));
}
template <typename T1, typename T2, typename T3>
inline Tree_node_index t1_node_idx_for_vba(T1 vba, T2 lvl, T3 degr)
{
return t1_node_idx_for_vba_typed((Virtual_block_address)vba, (Tree_level_index)lvl, (Tree_degree)degr);
}
inline Tree_node_index t2_node_idx_for_vba(Virtual_block_address vba, Tree_degree degr)
{
uint64_t const degr_log_2 { log2(degr) };
uint64_t const degr_mask { ((uint64_t)1 << degr_log_2) - 1 };
return (Tree_node_index)((uint64_t)vba & degr_mask);
}
inline Virtual_block_address vbd_node_min_vba(Tree_degree_log_2 vbd_degr_log_2,
Tree_level_index vbd_lvl,
Virtual_block_address vbd_leaf_vba)
@ -167,6 +160,120 @@ namespace Tresor {
}
template <typename REQ, typename STATE>
class Tresor::Request_helper : Noncopyable
{
private:
REQ const &_req;
bool _success { false };
public:
using Module = REQ::Module;
STATE state { STATE::INIT };
Request_helper(REQ &req) : _req(req) { }
bool complete() const { return state == STATE::COMPLETE; }
void mark_failed(bool &progress, Error_string const &err_str)
{
error(Module::name(), ": request (", _req, ") failed: ", err_str);
_success = false;
state = STATE::COMPLETE;
progress = true;
}
void mark_succeeded(bool &progress)
{
_success = true;
state = STATE::COMPLETE;
progress = true;
}
void generated_req_failed(bool &progress) { mark_failed(progress, "generated request failed"); }
void generated_req_succeeded(STATE target_state, bool &progress)
{
state = target_state;
progress = true;
}
void req_generated(STATE target_state, bool &progress)
{
state = target_state;
progress = true;
}
bool success() const { return _success; }
};
template <typename OWNER, typename OWNER_STATE, typename REQUEST>
class Tresor::Generatable_request
{
private:
struct Generated_request
{
OWNER &owner;
OWNER_STATE succeeded_state;
REQUEST req;
template <typename... ARGS>
Generated_request(OWNER &owner, OWNER_STATE generated_state, OWNER_STATE succeeded_state,
bool &progress, ARGS &&... args)
:
owner(owner), succeeded_state(succeeded_state), req(typename REQUEST::Attr(args...))
{
owner.req_generated(generated_state, progress);
if (VERBOSE_MODULE_COMMUNICATION)
log(OWNER::Module::name(), " --", req, "--> ", REQUEST::Module::name());
}
template <typename... ARGS>
bool execute(REQUEST::Module &dst_mod, ARGS &&... args)
{
bool progress = false;
progress |= dst_mod.execute(req, args...);
if (req.complete()) {
if (VERBOSE_MODULE_COMMUNICATION)
log(OWNER::Module::name(), " <--", req, "-- ", REQUEST::Module::name());
if (!req.success()) {
owner.generated_req_failed(progress);
return progress;
}
owner.generated_req_succeeded(succeeded_state, progress);
}
return progress;
}
};
Constructible<Generated_request> _generated_req { };
public:
template <typename... ARGS>
void generate(ARGS &&... args)
{
_generated_req.construct(args...);
}
template <typename... ARGS>
bool execute(REQUEST::Module &dst_mod, ARGS &&... args)
{
bool progress = _generated_req->execute(dst_mod, args...);
if (_generated_req->req.complete())
_generated_req.destruct();
return progress;
}
};
class Tresor::Pba_allocator
{
private:
@ -176,7 +283,7 @@ class Tresor::Pba_allocator
public:
Pba_allocator(Physical_block_address const first_pba) : _first_pba { first_pba } { }
Pba_allocator(Physical_block_address const first_pba) : _first_pba(first_pba) { }
Number_of_blocks num_used_pbas() { return _num_used_pbas; }
@ -317,10 +424,7 @@ class Tresor::Block_scanner
public:
Block_scanner(Block const &blk)
:
_blk { blk }
{ }
Block_scanner(Block const &blk) : _blk(blk) { }
template<typename T>
void fetch(T &dst);
@ -387,10 +491,7 @@ class Tresor::Block_generator
public:
Block_generator(Block &blk)
:
_blk { blk }
{ }
Block_generator(Block &blk) : _blk(blk) { }
template<typename T>
void append(T const &src);
@ -503,6 +604,14 @@ struct Tresor::Tree_root
};
struct Tresor::Tree_configuration
{
Tree_level_index max_lvl;
Tree_degree degree;
Number_of_leaves num_leaves;
};
struct Tresor::Type_1_node_block
{
Type_1_node nodes[NUM_NODES_PER_BLK] { };
@ -526,6 +635,11 @@ struct Tresor::Type_1_node_block
struct Tresor::Type_1_node_block_walk
{
Type_1_node_block items[TREE_MAX_NR_OF_LEVELS] { };
Type_1_node &node(Virtual_block_address vba, Tree_level_index lvl, Tree_degree degr)
{
return items[lvl].nodes[tree_node_index(vba, lvl, degr)];
}
};
@ -685,8 +799,8 @@ struct Tresor::Snapshots
snap.encode_to_blk(generator);
}
void discard_disposable_snapshots(Generation curr_gen,
Generation last_secured_gen)
void discard_disposable_snapshots(Generation last_secured_gen,
Generation curr_gen)
{
for (Snapshot &snap : items) {
@ -752,31 +866,31 @@ struct Tresor::Superblock
enum State {
INVALID, NORMAL, REKEYING, EXTENDING_VBD, EXTENDING_FT };
State state { INVALID }; // offset 0
Virtual_block_address rekeying_vba { 0 }; // offset 1
Number_of_blocks resizing_nr_of_pbas { 0 }; // offset 9
Number_of_leaves resizing_nr_of_leaves { 0 }; // offset 17
Key previous_key { }; // offset 25
Key current_key { }; // offset 61
Snapshots snapshots { }; // offset 97
Generation last_secured_generation { 0 }; // offset 3553
Snapshot_index curr_snap_idx { 0 }; // offset 3561
Tree_degree degree { TREE_MIN_DEGREE }; // offset 3565
Physical_block_address first_pba { 0 }; // offset 3569
Number_of_blocks nr_of_pbas { 0 }; // offset 3577
Generation free_gen { 0 }; // offset 3585
Physical_block_address free_number { 0 }; // offset 3593
Hash free_hash { }; // offset 3601
Tree_level_index free_max_level { 0 }; // offset 3633
Tree_degree free_degree { TREE_MIN_DEGREE }; // offset 3637
Number_of_leaves free_leaves { 0 }; // offset 3641
Generation meta_gen { 0 }; // offset 3649
Physical_block_address meta_number { 0 }; // offset 3657
Hash meta_hash { }; // offset 3665
Tree_level_index meta_max_level { 0 }; // offset 3697
Tree_degree meta_degree { TREE_MIN_DEGREE }; // offset 3701
Number_of_leaves meta_leaves { 0 }; // offset 3705
// offset 3713
State state { INVALID }; /* offset 0 */
Virtual_block_address rekeying_vba { 0 }; /* offset 1 */
Number_of_blocks resizing_nr_of_pbas { 0 }; /* offset 9 */
Number_of_leaves resizing_nr_of_leaves { 0 }; /* offset 17 */
Key previous_key { }; /* offset 25 */
Key current_key { }; /* offset 61 */
Snapshots snapshots { }; /* offset 97 */
Generation last_secured_generation { 0 }; /* offset 3553 */
Snapshot_index curr_snap_idx { 0 }; /* offset 3561 */
Tree_degree degree { TREE_MIN_DEGREE }; /* offset 3565 */
Physical_block_address first_pba { 0 }; /* offset 3569 */
Number_of_blocks nr_of_pbas { 0 }; /* offset 3577 */
Generation free_gen { 0 }; /* offset 3585 */
Physical_block_address free_number { 0 }; /* offset 3593 */
Hash free_hash { }; /* offset 3601 */
Tree_level_index free_max_level { 0 }; /* offset 3633 */
Tree_degree free_degree { TREE_MIN_DEGREE }; /* offset 3637 */
Number_of_leaves free_leaves { 0 }; /* offset 3641 */
Generation meta_gen { 0 }; /* offset 3649 */
Physical_block_address meta_number { 0 }; /* offset 3657 */
Hash meta_hash { }; /* offset 3665 */
Tree_level_index meta_max_level { 0 }; /* offset 3697 */
Tree_degree meta_degree { TREE_MIN_DEGREE }; /* offset 3701 */
Number_of_leaves meta_leaves { 0 }; /* offset 3705 */
/* offset 3713 */
static State decode_state(On_disc_state val)
{
@ -981,6 +1095,19 @@ struct Tresor::Snapshots_info
for (Generation &gen : generations)
gen = INVALID_GENERATION;
}
void print(Output &out) const
{
bool first { true };
for (unsigned idx { 0 }; idx < MAX_NR_OF_SNAPSHOTS; idx++) {
if (!generations[idx])
continue;
Genode::print(out, "snapshot ", first ? "" : "\n", idx, ": ", generations[idx]);
first = false;
}
}
};
@ -1028,8 +1155,7 @@ class Tresor::Pba_allocation {
Pba_allocation(Type_1_node_walk const &t1_node_walk,
Tree_walk_pbas const &new_pbas)
:
_t1_node_walk { t1_node_walk },
_new_pbas { new_pbas }
_t1_node_walk(t1_node_walk), _new_pbas(new_pbas)
{ }
void print(Output &out) const

View File

@ -16,94 +16,51 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/block_io.h>
namespace Tresor {
namespace Tresor { class Vbd_check; }
class Vbd_check;
class Vbd_check_request;
class Vbd_check_channel;
}
class Tresor::Vbd_check_request : public Module_request
struct Tresor::Vbd_check : Noncopyable
{
friend class Vbd_check_channel;
class Check : Noncopyable
{
public:
private:
using Module = Vbd_check;
Tree_root const &_vbd;
bool &_success;
struct Attr { Tree_root const &in_vbd; };
NONCOPYABLE(Vbd_check_request);
private:
public:
enum State { INIT, IN_PROGRESS, COMPLETE, READ_BLK, READ_BLK_SUCCEEDED };
Vbd_check_request(Module_id, Module_channel_id, Tree_root const &, bool &);
Request_helper<Check, State> _helper;
Attr const _attr;
Type_1_node_block_walk _t1_blks { };
bool _check_node[TREE_MAX_NR_OF_LEVELS][NUM_NODES_PER_BLK] { };
Block _blk { };
Number_of_leaves _num_remaining_leaves { 0 };
Generatable_request<Request_helper<Check, State>, State, Block_io::Read> _read_block { };
void print(Output &out) const override { Genode::print(out, "check ", _vbd); }
};
bool _execute_node(Block_io &, Tree_level_index, Tree_node_index, bool &);
public:
class Tresor::Vbd_check_channel : public Module_channel
{
private:
Check(Attr const &attr) : _helper(*this), _attr(attr) { }
using Request = Vbd_check_request;
void print(Output &out) const { Genode::print(out, "check ", _attr.in_vbd); }
enum State : State_uint { REQ_SUBMITTED, REQ_IN_PROGRESS, REQ_COMPLETE, REQ_GENERATED, READ_BLK_SUCCEEDED };
bool execute(Block_io &);
State _state { REQ_COMPLETE };
Type_1_node_block_walk _t1_blks { };
bool _check_node[TREE_MAX_NR_OF_LEVELS][NUM_NODES_PER_BLK] { };
Block _blk { };
Request *_req_ptr { };
Number_of_leaves _num_remaining_leaves { 0 };
bool _generated_req_success { false };
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
NONCOPYABLE(Vbd_check_channel);
Vbd_check() { }
void _generated_req_completed(State_uint) override;
bool execute(Check &req, Block_io &block_io) { return req.execute(block_io); }
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
void _mark_req_failed(bool &, Error_string);
void _mark_req_successful(bool &);
bool _execute_node(Tree_level_index, Tree_node_index, bool &);
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
}
public:
Vbd_check_channel(Module_channel_id id) : Module_channel { VBD_CHECK, id } { }
void execute(bool &);
};
class Tresor::Vbd_check : public Module
{
private:
using Channel = Vbd_check_channel;
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Vbd_check);
public:
Vbd_check();
void execute(bool &) override;
static constexpr char const *name() { return "vbd_check"; }
};
#endif /* _TRESOR__VBD_CHECK_H_ */

View File

@ -17,92 +17,65 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/block_io.h>
namespace Tresor {
namespace Tresor { class Vbd_initializer; }
class Vbd_initializer;
class Vbd_initializer_request;
class Vbd_initializer_channel;
}
class Tresor::Vbd_initializer_request : public Module_request
class Tresor::Vbd_initializer : Noncopyable
{
friend class Vbd_initializer_channel;
private:
Tree_root &_vbd;
Pba_allocator &_pba_alloc;
bool &_success;
NONCOPYABLE(Vbd_initializer_request);
public:
Vbd_initializer_request(Module_id, Module_channel_id, Tree_root &, Pba_allocator &, bool &);
class Initialize : Noncopyable
{
public:
void print(Output &out) const override { Genode::print(out, "init"); }
};
using Module = Vbd_initializer;
struct Attr
{
Tree_configuration const in_tree_cfg;
Type_1_node &out_tree_root;
Pba_allocator &in_out_pba_alloc;
};
class Tresor::Vbd_initializer_channel : public Module_channel
{
private:
private:
using Request = Vbd_initializer_request;
enum State { INIT, COMPLETE, WRITE_BLOCK, EXECUTE_NODES };
enum State { REQ_GENERATED, SUBMITTED, COMPLETE, EXECUTE_NODES };
enum Node_state { DONE, INIT_BLOCK, INIT_NODE, WRITING_BLOCK };
enum Node_state { DONE, INIT_BLOCK, INIT_NODE, WRITE_BLOCK };
using Helper = Request_helper<Initialize, State>;
State _state { COMPLETE };
Vbd_initializer_request *_req_ptr { };
Type_1_node_block_walk _t1_blks { };
Node_state _node_states[TREE_MAX_NR_OF_LEVELS][NUM_NODES_PER_BLK] { DONE };
bool _generated_req_success { false };
Block _blk { };
Number_of_leaves _num_remaining_leaves { };
Helper _helper;
Attr const _attr;
Type_1_node_block_walk _t1_blks { };
Node_state _node_states[TREE_MAX_NR_OF_LEVELS][NUM_NODES_PER_BLK] { DONE };
bool _generated_req_success { false };
Block _blk { };
Number_of_leaves _num_remaining_leaves { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
NONCOPYABLE(Vbd_initializer_channel);
void _reset_level(Tree_level_index, Node_state);
void _generated_req_completed(State_uint) override;
bool _execute_node(Tree_level_index, Tree_node_index, bool &);
bool _request_complete() override { return _state == COMPLETE; }
public:
void _request_submitted(Module_request &) override;
Initialize(Attr const &attr) : _helper(*this), _attr(attr) { }
void _reset_level(Tree_level_index, Node_state);
~Initialize() { }
bool _execute_node(Tree_level_index, Tree_node_index, bool &);
void print(Output &out) const { Genode::print(out, "initialize"); }
void _mark_req_failed(bool &, char const *);
bool execute(Block_io &);
void _mark_req_successful(bool &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
public:
bool execute(Initialize &req, Block_io &block_io) { return req.execute(block_io); }
Vbd_initializer_channel(Module_channel_id id) : Module_channel { VBD_INITIALIZER, id } { }
void execute(bool &);
};
class Tresor::Vbd_initializer : public Module
{
private:
using Channel = Vbd_initializer_channel;
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Vbd_initializer);
public:
Vbd_initializer();
void execute(bool &) override;
static constexpr char const *name() { return "vbd_initializer"; }
};
#endif /* _TRESOR__VBD_INITIALIZER_H_ */

View File

@ -24,7 +24,6 @@ namespace Tresor {
enum { VERBOSE_REKEYING = 0 };
enum { VERBOSE_READ_VBA = 0 };
enum { VERBOSE_WRITE_VBA = 0 };
enum { VERBOSE_CRYPTO = 0 };
enum { VERBOSE_BLOCK_IO = 0 };
enum { VERBOSE_BLOCK_IO_PBA_FILTER = 0 };
enum { VERBOSE_BLOCK_IO_PBA = 0 };

View File

@ -17,134 +17,270 @@
/* tresor includes */
#include <tresor/types.h>
#include <tresor/free_tree.h>
#include <tresor/block_io.h>
#include <tresor/client_data_interface.h>
#include <tresor/crypto.h>
namespace Tresor {
namespace Tresor { class Virtual_block_device; }
class Virtual_block_device;
class Virtual_block_device_request;
class Virtual_block_device_channel;
}
class Tresor::Virtual_block_device_request : public Module_request
class Tresor::Virtual_block_device : Noncopyable
{
friend class Virtual_block_device_channel;
public:
enum Type { REKEY_VBA, READ_VBA, WRITE_VBA, EXTENSION_STEP };
private:
Type const _type;
Virtual_block_address const _vba;
Snapshots &_snapshots;
Snapshot_index const _curr_snap_idx;
Tree_degree const _snap_degr;
Generation const _curr_gen;
Key_id const _curr_key_id;
Key_id const _prev_key_id;
Tree_root &_ft;
Tree_root &_mt;
Tree_degree const _vbd_degree;
Virtual_block_address const _vbd_highest_vba;
bool const _rekeying;
Request_offset const _client_req_offset;
Request_tag const _client_req_tag;
Generation const _last_secured_gen;
Physical_block_address &_pba;
Number_of_blocks &_num_pbas;
Number_of_leaves &_num_leaves;
Virtual_block_address const _rekeying_vba;
bool &_success;
NONCOPYABLE(Virtual_block_device_request);
public:
Virtual_block_device_request(Module_id, Module_channel_id, Type, Request_offset, Request_tag, Generation,
Tree_root &, Tree_root &, Tree_degree, Virtual_block_address, bool,
Virtual_block_address, Snapshot_index, Snapshots &, Tree_degree, Key_id,
Key_id, Generation, Physical_block_address &, bool &, Number_of_leaves &,
Number_of_blocks &, Virtual_block_address);
static char const *type_to_string(Type);
void print(Output &out) const override { Genode::print(out, type_to_string(_type)); }
};
class Tresor::Virtual_block_device_channel : public Module_channel
{
private:
using Request = Virtual_block_device_request;
enum State {
SUBMITTED, REQ_GENERATED, REQ_COMPLETE, READ_BLK_SUCCEEDED, WRITE_BLK_SUCCEEDED,
DECRYPT_LEAF_DATA_SUCCEEDED, ENCRYPT_LEAF_DATA_SUCCEEDED, ALLOC_PBAS_SUCCEEDED };
Request *_req_ptr { nullptr };
State _state { REQ_COMPLETE };
Snapshot_index _snap_idx { 0 };
Type_1_node_block_walk _t1_blks { };
Type_1_node_walk _t1_nodes { };
Tree_level_index _lvl { 0 };
Virtual_block_address _vba { 0 };
Tree_walk_pbas _old_pbas { };
Tree_walk_pbas _new_pbas { };
Hash _hash { };
Number_of_blocks _num_blks { 0 };
Generation _free_gen { 0 };
Block _encoded_blk { };
Block _data_blk { };
bool _first_snapshot { false };
bool _gen_req_success { false };
NONCOPYABLE(Virtual_block_device_channel);
class Rekey_vba;
class Read_vba;
class Write_vba;
class Extend_tree;
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint complete_state, bool &progress, ARGS &&... args)
bool execute(REQUEST &req, ARGS &&... args) { return req.execute(args...); }
static constexpr char const *name() { return "vbd"; }
};
class Tresor::Virtual_block_device::Rekey_vba : Noncopyable
{
public:
using Module = Virtual_block_device;
struct Attr
{
generate_req<REQUEST>(complete_state, progress, args..., _gen_req_success);
_state = REQ_GENERATED;
}
Snapshots &in_out_snapshots;
Tree_root &in_out_ft;
Tree_root &in_out_mt;
Virtual_block_address const in_vba;
Generation const in_curr_gen;
Generation const in_last_secured_gen;
Key_id const in_curr_key_id;
Key_id const in_prev_key_id;
Tree_degree const in_vbd_degree;
Virtual_block_address const in_vbd_highest_vba;
};
void _request_submitted(Module_request &) override;
private:
bool _request_complete() override { return _state == REQ_COMPLETE; }
enum State {
INIT, COMPLETE, READ_BLK, READ_BLK_SUCCEEDED, WRITE_BLK, WRITE_BLK_SUCCEEDED,
DECRYPT_BLOCK, DECRYPT_BLOCK_SUCCEEDED, ENCRYPT_BLOCK, ENCRYPT_BLOCK_SUCCEEDED,
ALLOC_PBAS, ALLOC_PBAS_SUCCEEDED };
void _generated_req_completed(State_uint) override;
using Helper = Request_helper<Rekey_vba, State>;
void _generate_ft_req(State, bool, Free_tree_request::Type);
Helper _helper;
Attr const _attr;
Tree_level_index _lvl { 0 };
Type_1_node_block_walk _t1_blks { };
Block _encoded_blk { };
Block _data_blk { };
Generation _free_gen { 0 };
Tree_walk_pbas _old_pbas { };
Tree_walk_pbas _new_pbas { };
Snapshot_index _snap_idx { 0 };
Type_1_node_walk _t1_nodes { };
Number_of_blocks _num_blks { 0 };
Hash _hash { };
bool _first_snapshot { false };
Generatable_request<Helper, State, Block_io::Read> _read_block { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
Generatable_request<Helper, State, Crypto::Encrypt> _encrypt_block { };
Generatable_request<Helper, State, Crypto::Decrypt> _decrypt_block { };
Generatable_request<Helper, State, Free_tree::Allocate_pbas> _alloc_pbas { };
Snapshot &snap() { return _req_ptr->_snapshots.items[_snap_idx]; }
bool _check_and_decode_read_blk(bool &);
void _start_alloc_pbas(bool &, Free_tree::Allocate_pbas::Application);
void _generate_write_blk_req(bool &);
bool _find_next_snap_to_rekey_vba_at(Snapshot_index &) const;
void _read_vba(bool &);
void _generate_ft_alloc_req_for_rekeying(Tree_level_index, bool &);
public:
Rekey_vba(Attr const &attr) : _helper(*this), _attr(attr) { }
~Rekey_vba() { }
void print(Output &out) const { Genode::print(out, "rekey vba"); }
bool execute(Block_io &, Crypto &, Free_tree &, Meta_tree &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Virtual_block_device::Read_vba : Noncopyable
{
public:
using Module = Virtual_block_device;
struct Attr
{
Snapshot const &in_snap;
Virtual_block_address const in_vba;
Key_id const in_key_id;
Tree_degree const in_vbd_degree;
Request_offset const in_client_req_offset;
Request_tag const in_client_req_tag;
};
private:
enum State { INIT, COMPLETE, READ_BLK, READ_BLK_SUCCEEDED, DECRYPT_BLOCK, DECRYPT_BLOCK_SUCCEEDED };
using Helper = Request_helper<Read_vba, State>;
Helper _helper;
Attr const _attr;
Tree_level_index _lvl { 0 };
Type_1_node_block_walk _t1_blks { };
Hash _hash { };
Block _blk { };
Tree_walk_pbas _new_pbas { };
Generatable_request<Helper, State, Block_io::Read> _read_block { };
Generatable_request<Helper, State, Crypto::Decrypt> _decrypt_block { };
bool _check_and_decode_read_blk(bool &);
Tree_node_index _node_idx(Tree_level_index, Virtual_block_address) const;
public:
Type_1_node &_node(Tree_level_index, Virtual_block_address);
Read_vba(Attr const &attr) : _helper(*this), _attr(attr) { }
void _mark_req_successful(bool &);
~Read_vba() { }
void _mark_req_failed(bool &, char const *);
void print(Output &out) const { Genode::print(out, "read vba"); }
bool execute(Client_data_interface &, Block_io &, Crypto &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Virtual_block_device::Write_vba : Noncopyable
{
public:
using Module = Virtual_block_device;
struct Attr
{
Snapshot &in_out_snap;
Snapshots const &in_snapshots;
Tree_root &in_out_ft;
Tree_root &in_out_mt;
Virtual_block_address const in_vba;
Key_id const in_curr_key_id;
Key_id const in_prev_key_id;
Tree_degree const in_vbd_degree;
Virtual_block_address const in_vbd_highest_vba;
Request_offset const in_client_req_offset;
Request_tag const in_client_req_tag;
Generation const in_curr_gen;
Generation const in_last_secured_gen;
bool in_rekeying;
Virtual_block_address const in_rekeying_vba;
};
private:
enum State {
INIT, COMPLETE, READ_BLK, READ_BLK_SUCCEEDED, DECRYPT_BLOCK, DECRYPT_BLOCK_SUCCEEDED,
WRITE_BLK, WRITE_BLK_SUCCEEDED, ENCRYPT_BLOCK, ENCRYPT_BLOCK_SUCCEEDED, ALLOC_PBAS, ALLOC_PBAS_SUCCEEDED };
using Helper = Request_helper<Write_vba, State>;
Helper _helper;
Attr const _attr;
Tree_level_index _lvl { 0 };
Type_1_node_block_walk _t1_blks { };
Hash _hash { };
Type_1_node_walk _t1_nodes { };
Block _data_blk { };
Block _encoded_blk { };
Tree_walk_pbas _new_pbas { };
Number_of_blocks _num_blks { 0 };
Generation _free_gen { 0 };
Generatable_request<Helper, State, Block_io::Read> _read_block { };
Generatable_request<Helper, State, Crypto::Decrypt> _decrypt_block { };
Generatable_request<Helper, State, Crypto::Encrypt> _encrypt_block { };
Generatable_request<Helper, State, Free_tree::Allocate_pbas> _alloc_pbas { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
bool _check_and_decode_read_blk(bool &);
void _set_new_pbas_and_num_blks_for_alloc();
void _generate_ft_alloc_req_for_write_vba(bool &);
void _write_vba(bool &);
void _update_nodes_of_branch_of_written_vba();
void _rekey_vba(bool &);
void _generate_ft_alloc_req_for_write_vba(bool &);
void _generate_ft_alloc_req_for_rekeying(Tree_level_index, bool &);
void _generate_write_blk_req(bool &);
public:
Write_vba(Attr const &attr) : _helper(*this), _attr(attr) { }
~Write_vba() { }
void print(Output &out) const { Genode::print(out, "write vba"); }
bool execute(Client_data_interface &, Block_io &, Free_tree &, Meta_tree &, Crypto &);
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Tresor::Virtual_block_device::Extend_tree : Noncopyable
{
public:
using Module = Virtual_block_device;
struct Attr
{
Number_of_leaves &out_num_leaves;
Snapshots &in_out_snapshots;
Tree_degree const in_snap_degr;
Generation const in_curr_gen;
Generation const in_last_secured_gen;
Physical_block_address &in_out_first_pba;
Number_of_blocks &in_out_num_pbas;
Tree_root &in_out_ft;
Tree_root &in_out_mt;
Tree_degree const in_vbd_degree;
Virtual_block_address const in_vbd_highest_vba;
Key_id const in_curr_key_id;
Key_id const in_prev_key_id;
bool in_rekeying;
Virtual_block_address const in_rekeying_vba;
};
private:
enum State {
INIT, COMPLETE, READ_BLK, READ_BLK_SUCCEEDED, WRITE_BLK, WRITE_BLK_SUCCEEDED, ALLOC_PBAS, ALLOC_PBAS_SUCCEEDED };
using Helper = Request_helper<Extend_tree, State>;
Helper _helper;
Attr const _attr;
Tree_level_index _lvl { 0 };
Snapshot_index _snap_idx { 0 };
Virtual_block_address _vba { 0 };
Tree_walk_pbas _old_pbas { };
Block _encoded_blk { };
Tree_walk_pbas _new_pbas { };
Type_1_node_block_walk _t1_blks { };
Number_of_blocks _num_blks { 0 };
Type_1_node_walk _t1_nodes { };
Block _data_blk { };
Generation _free_gen { 0 };
Generatable_request<Helper, State, Block_io::Read> _read_block { };
Generatable_request<Helper, State, Block_io::Write> _write_block { };
Generatable_request<Helper, State, Free_tree::Allocate_pbas> _alloc_pbas { };
void _add_new_root_lvl_to_snap();
@ -152,32 +288,22 @@ class Tresor::Virtual_block_device_channel : public Module_channel
void _set_new_pbas_identical_to_curr_pbas();
void _generate_write_blk_req(bool &);
void _generate_ft_alloc_req_for_resizing(Tree_level_index, bool &);
void _extension_step(bool &);
public:
Virtual_block_device_channel(Module_channel_id id) : Module_channel { VIRTUAL_BLOCK_DEVICE, id } { }
Extend_tree(Attr const &attr) : _helper(*this), _attr(attr) { }
void execute(bool &);
};
~Extend_tree() { }
class Tresor::Virtual_block_device : public Module
{
private:
void print(Output &out) const { Genode::print(out, "extend tree"); }
using Channel = Virtual_block_device_channel;
bool execute(Block_io &, Free_tree &, Meta_tree &);
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Virtual_block_device);
void execute(bool &) override;
public:
Virtual_block_device();
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
#endif /* _TRESOR__VIRTUAL_BLOCK_DEVICE_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Module for doing VBD COW allocations on the meta tree
* \brief Module for doing PBA allocations for the Free Tree via the Meta Tree
* \author Martin Stein
* \date 2023-02-13
*/
@ -13,149 +13,32 @@
/* tresor includes */
#include <tresor/meta_tree.h>
#include <tresor/block_io.h>
#include <tresor/hash.h>
using namespace Tresor;
char const *Meta_tree_request::type_to_string(Type type)
bool Meta_tree::execute(Allocate_pba &req, Block_io &block_io) { return req.execute(block_io); }
void Meta_tree::Allocate_pba::_start_tree_traversal(bool &progress)
{
switch (type) {
case ALLOC_PBA: return "alloc pba";
}
ASSERT_NEVER_REACHED;
}
Meta_tree_request::Meta_tree_request(Module_id src_module_id, Module_channel_id src_channel_id,
Type type, Tree_root &mt, Generation curr_gen,
Physical_block_address &pba, bool &success)
:
Module_request { src_module_id, src_channel_id, META_TREE }, _type { type }, _mt { mt },
_curr_gen { curr_gen }, _pba { pba }, _success { success }
{ }
void Meta_tree::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
}
bool Meta_tree_channel::_can_alloc_pba_of(Type_2_node &node)
{
return node.valid() && node.alloc_gen != _req_ptr->_curr_gen;
}
void Meta_tree_channel::_generated_req_completed(State_uint state_uint)
{
if (!_generated_req_success) {
error("meta tree: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
void Meta_tree_channel::_alloc_pba_of(Type_2_node &t2_node, Physical_block_address &pba)
{
Request &req { *_req_ptr };
Physical_block_address old_pba { pba };
pba = t2_node.pba;
t2_node.pba = old_pba;
t2_node.alloc_gen = req._curr_gen;
t2_node.free_gen = req._curr_gen;
t2_node.reserved = false;
}
void Meta_tree_channel::_mark_req_failed(bool &progress, char const *str)
{
error(Request::type_to_string(_req_ptr->_type), " request failed, reason: \"", str, "\"");
_req_ptr->_success = false;
_state = COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Meta_tree_channel::_mark_req_successful(bool &progress)
{
_req_ptr->_success = true;
_state = COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Meta_tree_channel::_start_tree_traversal(bool &progress)
{
Request &req { *_req_ptr };
_lvl = req._mt.max_lvl;
_lvl = _attr.in_out_mt.max_lvl;
_node_idx[_lvl] = 0;
_t1_blks[_lvl].nodes[_node_idx[_lvl]] = req._mt.t1_node();
_generate_req<Block_io::Read>(SEEK_DOWN, progress, req._mt.pba, _blk);
_t1_blks[_lvl].nodes[_node_idx[_lvl]] = _attr.in_out_mt.t1_node();
_read_block.generate(_helper, READ_BLK, SEEK_DOWN, progress, _attr.in_out_mt.pba, _blk);
}
void Meta_tree_channel::_traverse_curr_node(bool &progress)
bool Meta_tree::Allocate_pba::execute(Block_io &block_io)
{
Request &req { *_req_ptr };
if (_lvl) {
Type_1_node &t1_node { _t1_blks[_lvl].nodes[_node_idx[_lvl]] };
if (t1_node.pba)
_generate_req<Block_io::Read>(SEEK_DOWN, progress, t1_node.pba, _blk);
else {
_state = SEEK_LEFT_OR_UP;
progress = true;
}
} else {
Type_2_node &t2_node { _t2_blk.nodes[_node_idx[_lvl]] };
if (_can_alloc_pba_of(t2_node)) {
_alloc_pba_of(t2_node, _req_ptr->_pba);
for (Tree_level_index lvl { 1 }; lvl <= req._mt.max_lvl; lvl++) {
Type_1_node &t1_node { _t1_blks[lvl].nodes[_node_idx[lvl]] };
if (!t1_node.is_volatile(req._curr_gen)) {
bool pba_allocated { false };
for (Type_2_node &t2_node : _t2_blk.nodes) {
if (_can_alloc_pba_of(t2_node)) {
_alloc_pba_of(t2_node, t1_node.pba);
pba_allocated = true;
break;
}
}
ASSERT(pba_allocated);
}
}
_state = WRITE_BLK;
} else
_state = SEEK_LEFT_OR_UP;
progress = true;
}
}
void Meta_tree_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
_start_tree_traversal(progress);
break;
bool progress = false;
switch (_helper.state) {
case INIT: _start_tree_traversal(progress); break;
case READ_BLK: progress |= _read_block.execute(block_io); break;
case SEEK_DOWN:
if (!check_hash(_blk, _t1_blks[_lvl].nodes[_node_idx[_lvl]].hash)) {
_mark_req_failed(progress, "hash mismatch");
_helper.mark_failed(progress, "hash mismatch");
break;
}
_lvl--;
@ -169,54 +52,91 @@ void Meta_tree_channel::execute(bool &progress)
case SEEK_LEFT_OR_UP:
if (_lvl < req._mt.max_lvl) {
if (_node_idx[_lvl] < req._mt.degree - 1) {
if (_lvl < _attr.in_out_mt.max_lvl) {
if (_node_idx[_lvl] < _attr.in_out_mt.degree - 1) {
_node_idx[_lvl]++;
_traverse_curr_node(progress);
} else {
_lvl++;
_state = SEEK_LEFT_OR_UP;
_helper.state = SEEK_LEFT_OR_UP;
progress = true;
}
} else
_mark_req_failed(progress, "not enough free pbas");
_helper.mark_failed(progress, "not enough free pbas");
break;
case WRITE_BLK:
case WRITE_BLK: progress |= _write_block.execute(block_io); break;
case WRITE_BLK_SUCCEEDED:
if (_lvl < req._mt.max_lvl) {
if (_lvl < _attr.in_out_mt.max_lvl) {
if (_lvl)
_t1_blks[_lvl].encode_to_blk(_blk);
else
_t2_blk.encode_to_blk(_blk);
_lvl++;
Type_1_node &t1_node { _t1_blks[_lvl].nodes[_node_idx[_lvl]] };
t1_node.gen = req._curr_gen;
t1_node.gen = _attr.in_curr_gen;
calc_hash(_blk, t1_node.hash);
_generate_req<Block_io::Write>(WRITE_BLK, progress, t1_node.pba, _blk);
_write_block.generate(_helper, WRITE_BLK, WRITE_BLK_SUCCEEDED, progress, t1_node.pba, _blk);
} else {
req._mt.t1_node(_t1_blks[_lvl].nodes[_node_idx[_lvl]]);
_mark_req_successful(progress);
_attr.in_out_mt.t1_node(_t1_blks[_lvl].nodes[_node_idx[_lvl]]);
_helper.mark_succeeded(progress);
}
break;
default: break;
}
return progress;
}
void Meta_tree_channel::_request_submitted(Module_request &mod_req)
bool Meta_tree::Allocate_pba::_can_alloc_pba_of(Type_2_node &node)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
return node.valid() && node.alloc_gen != _attr.in_curr_gen;
}
Meta_tree::Meta_tree()
void Meta_tree::Allocate_pba::_alloc_pba_of(Type_2_node &t2_node, Physical_block_address &pba)
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
Physical_block_address old_pba { pba };
pba = t2_node.pba;
t2_node.pba = old_pba;
t2_node.alloc_gen = _attr.in_curr_gen;
t2_node.free_gen = _attr.in_curr_gen;
t2_node.reserved = false;
}
void Meta_tree::Allocate_pba::_traverse_curr_node(bool &progress)
{
if (_lvl) {
Type_1_node &t1_node { _t1_blks[_lvl].nodes[_node_idx[_lvl]] };
if (t1_node.pba)
_read_block.generate(_helper, READ_BLK, SEEK_DOWN, progress, t1_node.pba, _blk);
else {
_helper.state = SEEK_LEFT_OR_UP;
progress = true;
}
} else {
Type_2_node &t2_node { _t2_blk.nodes[_node_idx[_lvl]] };
if (_can_alloc_pba_of(t2_node)) {
_alloc_pba_of(t2_node, _attr.in_out_pba);
for (Tree_level_index lvl { 1 }; lvl <= _attr.in_out_mt.max_lvl; lvl++) {
Type_1_node &t1_node { _t1_blks[lvl].nodes[_node_idx[lvl]] };
if (!t1_node.is_volatile(_attr.in_curr_gen)) {
bool pba_allocated { false };
for (Type_2_node &t2_node : _t2_blk.nodes) {
if (_can_alloc_pba_of(t2_node)) {
_alloc_pba_of(t2_node, t1_node.pba);
pba_allocated = true;
break;
}
}
ASSERT(pba_allocated);
}
}
_helper.state = WRITE_BLK_SUCCEEDED;
} else
_helper.state = SEEK_LEFT_OR_UP;
progress = true;
}
}

View File

@ -1,145 +0,0 @@
/*
* \brief Framework for component internal modularization
* \author Martin Stein
* \date 2023-02-13
*/
/*
* Copyright (C) 2023 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.
*/
/* tresor includes */
#include <tresor/types.h>
#include <tresor/module.h>
using namespace Tresor;
Module_request::Module_request(Module_id src_module_id, Module_channel_id src_chan_id, Module_id dst_module_id)
:
_src_module_id { src_module_id }, _src_chan_id { src_chan_id }, _dst_module_id { dst_module_id }
{ }
char const *Tresor::module_name(Module_id id)
{
switch (id) {
case CRYPTO: return "crypto";
case BLOCK_IO: return "block_io";
case CACHE: return "cache";
case META_TREE: return "meta_tree";
case FREE_TREE: return "free_tree";
case VIRTUAL_BLOCK_DEVICE: return "vbd";
case SUPERBLOCK_CONTROL: return "sb_control";
case CLIENT_DATA: return "client_data";
case TRUST_ANCHOR: return "trust_anchor";
case COMMAND_POOL: return "command_pool";
case VBD_INITIALIZER: return "vbd_initializer";
case FT_INITIALIZER: return "ft_initializer";
case SB_INITIALIZER: return "sb_initializer";
case SB_CHECK: return "sb_check";
case VBD_CHECK: return "vbd_check";
case FT_CHECK: return "ft_check";
case SPLITTER: return "splitter";
case REQUEST_POOL: return "request_pool";
default: break;
}
ASSERT_NEVER_REACHED;
}
void Module_channel::generated_req_completed()
{
ASSERT(_gen_req_state == IN_PROGRESS);
_gen_req_state = NONE;
_generated_req_completed(_gen_req_complete_state);
}
bool Module_channel::try_submit_request(Module_request &req)
{
if (_req_ptr)
return false;
req.dst_chan_id(_id);
_req_ptr = &req;
_request_submitted(req);
return true;
}
bool Module::try_submit_request(Module_request &req)
{
bool success { false };
for_each_channel([&] (Module_channel &chan) {
if (success)
return;
success = chan.try_submit_request(req);
});
return success;
}
void Module_composition::execute_modules()
{
bool progress { true };
while (progress) {
progress = false;
for (Module_id id { 0 }; id <= MAX_MODULE_ID; id++) {
if (!_module_ptrs[id])
continue;
Module &mod { *_module_ptrs[id] };
mod.execute(progress);
mod.for_each_generated_request([&] (Module_request &req) {
ASSERT(req.dst_module_id() <= MAX_MODULE_ID);
ASSERT(_module_ptrs[req.dst_module_id()]);
Module &dst_module { *_module_ptrs[req.dst_module_id()] };
if (dst_module.try_submit_request(req)) {
if (VERBOSE_MODULE_COMMUNICATION)
log(module_name(id), " ", req.src_chan_id(), " --", req, "--> ",
module_name(req.dst_module_id()), " ", req.dst_chan_id());
progress = true;
return true;
}
if (VERBOSE_MODULE_COMMUNICATION)
log(module_name(id), " ", req.src_chan_id(), " --", req, "-| ", module_name(req.dst_module_id()));
return false;
});
mod.for_each_completed_request([&] (Module_request &req) {
ASSERT(req.src_module_id() <= MAX_MODULE_ID);
if (VERBOSE_MODULE_COMMUNICATION)
log(module_name(req.src_module_id()), " ", req.src_chan_id(), " <--", req,
"-- ", module_name(id), " ", req.dst_chan_id());
Module &src_module { *_module_ptrs[req.src_module_id()] };
src_module.with_channel(req.src_chan_id(), [&] (Module_channel &chan) {
chan.generated_req_completed(); });
progress = true;
});
}
};
}
void Module_composition::add_module(Module_id module_id, Module &mod)
{
ASSERT(module_id <= MAX_MODULE_ID);
ASSERT(!_module_ptrs[module_id]);
_module_ptrs[module_id] = &mod;
}
void Module_composition::remove_module(Module_id module_id)
{
ASSERT(module_id <= MAX_MODULE_ID);
ASSERT(_module_ptrs[module_id]);
_module_ptrs[module_id] = nullptr;
}

View File

@ -1,381 +0,0 @@
/*
* \brief Module for scheduling requests for processing
* \author Martin Stein
* \date 2023-03-17
*/
/*
* Copyright (C) 2023 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.
*/
/* tresor includes */
#include <tresor/request_pool.h>
using namespace Tresor;
Request::Request(Module_id src_module_id, Module_channel_id src_chan_id, Operation op, Virtual_block_address vba,
Request_offset offset, Number_of_blocks count, Key_id key_id, Request_tag tag, Generation &gen, bool &success)
:
Module_request { src_module_id, src_chan_id, REQUEST_POOL }, _op { op }, _vba { vba }, _offset { offset },
_count { count }, _key_id { key_id }, _tag { tag }, _gen { gen }, _success { success }
{ }
void Request::print(Output &out) const
{
Genode::print(out, op_to_string(_op));
switch (_op) {
case READ:
case WRITE:
case SYNC:
if (_count > 1)
Genode::print(out, " vbas ", _vba, "..", _vba + _count - 1);
else
Genode::print(out, " vba ", _vba);
break;
default: break;
}
}
char const *Request::op_to_string(Operation op)
{
switch (op) {
case Request::READ: return "read";
case Request::WRITE: return "write";
case Request::SYNC: return "sync";
case Request::CREATE_SNAPSHOT: return "create_snapshot";
case Request::DISCARD_SNAPSHOT: return "discard_snapshot";
case Request::REKEY: return "rekey";
case Request::EXTEND_VBD: return "extend_vbd";
case Request::EXTEND_FT: return "extend_ft";
case Request::RESUME_REKEYING: return "resume_rekeying";
case Request::DEINITIALIZE: return "deinitialize";
case Request::INITIALIZE: return "initialize";
}
ASSERT_NEVER_REACHED;
}
void Request_pool_channel::_gen_sb_control_req(bool &progress, Superblock_control_request::Type type,
State complete_state, Virtual_block_address vba = 0)
{
_state = REQ_GENERATED;
generate_req<Superblock_control_request>(
complete_state, progress, type, _req_ptr->_offset, _req_ptr->_tag, _req_ptr->_count, vba, _generated_req_success,
_request_finished, _sb_state, _req_ptr->_gen);
}
void Request_pool_channel::_access_vbas(bool &progress, Superblock_control_request::Type type)
{
switch (_state) {
case REQ_SUBMITTED:
_gen_sb_control_req(progress, type, ACCESS_VBA_AT_SB_CTRL_SUCCEEDED, _req_ptr->_vba + _num_blks);
break;
case ACCESS_VBA_AT_SB_CTRL_SUCCEEDED:
if (++_num_blks < _req_ptr->_count)
_gen_sb_control_req(progress, type, ACCESS_VBA_AT_SB_CTRL_SUCCEEDED, _req_ptr->_vba + _num_blks);
else
_mark_req_successful(progress);
break;
default: break;
}
}
void Request_pool_channel::_mark_req_successful(bool &progress)
{
_req_ptr->_success = true;
_state = REQ_COMPLETE;
_chan_queue.dequeue(*this);
_req_ptr = nullptr;
progress = true;
}
void Request_pool_channel::_try_prepone_requests(bool &progress)
{
enum { MAX_NUM_REQUESTS_PREPONED = 8 };
bool requests_preponed { false };
bool at_req_that_cannot_be_preponed { false };
_num_requests_preponed = 0;
while (_num_requests_preponed < MAX_NUM_REQUESTS_PREPONED &&
!at_req_that_cannot_be_preponed &&
!_chan_queue.is_tail(*this)) {
switch (_chan_queue.next(*this)._req_ptr->_op) {
case Request::READ:
case Request::WRITE:
case Request::SYNC:
case Request::DISCARD_SNAPSHOT:
_chan_queue.move_one_slot_towards_tail(*this);
_num_requests_preponed++;
requests_preponed = true;
progress = true;
break;
default:
at_req_that_cannot_be_preponed = true;
break;
}
}
if (!requests_preponed) {
_state = PREPONED_REQUESTS_COMPLETE;
progress = true;
}
}
void Request_pool_channel::_extend_tree(Superblock_control_request::Type type, bool &progress)
{
switch (_state) {
case REQ_SUBMITTED:
_gen_sb_control_req(progress, type, TREE_EXTENSION_STEP_SUCCEEDED);
break;
case TREE_EXTENSION_STEP_SUCCEEDED:
if (_request_finished)
_mark_req_successful(progress);
else
_try_prepone_requests(progress);
break;
case PREPONED_REQUESTS_COMPLETE:
_gen_sb_control_req(progress, type, TREE_EXTENSION_STEP_SUCCEEDED);
break;
default: break;
}
}
void Request_pool_channel::_rekey(bool &progress)
{
switch (_state) {
case REQ_SUBMITTED:
_gen_sb_control_req(progress, Superblock_control_request::INITIALIZE_REKEYING, REKEY_INIT_SUCCEEDED);
break;
case REQ_RESUMED:
case REKEY_INIT_SUCCEEDED: _try_prepone_requests(progress); break;
case REKEY_VBA_SUCCEEDED:
if (_request_finished)
_mark_req_successful(progress);
else
_try_prepone_requests(progress);
break;
case PREPONED_REQUESTS_COMPLETE:
_gen_sb_control_req(progress, Superblock_control_request::REKEY_VBA, REKEY_VBA_SUCCEEDED);
break;
default: break;
}
}
void Request_pool_channel::_resume_request(bool &progress, Request::Operation op)
{
_state = REQ_RESUMED;
_req_ptr->_op = op;
progress = true;
}
void Request_pool_channel::_initialize(bool &progress)
{
switch (_state) {
case REQ_SUBMITTED:
_gen_sb_control_req(progress, Superblock_control_request::INITIALIZE, INITIALIZE_SB_CTRL_SUCCEEDED);
break;
case INITIALIZE_SB_CTRL_SUCCEEDED:
switch (_sb_state) {
case Superblock::INVALID: ASSERT_NEVER_REACHED;
case Superblock::NORMAL:
_chan_queue.dequeue(*this);
_reset();
progress = true;
break;
case Superblock::REKEYING: _resume_request(progress, Request::REKEY); break;
case Superblock::EXTENDING_VBD: _resume_request(progress, Request::EXTEND_VBD); break;
case Superblock::EXTENDING_FT: _resume_request(progress, Request::EXTEND_FT); break;
}
break;
default: break;
}
}
void Request_pool_channel::_forward_to_sb_ctrl(bool &progress, Superblock_control_request::Type type)
{
switch (_state) {
case REQ_SUBMITTED: _gen_sb_control_req(progress, type, FORWARD_TO_SB_CTRL_SUCCEEDED); break;
case FORWARD_TO_SB_CTRL_SUCCEEDED: _mark_req_successful(progress); break;
default: break;
}
}
void Request_pool::execute(bool &progress)
{
if (!_chan_queue.empty())
_chan_queue.head().execute(progress);
}
void Request_pool_channel::execute(bool &progress)
{
switch (_req_ptr->_op) {
case Request::READ: _access_vbas(progress, Superblock_control_request::READ_VBA); break;
case Request::WRITE: _access_vbas(progress, Superblock_control_request::WRITE_VBA); break;
case Request::SYNC: _forward_to_sb_ctrl(progress, Superblock_control_request::SYNC); break;
case Request::REKEY: _rekey(progress); break;
case Request::EXTEND_VBD: _extend_tree(Superblock_control_request::VBD_EXTENSION_STEP, progress); break;
case Request::EXTEND_FT: _extend_tree(Superblock_control_request::FT_EXTENSION_STEP, progress); break;
case Request::INITIALIZE: _initialize(progress); break;
case Request::DEINITIALIZE: _forward_to_sb_ctrl(progress, Superblock_control_request::DEINITIALIZE); break;
case Request::CREATE_SNAPSHOT: _forward_to_sb_ctrl(progress, Superblock_control_request::CREATE_SNAPSHOT); break;
case Request::DISCARD_SNAPSHOT: _forward_to_sb_ctrl(progress, Superblock_control_request::DISCARD_SNAPSHOT); break;
default: break;
}
}
Request_pool::Request_pool()
{
for (Module_channel_id id { 0 }; id < NUM_CHANNELS; id++) {
_channels[id].construct(id, _chan_queue);
add_channel(*_channels[id]);
}
ASSERT(try_submit_request(_init_req));
}
void Request_pool_channel::_generated_req_completed(State_uint state_uint)
{
if (!_generated_req_success) {
error("request_pool: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_chan_queue.dequeue(*this);
_req_ptr = nullptr;
} else
_state = (State)state_uint;
}
void Request_pool_channel::_reset()
{
_state = INVALID;
_sb_state = Superblock::INVALID;
_num_blks = _num_requests_preponed = 0;
_request_finished = false;
}
Request_pool_channel &Request_pool_channel_queue::head() const
{
ASSERT(!empty());
return *_slots[_head];
}
void Request_pool_channel_queue::enqueue(Channel &chan)
{
ASSERT(!full());
_slots[_tail] = &chan;
_tail = (_tail + 1) % NUM_SLOTS;
_num_used_slots++;
}
void Request_pool_channel_queue::move_one_slot_towards_tail(Channel const &chan)
{
Slot_index slot_idx { _head };
Slot_index next_slot_idx;
ASSERT(!empty());
while (1) {
if (slot_idx < NUM_SLOTS - 1)
next_slot_idx = slot_idx + 1;
else
next_slot_idx = 0;
ASSERT(next_slot_idx != _tail);
if (_slots[slot_idx] == &chan) {
Channel *chan_ptr = _slots[next_slot_idx];
_slots[next_slot_idx] = _slots[slot_idx];
_slots[slot_idx] = chan_ptr;
return;
}
slot_idx = next_slot_idx;
}
}
bool Request_pool_channel_queue::is_tail(Channel const &chan) const
{
Slot_index slot_idx;
ASSERT(!empty());
if (_tail)
slot_idx = _tail - 1;
else
slot_idx = NUM_SLOTS - 1;
return _slots[slot_idx] == &chan;
}
Request_pool_channel &Request_pool_channel_queue::next(Channel const &chan) const
{
Slot_index slot_idx { _head };
Slot_index next_slot_idx;
ASSERT(!empty());
while (1) {
if (slot_idx < NUM_SLOTS - 1)
next_slot_idx = slot_idx + 1;
else
next_slot_idx = 0;
ASSERT(next_slot_idx != _tail);
if (_slots[slot_idx] == &chan)
return *_slots[next_slot_idx];
else
slot_idx = next_slot_idx;
}
}
void Request_pool_channel_queue::dequeue(Channel const &chan)
{
ASSERT(!empty() && &head() == &chan);
_head = (_head + 1) % NUM_SLOTS;
_num_used_slots--;
}
void Request_pool_channel::_request_submitted(Module_request &req)
{
_reset();
_req_ptr = static_cast<Request *>(&req);
_state = REQ_SUBMITTED;
_chan_queue.enqueue(*this);
}

View File

@ -13,64 +13,41 @@
/* tresor includes */
#include <tresor/sb_check.h>
#include <tresor/vbd_check.h>
#include <tresor/ft_check.h>
#include <tresor/block_io.h>
using namespace Tresor;
Sb_check_request::Sb_check_request(Module_id src_mod, Module_channel_id src_chan, bool &success)
:
Module_request { src_mod, src_chan, SB_CHECK }, _success { success }
{ }
void Sb_check_channel::_generated_req_completed(State_uint state_uint)
bool Sb_check::Check::execute(Vbd_check &vbd_check, Ft_check &ft_check, Block_io &block_io)
{
if (!_generated_req_success) {
error("sb check: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
void Sb_check_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
switch (_state) {
case REQ_SUBMITTED:
bool progress = false;
switch (_helper.state) {
case INIT:
_highest_gen = 0;
_highest_gen_sb_idx = 0;
_snap_idx = 0;
_sb_idx = 0;
_scan_for_highest_gen_sb_done = false;
_generate_req<Block_io::Read>(READ_BLK_SUCCESSFUL, progress, _sb_idx, _blk);
_read_block.generate(_helper, READ_BLK, READ_BLK_SUCCEEDED, progress, _sb_idx, _blk);
break;
case READ_BLK_SUCCESSFUL:
case READ_BLK: progress |= _read_block.execute(block_io); break;
case READ_BLK_SUCCEEDED:
_sb.decode_from_blk(_blk);
if (_scan_for_highest_gen_sb_done) {
if (!_sb.valid()) {
_mark_req_failed(progress, "no valid superblock");;
_helper.mark_failed(progress, "no valid superblock");;
break;
}
Snapshot &snap { _sb.snapshots.items[_snap_idx] };
if (snap.valid) {
Snapshot &snap { _sb.snapshots.items[_snap_idx] };
_tree_root.construct(snap.pba, snap.gen, snap.hash, snap.max_level, _sb.degree, snap.nr_of_leaves);
_generate_req<Vbd_check_request>(CHECK_VBD_SUCCESSFUL, progress, *_tree_root);
_check_vbd.generate(_helper, CHECK_VBD, CHECK_VBD_SUCCEEDED, progress, *_tree_root);
if (VERBOSE_CHECK)
log(" check snap ", _snap_idx, " (", snap, ")");
} else {
_state = CHECK_VBD_SUCCESSFUL;
_helper.state = CHECK_VBD_SUCCEEDED;
progress = true;
if (VERBOSE_CHECK)
log(" skip snap ", _snap_idx, " as it is unused");
@ -83,85 +60,45 @@ void Sb_check_channel::execute(bool &progress)
}
if (_sb_idx < MAX_SUPERBLOCK_INDEX) {
_sb_idx++;
_generate_req<Block_io::Read>(READ_BLK_SUCCESSFUL, progress, _sb_idx, _blk);
_read_block.generate(_helper, READ_BLK, READ_BLK_SUCCEEDED, progress, _sb_idx, _blk);
progress = true;
} else {
_scan_for_highest_gen_sb_done = true;
_generate_req<Block_io::Read>(READ_BLK_SUCCESSFUL, progress, _highest_gen_sb_idx, _blk);
_read_block.generate(_helper, READ_BLK, READ_BLK_SUCCEEDED, progress, _highest_gen_sb_idx, _blk);
if (VERBOSE_CHECK)
log("check superblock ", _highest_gen_sb_idx, "\n read superblock");
}
}
break;
case CHECK_VBD_SUCCESSFUL:
case CHECK_VBD: progress |= _check_vbd.execute(vbd_check, block_io); break;
case CHECK_VBD_SUCCEEDED:
if (_snap_idx < MAX_SNAP_IDX) {
_snap_idx++;
_state = READ_BLK_SUCCESSFUL;
_helper.state = READ_BLK_SUCCEEDED;
progress = true;
} else {
_snap_idx = 0;
_tree_root.construct(_sb.free_number, _sb.free_gen, _sb.free_hash, _sb.free_max_level, _sb.free_degree, _sb.free_leaves);
_generate_req<Ft_check_request>(CHECK_FT_SUCCESSFUL, progress, *_tree_root);
_check_ft.generate(_helper, CHECK_FT, CHECK_FT_SUCCEEDED, progress, *_tree_root);
if (VERBOSE_CHECK)
log(" check free tree");
}
break;
case CHECK_FT_SUCCESSFUL:
case CHECK_FT: progress |= _check_ft.execute(ft_check, block_io); break;
case CHECK_FT_SUCCEEDED:
_tree_root.construct(_sb.meta_number, _sb.meta_gen, _sb.meta_hash, _sb.meta_max_level, _sb.meta_degree, _sb.meta_leaves);
_generate_req<Ft_check_request>(CHECK_MT_SUCCESSFUL, progress, *_tree_root);
_check_ft.generate(_helper, CHECK_MT, CHECK_MT_SUCCEEDED, progress, *_tree_root);
if (VERBOSE_CHECK)
log(" check meta tree");
break;
case CHECK_MT_SUCCESSFUL: _mark_req_successful(progress); break;
case CHECK_MT: progress |= _check_ft.execute(ft_check, block_io); break;
case CHECK_MT_SUCCEEDED: _helper.mark_succeeded(progress); break;
default: break;
}
}
void Sb_check_channel::_mark_req_failed(bool &progress, char const *str)
{
error("sb check: request (", *_req_ptr, ") failed at step \"", str, "\"");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Sb_check_channel::_mark_req_successful(bool &progress)
{
Request &req { *_req_ptr };
req._success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Sb_check_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
Sb_check::Sb_check()
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
}
}
void Sb_check::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
return progress;
}

View File

@ -14,158 +14,100 @@
/* tresor includes */
#include <tresor/hash.h>
#include <tresor/block_io.h>
#include <tresor/vbd_initializer.h>
#include <tresor/ft_initializer.h>
#include <tresor/trust_anchor.h>
#include <tresor/sb_initializer.h>
using namespace Tresor;
Sb_initializer_request::
Sb_initializer_request(Module_id src_mod, Module_channel_id src_chan, Tree_level_index vbd_max_lvl,
Tree_degree vbd_degree, Number_of_leaves vbd_num_leaves, Tree_level_index ft_max_lvl,
Tree_degree ft_degree, Number_of_leaves ft_num_leaves, Tree_level_index mt_max_lvl,
Tree_degree mt_degree, Number_of_leaves mt_num_leaves, Pba_allocator &pba_alloc, bool &success)
:
Module_request { src_mod, src_chan, SB_INITIALIZER }, _vbd_max_lvl { vbd_max_lvl },
_vbd_degree { vbd_degree }, _vbd_num_leaves { vbd_num_leaves }, _ft_max_lvl { ft_max_lvl },
_ft_degree { ft_degree }, _ft_num_leaves { ft_num_leaves }, _mt_max_lvl { mt_max_lvl },
_mt_degree { mt_degree }, _mt_num_leaves { mt_num_leaves }, _pba_alloc { pba_alloc }, _success { success }
{ }
void Sb_initializer_channel::_generated_req_completed(State_uint state_uint)
bool Sb_initializer::Initialize::execute(Block_io &block_io, Trust_anchor &trust_anchor, Vbd_initializer &vbd_initializer, Ft_initializer &ft_initializer)
{
if (!_generated_req_success) {
error("sb initializer: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
void Sb_initializer_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
void Sb_initializer_channel::_mark_req_successful(bool &progress)
{
_req_ptr->_success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Sb_initializer_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
bool progress = false;
switch (_helper.state) {
case INIT:
{
_sb_idx = 0;
_sb = { };
Snapshot &snap = _sb.snapshots.items[0];
_vbd.construct(snap.pba, snap.gen, snap.hash, req._vbd_max_lvl, req._vbd_degree, req._vbd_num_leaves);
_generate_req<Vbd_initializer_request>(INIT_VBD_SUCCEEDED, progress, *_vbd, req._pba_alloc);
progress = true;
_init_vbd.generate(_helper, INIT_VBD, INIT_VBD_SUCCEEDED, progress, _attr.in_vbd_cfg, _vbd_root, _attr.in_out_pba_alloc);
break;
}
case INIT_VBD: progress |= _init_vbd.execute(vbd_initializer, block_io); break;
case INIT_VBD_SUCCEEDED:
_ft.construct(_sb.free_number, _sb.free_gen, _sb.free_hash, req._ft_max_lvl, req._ft_degree, req._ft_num_leaves);
_generate_req<Ft_initializer_request>(INIT_FT_SUCCEEDED, progress, *_ft, req._pba_alloc);
_init_ft.generate(_helper, INIT_FT, INIT_FT_SUCCEEDED, progress, _attr.in_ft_cfg, _ft_root, _attr.in_out_pba_alloc);
break;
case INIT_FT: progress |= _init_ft.execute(ft_initializer, block_io); break;
case INIT_FT_SUCCEEDED:
_mt.construct(_sb.meta_number, _sb.meta_gen, _sb.meta_hash, req._ft_max_lvl, req._ft_degree, req._ft_num_leaves);
_generate_req<Ft_initializer_request>(INIT_MT_SUCCEEDED, progress, *_mt, req._pba_alloc);
_init_ft.generate(_helper, INIT_FT, INIT_MT_SUCCEEDED, progress, _attr.in_mt_cfg, _mt_root, _attr.in_out_pba_alloc);
break;
case INIT_MT_SUCCEEDED:
_generate_req<Trust_anchor::Create_key>(CREATE_KEY_SUCCEEDED, progress, _sb.current_key.value);
_generate_key.generate(_helper, GENERATE_KEY, GENERATE_KEY_SUCCEEDED, progress, _sb.current_key.value);
break;
case CREATE_KEY_SUCCEEDED:
case GENERATE_KEY: progress |= _generate_key.execute(trust_anchor); break;
case GENERATE_KEY_SUCCEEDED:
_generate_req<Trust_anchor::Encrypt_key>(ENCRYPT_KEY_SUCCEEDED, progress, _sb.current_key.value, _sb.current_key.value);
_encrypt_key.generate(_helper, ENCRYPT_KEY, ENCRYPT_KEY_SUCCEEDED, progress, _sb.current_key.value, _sb.current_key.value);
break;
case ENCRYPT_KEY: progress |= _encrypt_key.execute(trust_anchor); break;
case ENCRYPT_KEY_SUCCEEDED:
{
Snapshot &snap = _sb.snapshots.items[0];
snap.gen = 0;
snap.nr_of_leaves = req._vbd_num_leaves;
snap.max_level = req._vbd_max_lvl;
snap.pba = _vbd_root.pba;
snap.gen = _vbd_root.gen;
snap.hash = _vbd_root.hash;
snap.nr_of_leaves = _attr.in_vbd_cfg.num_leaves;
snap.max_level = _attr.in_vbd_cfg.max_lvl;
snap.valid = true;
snap.id = 0;
_sb.current_key.id = 1;
_sb.state = Superblock::NORMAL;
_sb.degree = req._vbd_degree;
_sb.first_pba = req._pba_alloc.first_pba() - NR_OF_SUPERBLOCK_SLOTS;
_sb.nr_of_pbas = req._pba_alloc.num_used_pbas() + NR_OF_SUPERBLOCK_SLOTS;
_sb.free_max_level = _ft->max_lvl;
_sb.free_degree = _ft->degree;
_sb.free_leaves = _ft->num_leaves;
_sb.meta_max_level = _mt->max_lvl;
_sb.meta_degree = _mt->degree;
_sb.meta_leaves = _mt->num_leaves;
_sb.degree = _attr.in_vbd_cfg.degree;
_sb.first_pba = _attr.in_out_pba_alloc.first_pba() - NR_OF_SUPERBLOCK_SLOTS;
_sb.nr_of_pbas = _attr.in_out_pba_alloc.num_used_pbas() + NR_OF_SUPERBLOCK_SLOTS;
_sb.free_number = _ft_root.pba;
_sb.free_gen = _ft_root.gen;
_sb.free_hash = _ft_root.hash;
_sb.free_max_level = _attr.in_ft_cfg.max_lvl;
_sb.free_degree = _attr.in_ft_cfg.degree;
_sb.free_leaves = _attr.in_ft_cfg.num_leaves;
_sb.meta_number = _mt_root.pba;
_sb.meta_gen = _mt_root.gen;
_sb.meta_hash = _mt_root.hash;
_sb.meta_max_level = _attr.in_mt_cfg.max_lvl;
_sb.meta_degree = _attr.in_mt_cfg.degree;
_sb.meta_leaves = _attr.in_mt_cfg.num_leaves;
_sb.encode_to_blk(_blk);
_generate_req<Block_io::Write>(WRITE_BLK_SUCCEEDED, progress, _sb_idx, _blk);
_write_block.generate(_helper, WRITE_BLK, WRITE_BLK_SUCCEEDED, progress, _sb_idx, _blk);
break;
}
case WRITE_BLK: progress |= _write_block.execute(block_io); break;
case WRITE_BLK_SUCCEEDED:
_generate_req<Block_io::Sync>(_sb_idx ? SB_COMPLETE : WRITE_HASH_TO_TA, progress);
progress = true;
_sync_block_io.generate(_helper, SYNC_BLOCK_IO, _sb_idx ? SB_COMPLETE : WRITE_HASH_TO_TA, progress);
break;
case SYNC_BLOCK_IO: progress |= _sync_block_io.execute(block_io); break;
case WRITE_HASH_TO_TA:
calc_hash(_blk, _hash);
_generate_req<Trust_anchor::Write_hash>(SB_COMPLETE, progress, _hash);
_write_sb_hash.generate(_helper, WRITE_SB_HASH, SB_COMPLETE, progress, _hash);
break;
case WRITE_SB_HASH: progress |= _write_sb_hash.execute(trust_anchor); break;
case SB_COMPLETE:
if (_sb_idx < NR_OF_SUPERBLOCK_SLOTS - 1) {
_sb_idx++;
_sb = { };
_sb.encode_to_blk(_blk);
_generate_req<Block_io::Write>(WRITE_BLK_SUCCEEDED, progress, _sb_idx, _blk);
_write_block.generate(_helper, WRITE_BLK, WRITE_BLK_SUCCEEDED, progress, _sb_idx, _blk);
} else
_mark_req_successful(progress);
_helper.mark_succeeded(progress);
break;
default: break;
}
}
Sb_initializer::Sb_initializer()
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
}
}
void Sb_initializer::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
return progress;
}

File diff suppressed because it is too large Load Diff

View File

@ -16,174 +16,132 @@
using namespace Tresor;
Trust_anchor_request::Trust_anchor_request(Module_id src_module_id, Module_channel_id src_chan_id,
Type type, Key_value &key_plaintext, Key_value &key_ciphertext,
Hash &hash, Passphrase passphrase, bool &success)
:
Module_request { src_module_id, src_chan_id, TRUST_ANCHOR }, _type { type }, _key_plaintext { key_plaintext },
_key_ciphertext { key_ciphertext }, _hash { hash }, _pass { passphrase }, _success { success }
{ }
char const *Trust_anchor_request::type_to_string(Type type)
bool Trust_anchor::Encrypt_key::execute(Trust_anchor::Attr const &ta_attr)
{
switch (type) {
case CREATE_KEY: return "create_key";
case ENCRYPT_KEY: return "encrypt_key";
case DECRYPT_KEY: return "decrypt_key";
case WRITE_HASH: return "write_hash";
case READ_HASH: return "read_hash";
case INITIALIZE: return "initialize";
}
ASSERT_NEVER_REACHED;
}
bool progress = false;
switch (_helper.state) {
case INIT:
_file.construct(_helper.state, ta_attr.encrypt_file);
_helper.state = WRITE;
progress = true;
break;
void Trust_anchor_channel::_mark_req_failed(bool &progress, Error_string str)
{
error("trust_anchor: request (", *_req_ptr, ") failed: ", str);
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Trust_anchor_channel::_mark_req_successful(bool &progress)
{
Request &req { *_req_ptr };
req._success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Trust_anchor_channel::_read_hash(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _hashsum_file.read(READ_OK, FILE_ERR, 0, { (char *)&req._hash, HASH_SIZE }, progress); break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, 0, { (char *)&_attr.in_key_plaintext, KEY_SIZE }, progress); break;
case WRITE_OK: _file->read(READ_OK, FILE_ERR, 0, { (char *)&_attr.out_key_ciphertext, KEY_SIZE }, progress); break;
case READ_OK: _helper.mark_succeeded(progress); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
void Trust_anchor_channel::_create_key(bool &progress)
bool Trust_anchor::Decrypt_key::execute(Trust_anchor::Attr const &ta_attr)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _generate_key_file.read(READ_OK, FILE_ERR, 0, { (char *)&req._key_plaintext, KEY_SIZE }, progress); break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
bool progress = false;
switch (_helper.state) {
case INIT:
_file.construct(_helper.state, ta_attr.decrypt_file);
_helper.state = WRITE;
progress = true;
break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, 0, { (char *)&_attr.in_key_ciphertext, KEY_SIZE }, progress); break;
case WRITE_OK: _file->read(READ_OK, FILE_ERR, 0, { (char *)&_attr.out_key_plaintext, KEY_SIZE }, progress); break;
case READ_OK: _helper.mark_succeeded(progress); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
void Trust_anchor_channel::_initialize(bool &progress)
bool Trust_anchor::Write_hash::execute(Trust_anchor::Attr const &ta_attr)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _initialize_file.write(WRITE_OK, FILE_ERR, 0, { req._pass.string(), req._pass.length() - 1 }, progress); break;
case WRITE_OK: _initialize_file.read(READ_OK, FILE_ERR, 0, { _result_buf, sizeof(_result_buf) }, progress); break;
bool progress = false;
switch (_helper.state) {
case INIT:
_file.construct(_helper.state, ta_attr.hash_file);
_helper.state = WRITE;
progress = true;
break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, 0, { (char *)&_attr.in_hash, HASH_SIZE }, progress); break;
case WRITE_OK: _file->read(READ_OK, FILE_ERR, 0, { _result_buf, sizeof(_result_buf) }, progress); break;
case READ_OK: _helper.mark_succeeded(progress); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
bool Trust_anchor::Read_hash::execute(Trust_anchor::Attr const &ta_attr)
{
bool progress = false;
switch (_helper.state) {
case INIT:
_file.construct(_helper.state, ta_attr.hash_file);
_helper.state = READ;
progress = true;
break;
case READ: _file->read(READ_OK, FILE_ERR, 0, { (char *)&_attr.out_hash, HASH_SIZE }, progress); break;
case READ_OK: _helper.mark_succeeded(progress); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
bool Trust_anchor::Generate_key::execute(Trust_anchor::Attr const &ta_attr)
{
bool progress = false;
switch (_helper.state) {
case INIT:
_file.construct(_helper.state, ta_attr.generate_key_file);
_helper.state = READ;
progress = true;
break;
case READ: _file->read(READ_OK, FILE_ERR, 0, { (char *)&_attr.out_key_plaintext, KEY_SIZE }, progress); break;
case READ_OK: _helper.mark_succeeded(progress); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
return progress;
}
bool Trust_anchor::Initialize::execute(Trust_anchor::Attr const &ta_attr)
{
bool progress = false;
switch (_helper.state) {
case INIT:
_file.construct(_helper.state, ta_attr.initialize_file);
_helper.state = WRITE;
progress = true;
break;
case WRITE: _file->write(WRITE_OK, FILE_ERR, 0, { _attr.in_passphrase.string(), _attr.in_passphrase.length() - 1 }, progress); break;
case WRITE_OK: _file->read(READ_OK, FILE_ERR, 0, { _result_buf, sizeof(_result_buf) }, progress); break;
case READ_OK:
if (strcmp(_result_buf, "ok", sizeof(_result_buf)))
_mark_req_failed(progress, { "trust anchor did not return \"ok\""});
_helper.mark_failed(progress, {"trust anchor did not return \"ok\""});
else
_mark_req_successful(progress);
_helper.mark_succeeded(progress);
break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
case FILE_ERR: _helper.mark_failed(progress, "file operation failed"); break;
default: break;
}
}
void Trust_anchor_channel::_write_hash(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _hashsum_file.write(WRITE_OK, FILE_ERR, 0, { (char *)&req._hash, HASH_SIZE }, progress); break;
case WRITE_OK: _hashsum_file.read(READ_OK, FILE_ERR, 0, { _result_buf, 0 }, progress); break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
default: break;
}
}
void Trust_anchor_channel::_encrypt_key(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _encrypt_file.write(WRITE_OK, FILE_ERR, 0, { (char *)&req._key_plaintext, KEY_SIZE }, progress); break;
case WRITE_OK: _encrypt_file.read(READ_OK, FILE_ERR, 0, { (char *)&req._key_ciphertext, KEY_SIZE }, progress); break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
default: break;
}
}
void Trust_anchor_channel::_decrypt_key(bool &progress)
{
Request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED: _decrypt_file.write(WRITE_OK, FILE_ERR, 0, { (char *)&req._key_ciphertext, KEY_SIZE }, progress); break;
case WRITE_OK: _decrypt_file.read(READ_OK, FILE_ERR, 0, { (char *)&req._key_plaintext, KEY_SIZE }, progress); break;
case READ_OK: _mark_req_successful(progress); break;
case FILE_ERR: _mark_req_failed(progress, "file operation failed"); break;
default: break;
}
}
void Trust_anchor_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
Request &req { *_req_ptr };
switch (req._type) {
case Request::INITIALIZE: _initialize(progress); break;
case Request::WRITE_HASH: _write_hash(progress); break;
case Request::READ_HASH: _read_hash(progress); break;
case Request::CREATE_KEY: _create_key(progress); break;
case Request::ENCRYPT_KEY: _encrypt_key(progress); break;
case Request::DECRYPT_KEY: _decrypt_key(progress); break;
}
}
Trust_anchor_channel::Trust_anchor_channel(Module_channel_id id, Vfs::Env &vfs_env, Xml_node const &xml_node)
:
Module_channel { TRUST_ANCHOR, id }, _vfs_env { vfs_env }, _path { xml_node.attribute_value("path", Tresor::Path()) }
{ }
Trust_anchor::Trust_anchor(Vfs::Env &vfs_env, Xml_node const &xml_node)
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++, vfs_env, xml_node);
add_channel(*chan);
}
}
void Trust_anchor_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
void Trust_anchor::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
return progress;
}

View File

@ -13,52 +13,31 @@
/* tresor includes */
#include <tresor/vbd_check.h>
#include <tresor/block_io.h>
#include <tresor/hash.h>
using namespace Tresor;
Vbd_check_request::Vbd_check_request(Module_id src_mod, Module_channel_id src_chan, Tree_root const &vbd, bool &success)
:
Module_request { src_mod, src_chan, VBD_CHECK }, _vbd { vbd }, _success { success }
{ }
void Vbd_check_channel::_generated_req_completed(State_uint state_uint)
{
if (!_generated_req_success) {
error("vbd check: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
bool Vbd_check_channel::_execute_node(Tree_level_index lvl, Tree_node_index node_idx, bool &progress)
bool Vbd_check::Check::_execute_node(Block_io &block_io, Tree_level_index lvl, Tree_node_index node_idx, bool &progress)
{
bool &check_node = _check_node[lvl][node_idx];
if (!check_node)
return false;
Request &req { *_req_ptr };
Type_1_node const &node = _t1_blks.items[lvl].nodes[node_idx];
switch (_state) {
case REQ_IN_PROGRESS:
switch (_helper.state) {
case IN_PROGRESS:
if (lvl == 1) {
if (!_num_remaining_leaves) {
if (node.valid()) {
_mark_req_failed(progress, { "lvl ", lvl, " node ", node_idx, " (", node,
") valid but no leaves remaining" });
_helper.mark_failed(progress, { "lvl ", lvl, " node ", node_idx, " (", node,
") valid but no leaves remaining" });
break;
}
check_node = false;
progress = true;
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, ": expectedly invalid");
log(Level_indent { lvl, _attr.in_vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, ": expectedly invalid");
break;
}
if (node.gen == INITIAL_GENERATION) {
@ -66,33 +45,34 @@ bool Vbd_check_channel::_execute_node(Tree_level_index lvl, Tree_node_index node
check_node = false;
progress = true;
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, ": uninitialized");
log(Level_indent { lvl, _attr.in_vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, ": uninitialized");
break;
}
} else {
if (!node.valid()) {
if (_num_remaining_leaves) {
_mark_req_failed(progress, { "lvl ", lvl, " node ", node_idx, " invalid but ",
_num_remaining_leaves, " leaves remaining" });
_helper.mark_failed(progress, { "lvl ", lvl, " node ", node_idx, " invalid but ",
_num_remaining_leaves, " leaves remaining" });
break;
}
check_node = false;
progress = true;
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, ": expectedly invalid");
log(Level_indent { lvl, _attr.in_vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, ": expectedly invalid");
break;
}
}
_generate_req<Block_io::Read>(READ_BLK_SUCCEEDED, progress, node.pba, _blk);
_read_block.generate(_helper, READ_BLK, READ_BLK_SUCCEEDED, progress, node.pba, _blk);
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, " (", node,
log(Level_indent { lvl, _attr.in_vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, " (", node,
"): load to lvl ", lvl - 1);
break;
case READ_BLK: progress |= _read_block.execute(block_io); break;
case READ_BLK_SUCCEEDED:
if (!(lvl > 1 && node.gen == INITIAL_GENERATION) && !check_hash(_blk, node.hash)) {
_mark_req_failed(progress, { "lvl ", lvl, " node ", node_idx, " (", node, ") has bad hash" });
_helper.mark_failed(progress, { "lvl ", lvl, " node ", node_idx, " (", node, ") has bad hash" });
break;
}
if (lvl == 1)
@ -103,10 +83,10 @@ bool Vbd_check_channel::_execute_node(Tree_level_index lvl, Tree_node_index node
cn = true;
}
check_node = false;
_state = REQ_IN_PROGRESS;
_helper.state = IN_PROGRESS;
progress = true;
if (VERBOSE_CHECK)
log(Level_indent { lvl, req._vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, ": good hash");
log(Level_indent { lvl, _attr.in_vbd.max_lvl }, " lvl ", lvl, " node ", node_idx, ": good hash");
break;
default: break;
@ -115,69 +95,24 @@ bool Vbd_check_channel::_execute_node(Tree_level_index lvl, Tree_node_index node
}
void Vbd_check_channel::execute(bool &progress)
bool Vbd_check::Check::execute(Block_io &block_io)
{
if (!_req_ptr)
return;
Request &req { *_req_ptr };
if (_state == REQ_SUBMITTED) {
for (Tree_level_index lvl { 1 }; lvl <= req._vbd.max_lvl + 1; lvl++)
for (Tree_node_index node_idx { 0 }; node_idx < req._vbd.degree; node_idx++)
bool progress = false;
if (_helper.state == INIT) {
for (Tree_level_index lvl { 1 }; lvl <= _attr.in_vbd.max_lvl + 1; lvl++)
for (Tree_node_index node_idx { 0 }; node_idx < _attr.in_vbd.degree; node_idx++)
_check_node[lvl][node_idx] = false;
_num_remaining_leaves = req._vbd.num_leaves;
_t1_blks.items[req._vbd.max_lvl + 1].nodes[0] = req._vbd.t1_node();
_check_node[req._vbd.max_lvl + 1][0] = true;
_state = REQ_IN_PROGRESS;
_num_remaining_leaves = _attr.in_vbd.num_leaves;
_t1_blks.items[_attr.in_vbd.max_lvl + 1].nodes[0] = _attr.in_vbd.t1_node();
_check_node[_attr.in_vbd.max_lvl + 1][0] = true;
_helper.state = IN_PROGRESS;
}
for (Tree_level_index lvl { 1 }; lvl <= req._vbd.max_lvl + 1; lvl++)
for (Tree_node_index node_idx { 0 }; node_idx < req._vbd.degree; node_idx++)
if (_execute_node(lvl, node_idx, progress))
return;
for (Tree_level_index lvl { 1 }; lvl <= _attr.in_vbd.max_lvl + 1; lvl++)
for (Tree_node_index node_idx { 0 }; node_idx < _attr.in_vbd.degree; node_idx++)
if (_execute_node(block_io, lvl, node_idx, progress))
return progress;
_mark_req_successful(progress);
}
void Vbd_check_channel::_mark_req_failed(bool &progress, Error_string str)
{
error("vbd check request (", *_req_ptr, ") failed: ", str);
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Vbd_check_channel::_mark_req_successful(bool &progress)
{
_req_ptr->_success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Vbd_check_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = REQ_SUBMITTED;
}
Vbd_check::Vbd_check()
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
}
}
void Vbd_check::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
_helper.mark_succeeded(progress);
return progress;
}

View File

@ -13,20 +13,12 @@
*/
/* tresor includes */
#include <tresor/block_io.h>
#include <tresor/hash.h>
#include <tresor/vbd_initializer.h>
using namespace Tresor;
Vbd_initializer_request::Vbd_initializer_request(Module_id src_mod, Module_channel_id src_chan, Tree_root &vbd,
Pba_allocator &pba_alloc, bool &success)
:
Module_request { src_mod, src_chan, VBD_INITIALIZER }, _vbd { vbd }, _pba_alloc { pba_alloc }, _success { success }
{ }
bool Vbd_initializer_channel::_execute_node(Tree_level_index lvl, Tree_node_index node_idx, bool &progress)
bool Vbd_initializer::Initialize::_execute_node(Tree_level_index lvl, Tree_node_index node_idx, bool &progress)
{
Type_1_node &node = _t1_blks.items[lvl].nodes[node_idx];
Node_state &node_state = _node_states[lvl][node_idx];
@ -58,8 +50,8 @@ bool Vbd_initializer_channel::_execute_node(Tree_level_index lvl, Tree_node_inde
if (lvl == 1)
if (_num_remaining_leaves) {
node = { };
if (!_req_ptr->_pba_alloc.alloc(node.pba)) {
_mark_req_failed(progress, "allocate pba");
if (!_attr.in_out_pba_alloc.alloc(node.pba)) {
_helper.mark_failed(progress, "allocate pba");
break;
}
node_state = DONE;
@ -76,21 +68,20 @@ bool Vbd_initializer_channel::_execute_node(Tree_level_index lvl, Tree_node_inde
}
else {
node = { };
if (!_req_ptr->_pba_alloc.alloc(node.pba)) {
_mark_req_failed(progress, "allocate pba");
if (!_attr.in_out_pba_alloc.alloc(node.pba)) {
_helper.mark_failed(progress, "allocate pba");
break;
}
_t1_blks.items[lvl - 1].encode_to_blk(_blk);
calc_hash(_blk, node.hash);
node_state = WRITE_BLOCK;
generate_req<Block_io::Write>(EXECUTE_NODES, progress, node.pba, _blk, _generated_req_success);
_state = REQ_GENERATED;
_write_block.generate(_helper, WRITE_BLOCK, EXECUTE_NODES, progress, node.pba, _blk);
node_state = WRITING_BLOCK;
if (VERBOSE_VBD_INIT)
log("[vbd_init] node: ", lvl, " ", node_idx, " assign pba: ", node.pba);
}
break;
case WRITE_BLOCK:
case WRITING_BLOCK:
ASSERT(lvl > 1);
node_state = DONE;
@ -103,103 +94,47 @@ bool Vbd_initializer_channel::_execute_node(Tree_level_index lvl, Tree_node_inde
}
void Vbd_initializer_channel::_generated_req_completed(State_uint state_uint)
bool Vbd_initializer::Initialize::execute(Block_io &block_io)
{
if (!_generated_req_success) {
error("vbd initializer: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
bool progress = false;
switch (_helper.state) {
case INIT:
void Vbd_initializer_channel::_mark_req_failed(bool &progress, char const *str)
{
error("vbd_initializer request (", *_req_ptr, ") failed because: ", str);
_req_ptr->_success = false;
_state = COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Vbd_initializer_channel::_mark_req_successful(bool &progress)
{
_req_ptr->_vbd.t1_node(_t1_blks.items[_req_ptr->_vbd.max_lvl + 1].nodes[0]);
_req_ptr->_success = true;
_state = COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Vbd_initializer_channel::_request_submitted(Module_request &mod_req)
{
_req_ptr = static_cast<Request *>(&mod_req);
_state = SUBMITTED;
}
void Vbd_initializer_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
Request &req { *_req_ptr };
switch (_state) {
case SUBMITTED:
_num_remaining_leaves = req._vbd.num_leaves;
_num_remaining_leaves = _attr.in_tree_cfg.num_leaves;
for (Tree_level_index lvl = 0; lvl < TREE_MAX_LEVEL; lvl++)
_reset_level(lvl, Vbd_initializer_channel::DONE);
_reset_level(lvl, Vbd_initializer::Initialize::DONE);
_node_states[req._vbd.max_lvl + 1][0] = Vbd_initializer_channel::INIT_BLOCK;
_state = EXECUTE_NODES;
_node_states[_attr.in_tree_cfg.max_lvl + 1][0] = Vbd_initializer::Initialize::INIT_BLOCK;
_helper.state = EXECUTE_NODES;
progress = true;
return;
break;
case EXECUTE_NODES:
for (Tree_level_index lvl = 0; lvl <= req._vbd.max_lvl + 1; lvl++)
for (Tree_node_index node_idx = 0; node_idx < req._vbd.degree; node_idx++)
for (Tree_level_index lvl = 0; lvl <= _attr.in_tree_cfg.max_lvl + 1; lvl++)
for (Tree_node_index node_idx = 0; node_idx < _attr.in_tree_cfg.degree; node_idx++)
if (_execute_node(lvl, node_idx, progress))
return;
return progress;
if (_num_remaining_leaves)
_mark_req_failed(progress, "leaves remaining");
else
_mark_req_successful(progress);
return;
_helper.mark_failed(progress, "leaves remaining");
else {
_attr.out_tree_root = _t1_blks.items[_attr.in_tree_cfg.max_lvl + 1].nodes[0];
_helper.mark_succeeded(progress);
}
break;
default: return;
case WRITE_BLOCK: progress |= _write_block.execute(block_io); break;
default: break;
}
return progress;
}
void Vbd_initializer_channel::_reset_level(Tree_level_index lvl, Node_state state)
void Vbd_initializer::Initialize::_reset_level(Tree_level_index lvl, Node_state state)
{
for (unsigned int idx = 0; idx < NUM_NODES_PER_BLK; idx++) {
_t1_blks.items[lvl].nodes[idx] = { };
_node_states[lvl][idx] = state;
}
}
Vbd_initializer::Vbd_initializer()
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
}
}
void Vbd_initializer::execute(bool &progress)
{
for_each_channel<Channel>([&] (Channel &chan) {
chan.execute(progress); });
}

File diff suppressed because it is too large Load Diff

View File

@ -1,225 +0,0 @@
/*
* \brief Module for splitting unaligned/uneven I/O requests
* \author Martin Stein
* \author Josef Soentgen
* \date 2023-09-11
*/
/*
* Copyright (C) 2023 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.
*/
/* vfs tresor includes */
#include <splitter.h>
using namespace Tresor;
Splitter_request::Splitter_request(Module_id src_mod, Module_channel_id src_chan, Operation op, bool &success,
Request_offset off, Byte_range_ptr const &buf, Key_id key_id, Generation gen)
:
Module_request { src_mod, src_chan, SPLITTER }, _op { op }, _off { off }, _key_id { key_id }, _gen { gen },
_buf { buf.start, buf.num_bytes }, _success { success }
{ }
char const *Splitter_request::op_to_string(Operation op)
{
switch (op) {
case Operation::READ: return "read";
case Operation::WRITE: return "write";
}
ASSERT_NEVER_REACHED;
}
void Splitter_channel::_generated_req_completed(State_uint state_uint)
{
if (!_generated_req_success) {
error("splitter: request (", *_req_ptr, ") failed because generated request failed)");
_req_ptr->_success = false;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
return;
}
_state = (State)state_uint;
}
void Splitter_channel::_mark_req_successful(bool &progress)
{
Request &req { *_req_ptr };
req._success = true;
_state = REQ_COMPLETE;
_req_ptr = nullptr;
progress = true;
}
void Splitter_channel::_request_submitted(Module_request &req)
{
_req_ptr = static_cast<Request*>(&req);
_state = REQ_SUBMITTED;
}
void Splitter_channel::_advance_curr_off(addr_t advance, Tresor::Request::Operation op, bool &progress)
{
Splitter_request &req { *_req_ptr };
_curr_off += advance;
if (!_num_remaining_bytes()) {
_mark_req_successful(progress);
} else if (_curr_off % BLOCK_SIZE) {
_curr_buf_addr = (addr_t)&_blk;
_generate_req<Tresor::Request>(
PROTRUDING_FIRST_BLK_READ, progress, Tresor::Request::READ, _curr_vba(), 0, 1, req._key_id, id(), _gen);
} else if (_num_remaining_bytes() < BLOCK_SIZE) {
_curr_buf_addr = (addr_t)&_blk;
_generate_req<Tresor::Request>(
PROTRUDING_LAST_BLK_READ, progress, Tresor::Request::READ, _curr_vba(), 0, 1, req._key_id, id(), _gen);
} else {
_curr_buf_addr = (addr_t)req._buf.start + _curr_buf_off();
_generate_req<Tresor::Request>(
INSIDE_BLKS_ACCESSED, progress, op, _curr_vba(), 0, _num_remaining_bytes() / BLOCK_SIZE, req._key_id, id(), _gen);
}
}
void Splitter_channel::_write(bool &progress)
{
Splitter_request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
_curr_off = 0;
_gen = req._gen;
_advance_curr_off(req._off, Tresor::Request::WRITE, progress);
break;
case PROTRUDING_FIRST_BLK_READ:
{
size_t num_outside_bytes { _curr_off % BLOCK_SIZE };
size_t num_inside_bytes { min(_num_remaining_bytes(), BLOCK_SIZE - num_outside_bytes) };
memcpy((void *)((addr_t)&_blk + num_outside_bytes), req._buf.start, num_inside_bytes);
_curr_buf_addr = (addr_t)&_blk;
_generate_req<Tresor::Request>(
PROTRUDING_FIRST_BLK_WRITTEN, progress, Tresor::Request::WRITE, _curr_vba(), 0, 1, req._key_id, id(), _gen);
break;
}
case PROTRUDING_FIRST_BLK_WRITTEN:
{
size_t num_outside_bytes { _curr_off % BLOCK_SIZE };
size_t num_inside_bytes { min(_num_remaining_bytes(), BLOCK_SIZE - num_outside_bytes) };
_advance_curr_off(num_inside_bytes, Tresor::Request::WRITE, progress);
break;
}
case INSIDE_BLKS_ACCESSED:
_advance_curr_off((_num_remaining_bytes() / BLOCK_SIZE) * BLOCK_SIZE, Tresor::Request::WRITE, progress);
break;
case PROTRUDING_LAST_BLK_READ:
memcpy(&_blk, (void *)((addr_t)req._buf.start + _curr_buf_off()), _num_remaining_bytes());
_curr_buf_addr = (addr_t)&_blk;
_generate_req<Tresor::Request>(
PROTRUDING_LAST_BLK_WRITTEN, progress, Tresor::Request::WRITE, _curr_vba(), 0, 1, req._key_id, id(), _gen);
break;
case PROTRUDING_LAST_BLK_WRITTEN: _advance_curr_off(_num_remaining_bytes(), Tresor::Request::WRITE, progress); break;
default: break;
}
}
void Splitter_channel::_read(bool &progress)
{
Splitter_request &req { *_req_ptr };
switch (_state) {
case REQ_SUBMITTED:
_curr_off = 0;
_gen = req._gen;
_advance_curr_off(req._off, Tresor::Request::READ, progress);
break;
case PROTRUDING_FIRST_BLK_READ:
{
size_t num_outside_bytes { _curr_off % BLOCK_SIZE };
size_t num_inside_bytes { min(_num_remaining_bytes(), BLOCK_SIZE - num_outside_bytes) };
memcpy(req._buf.start, (void *)((addr_t)&_blk + num_outside_bytes), num_inside_bytes);
_advance_curr_off(num_inside_bytes, Tresor::Request::READ, progress);
break;
}
case INSIDE_BLKS_ACCESSED:
_advance_curr_off((_num_remaining_bytes() / BLOCK_SIZE) * BLOCK_SIZE, Tresor::Request::READ, progress);
break;
case PROTRUDING_LAST_BLK_READ:
memcpy((void *)((addr_t)req._buf.start + _curr_buf_off()), &_blk, _num_remaining_bytes());
_advance_curr_off(_num_remaining_bytes(), Tresor::Request::READ, progress);
break;
default: break;
}
}
void Splitter_channel::execute(bool &progress)
{
if (!_req_ptr)
return;
switch (_req_ptr->_op) {
case Request::READ: _read(progress); break;
case Request::WRITE: _write(progress); break;
}
}
Block &Splitter_channel::_blk_buf_for_vba(Virtual_block_address vba)
{
ASSERT(_state == REQ_GENERATED);
return *(Block *)(_curr_buf_addr + (vba - _curr_vba()) * BLOCK_SIZE);
}
Block const &Splitter::src_for_writing_vba(Request_tag tag, Virtual_block_address vba)
{
Block const *blk_ptr { };
with_channel<Splitter_channel>(tag, [&] (Splitter_channel &chan) {
blk_ptr = &chan.src_for_writing_vba(vba); });
ASSERT(blk_ptr);
return *blk_ptr;
}
Block &Splitter::dst_for_reading_vba(Request_tag tag, Virtual_block_address vba)
{
Block *blk_ptr { };
with_channel<Splitter_channel>(tag, [&] (Splitter_channel &chan) {
blk_ptr = &chan.dst_for_reading_vba(vba); });
ASSERT(blk_ptr);
return *blk_ptr;
}
Splitter::Splitter()
{
Module_channel_id id { 0 };
for (Constructible<Channel> &chan : _channels) {
chan.construct(id++);
add_channel(*chan);
}
}
void Splitter::execute(bool &progress)
{
for_each_channel<Splitter_channel>([&] (Splitter_channel &chan) {
chan.execute(progress); });
}

View File

@ -16,141 +16,393 @@
#define _TRESOR__IO_SPLITTER_H_
/* tresor includes */
#include <tresor/request_pool.h>
#include <tresor/superblock_control.h>
namespace Tresor {
namespace Tresor { class Splitter; }
struct Lookup_buffer : Genode::Interface
{
virtual Block const &src_for_writing_vba(Request_tag, Virtual_block_address) = 0;
virtual Block &dst_for_reading_vba(Request_tag, Virtual_block_address) = 0;
};
class Splitter_request;
class Splitter_channel;
class Splitter;
}
class Tresor::Splitter_request : public Tresor::Module_request
struct Tresor::Splitter : Noncopyable
{
friend class Splitter_channel;
public:
enum Operation { READ, WRITE };
class Read : Noncopyable
{
public:
using Module = Splitter;
struct Attr
{
Request_offset const in_off;
Generation const in_gen;
char *const in_buf_start;
size_t const in_buf_num_bytes;
};
struct Execute_attr
{
Superblock_control &sb_control;
Virtual_block_device &vbd;
Client_data_interface &client_data;
Block_io &block_io;
Crypto &crypto;
};
private:
enum State {
INIT, COMPLETE, READ_FIRST_VBA, READ_FIRST_VBA_SUCCEEDED, READ_LAST_VBA, READ_LAST_VBA_SUCCEEDED,
READ_MIDDLE_VBAS, READ_MIDDLE_VBAS_SUCCEEDED };
Request_helper<Read, State> _helper;
Attr const _attr;
addr_t _curr_off { };
addr_t _curr_buf_addr { };
Block _blk { };
Generation _gen { };
Constructible<Superblock_control::Read_vbas> _read_vbas { };
Virtual_block_address _curr_vba() const { return (Virtual_block_address)(_curr_off / BLOCK_SIZE); }
void _generate_read(State target_state, bool &progress)
{
Number_of_blocks num_blocks =
target_state == READ_MIDDLE_VBAS ? _num_remaining_bytes() / BLOCK_SIZE : 1;
_read_vbas.construct(Superblock_control::Read_vbas::Attr{_curr_vba(), num_blocks, 0, 0});
_helper.state = target_state;
progress = true;
}
bool _execute_read(State succeeded_state, Execute_attr const &attr)
{
bool progress = attr.sb_control.execute(*_read_vbas, attr.vbd, attr.client_data, attr.block_io, attr.crypto);
if (_read_vbas->complete()) {
if (_read_vbas->success())
_helper.generated_req_succeeded(succeeded_state, progress);
else
_helper.generated_req_failed(progress);
}
return progress;
}
addr_t _curr_buf_off() const
{
ASSERT(_curr_off >= _attr.in_off && _curr_off <= _attr.in_off + _attr.in_buf_num_bytes);
return _curr_off - _attr.in_off;
}
addr_t _num_remaining_bytes() const
{
ASSERT(_curr_off >= _attr.in_off && _curr_off <= _attr.in_off + _attr.in_buf_num_bytes);
return _attr.in_off + _attr.in_buf_num_bytes - _curr_off;
}
void _advance_curr_off(size_t advance, bool &progress)
{
_curr_off += advance;
if (!_num_remaining_bytes()) {
_helper.mark_succeeded(progress);
} else if (_curr_off % BLOCK_SIZE) {
_curr_buf_addr = (addr_t)&_blk;
_generate_read(READ_FIRST_VBA, progress);
} else if (_num_remaining_bytes() < BLOCK_SIZE) {
_curr_buf_addr = (addr_t)&_blk;
_generate_read(READ_LAST_VBA, progress);
} else {
_curr_buf_addr = (addr_t)_attr.in_buf_start + _curr_buf_off();
_generate_read(READ_MIDDLE_VBAS, progress);
}
}
public:
Read(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "read"); }
bool execute(Execute_attr const &attr)
{
bool progress = false;
switch (_helper.state) {
case INIT:
_gen = _attr.in_gen;
_advance_curr_off(_attr.in_off, progress);
break;
case READ_FIRST_VBA: progress |= _execute_read(READ_FIRST_VBA_SUCCEEDED, attr); break;
case READ_FIRST_VBA_SUCCEEDED:
{
size_t num_outside_bytes { _curr_off % BLOCK_SIZE };
size_t num_inside_bytes { min(_num_remaining_bytes(), BLOCK_SIZE - num_outside_bytes) };
memcpy(_attr.in_buf_start, (void *)((addr_t)&_blk + num_outside_bytes), num_inside_bytes);
_advance_curr_off(num_inside_bytes, progress);
break;
}
case READ_MIDDLE_VBAS: progress |= _execute_read(READ_MIDDLE_VBAS_SUCCEEDED, attr); break;
case READ_MIDDLE_VBAS_SUCCEEDED:
_advance_curr_off((_num_remaining_bytes() / BLOCK_SIZE) * BLOCK_SIZE, progress);
break;
case READ_LAST_VBA: progress |= _execute_read(READ_LAST_VBA_SUCCEEDED, attr); break;
case READ_LAST_VBA_SUCCEEDED:
memcpy((void *)((addr_t)_attr.in_buf_start + _curr_buf_off()), &_blk, _num_remaining_bytes());
_advance_curr_off(_num_remaining_bytes(), progress);
break;
default: break;
}
return progress;
}
Block &destination_buffer(Virtual_block_address vba)
{
return *(Block *)(_curr_buf_addr + (vba - _curr_vba()) * BLOCK_SIZE);
}
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
class Write : Noncopyable
{
public:
using Module = Splitter;
struct Attr
{
Request_offset const in_off;
Generation const in_gen;
char const *const in_buf_start;
size_t const in_buf_num_bytes;
};
struct Execute_attr
{
Superblock_control &sb_control;
Virtual_block_device &vbd;
Client_data_interface &client_data;
Block_io &block_io;
Free_tree &free_tree;
Meta_tree &meta_tree;
Crypto &crypto;
};
private:
enum State {
INIT, COMPLETE, READ_FIRST_VBA, READ_FIRST_VBA_SUCCEEDED, READ_LAST_VBA, READ_LAST_VBA_SUCCEEDED,
WRITE_FIRST_VBA, WRITE_FIRST_VBA_SUCCEEDED, WRITE_LAST_VBA, WRITE_LAST_VBA_SUCCEEDED,
WRITE_MIDDLE_VBAS, WRITE_MIDDLE_VBAS_SUCCEEDED };
Request_helper<Write, State> _helper;
Attr const _attr;
addr_t _curr_off { };
addr_t _curr_buf_addr { };
Block _blk { };
Generation _gen { };
Constructible<Superblock_control::Read_vbas> _read_vbas { };
Constructible<Superblock_control::Write_vbas> _write_vbas { };
Virtual_block_address _curr_vba() const { return (Virtual_block_address)(_curr_off / BLOCK_SIZE); }
addr_t _curr_buf_off() const
{
ASSERT(_curr_off >= _attr.in_off && _curr_off <= _attr.in_off + _attr.in_buf_num_bytes);
return _curr_off - _attr.in_off;
}
addr_t _num_remaining_bytes() const
{
ASSERT(_curr_off >= _attr.in_off && _curr_off <= _attr.in_off + _attr.in_buf_num_bytes);
return _attr.in_off + _attr.in_buf_num_bytes - _curr_off;
}
void _generate_sb_control_request(State target_state, bool &progress)
{
Number_of_blocks num_blocks =
target_state == WRITE_MIDDLE_VBAS ? _num_remaining_bytes() / BLOCK_SIZE : 1;
switch (target_state) {
case READ_FIRST_VBA:
case READ_LAST_VBA: _read_vbas.construct(Superblock_control::Read_vbas::Attr{_curr_vba(), num_blocks, 0, 0}); break;
case WRITE_FIRST_VBA:
case WRITE_MIDDLE_VBAS:
case WRITE_LAST_VBA: _write_vbas.construct(Superblock_control::Write_vbas::Attr{_curr_vba(), num_blocks, 0, 0}); break;
default: ASSERT_NEVER_REACHED;
}
_helper.state = target_state;
progress = true;
}
void _advance_curr_off(size_t advance, bool &progress)
{
_curr_off += advance;
if (!_num_remaining_bytes()) {
_helper.mark_succeeded(progress);
} else if (_curr_off % BLOCK_SIZE) {
_curr_buf_addr = (addr_t)&_blk;
_generate_sb_control_request(READ_FIRST_VBA, progress);
} else if (_num_remaining_bytes() < BLOCK_SIZE) {
_curr_buf_addr = (addr_t)&_blk;
_generate_sb_control_request(READ_LAST_VBA, progress);
} else {
_curr_buf_addr = (addr_t)_attr.in_buf_start + _curr_buf_off();
_generate_sb_control_request(WRITE_MIDDLE_VBAS, progress);
}
}
bool _execute_read(State succeeded_state, Execute_attr const &attr)
{
bool progress = attr.sb_control.execute(*_read_vbas, attr.vbd, attr.client_data, attr.block_io, attr.crypto);
if (_read_vbas->complete()) {
if (_read_vbas->success())
_helper.generated_req_succeeded(succeeded_state, progress);
else
_helper.generated_req_failed(progress);
}
return progress;
}
bool _execute_write(State succeeded_state, Execute_attr const &attr)
{
bool progress = attr.sb_control.execute(*_write_vbas, attr.vbd, attr.client_data, attr.block_io, attr.free_tree, attr.meta_tree, attr.crypto);
if (_write_vbas->complete()) {
if (_write_vbas->success())
_helper.generated_req_succeeded(succeeded_state, progress);
else
_helper.generated_req_failed(progress);
}
return progress;
}
public:
Write(Attr const &attr) : _helper(*this), _attr(attr) { }
void print(Output &out) const { Genode::print(out, "write"); }
bool execute(Execute_attr const &attr)
{
bool progress = false;
switch (_helper.state) {
case INIT:
_gen = _attr.in_gen;
_advance_curr_off(_attr.in_off, progress);
break;
case READ_FIRST_VBA: progress |= _execute_read(READ_FIRST_VBA_SUCCEEDED, attr); break;
case READ_FIRST_VBA_SUCCEEDED:
{
size_t num_outside_bytes { _curr_off % BLOCK_SIZE };
size_t num_inside_bytes { min(_num_remaining_bytes(), BLOCK_SIZE - num_outside_bytes) };
memcpy((void *)((addr_t)&_blk + num_outside_bytes), _attr.in_buf_start, num_inside_bytes);
_curr_buf_addr = (addr_t)&_blk;
_generate_sb_control_request(WRITE_FIRST_VBA, progress);
break;
}
case WRITE_FIRST_VBA: progress |= _execute_write(WRITE_FIRST_VBA_SUCCEEDED, attr); break;
case WRITE_FIRST_VBA_SUCCEEDED:
{
size_t num_outside_bytes { _curr_off % BLOCK_SIZE };
size_t num_inside_bytes { min(_num_remaining_bytes(), BLOCK_SIZE - num_outside_bytes) };
_advance_curr_off(num_inside_bytes, progress);
break;
}
case WRITE_MIDDLE_VBAS: progress |= _execute_write(WRITE_MIDDLE_VBAS_SUCCEEDED, attr); break;
case WRITE_MIDDLE_VBAS_SUCCEEDED:
_advance_curr_off((_num_remaining_bytes() / BLOCK_SIZE) * BLOCK_SIZE, progress);
break;
case READ_LAST_VBA: progress |= _execute_read(READ_LAST_VBA_SUCCEEDED, attr); break;
case READ_LAST_VBA_SUCCEEDED:
memcpy(&_blk, (void *)((addr_t)_attr.in_buf_start + _curr_buf_off()), _num_remaining_bytes());
_curr_buf_addr = (addr_t)&_blk;
_generate_sb_control_request(WRITE_LAST_VBA, progress);
break;
case WRITE_LAST_VBA: progress |= _execute_write(WRITE_LAST_VBA_SUCCEEDED, attr); break;
case WRITE_LAST_VBA_SUCCEEDED: _advance_curr_off(_num_remaining_bytes(), progress); break;
default: break;
}
return progress;
}
Block const &source_buffer(Virtual_block_address vba)
{
return *(Block *)(_curr_buf_addr + (vba - _curr_vba()) * BLOCK_SIZE);
}
Block &destination_buffer()
{
ASSERT(_helper.state == READ_FIRST_VBA || _helper.state == READ_LAST_VBA);
return _blk;
}
bool complete() const { return _helper.complete(); }
bool success() const { return _helper.success(); }
};
private:
Operation const _op;
Request_offset const _off;
Key_id const _key_id;
Generation const _gen;
Byte_range_ptr const _buf;
bool &_success;
NONCOPYABLE(Splitter_request);
Read *_read_ptr { };
Write *_write_ptr { };
public:
Splitter_request(Module_id, Module_channel_id, Operation, bool &, Request_offset, Byte_range_ptr const &, Key_id, Generation);
static char const *op_to_string(Operation);
void print(Genode::Output &out) const override { Genode::print(out, op_to_string(_op), " off ", _off, " size ", _buf.num_bytes); }
};
class Tresor::Splitter_channel : public Tresor::Module_channel
{
private:
using Request = Splitter_request;
enum State : State_uint {
PROTRUDING_FIRST_BLK_WRITTEN, PROTRUDING_LAST_BLK_WRITTEN, PROTRUDING_FIRST_BLK_READ, PROTRUDING_LAST_BLK_READ, INSIDE_BLKS_ACCESSED,
REQ_SUBMITTED, REQ_GENERATED, REQ_COMPLETE };
State _state { };
Request *_req_ptr { };
addr_t _curr_off { };
addr_t _curr_buf_addr { };
Block _blk { };
Generation _gen { };
bool _generated_req_success { };
NONCOPYABLE(Splitter_channel);
void _generated_req_completed(State_uint) override;
void _request_submitted(Module_request &) override;
bool _request_complete() override { return _state == REQ_COMPLETE; }
Virtual_block_address _curr_vba() const { return (Virtual_block_address)(_curr_off / BLOCK_SIZE); }
addr_t _curr_buf_off() const
bool execute(Read &req, Read::Execute_attr const &attr)
{
ASSERT(_curr_off >= _req_ptr->_off && _curr_off <= _req_ptr->_off + _req_ptr->_buf.num_bytes);
return _curr_off - _req_ptr->_off;
if (!_read_ptr && !_write_ptr)
_read_ptr = &req;
if (_read_ptr != &req)
return false;
bool progress = req.execute(attr);
if (req.complete())
_read_ptr = nullptr;
return progress;
}
addr_t _num_remaining_bytes() const
bool execute(Write &req, Write::Execute_attr const &attr)
{
ASSERT(_curr_off >= _req_ptr->_off && _curr_off <= _req_ptr->_off + _req_ptr->_buf.num_bytes);
return _req_ptr->_off + _req_ptr->_buf.num_bytes - _curr_off;
if (!_write_ptr && !_write_ptr)
_write_ptr = &req;
if (_write_ptr != &req)
return false;
bool progress = req.execute(attr);
if (req.complete())
_write_ptr = nullptr;
return progress;
}
template <typename REQUEST, typename... ARGS>
void _generate_req(State_uint state, bool &progress, ARGS &&... args)
Block const &source_buffer(Virtual_block_address vba)
{
_state = REQ_GENERATED;
generate_req<REQUEST>(state, progress, args..., _generated_req_success);
ASSERT(_write_ptr);
return _write_ptr->source_buffer(vba);
}
void _mark_req_successful(bool &);
Block &destination_buffer(Virtual_block_address vba)
{
if (_read_ptr)
return _read_ptr->destination_buffer(vba);
if (_write_ptr)
return _write_ptr->destination_buffer();
ASSERT_NEVER_REACHED;
}
void _advance_curr_off(addr_t, Tresor::Request::Operation, bool &);
void _read(bool &progress);
void _write(bool &progress);
Block &_blk_buf_for_vba(Virtual_block_address);
public:
Splitter_channel(Module_channel_id id) : Module_channel { SPLITTER, id } { }
void execute(bool &progress);
Block const &src_for_writing_vba(Virtual_block_address vba) { return _blk_buf_for_vba(vba); }
Block &dst_for_reading_vba(Virtual_block_address vba) { return _blk_buf_for_vba(vba); }
static constexpr char const *name() { return "sb_control"; }
};
class Tresor::Splitter : public Tresor::Module, public Tresor::Lookup_buffer
{
private:
using Channel = Splitter_channel;
Constructible<Channel> _channels[1] { };
NONCOPYABLE(Splitter);
public:
Splitter();
void execute(bool &) override;
Block const &src_for_writing_vba(Request_tag, Virtual_block_address) override;
Block &dst_for_reading_vba(Request_tag, Virtual_block_address) override;
};
#endif /* _TRESOR__IO_SPLITTER_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -65,10 +65,7 @@ class Vfs_tresor_crypto::Encrypt_file_system : public Vfs::Single_file_system
Tresor_crypto::Interface &crypto,
uint32_t key_id)
:
Single_vfs_handle { ds, fs, alloc, 0 },
_crypto { crypto },
_key_id { key_id },
_state { State::NONE }
Single_vfs_handle(ds, fs, alloc, 0), _crypto(crypto), _key_id(key_id), _state(State::NONE)
{ }
Read_result read(Byte_range_ptr const &dst, size_t &out_count) override
@ -130,10 +127,8 @@ class Vfs_tresor_crypto::Encrypt_file_system : public Vfs::Single_file_system
Encrypt_file_system(Tresor_crypto::Interface &crypto, uint32_t key_id)
:
Single_file_system { Node_type::TRANSACTIONAL_FILE, type_name(),
Node_rwx::rw(), Xml_node("<encrypt/>") },
_crypto { crypto },
_key_id { key_id }
Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(), Node_rwx::rw(), Xml_node("<encrypt/>")),
_crypto(crypto), _key_id(key_id)
{ }
static char const *type_name() { return "encrypt"; }
@ -199,10 +194,7 @@ class Vfs_tresor_crypto::Decrypt_file_system : public Vfs::Single_file_system
Tresor_crypto::Interface &crypto,
uint32_t key_id)
:
Single_vfs_handle { ds, fs, alloc, 0 },
_crypto { crypto },
_key_id { key_id },
_state { State::NONE }
Single_vfs_handle(ds, fs, alloc, 0), _crypto(crypto), _key_id(key_id), _state(State::NONE)
{ }
Read_result read(Byte_range_ptr const &dst, size_t &out_count) override
@ -261,10 +253,8 @@ class Vfs_tresor_crypto::Decrypt_file_system : public Vfs::Single_file_system
Decrypt_file_system(Tresor_crypto::Interface &crypto, uint32_t key_id)
:
Single_file_system { Node_type::TRANSACTIONAL_FILE, type_name(),
Node_rwx::rw(), Xml_node("<decrypt/>") },
_crypto { crypto },
_key_id { key_id }
Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(), Node_rwx::rw(), Xml_node("<decrypt/>")),
_crypto(crypto), _key_id(key_id)
{ }
static char const *type_name() { return "decrypt"; }
@ -317,8 +307,7 @@ struct Vfs_tresor_crypto::Key_local_factory : File_system_factory
Key_local_factory(Tresor_crypto::Interface &crypto,
uint32_t key_id)
:
_encrypt_fs { crypto, key_id },
_decrypt_fs { crypto, key_id }
_encrypt_fs(crypto, key_id), _decrypt_fs(crypto, key_id)
{ }
Vfs::File_system *create(Vfs::Env&, Xml_node node) override
@ -364,11 +353,8 @@ class Vfs_tresor_crypto::Key_file_system : private Key_local_factory,
Tresor_crypto::Interface &crypto,
uint32_t key_id)
:
Key_local_factory { crypto, key_id },
Vfs::Dir_file_system { vfs_env,
Xml_node(_config(key_id).string()),
*this },
_key_id { key_id }
Key_local_factory(crypto, key_id),
Vfs::Dir_file_system(vfs_env, Xml_node(_config(key_id).string()), *this), _key_id(key_id)
{ }
static char const *type_name() { return "keys"; }
@ -405,8 +391,7 @@ class Vfs_tresor_crypto::Keys_file_system : public Vfs::File_system
Key_registry(Genode::Allocator &alloc, Tresor_crypto::Interface &crypto)
:
_alloc { alloc },
_crypto { crypto }
_alloc(alloc), _crypto(crypto)
{ }
void update(Vfs::Env &vfs_env)
@ -652,8 +637,7 @@ class Vfs_tresor_crypto::Keys_file_system : public Vfs::File_system
Keys_file_system(Vfs::Env &vfs_env,
Tresor_crypto::Interface &crypto)
:
_vfs_env { vfs_env },
_key_reg { vfs_env.alloc(), crypto }
_vfs_env(vfs_env), _key_reg(vfs_env.alloc(), crypto)
{ }
static char const *type_name() { return "keys"; }
@ -940,9 +924,7 @@ class Vfs_tresor_crypto::Management_file_system : public Vfs::Single_file_system
Type type,
Tresor_crypto::Interface &crypto)
:
Single_vfs_handle { ds, fs, alloc, 0 },
_type { type },
_crypto { crypto }
Single_vfs_handle(ds, fs, alloc, 0), _type(type), _crypto(crypto)
{ }
Read_result read(Byte_range_ptr const &, size_t &) override
@ -1010,11 +992,8 @@ class Vfs_tresor_crypto::Management_file_system : public Vfs::Single_file_system
Management_file_system(Tresor_crypto::Interface &crypto, Type type, char const *type_name)
:
Single_file_system { Node_type::TRANSACTIONAL_FILE, type_name,
Node_rwx::wo(), Xml_node("<manage_keys/>") },
_type { type },
_crypto { crypto },
_type_name { type_name }
Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name, Node_rwx::wo(), Xml_node("<manage_keys/>")),
_type(type), _crypto(crypto), _type_name(type_name)
{ }
char const *type() override { return _type_name; }
@ -1090,9 +1069,7 @@ struct Vfs_tresor_crypto::Local_factory : File_system_factory
Local_factory(Vfs::Env &env,
Tresor_crypto::Interface &crypto)
:
_keys_fs { env, crypto },
_add_key_fs { crypto },
_remove_key_fs { crypto }
_keys_fs(env, crypto), _add_key_fs(crypto), _remove_key_fs(crypto)
{ }
Vfs::File_system *create(Vfs::Env&, Xml_node node) override
@ -1142,9 +1119,8 @@ class Vfs_tresor_crypto::File_system : private Local_factory,
File_system(Vfs::Env &vfs_env, Genode::Xml_node node)
:
Local_factory { vfs_env, Tresor_crypto::get_interface() },
Vfs::Dir_file_system { vfs_env, Xml_node(_config(node).string()),
*this }
Local_factory(vfs_env, Tresor_crypto::get_interface()),
Vfs::Dir_file_system(vfs_env, Xml_node(_config(node).string()), *this)
{ }
~File_system() { }

View File

@ -257,16 +257,10 @@ namespace Util {
Vfs::file_offset base_offset,
Partial_result partial_result = Partial_result::DENY)
:
_handle { handle },
_op { op },
_state { _initial_state(op) },
_data { buffer.base },
_base_offset { base_offset },
_current_offset { 0 },
_current_count { buffer.size },
_allow_partial { partial_result == Partial_result::ALLOW },
_success { false },
_complete { false }
_handle(handle), _op(op), _state(_initial_state(op)), _data(buffer.base),
_base_offset(base_offset), _current_offset(0), _current_count(buffer.size),
_allow_partial(partial_result == Partial_result::ALLOW), _success(false),
_complete(false)
{ }
bool completed() const { return _complete; }

View File

@ -712,7 +712,7 @@ class Trust_anchor
return true;
}
// XXX trigger sync
/* XXX trigger sync */
bool const progress = _private_key_io_job->execute();
bool const completed = _private_key_io_job->completed();
@ -731,7 +731,7 @@ class Trust_anchor
return true;
}
// XXX trigger sync
/* XXX trigger sync */
bool const progress = _jitterentropy_io_job->execute();
bool const completed = _jitterentropy_io_job->completed();
@ -750,7 +750,7 @@ class Trust_anchor
return true;
}
// XXX trigger sync
/* XXX trigger sync */
bool const progress = _key_io_job->execute();
bool const completed = _key_io_job->completed();
@ -960,10 +960,7 @@ class Trust_anchor
public:
Trust_anchor(Vfs::Env &vfs_env, Path const &path)
:
_vfs_env { vfs_env },
_base_path { path }
Trust_anchor(Vfs::Env &vfs_env, Path const &path) : _vfs_env(vfs_env), _base_path(path)
{
if (_check_key_file(_base_path)) {
@ -1275,8 +1272,7 @@ class Vfs_tresor_trust_anchor::Hashsum_file_system : public Vfs::Single_file_sys
Genode::Allocator &alloc,
Trust_anchor &ta)
:
Single_vfs_handle { ds, fs, alloc, 0 },
_trust_anchor { ta }
Single_vfs_handle(ds, fs, alloc, 0), _trust_anchor(ta)
{ }
Read_result read(Byte_range_ptr const &src, size_t &out_count) override
@ -1367,12 +1363,11 @@ class Vfs_tresor_trust_anchor::Hashsum_file_system : public Vfs::Single_file_sys
Hashsum_file_system(Trust_anchor &ta)
:
Single_file_system { Node_type::TRANSACTIONAL_FILE, type_name(),
Node_rwx::ro(), Xml_node("<hashsum/>") },
_trust_anchor { ta }
Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(), Node_rwx::ro(), Xml_node("<hash/>")),
_trust_anchor(ta)
{ }
static char const *type_name() { return "hashsum"; }
static char const *type_name() { return "hash"; }
char const *type() override { return type_name(); }
@ -1433,8 +1428,7 @@ class Vfs_tresor_trust_anchor::Generate_key_file_system : public Vfs::Single_fil
Genode::Allocator &alloc,
Trust_anchor &ta)
:
Single_vfs_handle { ds, fs, alloc, 0 },
_trust_anchor { ta }
Single_vfs_handle(ds, fs, alloc, 0), _trust_anchor(ta)
{ }
Read_result read(Byte_range_ptr const &dst, size_t &out_count) override
@ -1473,9 +1467,8 @@ class Vfs_tresor_trust_anchor::Generate_key_file_system : public Vfs::Single_fil
Generate_key_file_system(Trust_anchor &ta)
:
Single_file_system { Node_type::TRANSACTIONAL_FILE, type_name(),
Node_rwx::ro(), Xml_node("<generate_key/>") },
_trust_anchor { ta }
Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(), Node_rwx::ro(), Xml_node("<generate_key/>")),
_trust_anchor(ta)
{ }
static char const *type_name() { return "generate_key"; }
@ -1539,9 +1532,7 @@ class Vfs_tresor_trust_anchor::Encrypt_file_system : public Vfs::Single_file_sys
Genode::Allocator &alloc,
Trust_anchor &ta)
:
Single_vfs_handle { ds, fs, alloc, 0 },
_trust_anchor { ta },
_state { State::NONE }
Single_vfs_handle(ds, fs, alloc, 0), _trust_anchor(ta), _state(State::NONE)
{ }
Read_result read(Byte_range_ptr const &dst, size_t &out_count) override
@ -1600,9 +1591,8 @@ class Vfs_tresor_trust_anchor::Encrypt_file_system : public Vfs::Single_file_sys
Encrypt_file_system(Trust_anchor &ta)
:
Single_file_system { Node_type::TRANSACTIONAL_FILE, type_name(),
Node_rwx::rw(), Xml_node("<encrypt/>") },
_trust_anchor { ta }
Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(), Node_rwx::rw(), Xml_node("<encrypt/>")),
_trust_anchor(ta)
{ }
static char const *type_name() { return "encrypt"; }
@ -1665,9 +1655,7 @@ class Vfs_tresor_trust_anchor::Decrypt_file_system : public Vfs::Single_file_sys
Genode::Allocator &alloc,
Trust_anchor &ta)
:
Single_vfs_handle { ds, fs, alloc, 0 },
_trust_anchor { ta },
_state { State::NONE }
Single_vfs_handle(ds, fs, alloc, 0), _trust_anchor(ta), _state(State::NONE)
{ }
Read_result read(Byte_range_ptr const &dst, size_t &out_count) override
@ -1726,9 +1714,8 @@ class Vfs_tresor_trust_anchor::Decrypt_file_system : public Vfs::Single_file_sys
Decrypt_file_system(Trust_anchor &ta)
:
Single_file_system { Node_type::TRANSACTIONAL_FILE, type_name(),
Node_rwx::rw(), Xml_node("<decrypt/>") },
_trust_anchor { ta }
Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(), Node_rwx::rw(), Xml_node("<decrypt/>")),
_trust_anchor(ta)
{ }
static char const *type_name() { return "decrypt"; }
@ -1793,8 +1780,7 @@ class Vfs_tresor_trust_anchor::Initialize_file_system : public Vfs::Single_file_
Genode::Allocator &alloc,
Trust_anchor &ta)
:
Single_vfs_handle { ds, fs, alloc, 0 },
_trust_anchor { ta }
Single_vfs_handle(ds, fs, alloc, 0), _trust_anchor(ta)
{ }
Read_result read(Byte_range_ptr const &buf,
@ -1867,9 +1853,8 @@ class Vfs_tresor_trust_anchor::Initialize_file_system : public Vfs::Single_file_
Initialize_file_system(Trust_anchor &ta)
:
Single_file_system { Node_type::TRANSACTIONAL_FILE, type_name(),
Node_rwx::rw(), Xml_node("<initialize/>") },
_trust_anchor { ta }
Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(), Node_rwx::rw(), Xml_node("<initialize/>")),
_trust_anchor(ta)
{ }
static char const *type_name() { return "initialize"; }
@ -1938,12 +1923,9 @@ struct Vfs_tresor_trust_anchor::Local_factory : File_system_factory
Local_factory(Vfs::Env &vfs_env, Xml_node config)
:
_trust_anchor { vfs_env, _storage_path(config).string() },
_decrypt_fs { _trust_anchor },
_encrypt_fs { _trust_anchor },
_gen_key_fs { _trust_anchor },
_hash_fs { _trust_anchor },
_init_fs { _trust_anchor }
_trust_anchor(vfs_env, _storage_path(config).string()),
_decrypt_fs(_trust_anchor), _encrypt_fs(_trust_anchor),
_gen_key_fs(_trust_anchor), _hash_fs(_trust_anchor), _init_fs(_trust_anchor)
{ }
Vfs::File_system *create(Vfs::Env&, Xml_node node) override
@ -1990,7 +1972,7 @@ class Vfs_tresor_trust_anchor::File_system : private Local_factory,
xml.node("decrypt", [&] () { });
xml.node("encrypt", [&] () { });
xml.node("generate_key", [&] () { });
xml.node("hashsum", [&] () { });
xml.node("hash", [&] () { });
xml.node("initialize", [&] () { });
});
@ -2001,8 +1983,7 @@ class Vfs_tresor_trust_anchor::File_system : private Local_factory,
File_system(Vfs::Env &vfs_env, Genode::Xml_node node)
:
Local_factory { vfs_env, node },
Vfs::Dir_file_system { vfs_env, Xml_node(_config(node).string()), *this }
Local_factory(vfs_env, node), Vfs::Dir_file_system(vfs_env, Xml_node(_config(node).string()), *this)
{ }
~File_system() { }

View File

@ -97,6 +97,7 @@ vbox5_win7_64_share
verify
vfs_cfg
vfs_import
vfs_tresor
vm_stress_seoul-debian32
vm_stress_vbox5-debian32
vm_stress_vbox5-debian64