nixos/luksroot: add bypassWorkqueues (#118114)
https://wiki.archlinux.org/index.php/Dm-crypt/Specialties#Disable_workqueue_for_increased_solid_state_drive_(SSD)_performance
This commit is contained in:
parent
11e02bd01d
commit
a6788be01a
@ -140,24 +140,27 @@ let
|
||||
umount /crypt-ramfs 2>/dev/null
|
||||
'';
|
||||
|
||||
openCommand = name': { name, device, header, keyFile, keyFileSize, keyFileOffset, allowDiscards, yubikey, gpgCard, fido2, fallbackToPassword, preOpenCommands, postOpenCommands,... }: assert name' == name;
|
||||
openCommand = name: dev: assert name == dev.name;
|
||||
let
|
||||
csopen = "cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} ${optionalString (header != null) "--header=${header}"}";
|
||||
cschange = "cryptsetup luksChangeKey ${device} ${optionalString (header != null) "--header=${header}"}";
|
||||
csopen = "cryptsetup luksOpen ${dev.device} ${dev.name}"
|
||||
+ optionalString dev.allowDiscards " --allow-discards"
|
||||
+ optionalString dev.bypassWorkqueues " --perf-no_read_workqueue --perf-no_write_workqueue"
|
||||
+ optionalString (dev.header != null) " --header=${dev.header}";
|
||||
cschange = "cryptsetup luksChangeKey ${dev.device} ${optionalString (dev.header != null) "--header=${dev.header}"}";
|
||||
in ''
|
||||
# Wait for luksRoot (and optionally keyFile and/or header) to appear, e.g.
|
||||
# if on a USB drive.
|
||||
wait_target "device" ${device} || die "${device} is unavailable"
|
||||
wait_target "device" ${dev.device} || die "${dev.device} is unavailable"
|
||||
|
||||
${optionalString (header != null) ''
|
||||
wait_target "header" ${header} || die "${header} is unavailable"
|
||||
${optionalString (dev.header != null) ''
|
||||
wait_target "header" ${dev.header} || die "${dev.header} is unavailable"
|
||||
''}
|
||||
|
||||
do_open_passphrase() {
|
||||
local passphrase
|
||||
|
||||
while true; do
|
||||
echo -n "Passphrase for ${device}: "
|
||||
echo -n "Passphrase for ${dev.device}: "
|
||||
passphrase=
|
||||
while true; do
|
||||
if [ -e /crypt-ramfs/passphrase ]; then
|
||||
@ -166,7 +169,7 @@ let
|
||||
break
|
||||
else
|
||||
# ask cryptsetup-askpass
|
||||
echo -n "${device}" > /crypt-ramfs/device
|
||||
echo -n "${dev.device}" > /crypt-ramfs/device
|
||||
|
||||
# and try reading it from /dev/console with a timeout
|
||||
IFS= read -t 1 -r passphrase
|
||||
@ -182,7 +185,7 @@ let
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo -n "Verifying passphrase for ${device}..."
|
||||
echo -n "Verifying passphrase for ${dev.device}..."
|
||||
echo -n "$passphrase" | ${csopen} --key-file=-
|
||||
if [ $? == 0 ]; then
|
||||
echo " - success"
|
||||
@ -202,13 +205,13 @@ let
|
||||
|
||||
# LUKS
|
||||
open_normally() {
|
||||
${if (keyFile != null) then ''
|
||||
if wait_target "key file" ${keyFile}; then
|
||||
${csopen} --key-file=${keyFile} \
|
||||
${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"} \
|
||||
${optionalString (keyFileOffset != null) "--keyfile-offset=${toString keyFileOffset}"}
|
||||
${if (dev.keyFile != null) then ''
|
||||
if wait_target "key file" ${dev.keyFile}; then
|
||||
${csopen} --key-file=${dev.keyFile} \
|
||||
${optionalString (dev.keyFileSize != null) "--keyfile-size=${toString dev.keyFileSize}"} \
|
||||
${optionalString (dev.keyFileOffset != null) "--keyfile-offset=${toString dev.keyFileOffset}"}
|
||||
else
|
||||
${if fallbackToPassword then "echo" else "die"} "${keyFile} is unavailable"
|
||||
${if dev.fallbackToPassword then "echo" else "die"} "${dev.keyFile} is unavailable"
|
||||
echo " - failing back to interactive password prompt"
|
||||
do_open_passphrase
|
||||
fi
|
||||
@ -217,7 +220,7 @@ let
|
||||
''}
|
||||
}
|
||||
|
||||
${optionalString (luks.yubikeySupport && (yubikey != null)) ''
|
||||
${optionalString (luks.yubikeySupport && (dev.yubikey != null)) ''
|
||||
# YubiKey
|
||||
rbtohex() {
|
||||
( od -An -vtx1 | tr -d ' \n' )
|
||||
@ -243,16 +246,16 @@ let
|
||||
local new_response
|
||||
local new_k_luks
|
||||
|
||||
mount -t ${yubikey.storage.fsType} ${yubikey.storage.device} /crypt-storage || \
|
||||
mount -t ${dev.yubikey.storage.fsType} ${dev.yubikey.storage.device} /crypt-storage || \
|
||||
die "Failed to mount YubiKey salt storage device"
|
||||
|
||||
salt="$(cat /crypt-storage${yubikey.storage.path} | sed -n 1p | tr -d '\n')"
|
||||
iterations="$(cat /crypt-storage${yubikey.storage.path} | sed -n 2p | tr -d '\n')"
|
||||
salt="$(cat /crypt-storage${dev.yubikey.storage.path} | sed -n 1p | tr -d '\n')"
|
||||
iterations="$(cat /crypt-storage${dev.yubikey.storage.path} | sed -n 2p | tr -d '\n')"
|
||||
challenge="$(echo -n $salt | openssl-wrap dgst -binary -sha512 | rbtohex)"
|
||||
response="$(ykchalresp -${toString yubikey.slot} -x $challenge 2>/dev/null)"
|
||||
response="$(ykchalresp -${toString dev.yubikey.slot} -x $challenge 2>/dev/null)"
|
||||
|
||||
for try in $(seq 3); do
|
||||
${optionalString yubikey.twoFactor ''
|
||||
${optionalString dev.yubikey.twoFactor ''
|
||||
echo -n "Enter two-factor passphrase: "
|
||||
k_user=
|
||||
while true; do
|
||||
@ -278,9 +281,9 @@ let
|
||||
''}
|
||||
|
||||
if [ ! -z "$k_user" ]; then
|
||||
k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString yubikey.keyLength} $iterations $response | rbtohex)"
|
||||
k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString dev.yubikey.keyLength} $iterations $response | rbtohex)"
|
||||
else
|
||||
k_luks="$(echo | pbkdf2-sha512 ${toString yubikey.keyLength} $iterations $response | rbtohex)"
|
||||
k_luks="$(echo | pbkdf2-sha512 ${toString dev.yubikey.keyLength} $iterations $response | rbtohex)"
|
||||
fi
|
||||
|
||||
echo -n "$k_luks" | hextorb | ${csopen} --key-file=-
|
||||
@ -302,7 +305,7 @@ let
|
||||
[ "$opened" == false ] && die "Maximum authentication errors reached"
|
||||
|
||||
echo -n "Gathering entropy for new salt (please enter random keys to generate entropy if this blocks for long)..."
|
||||
for i in $(seq ${toString yubikey.saltLength}); do
|
||||
for i in $(seq ${toString dev.yubikey.saltLength}); do
|
||||
byte="$(dd if=/dev/random bs=1 count=1 2>/dev/null | rbtohex)";
|
||||
new_salt="$new_salt$byte";
|
||||
echo -n .
|
||||
@ -310,25 +313,25 @@ let
|
||||
echo "ok"
|
||||
|
||||
new_iterations="$iterations"
|
||||
${optionalString (yubikey.iterationStep > 0) ''
|
||||
new_iterations="$(($new_iterations + ${toString yubikey.iterationStep}))"
|
||||
${optionalString (dev.yubikey.iterationStep > 0) ''
|
||||
new_iterations="$(($new_iterations + ${toString dev.yubikey.iterationStep}))"
|
||||
''}
|
||||
|
||||
new_challenge="$(echo -n $new_salt | openssl-wrap dgst -binary -sha512 | rbtohex)"
|
||||
|
||||
new_response="$(ykchalresp -${toString yubikey.slot} -x $new_challenge 2>/dev/null)"
|
||||
new_response="$(ykchalresp -${toString dev.yubikey.slot} -x $new_challenge 2>/dev/null)"
|
||||
|
||||
if [ ! -z "$k_user" ]; then
|
||||
new_k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString yubikey.keyLength} $new_iterations $new_response | rbtohex)"
|
||||
new_k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString dev.yubikey.keyLength} $new_iterations $new_response | rbtohex)"
|
||||
else
|
||||
new_k_luks="$(echo | pbkdf2-sha512 ${toString yubikey.keyLength} $new_iterations $new_response | rbtohex)"
|
||||
new_k_luks="$(echo | pbkdf2-sha512 ${toString dev.yubikey.keyLength} $new_iterations $new_response | rbtohex)"
|
||||
fi
|
||||
|
||||
echo -n "$new_k_luks" | hextorb > /crypt-ramfs/new_key
|
||||
echo -n "$k_luks" | hextorb | ${cschange} --key-file=- /crypt-ramfs/new_key
|
||||
|
||||
if [ $? == 0 ]; then
|
||||
echo -ne "$new_salt\n$new_iterations" > /crypt-storage${yubikey.storage.path}
|
||||
echo -ne "$new_salt\n$new_iterations" > /crypt-storage${dev.yubikey.storage.path}
|
||||
else
|
||||
echo "Warning: Could not update LUKS key, current challenge persists!"
|
||||
fi
|
||||
@ -338,7 +341,7 @@ let
|
||||
}
|
||||
|
||||
open_with_hardware() {
|
||||
if wait_yubikey ${toString yubikey.gracePeriod}; then
|
||||
if wait_yubikey ${toString dev.yubikey.gracePeriod}; then
|
||||
do_open_yubikey
|
||||
else
|
||||
echo "No YubiKey found, falling back to non-YubiKey open procedure"
|
||||
@ -347,7 +350,7 @@ let
|
||||
}
|
||||
''}
|
||||
|
||||
${optionalString (luks.gpgSupport && (gpgCard != null)) ''
|
||||
${optionalString (luks.gpgSupport && (dev.gpgCard != null)) ''
|
||||
|
||||
do_open_gpg_card() {
|
||||
# Make all of these local to this function
|
||||
@ -355,12 +358,12 @@ let
|
||||
local pin
|
||||
local opened
|
||||
|
||||
gpg --import /gpg-keys/${device}/pubkey.asc > /dev/null 2> /dev/null
|
||||
gpg --import /gpg-keys/${dev.device}/pubkey.asc > /dev/null 2> /dev/null
|
||||
|
||||
gpg --card-status > /dev/null 2> /dev/null
|
||||
|
||||
for try in $(seq 3); do
|
||||
echo -n "PIN for GPG Card associated with device ${device}: "
|
||||
echo -n "PIN for GPG Card associated with device ${dev.device}: "
|
||||
pin=
|
||||
while true; do
|
||||
if [ -e /crypt-ramfs/passphrase ]; then
|
||||
@ -382,8 +385,8 @@ let
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo -n "Verifying passphrase for ${device}..."
|
||||
echo -n "$pin" | gpg -q --batch --passphrase-fd 0 --pinentry-mode loopback -d /gpg-keys/${device}/cryptkey.gpg 2> /dev/null | ${csopen} --key-file=- > /dev/null 2> /dev/null
|
||||
echo -n "Verifying passphrase for ${dev.device}..."
|
||||
echo -n "$pin" | gpg -q --batch --passphrase-fd 0 --pinentry-mode loopback -d /gpg-keys/${dev.device}/cryptkey.gpg 2> /dev/null | ${csopen} --key-file=- > /dev/null 2> /dev/null
|
||||
if [ $? == 0 ]; then
|
||||
echo " - success"
|
||||
${if luks.reusePassphrases then ''
|
||||
@ -403,7 +406,7 @@ let
|
||||
}
|
||||
|
||||
open_with_hardware() {
|
||||
if wait_gpgcard ${toString gpgCard.gracePeriod}; then
|
||||
if wait_gpgcard ${toString dev.gpgCard.gracePeriod}; then
|
||||
do_open_gpg_card
|
||||
else
|
||||
echo "No GPG Card found, falling back to normal open procedure"
|
||||
@ -412,15 +415,15 @@ let
|
||||
}
|
||||
''}
|
||||
|
||||
${optionalString (luks.fido2Support && (fido2.credential != null)) ''
|
||||
${optionalString (luks.fido2Support && (dev.fido2.credential != null)) ''
|
||||
|
||||
open_with_hardware() {
|
||||
local passsphrase
|
||||
|
||||
${if fido2.passwordLess then ''
|
||||
${if dev.fido2.passwordLess then ''
|
||||
export passphrase=""
|
||||
'' else ''
|
||||
read -rsp "FIDO2 salt for ${device}: " passphrase
|
||||
read -rsp "FIDO2 salt for ${dev.device}: " passphrase
|
||||
echo
|
||||
''}
|
||||
${optionalString (lib.versionOlder kernelPackages.kernel.version "5.4") ''
|
||||
@ -428,7 +431,7 @@ let
|
||||
echo "Please move your mouse to create needed randomness."
|
||||
''}
|
||||
echo "Waiting for your FIDO2 device..."
|
||||
fido2luks open ${device} ${name} ${fido2.credential} --await-dev ${toString fido2.gracePeriod} --salt string:$passphrase
|
||||
fido2luks open ${dev.device} ${dev.name} ${dev.fido2.credential} --await-dev ${toString dev.fido2.gracePeriod} --salt string:$passphrase
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "No FIDO2 key found, falling back to normal open procedure"
|
||||
open_normally
|
||||
@ -437,16 +440,16 @@ let
|
||||
''}
|
||||
|
||||
# commands to run right before we mount our device
|
||||
${preOpenCommands}
|
||||
${dev.preOpenCommands}
|
||||
|
||||
${if (luks.yubikeySupport && (yubikey != null)) || (luks.gpgSupport && (gpgCard != null)) || (luks.fido2Support && (fido2.credential != null)) then ''
|
||||
${if (luks.yubikeySupport && (dev.yubikey != null)) || (luks.gpgSupport && (dev.gpgCard != null)) || (luks.fido2Support && (dev.fido2.credential != null)) then ''
|
||||
open_with_hardware
|
||||
'' else ''
|
||||
open_normally
|
||||
''}
|
||||
|
||||
# commands to run right after we mounted our device
|
||||
${postOpenCommands}
|
||||
${dev.postOpenCommands}
|
||||
'';
|
||||
|
||||
askPass = pkgs.writeScriptBin "cryptsetup-askpass" ''
|
||||
@ -621,6 +624,17 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
bypassWorkqueues = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to bypass dm-crypt's internal read and write workqueues.
|
||||
Enabling this should improve performance on SSDs; see
|
||||
<link xlink:href="https://wiki.archlinux.org/index.php/Dm-crypt/Specialties#Disable_workqueue_for_increased_solid_state_drive_(SSD)_performance">here</link>
|
||||
for more information. Needs Linux 5.9 or later.
|
||||
'';
|
||||
};
|
||||
|
||||
fallbackToPassword = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
@ -833,6 +847,11 @@ in
|
||||
{ assertion = !(luks.fido2Support && luks.yubikeySupport);
|
||||
message = "FIDO2 and YubiKey may not be used at the same time.";
|
||||
}
|
||||
|
||||
{ assertion = any (dev: dev.bypassWorkqueues) (attrValues luks.devices)
|
||||
-> versionAtLeast kernelPackages.kernel.version "5.9";
|
||||
message = "boot.initrd.luks.devices.<name>.bypassWorkqueues is not supported for kernels older than 5.9";
|
||||
}
|
||||
];
|
||||
|
||||
# actually, sbp2 driver is the one enabling the DMA attack, but this needs to be tested
|
||||
|
Loading…
Reference in New Issue
Block a user