Skip to content

Commit

Permalink
feat(90crypt): add support for AF_UNIX key files
Browse files Browse the repository at this point in the history
systemd v248 introduced support for using AF_UNIX stream sockets
as key files in /etc/crypttab. This commit enhances the 90crypt module
to identify socket units with matching socket file paths. It then
includes the first matching socket unit along with its corresponding
service unit. This correspondence is determined by checking the
Service= option in the socket unit or, if that's not available,
by replacing the .socket suffix with either @.service or .service,
depending on the Accept= option (see man page for systemd.socket).

Futhermore, this functionality handles sockets located under
/run/cryptsetup-keys.d/, which are automatically discoverable by
the systemd-cryptsetup utility when the key file field in /etc/crypttab
is empty.
  • Loading branch information
kszczek committed Apr 30, 2024
1 parent 5d2bda4 commit ec3b8a9
Showing 1 changed file with 69 additions and 0 deletions.
69 changes: 69 additions & 0 deletions modules.d/90crypt/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,73 @@ cmdline() {
# called by dracut
install() {

# systemd only - check if the key file is a socket and if so, include required units
install_socket_units() {
local volume_name=$1
local socket_path=$2

# ignore paths followed by a device specification
if [[ $socket_path == *":"* ]]; then
return
fi

# if no explicit path is provided, try to include units for auto-discoverable keys
if [[ $socket_path == "-" ]] || [[ $socket_path == "none" ]]; then
socket_path="/run/cryptsetup-keys.d/$volume_name.key"
fi

if ! dracut_module_included "systemd"; then
return
fi

find "$systemdsystemunitdir" "$systemdsystemconfdir" -type f -name "*.socket" | while read -r socket_unit; do
# systemd-cryptsetup utility only supports SOCK_STREAM (ListenStream) sockets, so we ignore
# other types like SOCK_DGRAM (ListenDatagram), SOCK_SEQPACKET (ListenSequentialPacket), etc.
if ! grep -E -q "^ListenStream\s*=\s*$socket_path$" "$socket_unit"; then
continue
fi

service_name=$(grep -E "^Service\s*=\s*" "$socket_unit" | cut -d= -f2)

if [ -z "$service_name" ]; then
# if no explicit Service= is defined, construct the service name based on the socket unit's name
if grep -P -q "^Accept\s*=\s*(?i)(1|yes|y|true|t|on)$" "$socket_unit"; then
# if Accept is truthy, assemble a service template
service_name=$(basename "$socket_unit" .socket)"@.service"
else
# otherwise, just replace .socket with .service
service_name=$(basename "$socket_unit" .socket)".service"
fi
fi

# this assumes the service file is in the same directory as the socket file,
# which is a common configuration but not guaranteed.
if ! inst_multiple -H "${socket_unit%/*}/$service_name" "$socket_unit"; then
continue
fi

# sanity check - all units which use default dependencies will depend on sysinit.target,
# which itself depends on cryptsetup.target. This could lead to either:
# a) systemd-cryptsetup falling back to a passphrase prompt due to a missing socket file
# b) a deadlock caused by a circular dependency (service unit -> sysinit.target -> cryptsetup.target -> service unit)
if ! grep -P -q "^DefaultDependencies\s*=\s*(?i)(0|no|n|false|f|off)" "$socket_unit"; then
dwarning "crypt: $socket_unit: default dependencies are not disabled," \
"the socket file may not exist by the time systemd-cryptsetup gets executed"
fi

if ! grep -P -q "^DefaultDependencies\s*=\s*(?i)(0|no|n|false|f|off)" "${socket_unit%/*}/$service_name"; then
dwarning "crypt: ${socket_unit%/*}/$service_name: default dependencies are not disabled," \
"the service unit may encounter a deadlock due to a circular dependency"
fi

socket_unit_basename=$(basename "$socket_unit")
inst_multiple -H -o \
"$systemdsystemunitdir"/sockets.target.wants/"$socket_unit_basename" \
"$systemdsystemconfdir"/sockets.target.wants/"$socket_unit_basename"
break
done
}

if [[ $hostonly_cmdline == "yes" ]]; then
local _cryptconf
_cryptconf=$(cmdline)
Expand Down Expand Up @@ -143,12 +210,14 @@ install() {
# include the entry regardless
if [ "${forceentry}" = "yes" ]; then
echo "$_mapper $_dev $_luksfile $_luksoptions"
install_socket_units "$_mapper" "$_luksfile"
else
# shellcheck disable=SC2031
for _hdev in "${!host_fs_types[@]}"; do
[[ ${host_fs_types[$_hdev]} == "crypto_LUKS" ]] || continue
if [[ $_hdev -ef $_dev ]] || [[ /dev/block/$_hdev -ef $_dev ]]; then
echo "$_mapper $_dev $_luksfile $_luksoptions"
install_socket_units "$_mapper" "$_luksfile"
break
fi
done
Expand Down

0 comments on commit ec3b8a9

Please sign in to comment.