genode/repos/gems/run/vfs_tresor.sh
Martin Stein b4c4681733 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
2024-04-12 15:00:45 +02:00

235 lines
4.8 KiB
Bash

#!/bin/bash
echo "--- Automated Tresor testing ---"
produce_pattern() {
local pattern="$1"
local size="$2"
[ "$pattern" = "" ] && exit 1
local tmp_file="/tmp/pattern.tmp"
local N=1041
# prints numbers until N and uses pattern as delimiter and
# generates about 4 KiB of data with a 1 byte pattern
seq -s "$pattern" $N > $tmp_file
dd if=$tmp_file count=1 bs=$size 2>/dev/null
}
test_write_1() {
local data_file="$1"
local offset=$2
local pattern_file="/tmp/pattern"
dd bs=4096 count=1 if=$pattern_file of=$data_file seek=$offset 2>/dev/null || exit 1
}
test_read_seq_unaligned_512() {
local data_file="$1"
local length="$2"
dd bs=512 count=$((length / 512)) if=$data_file of=/dev/null
}
test_read_compare_1() {
local data_file="$1"
local offset=$2
local pattern_file="/tmp/pattern"
rm $pattern_file.out 2>/dev/null
dd bs=4096 count=1 if=$data_file of=$pattern_file.out skip=$offset 2>/dev/null || exit 1
local sha1=$(sha1sum $pattern_file)
local sha1_sum=${sha1:0:40}
local sha1out=$(sha1sum $pattern_file.out)
local sha1out_sum=${sha1out:0:40}
if [ "$sha1_sum" != "$sha1out_sum" ]; then
echo "mismatch for block $offset:"
echo " expected: $sha1_sum"
echo -n " "
dd if=$pattern_file bs=32 count=1 2>/dev/null; echo
echo " got: $sha1out_sum"
echo -n " "
dd if=$pattern_file.out bs=32 count=1 2>/dev/null; echo
return 1
fi
}
test_deinitialize() {
local tresor_dir="$1"
echo "Deinitialize"
local state="$(< $tresor_dir/control/deinitialize)"
echo true > $tresor_dir/control/deinitialize
}
wait_for_deinitialize() {
local tresor_dir="$1"
echo "Wait for deinitialize"
local state="$(< $tresor_dir/control/deinitialize)"
}
test_rekey_start() {
local tresor_dir="$1"
echo "Start rekeying"
local state="$(< $tresor_dir/control/rekey)"
echo true > $tresor_dir/control/rekey
echo "Reykeying started"
}
test_vbd_extension() {
local tresor_dir="$1"
local nr_of_phys_blocks="$2"
echo "Start extending VBD"
echo tree=vbd, blocks=$nr_of_phys_blocks > $tresor_dir/control/extend
echo "VBD extension started"
}
test_ft_extension() {
local tresor_dir="$1"
local nr_of_phys_blocks="$2"
echo "Start extending FT"
echo tree=ft, blocks=$nr_of_phys_blocks > $tresor_dir/control/extend
echo "FT extension started"
}
test_rekey_state() {
local tresor_dir="$1"
local state="$(< $tresor_dir/control/rekey)"
local progress="$(< $tresor_dir/control/rekey_progress)"
local result="unknown"
case "$progress" in
*at*)
result="$progress"
;;
*idle*)
result="done"
;;
esac
echo "Rekeying state: $state progress: $result"
}
test_rekey() {
local tresor_dir="$1"
test_rekey_start "$tresor_dir"
wait_for_rekeying "$tresor_dir" "yes"
}
wait_for_rekeying() {
local tresor_dir="$1"
local verbose="$2"
local result="unknown"
echo "Wait for rekeying to finish..."
while : ; do
local done=0
local file_content="$(< $tresor_dir/control/rekey)"
# XXX remove later
echo "file_content: ${file_content}"
case "$file_content" in
*failed*)
done=1;
;;
*succeeded*)
done=1;
;;
esac
if [ $done -gt 0 ]; then
break
fi
done
echo "Rekeying done"
}
wait_for_vbd_extension() {
local tresor_dir="$1"
echo "Wait for VBD extension to finish..."
while : ; do
local done=0
local file_content="$(< $tresor_dir/control/extend)"
# XXX remove later
echo "file_content: ${file_content}"
case "$file_content" in
*failed*)
done=1;
;;
*succeeded*)
done=1;
;;
esac
if [ $done -gt 0 ]; then
break
fi
done
echo "VBD extension done"
}
wait_for_ft_extension() {
local tresor_dir="$1"
echo "Wait for FT extension to finish..."
while : ; do
local done=0
local file_content="$(< $tresor_dir/control/extend)"
# XXX remove later
echo "file_content: ${file_content}"
case "$file_content" in
*failed*)
done=1;
;;
*succeeded*)
done=1;
;;
esac
if [ $done -gt 0 ]; then
break
fi
done
echo "FT extension done"
}
main() {
local tresor_dir="/dev/tresor"
local data_file="$tresor_dir/current/data"
echo "list files..."
ls -l $tresor_dir
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