Fix interactive query retry if LUKS2 unbound keyslot is present

If an unbound keyslot is present (e.g.. slot 0 usual slot, slot 1 unbound),
the query loop could return ENOENT (keyslot not valid for segment) and this
will stop epxected retry for slot quewry (--tries option).

If any previous slot rerutned EPERM (no valid passphrase), prefer
this return code.
This commit is contained in:
Milan Broz
2024-05-10 09:36:37 +02:00
parent 7de4782e95
commit e806276dca
2 changed files with 49 additions and 2 deletions

View File

@@ -415,11 +415,13 @@ static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
int keyslot, r = -ENOENT;
int keyslot, r = -ENOENT, r_old;
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
json_object_object_foreach(jobj_keyslots, slot, val) {
r_old = r;
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
@@ -438,6 +440,9 @@ static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
former meaning password wrong, latter key slot unusable for segment */
if ((r != -EPERM) && (r != -ENOENT))
break;
/* If a previous keyslot failed with EPERM (bad password) prefer it */
if (r_old == -EPERM && r == -ENOENT)
r = -EPERM;
}
return r;
@@ -453,11 +458,13 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
int keyslot, r = -ENOENT;
int keyslot, r = -ENOENT, r_old;
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
json_object_object_foreach(jobj_keyslots, slot, val) {
r_old = r;
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
@@ -476,6 +483,9 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
former meaning password wrong, latter key slot unusable for segment */
if ((r != -EPERM) && (r != -ENOENT))
break;
/* If a previous keyslot failed with EPERM (bad password) prefer it */
if (r_old == -EPERM && r == -ENOENT)
r = -EPERM;
}
return r;

View File

@@ -501,6 +501,37 @@ EOF
[ $? -eq 0 ] || return 1
}
# expected unlocked keyslot id
# password
# command arguments
function expect_retried_unlocked_keyslot()
{
command -v expect >/dev/null || {
echo "WARNING: expect tool missing, interactive test will be skipped."
return 0
}
EXPECT_TIMEOUT=60
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW $3
expect timeout abort "Enter passphrase for*:"
sleep 0.1
send "$2 x\n"
expect timeout abort "No key available with this passphrase."
expect timeout abort "Enter passphrase for*:"
sleep 0.1
send "$2\n"
expect timeout abort "Key slot $1 unlocked."
expect timeout abort "Command successful."
expect timeout abort eof
exit
EOF
[ $? -eq 0 ] || return 1
}
export LANG=C
[ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped."
@@ -1618,5 +1649,11 @@ if [ $? -eq 0 ] ; then
$CRYPTSETUP close $DEV_NAME || fail
fi
prepare "[48] Interactive retry keyslot test" wipe
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail
echo $PWD2 | $CRYPTSETUP -q luksAddKey $FAST_PBKDF_OPT --unbound --key-size 256 $LOOPDEV || fail
expect_retried_unlocked_keyslot 0 $PWD1 "open -v --test-passphrase --tries 2 $LOOPDEV" || fail
expect_retried_unlocked_keyslot 1 $PWD2 "open -v --test-passphrase --tries 2 -S1 $LOOPDEV" || fail
remove_mapping
exit 0