/
githubmirror
/
clevis
Обзор
Документация
Войти
/
githubmirror
/
clevis
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/initramfs-tools/scripts/local-top/clevis.in
311 строк
9 KB
Oldřich Jedlička
initramfs: fix running on root-only readable initrd filesystem
19 апр 2026, 01:19
19 апр 2026, 01:19
cffb012
Код
Авторство
О чём код?
#!/bin/bash # # Copyright (c) 2017 Red Hat, Inc. # Copyright (c) 2017 Shawn Rose # Copyright (c) 2017 Guilhem Moulin # # Author: Harald Hoyer <harald@redhat.com> # Author: Nathaniel McCallum <npmccallum@redhat.com> # Author: Shawn Rose <shawnandrewrose@gmail.com> # Author: Guilhem Moulin <guilhem@guilhem.org> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # case $1 in prereqs) exit 0 ;; esac # Return fifo path or nothing if not found get_pid_fifo_path() { local pid="$1" for fd in /proc/$pid/fd/*; do if [ -e "$fd" ]; then if [[ $(readlink -f "${fd}") == *"/cryptsetup/passfifo" ]]; then readlink -f "${fd}" return 0 fi fi done return 1 } # Gets the luks device to be unlocked and used pins get_pid_device_pins() { local pid="$1" local CRYPTTAB_SOURCE CRYPTTAB_SOURCE=$(tr '\0' '\n' 2>/dev/null </proc/${pid}/environ | \ grep '^CRYPTTAB_SOURCE=' | cut -d= -f2) # Wrong process, no CRYPTTAB_SOURCE, return error [ -n "$CRYPTTAB_SOURCE" ] || return 1 [ -b "$CRYPTTAB_SOURCE" ] || return 0 local cache="/var/cache/clevis-disks/${CRYPTTAB_SOURCE//\//_}" if [ ! -f "$cache" ]; then local pins if ! pins=$(clevis_luks_read_used_pins "$CRYPTTAB_SOURCE"); then return 1 fi echo "${CRYPTTAB_SOURCE}:${pins}" > "$cache" fi cat "$cache" return 0 } # Print colon-separated password-asking info like device, pins and fifo # path for unlocking with password get_askpass_info() { local cryptkeyscript=$1 local psinfo pf dev_pins psinfo=$(ps) # Doing this so I don't end up matching myself echo "$psinfo" | awk "/$cryptkeyscript/ { print \$1 }" | { while read -r pid; do if pf=$(get_pid_fifo_path "${pid}") && dev_pins=$(get_pid_device_pins "${pid}"); then if [[ $pf != "" && $dev_pins != "" ]]; then # Output only in case of clevis device echo "${dev_pins}:${pf}" fi # Return that we found valid process return 0 fi done return 1 } } # Try to decrypt the password to fifo file luks_decrypt() { local CRYPTTAB_SOURCE=$1 local PASSFIFO=$2 local pt if pt=$(clevis_luks_unlock_device "${CRYPTTAB_SOURCE}"); then echo -n "${pt}" >"${PASSFIFO}" return 0 else return 1 fi } # Wait for askpass, and then try and decrypt immediately. Just in case # there are multiple devices that need decrypting, this will loop # infinitely (The local-bottom script will kill this after decryption) clevisloop() { # Set the path how we want it (Probably not all needed) PATH="/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin" local cryptkeyscript local askpass_info local sleep_time local CRYPTTAB_SOURCE local OLD_CRYPTTAB_SOURCE="" local netcfg_attempted=0 local tpm1cfg_attempted=0 local pins local PASSFIFO if [ -x /bin/plymouth ] && plymouth --ping; then cryptkeyscript='plymouth ask-for-password' else # This has to be escaped for awk cryptkeyscript='\/lib\/cryptsetup\/askpass' fi while true; do # Re-get the askpass PID in case there are multiple encrypted devices CRYPTTAB_SOURCE="" sleep_time=.1 until [ -n "$CRYPTTAB_SOURCE" ] && [ -p "$PASSFIFO" ]; do sleep $sleep_time if askpass_info=$(get_askpass_info "$cryptkeyscript"); then # Workaround for initramfs-tools checking the script as sh-compatible IFS=':' read -r CRYPTTAB_SOURCE pins PASSFIFO <<EOM ${askpass_info} EOM # Ask process is running, variables might be empty for non-clevis device sleep_time=.5 else # No valid process found sleep_time=.1 fi done # Make the source has changed if needed [ "$CRYPTTAB_SOURCE" = "$OLD_CRYPTTAB_SOURCE" ] && continue OLD_CRYPTTAB_SOURCE="$CRYPTTAB_SOURCE" if [[ " $pins " == *" tang "* ]] && [ $netcfg_attempted -eq 0 ]; then netcfg_attempted=1 do_configure_networking fi if [[ " $pins " == *" tpm1 "* ]] && [ $tpm1cfg_attempted -eq 0 ]; then tpm1cfg_attempted=1 do_configure_tpm1 fi if luks_decrypt "${CRYPTTAB_SOURCE}" "${PASSFIFO}"; then echo "Unlocked ${CRYPTTAB_SOURCE} with clevis" # Now that the current device has its password, let's sleep a # bit. This gives cryptsetup time to actually decrypt the # device and prompt for the next password if needed. sleep .5 else # Unable to unlock now, retry later OLD_CRYPTTAB_SOURCE="" sleep 5 fi done } . /scripts/functions . clevis-luks-common-functions # This is a copy of 'all_netbootable_devices/all_non_enslaved_devices' for # platforms that might not provide it. clevis_all_netbootable_devices() { for device in /sys/class/net/*; do if [ ! -e "$device/flags" ]; then continue fi loop=$(($(cat "$device/flags") & 0x8 && 1 || 0)) bc=$(($(cat "$device/flags") & 0x2 && 1 || 0)) ptp=$(($(cat "$device/flags") & 0x10 && 1 || 0)) # Skip any device that is a loopback if [ $loop = 1 ]; then continue fi # Skip any device that isn't a broadcast # or point-to-point. if [ $bc = 0 ] && [ $ptp = 0 ]; then continue fi # Skip any enslaved device (has "master" link # attribute on it) device=$(basename "$device") ip -o link show "$device" | grep -q -w master && continue if [ -z "$DEVICE" ]; then DEVICE="$device" else DEVICE="$DEVICE $device" fi done echo "$DEVICE" } get_specified_device() { local dev="$(echo $IP | awk -F: '{ print $6 }')" [ -z "$dev" ] || echo $dev } # Workaround configure_networking() not waiting long enough for an interface # to appear. This code can be removed once that has been fixed in all the # distro releases we care about. wait_for_device() { local device local ret=0 device=$(get_specified_device) if [ -n "$device" ]; then log_begin_msg "clevis: Waiting for interface ${device} to become available" local netdev_wait=0 while [ $netdev_wait -lt 10 ]; do if [ -e "/sys/class/net/${device}" ]; then break fi netdev_wait=$((netdev_wait + 1)) sleep 1 done if [ ! -e "/sys/class/net/${device}" ]; then log_failure_msg "clevis: Interface ${device} did not appear in time" ret=1 fi log_end_msg fi wait_for_udev 10 return $ret } do_configure_networking() { # Make sure networking is set up: if booting via nfs, it already is if [ "$boot" != nfs ] && wait_for_device; then clevis_net_cnt=$(clevis_all_netbootable_devices | tr ' ' '\n' | wc -l) if [ -z "$IP" ] && [ "$clevis_net_cnt" -gt 1 ]; then echo "" echo "clevis: Warning: multiple network interfaces available but no ip= parameter provided." fi configure_networking # Add DNS servers from configure_networking to /etc/resolv.conf if [ ! -e /etc/resolv.conf ]; then touch /etc/resolv.conf for intf in /run/net-*.conf; do . "${intf}" if [ ! -z "${IPV4DNS0}" ] && [ "${IPV4DNS0}" != "0.0.0.0" ]; then echo nameserver "${IPV4DNS0}" >> /etc/resolv.conf fi if [ ! -z "${IPV4DNS1}" ] && [ "${IPV4DNS1}" != "0.0.0.0" ]; then echo nameserver "${IPV4DNS1}" >> /etc/resolv.conf fi if [ ! -z "${IPV6DNS0}" ]; then echo nameserver "${IPV6DNS0}" >> /etc/resolv.conf fi done fi fi } do_configure_tpm1() { local tcsd_output= [ -x @bindir@/clevis-decrypt-tpm1 ] && [ -f @libexecdir@/clevis-luks-tpm1-functions ] || return . @libexecdir@/clevis-luks-tpm1-functions log_begin_msg "clevis: Starting TCSD daemon" wait_for_udev 10 # shellcheck disable=SC2034 # setting default value TCSD_NO_PRIVILEGE_DROP=0 [ -f /conf/conf.d/clevis ] && . /conf/conf.d/clevis if ! tcsd_output=$(start_tcsd 2>&1); then if [ -n "$tcsd_output" ]; then log_failure_msg "failed to start TCSD: $tcsd_output" else log_failure_msg "failed to start TCSD" fi fi log_end_msg } mkdir -p /var/cache/clevis-disks chmod 0700 /var/cache/clevis-disks clevisloop & echo $! >/run/clevis.pid