From patchwork Tue Oct 27 11:06:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "srinuvasan.a" X-Patchwork-Id: 5573 Return-Path: Received: from shymkent.ilbers.de ([unix socket]) by shymkent (Cyrus 2.5.10-Debian-2.5.10-3+deb9u2) with LMTPA; Tue, 27 Oct 2026 12:05:38 +0100 X-Sieve: CMU Sieve 2.4 Received: from mail-pj1-f55.google.com (mail-pj1-f55.google.com [209.85.216.55]) by shymkent.ilbers.de (8.15.2/8.15.2/Debian-8+deb9u1) with ESMTPS id 69RB5agY018223 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 27 Oct 2026 12:05:37 +0100 Received: by mail-pj1-f55.google.com with SMTP id 98e67ed59e1d1-3adcb81f487sf6442994a91.3 for ; Tue, 27 Oct 2026 04:05:37 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1793099131; cv=pass; d=google.com; s=arc-20260327; b=AKbX6E8yks0/HMM7l1025P8JJnkjyicw2s/5c8QeWDH+rNC4i+PZTs4xec9N2VBc8t pJU+p16zArynClz+U56cohjj1e1lp2eb6ps48WAR/bGCnpOYfwpO1B8vopsfP2FogPoQ giunvBkE+qHZOs6BY8Fj9uh6R1oV3QudszruJzekmdPX0M8VFitXwDL23V6s1d5F2dLu /sn8VopnEeJQ4t/R1g4WLKxh+jo0UVhxbT1r0rM6e0kPrU0mBOkBND2W/lNYFG9B2UBC Ss4W7y4cqqAkOUwhWqkEx4ajOCgqQ8r84KMMNqFlhdIr72rpUWQIsR4iYqy//u4kIErk M1Vg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to:feedback-id:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=y8rCDCB7AZFeYuBJIRAkL8/BE9mBZrzXyMdMwaLtnBg=; fh=4say46dYkotbJMkfMkuUMagtq63wZew4SHJbtCMFdk4=; b=FUpL2s+dQUaT5FZyVGpeHXDvBlVfhIB5j/7fgEx7EB5G/gZnF1F2I1PFansdQfVKpC IRw7pnDdqRrMr+qTN+oAwaKqaw3Eph5Wq+mQ2fSenOmLinc644KwZ/m03nIihOLxeKFw IqndoOVu4vDJrq5AEJp8VHRsM1kBQhvR5pWKVSkMa3wFSGoLSrjW6edMd6ufbu9P64Qv U4lRzDtvrL+3qQ905UWvkmzHCgRQEK22dgrpb/ZB0pLw9wZcc26NIP26A/8dL5qVMmE6 0Wh+wUgCBTe8ouEKF9ovKkBgg7sqSpwZG13hQOXDsLlqSPkiccdK6w5EPAlwlMCRayFi 6NvA==; darn=isar-build.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=fm2 header.b=BZitemSQ; spf=pass (google.com: domain of fm-1324425-202610271105245f263c63fd00020789-ts0myf@rts-flowmailer.siemens.com designates 185.136.65.226 as permitted sender) smtp.mailfrom=fm-1324425-202610271105245f263c63fd00020789-tS0MYF@rts-flowmailer.siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1793099131; x=1793703931; darn=isar-build.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:content-type:reply-to :x-original-authentication-results:x-original-sender:feedback-id :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=y8rCDCB7AZFeYuBJIRAkL8/BE9mBZrzXyMdMwaLtnBg=; b=kglZIpd5siZRCxwLyvvhS3JPwx85ePJr5MgDDAxvgQjjQAgWsuTBi1xRAsTg8YpMVf g6AA3LEnDErDE0hiNCywRMAbFepz+y7cz0D6AvRAMI/cD9zQRPg+ZLJ7Kho+eHB2N9Yz qglZWK6/uN+SHdA38pMbUzHr0jOC2CWrLLZgPLt3bUcWits0LAR0SHYalngx2rDhidc5 AMXpwORZ3lCV5TGlNrX3TmQJTxrvTPyWQhOGaeaNoqv8aSqsXRDQoQX2TJD0lan2RAYz D6sTcqdFNbne7gfoI37/AsH9DXDVK9w8B/5wsednMWIpbvSHwdt8PC+oeItKsi/zZ0R1 8amA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793099131; x=1793703931; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :content-type:reply-to:x-original-authentication-results :x-original-sender:feedback-id:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-beenthere:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to:content-type; bh=y8rCDCB7AZFeYuBJIRAkL8/BE9mBZrzXyMdMwaLtnBg=; b=hpQep4yS1hEzdnuCmFE9hsondLClDZoFAAkT/T8A2MeWKLNPz2toNc7I+2IushlrDU 6FfmfPoZCSdL/zjkOZRNb4RKhG1dbeMXPVLfoXW8MASKQDFQ/1smrK1Y0NqsNATyzae9 JN+arV0gePTYNT6Neb23CLbwTX9qDZwJvaD3q4V26xjEC5bCBQ7OzR67b9HjNT3qYp1M YA5uY2i1FrvxpjbGNKGvu+B/iTLZEdoiKqw8T/HpuTv6GpkJoBF2FnlCY7rqEVok+CEo qWuM44EGcehWTwOjenyFlrYx/tBTaRb+wMXuvtUd8Hqc5z1vlzIjMkZSY91kMF8nwZ9h rIXQ== X-Forwarded-Encrypted: i=2; AKwUvBw3uhYkrDm1CsIZw3DE+NG7rGSUTZcx7ZeLi4zuQMKfJ2m23xipamFImGupxkPsC91MGMFtgp4=@isar-build.org X-Gm-Message-State: AFq9FYLGTXxCIB8UUsZPGF3h6eDT1WLeSFog31vK5Wl15siI4qquy8wu gVB0ow7qN2z8TCZaWrjWr5dCewMZY5QbJ5Gi0KbvuRj52PbGeem5fY6j X-Received: by 2002:a17:90b:1647:b0:3ac:b145:8f4 with SMTP id 98e67ed59e1d1-3adeae9c56bmr8521652a91.41.1793099130572; Tue, 27 Oct 2026 04:05:30 -0700 (PDT) X-BeenThere: isar-users@googlegroups.com; h="ATskLddZLA/+6lzXTieZCx4Hfz2VOGC2Kn3fVtTQLk8JsAAiyw==" Received: by 2002:a17:90b:1c85:b0:3ad:6c5f:feaa with SMTP id 98e67ed59e1d1-3adc9922502ls5329601a91.0.-pod-prod-03-us; Tue, 27 Oct 2026 04:05:29 -0700 (PDT) X-Received: by 2002:a17:90b:1d47:b0:3ac:a203:e0a5 with SMTP id 98e67ed59e1d1-3adeac04a17mr8818579a91.11.1793099129579; Tue, 27 Oct 2026 04:05:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1793099129; cv=none; d=google.com; s=arc-20260327; b=QosTj7HcMn9YDDHmnNu9Go7GlPxirxM5dIia5MLhxYaaGLINR0VQ5Sq1Au4O5yJnSP 7VlYQqTa7srF4t64U07Brh7b6uoOBFWaEcLz2PjDmMW1F/t3VgymylXDSdn5dLBoYb7x QW//ceof5dRFENYFzGk+/trrG7CKXjiul5G2ZIwQxFrVfb8bhhAr0pjnxtOi823yedWE +LmVr9Ws7Or/C1A4V5/gtswim2ojqreC//Bc5YsEDyDvFUEM4FO4VKCoN6tXuc2zY6eI KZJs001901A7Gri15ucrX01GX+E973JNfUi4yh9gNHq2CoBRkxIO2iAttBFcu7BG8hA5 dX7w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=feedback-id:content-transfer-encoding:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature; bh=8DNRW4i2m9anNZhhF0uuM/xOJB46E5uGdxgDPsTgbSo=; fh=VulK/l3XeLoc9JOOMl9NSLlfbMahF+GjHF6HwceMpeQ=; b=LlIPIi189mxWdch/DA71Ry3s6ZNSrBml1nnh2HV10o7kjZ5Leo6UySKC1RtaGOHwmg Cwja9gT0lYHq3PrYlSpKHZwqj1W4B47cvEU2ncdO34uhJR/XvyD82+hUCoLM/lcxEE2Y wD+68TvdycdeOlq2jENPAw7rClz1PSFJ/Kswt8lgV+KKh02Wcf7055I6syj4IvP8LpZ5 UZDUaVINfly6J3DZI4+tpUlDe4/T9pDfrKw5aEd2asxx52u+Z2nl7Hmz8hnBh3BmAhz3 CJwzwCEzlfd2/36I2KL78B/Kx2SllDuU78eJ/oW2kF8LXPOvi7XPnkx87cW23AJylDGt ORWg==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=fm2 header.b=BZitemSQ; spf=pass (google.com: domain of fm-1324425-202610271105245f263c63fd00020789-ts0myf@rts-flowmailer.siemens.com designates 185.136.65.226 as permitted sender) smtp.mailfrom=fm-1324425-202610271105245f263c63fd00020789-tS0MYF@rts-flowmailer.siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com Received: from mta-65-226.siemens.flowmailer.net (mta-65-226.siemens.flowmailer.net. [185.136.65.226]) by gmr-mx.google.com with ESMTPS id 41be03b00d2f7-cd8ccc5afc0si185777a12.11.2026.10.27.04.05.28 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 27 Oct 2026 04:05:29 -0700 (PDT) Received-SPF: pass (google.com: domain of fm-1324425-202610271105245f263c63fd00020789-ts0myf@rts-flowmailer.siemens.com designates 185.136.65.226 as permitted sender) client-ip=185.136.65.226; Received: by mta-65-226.siemens.flowmailer.net with ESMTPSA id 202610271105245f263c63fd00020789 for ; Tue, 27 Oct 2026 12:05:24 +0100 X-Patchwork-Original-From: "srinuvasan.a via isar-users" From: "srinuvasan.a" To: isar-users@googlegroups.com Cc: cedric.hombourger@siemens.com, Srinuvasan A Subject: [PATCH 3/3] deploy-image: re-encrypt LUKS volumes with new master keys Date: Tue, 27 Oct 2026 16:36:01 +0530 Message-Id: <20261027110601.1197504-3-srinuvasan.a@siemens.com> In-Reply-To: <20261027110601.1197504-1-srinuvasan.a@siemens.com> References: <20261027110601.1197504-1-srinuvasan.a@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-1324425:519-21489:flowmailer X-Original-Sender: srinuvasan.a@siemens.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=fm2 header.b=BZitemSQ; spf=pass (google.com: domain of fm-1324425-202610271105245f263c63fd00020789-ts0myf@rts-flowmailer.siemens.com designates 185.136.65.226 as permitted sender) smtp.mailfrom=fm-1324425-202610271105245f263c63fd00020789-tS0MYF@rts-flowmailer.siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com X-Original-From: srinuvasan.a@siemens.com Reply-To: srinuvasan.a@siemens.com Precedence: list Mailing-list: list isar-users@googlegroups.com; contact isar-users+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: isar-users@googlegroups.com X-Google-Group-Id: 914930254986 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Status: No, score=-4.9 required=5.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, RCVD_IN_RP_CERTIFIED,RCVD_IN_RP_RNBL,RCVD_IN_RP_SAFE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on shymkent.ilbers.de X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= From: Srinuvasan A Raw image installation clones the LUKS volume keys of the source image to every installed device. Add sys_api functions that rotate them on the offline target before the installation lock is released: - sys_luks_list_volumes: verify the target is idle and every LUKS2 volume is a pristine provisioning container - sys_luks_reencrypt_volume: reencrypt one volume (no resilience journal, as a failure requires reinstalling) emitting percentages - sys_luks_rotate_keys: orchestrate the above, one progress gauge per volume through the optional ui_reencrypt_volume_gauge hook, which uses ui_progress_gauge The initial passphrase defaults to empty and can be supplied through the optional sys_luks_passphrase_hook callback. cryptsetup and jq are only required when an encrypted volume is found; when missing, key rotation is skipped with a warning. A failed rotation is recorded as the installation result, so that other consoles report it. Signed-off-by: Srinuvasan A Suggested-by: Cedric Hombourger --- .../files/usr/bin/installer_ui.sh | 14 ++ .../deploy-image/files/usr/bin/sys_api.sh | 212 +++++++++++++++++- 2 files changed, 222 insertions(+), 4 deletions(-) diff --git a/meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh b/meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh index aa906221..6f2433e6 100644 --- a/meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh +++ b/meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh @@ -209,6 +209,20 @@ ui_progress_gauge() { return "$status" } +#-------------------------------------------------------------------------- +# ui_reencrypt_volume_gauge +# +# Shows a gauge for one encrypted volume, fed with percentages on stdin +# (see sys_luks_reencrypt_volume). +#-------------------------------------------------------------------------- +ui_reencrypt_volume_gauge() { + local device="$1" + local index="$2" + local count="$3" + + ui_progress_gauge "Securing volume $index/$count ($device) with a new encryption key.\nDo not power off." +} + #-------------------------------------------------------------------------- # ui_stop_progress_gauge # diff --git a/meta-isar/recipes-installer/deploy-image/files/usr/bin/sys_api.sh b/meta-isar/recipes-installer/deploy-image/files/usr/bin/sys_api.sh index 26b39108..4f246697 100644 --- a/meta-isar/recipes-installer/deploy-image/files/usr/bin/sys_api.sh +++ b/meta-isar/recipes-installer/deploy-image/files/usr/bin/sys_api.sh @@ -273,18 +273,215 @@ sys_bmap_options_for_image() { fi } +#-------------------------------------------------------------------------- +# sys_luks_list_volumes +# +# Prints the LUKS2 volumes found on target_device (and its partitions), +# one per line, once the target has been verified to be offline and every +# volume to be a pristine provisioning container: a single keyslot, no +# tokens and no pending reencryption. Unencrypted targets yield no output +# and need neither cryptsetup nor jq; encrypted ones yield no output (with a +# warning) when either is missing, so that key rotation is skipped. +# +# Returns: +# 0 on success (also when tools are missing, see above), 1 when the +# target is busy or a volume is unsupported (reason on stderr). +#-------------------------------------------------------------------------- +sys_luks_list_volumes() { + local target_device="$1" + local devices device mounts fstype metadata probe_status + local holders + local volumes=() + + partprobe "$target_device" || true + ! command -v udevadm >/dev/null || udevadm settle || true + + devices=$(lsblk --list --noheadings --paths --output NAME "$target_device") || return 1 + while IFS= read -r device; do + mounts=$(lsblk --nodeps --noheadings --output MOUNTPOINTS "$device") + if [ -n "${mounts//[[:space:]]/}" ]; then + echo "Error: $device is mounted" >&2 + return 1 + fi + holders=(/sys/class/block/"${device##*/}"/holders/*) + if [ -e "${holders[0]}" ]; then + echo "Error: $device has active holders" >&2 + return 1 + fi + + probe_status=0 + fstype=$(blkid --probe --output value --match-tag TYPE "$device" 2>/dev/null) || probe_status=$? + if [ "$probe_status" != 0 ] && [ "$probe_status" != 2 ]; then + echo "Error: cannot probe $device" >&2 + return 1 + fi + [ "$fstype" = crypto_LUKS ] || continue + + # Optional tools: without them keys are not rotated (see sys_luks_rotate_keys). + if ! command -v cryptsetup >/dev/null || ! command -v jq >/dev/null; then + echo "Warning: $device is encrypted but cryptsetup/jq are missing, skipping key rotation" >&2 + return 0 + fi + if ! cryptsetup isLuks --type luks2 "$device"; then + echo "Error: $device is not a LUKS2 volume" >&2 + return 1 + fi + metadata=$(cryptsetup luksDump --dump-json-metadata "$device") || return 1 + if ! jq -e ' + (.tokens | length) == 0 and + (.keyslots | length) == 1 and + all(.keyslots[]; .type == "luks2") and + (.segments | length) == 1 and + all(.segments[]; .type == "crypt" and ((.flags // []) | length) == 0) + ' <<< "$metadata" >/dev/null; then + echo "Error: unsupported or interrupted LUKS state on $device" >&2 + return 1 + fi + volumes+=("$device") + done <<< "$devices" + + [ ${#volumes[@]} -eq 0 ] || printf '%s\n' "${volumes[@]}" +} + +#-------------------------------------------------------------------------- +# sys_luks_make_keyfile +# +# Creates a private key file holding the initial passphrase of and +# prints its path. The passphrase is empty unless the optional hook +# sys_luks_passphrase_hook is defined; it is called with the device and +# must print the passphrase on stdout (no trailing newline is added). +#-------------------------------------------------------------------------- +sys_luks_make_keyfile() { + local device="$1" + local keyfile passphrase="" + + if declare -F sys_luks_passphrase_hook >/dev/null; then + passphrase=$(sys_luks_passphrase_hook "$device") || return 1 + fi + keyfile=$(mktemp /run/installer-luks-key.XXXXXX) || return 1 + printf '%s' "$passphrase" > "$keyfile" || { rm -f -- "$keyfile"; return 1; } + echo "$keyfile" +} + +#-------------------------------------------------------------------------- +# sys_luks_reencrypt_volume +# +# Generates a new volume key for a provisioning LUKS2 volume, unlocking it +# with its initial passphrase (see sys_luks_make_keyfile), and emits one +# integer percentage per line on stdout so callers can drive a progress +# indicator. The volume is offline and a failed run requires reinstalling, +# so no resilience journal is kept (this halves the amount of data written). +# +# Returns: +# 0 when the volume was reencrypted and verified, 1 otherwise. +#-------------------------------------------------------------------------- +sys_luks_reencrypt_volume() { + local device="$1" + local keyfile log uuid metadata status + + keyfile=$(sys_luks_make_keyfile "$device") || return 1 + uuid=$(cryptsetup luksUUID "$device") || { rm -f -- "$keyfile"; return 1; } + log=$(mktemp /run/installer-luks-reencrypt.XXXXXX) || { rm -f -- "$keyfile"; return 1; } + + # Progress is printed on stdout, errors on stderr (kept for reporting). + cryptsetup reencrypt --batch-mode --force-offline-reencrypt \ + --resilience none --progress-json --progress-frequency 1 \ + --key-file "$keyfile" "$device" 2> "$log" | + jq -R --unbuffered -r ' + fromjson? | select(.device_size != null) | + (((.device_bytes | tonumber) * 100) / (.device_size | tonumber) | floor)' + status=${PIPESTATUS[0]} + [ "$status" = 0 ] || cat "$log" >&2 + rm -f -- "$log" + + if [ "$status" = 0 ]; then + [ "$(cryptsetup luksUUID "$device")" = "$uuid" ] || status=1 + fi + if [ "$status" = 0 ]; then + cryptsetup open --test-passphrase --key-file "$keyfile" "$device" || status=1 + fi + if [ "$status" = 0 ]; then + metadata=$(cryptsetup luksDump --dump-json-metadata "$device") || status=1 + jq -e 'all(.keyslots[]; .type != "reencrypt") and + all(.segments[]; .type == "crypt" and ((.flags // []) | length) == 0)' \ + <<< "$metadata" >/dev/null || status=1 + fi + + rm -f -- "$keyfile" + [ "$status" = 0 ] || echo "Error: reencryption of $device failed" >&2 + [ "$status" = 0 ] +} + +#-------------------------------------------------------------------------- +# sys_luks_rotate_keys +# +# Installed images share the volume keys of the image they were built +# from. Reencrypt every LUKS2 volume of target_device so the installed +# system uses its own master keys. Must run while the target is offline. +# +# Optional hooks (if defined): +# sys_luks_passphrase_hook +# prints the initial passphrase of (default: empty) +# ui_reencrypt_volume_gauge +# reads percentages from stdin while a volume is reencrypted +# +# Returns: +# 0 when all volumes were rotated, none are encrypted, or rotation was +# skipped because cryptsetup or jq is missing (warning on stderr); +# 1 otherwise. On failure the target must not be booted and must be +# reinstalled. +#-------------------------------------------------------------------------- +sys_luks_rotate_keys() { + local target_device="$1" + local volumes=() + local device keyfile listing status index=0 count + + listing=$(sys_luks_list_volumes "$target_device") || return 1 + [ -n "$listing" ] || return 0 + mapfile -t volumes <<< "$listing" + count=${#volumes[@]} + + # Fail before touching any volume when the initial credential is wrong. + for device in "${volumes[@]}"; do + keyfile=$(sys_luks_make_keyfile "$device") || return 1 + if ! cryptsetup open --test-passphrase --key-file "$keyfile" "$device"; then + echo "Error: initial unlock credential is unavailable for $device" >&2 + rm -f -- "$keyfile" + return 1 + fi + rm -f -- "$keyfile" + done + + for device in "${volumes[@]}"; do + index=$((index + 1)) + if declare -F ui_reencrypt_volume_gauge >/dev/null; then + sys_luks_reencrypt_volume "$device" | ui_reencrypt_volume_gauge "$device" "$index" "$count" + status=${PIPESTATUS[0]} + else + echo "Reencrypting $device ($index/$count); do not power off." + sys_luks_reencrypt_volume "$device" | while read -r percent; do + printf '\r%s: %s%%' "$device" "$percent" + done + status=${PIPESTATUS[0]} + echo + fi + [ "$status" = 0 ] || return 1 + done +} + #-------------------------------------------------------------------------- # sys_install_image_with_lock # # Performs the actual bmaptool copy, serializing concurrent installer -# consoles via flock. When UI hook functions are available, this API -# uses them to present a progress gauge in attended mode. Consoles that -# do not get the lock wait for its holder and report its result, which is -# kept in /run/installer.result. +# consoles via flock, then rotates the LUKS volume keys of the target +# (see sys_luks_rotate_keys) before the lock is released. When UI hook +# functions are available, this API uses them to present progress gauges +# in attended mode. # # Optional UI hooks (if defined): # ui_start_progress_gauge # ui_stop_progress_gauge +# ui_reencrypt_volume_gauge #-------------------------------------------------------------------------- sys_install_image_with_lock() { local image_path="$1" @@ -335,6 +532,13 @@ sys_install_image_with_lock() { ui_stop_progress_gauge fi + # Still under the lock: give the installed system its own volume keys. + if ! sys_luks_rotate_keys "$target_device"; then + echo "Volume-key rotation failed. Installation is incomplete; do not boot the target." >&2 + echo failed > "$result_file" + return 1 + fi + echo ok > "$result_file" else echo "Installation already running in another console. Waiting for it to finish..."