"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/tests/luks2-reencryption-mangle-test" (13 Jan 2022, 12892 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Bash source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 #!/bin/bash
    2 
    3 PS4='$LINENO:'
    4 [ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
    5 CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
    6 CRYPTSETUP_RAW=$CRYPTSETUP
    7 
    8 CRYPTSETUP_VALGRIND=../.libs/cryptsetup
    9 CRYPTSETUP_LIB_VALGRIND=../.libs
   10 IMG=reenc-mangle-data
   11 IMG_HDR=$IMG.hdr
   12 IMG_JSON=$IMG.json
   13 KEY1=key1
   14 DEV_NAME=reenc3492834
   15 
   16 FAST_PBKDF2="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
   17 CS_PWPARAMS="--disable-keyring --key-file $KEY1"
   18 CS_PARAMS="-q --disable-locks $CS_PWPARAMS"
   19 JSON_MSIZE=16384
   20 
   21 function remove_mapping()
   22 {
   23     [ -b /dev/mapper/$DEV_NAME ] && dmsetup remove --retry $DEV_NAME
   24     rm -f $IMG $IMG_HDR $IMG_JSON $KEY1 >/dev/null 2>&1
   25 }
   26 
   27 function fail()
   28 {
   29     local frame=0
   30     [ -n "$1" ] && echo "$1"
   31     echo "FAILED backtrace:"
   32     while caller $frame; do ((frame++)); done
   33     remove_mapping
   34     exit 2
   35 }
   36 
   37 function skip()
   38 {
   39     [ -n "$1" ] && echo "$1"
   40     remove_mapping
   41     exit 77
   42 }
   43 
   44 function bin_check()
   45 {
   46     which $1 >/dev/null 2>&1 || skip "WARNING: test require $1 binary, test skipped."
   47 }
   48 
   49 function img_json_save()
   50 {
   51     # FIXME: why --json-file cannot be used?
   52     $CRYPTSETUP luksDump --dump-json-metadata $IMG | jq -c -M . | tr -d '\n' >$IMG_JSON
   53 }
   54 
   55 function img_json_dump()
   56 {
   57     img_json_save
   58     jq . $IMG_JSON
   59 }
   60 
   61 function img_hash_save()
   62 {
   63     IMG_HASH=$(sha256sum $IMG | cut -d' ' -f 1)
   64 }
   65 
   66 function img_hash_unchanged()
   67 {
   68     local IMG_HASH2=$(sha256sum $IMG | cut -d' ' -f 1)
   69     [ "$IMG_HASH" != "$IMG_HASH2" ] && fail "Image changed!"
   70 }
   71 
   72 function img_prepare_raw() # $1 options
   73 {
   74     remove_mapping
   75 
   76     if [ ! -e $KEY1 ]; then
   77         dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
   78     fi
   79 
   80     truncate -s 32M $IMG || fail
   81     $CRYPTSETUP luksFormat $FAST_PBKDF2 $CS_PARAMS --luks2-metadata-size $JSON_MSIZE $IMG $1 || fail
   82 }
   83 
   84 function img_prepare() # $1 options
   85 {
   86     img_prepare_raw
   87     # FIXME: resilience is not saved here (always none)?
   88     $CRYPTSETUP reencrypt $IMG $CS_PARAMS -q --init-only --resilience none $1 >/dev/null 2>&1
   89     [ $? -ne 0 ] && skip "Reencryption unsupported, test skipped."
   90     img_json_save
   91     img_hash_save
   92 }
   93 
   94 function _dd()
   95 {
   96     dd $@ status=none conv=notrunc bs=1
   97 }
   98 
   99 # header mangle functions
  100 function img_update_json()
  101 {
  102     local LUKS2_BIN1_OFFSET=448
  103     local LUKS2_BIN2_OFFSET=$((LUKS2_BIN1_OFFSET + $JSON_MSIZE))
  104     local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096))
  105 
  106     # if present jq script, mangle JSON
  107     if [ -n "$1" ]; then
  108         local JSON=$(cat $IMG_JSON)
  109         echo $JSON | jq -M -c "$1" >$IMG_JSON || fail
  110         local JSON=$(cat $IMG_JSON)
  111         echo $JSON | tr -d '\n' >$IMG_JSON || fail
  112     fi
  113 
  114     # wipe JSON areas
  115     _dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=4096
  116     _dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
  117 
  118     # write JSON data
  119     _dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=4096
  120     _dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
  121 
  122     # erase sha256 checksums
  123     _dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN1_OFFSET
  124     _dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN2_OFFSET
  125 
  126     # calculate sha256 and write chexksums
  127     local SUM1_HEX=$(_dd if=$IMG count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
  128     echo $SUM1_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN1_OFFSET count=64 || fail
  129 
  130     local SUM2_HEX=$(_dd if=$IMG skip=$JSON_MSIZE count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
  131     echo $SUM2_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN2_OFFSET count=64 || fail
  132 
  133     img_hash_save
  134 }
  135 
  136 function img_check_ok()
  137 {
  138     if [ $(id -u) == 0 ]; then
  139         $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME || fail
  140         $CRYPTSETUP close $DEV_NAME || fail
  141     fi
  142 
  143     $CRYPTSETUP repair $IMG $CS_PARAMS || fail
  144 }
  145 
  146 function img_check_fail()
  147 {
  148     if [ $(id -u) == 0 ]; then
  149         $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
  150     fi
  151 
  152     $CRYPTSETUP repair $IMG $CS_PARAMS 2>/dev/null && fail
  153     img_hash_unchanged
  154 }
  155 
  156 function img_run_reenc_ok()
  157 {
  158 local EXPECT_TIMEOUT=5
  159 [ -n "$VALG" ] && EXPECT_TIMEOUT=60
  160 # For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
  161 expect_run - >/dev/null <<EOF
  162 proc abort {} { send_error "Timeout. "; exit 2 }
  163 set timeout $EXPECT_TIMEOUT
  164 eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks --resilience none
  165 expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
  166 send "YES\n"
  167 expect timeout abort eof
  168 exit
  169 EOF
  170 [ $? -eq 0 ] || fail "Expect script failed."
  171 }
  172 
  173 function img_run_reenc_fail()
  174 {
  175 local EXPECT_TIMEOUT=5
  176 [ -n "$VALG" ] && EXPECT_TIMEOUT=60
  177 # For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
  178 expect_run - >/dev/null <<EOF
  179 proc abort {} { send_error "Timeout. "; exit 42 }
  180 set timeout $EXPECT_TIMEOUT
  181 eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks
  182 expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
  183 send "YES\n"
  184 expect timeout abort eof
  185 catch wait result
  186 exit [lindex \$result 3]
  187 EOF
  188 local ret=$?
  189 [ $ret -eq 0 ] &&  fail "Reencryption passed (should have failed)."
  190 [ $ret -eq 42 ] && fail "Expect script failed."
  191 img_hash_unchanged
  192 }
  193 
  194 function img_check_fail_repair_ok()
  195 {
  196     if [ $(id -u) == 0 ]; then
  197         $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
  198     fi
  199 
  200     img_run_reenc_fail
  201 
  202     # repair metadata
  203     $CRYPTSETUP repair $IMG $CS_PARAMS || fail
  204 
  205     img_check_ok
  206     img_run_reenc_ok
  207 }
  208 
  209 function valgrind_setup()
  210 {
  211     bin_check valgrind
  212     [ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable."
  213     export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
  214     CRYPTSETUP=valgrind_run
  215     CRYPTSETUP_RAW="./valg.sh ${CRYPTSETUP_VALGRIND}"
  216 }
  217 
  218 function valgrind_run()
  219 {
  220     INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@"
  221 }
  222 
  223 function expect_run()
  224 {
  225         export INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}"
  226         expect "$@"
  227 }
  228 
  229 bin_check jq
  230 bin_check sha256sum
  231 bin_check xxd
  232 bin_check expect
  233 
  234 export LANG=C
  235 
  236 [ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
  237 
  238 #while false; do
  239 
  240 echo "[1] Reencryption with old flag is rejected"
  241 img_prepare
  242 img_update_json '.config.requirements.mandatory = ["online-reencryptx"]'
  243 img_check_fail
  244 img_update_json '.config.requirements.mandatory = ["online-reencrypt-v2"]'
  245 img_check_ok
  246 img_run_reenc_ok
  247 img_check_ok
  248 
  249 # Simulate old reencryption with no digest (repairable)
  250 img_prepare
  251 img_update_json 'del(.digests."2") | .config.requirements.mandatory = ["online-reencrypt"]'
  252 img_check_fail_repair_ok
  253 
  254 # This must fail for new releases
  255 echo "[2] Old reencryption in-progress (journal)"
  256 img_prepare
  257 img_update_json '
  258     del(.digests."2") |
  259     .keyslots."2".area.type = "journal" |
  260     .segments = {
  261         "0" : (.segments."0" +
  262             {"size" : .keyslots."2".area.size} +
  263             {"flags" : ["in-reencryption"]}),
  264         "1" : (.segments."0" +
  265             {"offset" : ((.segments."0".offset|tonumber) +
  266             (.keyslots."2".area.size|tonumber))|tostring}),
  267         "2" : .segments."1",
  268         "3" : .segments."2"
  269     } |
  270     .digests."0".segments = ["1","2"] |
  271     .digests."1".segments = ["0","3"] |
  272     .config.requirements.mandatory = ["online-reencrypt"]'
  273 img_check_fail_repair_ok
  274 
  275 echo "[3] Old reencryption in-progress (checksum)"
  276 img_prepare
  277 img_update_json '
  278     del(.digests."2") |
  279     .keyslots."2".area.type = "checksum" |
  280     .keyslots."2".area.hash = "sha256" |
  281     .keyslots."2".area.sector_size = 4096 |
  282     .segments = {
  283         "0" : (.segments."0" +
  284             {"size" : .keyslots."2".area.size} +
  285             {"flags" : ["in-reencryption"]}),
  286         "1" : (.segments."0" +
  287             {"offset": ((.segments."0".offset|tonumber) +
  288             (.keyslots."2".area.size|tonumber))|tostring}),
  289         "2" : .segments."1",
  290         "3" : .segments."2"
  291     } |
  292     .digests."0".segments = ["1","2"] |
  293     .digests."1".segments = ["0","3"] |
  294     .config.requirements.mandatory = ["online-reencrypt"]'
  295 img_check_fail_repair_ok
  296 
  297 # Note: older tools cannot create this from commandline
  298 echo "[4] Old decryption in-progress (journal)"
  299 img_prepare
  300 img_update_json '
  301     del(.digests."1") |
  302     del(.digests."2") |
  303     del(.keyslots."1") |
  304     .keyslots."2".mode = "decrypt" |
  305     .keyslots."2".area.type = "journal" |
  306     .segments = {
  307         "0" : {
  308             "type" : "linear",
  309             "offset" : .segments."0".offset,
  310             "size" : .keyslots."2".area.size,
  311             "flags" : ["in-reencryption"]
  312         },
  313         "1" : (.segments."0" +
  314             {"offset" : ((.segments."0".offset|tonumber) +
  315             (.keyslots."2".area.size|tonumber))|tostring}),
  316         "2" : .segments."1",
  317         "3" : {
  318             "type" : "linear",
  319             "offset" : .segments."0".offset,
  320             "size" : "dynamic",
  321             "flags" : ["backup-final"]
  322         }
  323     } |
  324     .digests."0".segments = ["1","2"] |
  325     .config.requirements.mandatory = ["online-reencrypt"]'
  326 img_check_fail_repair_ok
  327 
  328 echo "[5] Old decryption in-progress (checksum)"
  329 img_prepare
  330 img_update_json '
  331     del(.digests."1") |
  332     del(.digests."2") |
  333     del(.keyslots."1") |
  334     .keyslots."2".mode = "decrypt" |
  335     .keyslots."2".area.type = "checksum" |
  336     .keyslots."2".area.hash = "sha256" |
  337     .keyslots."2".area.sector_size = 4096 |
  338     .segments = {
  339         "0" : {
  340             "type" : "linear",
  341             "offset" : .segments."0".offset,
  342             "size" : .keyslots."2".area.size,
  343             "flags" : ["in-reencryption"]
  344         },
  345         "1" : (.segments."0" +
  346             {"offset" : ((.segments."0".offset|tonumber) +
  347             (.keyslots."2".area.size|tonumber))|tostring}),
  348         "2" : .segments."1",
  349         "3" : {
  350             "type" : "linear",
  351             "offset" : .segments."0".offset,
  352             "size" : "dynamic",
  353             "flags" : ["backup-final"]
  354         }
  355     } |
  356     .digests."0".segments = ["1","2"] |
  357     .config.requirements.mandatory = ["online-reencrypt"]'
  358 img_check_fail_repair_ok
  359 
  360 # Note - offset is set to work with the old version (with a datashift bug)
  361 echo "[6] Old reencryption in-progress (datashift)"
  362 img_prepare
  363 img_update_json '
  364     del(.digests."2") |
  365     .keyslots."2".direction = "backward" |
  366     .keyslots."2".area.type = "datashift" |
  367     .keyslots."2".area.size = "4096" |
  368     .keyslots."2".area.shift_size = ((1 * 1024 * 1024)|tostring) |
  369     .segments = {
  370         "0" : (.segments."0" +
  371             {"size" : ((13 * 1024 * 1024)|tostring)}),
  372         "1" : (.segments."0" +
  373             {"offset" : ((30 * 1024 * 1024)|tostring)}),
  374         "2" : .segments."1",
  375         "3" : (.segments."2" +
  376             {"offset" : ((17 * 1024 * 1024)|tostring)}),
  377     } |
  378     .digests."0".segments = ["0","2"] |
  379     .digests."1".segments = ["1","3"] |
  380     .config.requirements.mandatory = ["online-reencrypt"]'
  381 img_check_fail_repair_ok
  382 
  383 #
  384 # NEW metadata (with reenc digest)
  385 #
  386 echo "[7] Reencryption with various mangled metadata"
  387 
  388 # Normal situation
  389 img_prepare
  390 img_run_reenc_ok
  391 img_check_ok
  392 
  393 # The same in various steps.
  394 # Repair must validate not only metadata, but also reencryption digest.
  395 img_prepare
  396 img_update_json 'del(.digests."2")'
  397 img_check_fail_repair_ok
  398 
  399 img_prepare '--reduce-device-size 2M'
  400 img_update_json '.keyslots."2".area.shift_size = ((.keyslots."2".area.shift_size|tonumber / 2)|tostring)'
  401 img_check_fail
  402 
  403 #FIXME: cannot check with correct digest for now (--init-only does not store area type)
  404 img_prepare
  405 img_update_json '
  406     .keyslots."2".area.type = "checksum" |
  407     .keyslots."2".area.hash = "sha256" |
  408     .keyslots."2".area.sector_size = 4096'
  409 img_check_fail
  410 
  411 img_prepare
  412 img_update_json '.keyslots."2".area.type = "journal"'
  413 img_check_fail
  414 
  415 img_prepare
  416 img_update_json '.keyslots."2".mode = "decrypt"'
  417 img_check_fail
  418 
  419 img_prepare
  420 img_update_json '.keyslots."2".direction = "backward"'
  421 img_check_fail
  422 
  423 # key_size must be 1
  424 img_prepare
  425 img_update_json '.keyslots."2".key_size = 16'
  426 img_check_fail
  427 
  428 # Mangling segments
  429 img_prepare
  430 img_update_json 'del(.segments."1")'
  431 img_check_fail
  432 
  433 img_prepare
  434 img_update_json '.segments."0".encryption = "aes-cbc-null"'
  435 img_check_fail
  436 
  437 img_prepare
  438 img_update_json '.segments."1".encryption = "aes-cbc-null"'
  439 img_check_fail
  440 
  441 img_prepare
  442 img_update_json '.segments."2".encryption = "aes-cbc-null"'
  443 img_check_fail
  444 
  445 # Mangling digests
  446 img_prepare
  447 img_update_json '
  448     .digests."2" = .digests."0" |
  449     .digests."2".keyslots = ["2"] |
  450     .digests."2".segments = []'
  451 img_check_fail
  452 
  453 img_prepare
  454 img_update_json '.digests."2".iterations = 1111'
  455 img_check_fail
  456 
  457 # Simulate correct progress
  458 img_prepare
  459 img_update_json '
  460     .segments = {
  461         "0" : (.segments."0" +
  462             {"size" : ((1 * 1024 * 1024)|tostring)}),
  463         "1" : (.segments."0" +
  464             {"offset" : ((17 * 1024 * 1024)|tostring)}),
  465         "2" : .segments."1",
  466         "3" : .segments."2"
  467     } |
  468     .digests."0".segments = ["1","2"] |
  469     .digests."1".segments = ["0","3"]'
  470 img_check_ok
  471 
  472 # Mangling keyslots
  473 
  474 # Set reencrypt slot to non-ignore priority
  475 # This should be benign, just avoid noisy messages
  476 img_prepare
  477 img_update_json 'del(.keyslots."2".priority)'
  478 img_check_ok
  479 
  480 # Flags
  481 
  482 # Remove mandatory reenc flag, but keep reenc metadata
  483 img_prepare
  484 img_update_json '.config.requirements.mandatory = []'
  485 img_check_fail
  486 
  487 # Unknown segment flag, should be ignored
  488 img_prepare
  489 img_update_json '.segments."0".flags = ["dead-parrot"]'
  490 img_check_ok
  491 
  492 echo "[8] Reencryption with AEAD is not supported"
  493 img_prepare_raw
  494 img_json_save
  495 img_update_json '
  496     .segments."0".integrity = {
  497         "type" : "hmac(sha256)",
  498         "journal_encryption": "none",
  499         "journal_integrity": "none"
  500     }'
  501 $CRYPTSETUP reencrypt $IMG $CS_PARAMS >/dev/null 2>&1 && fail
  502 
  503 remove_mapping
  504 exit 0