-
-
Notifications
You must be signed in to change notification settings - Fork 211
Expand file tree
/
Copy pathkexec-save-default
More file actions
executable file
·373 lines (322 loc) · 12.7 KB
/
Copy pathkexec-save-default
File metadata and controls
executable file
·373 lines (322 loc) · 12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#!/bin/bash
# Save these options to be the persistent default
set -e -o pipefail
# shellcheck disable=SC1091
. /tmp/config
# shellcheck disable=SC1091
. /etc/functions
TRACE "Under /bin/kexec-save-default"
while getopts "b:d:p:i:" arg; do
case $arg in
b) bootdir="$OPTARG" ;;
d) paramsdev="$OPTARG" ;;
p) paramsdir="$OPTARG" ;;
i) index="$OPTARG" ;;
*) echo "Invalid flag: -$OPTARG" >&2 ;;
esac
done
if [ -z "$bootdir" -o -z "$index" ]; then
die "Usage: $0 -b /boot -i menu_option "
fi
if [ -z "$paramsdev" ]; then
paramsdev="$bootdir"
fi
if [ -z "$paramsdir" ]; then
paramsdir="$bootdir"
fi
bootdir="${bootdir%%/}"
paramsdev="${paramsdev%%/}"
paramsdir="${paramsdir%%/}"
TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt"
ENTRY_FILE="$paramsdir/kexec_default.$index.txt"
HASH_FILE="$paramsdir/kexec_default_hashes.txt"
PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt"
KEY_DEVICES="$paramsdir/kexec_key_devices.txt"
KEY_LVM="$paramsdir/kexec_key_lvm.txt"
#Reusable function when user wants to define new TPM DUK for lvms/disks
prompt_for_existing_encrypted_lvms_or_disks() {
TRACE "Under kexec-save-default:prompt_for_existing_encrypted_lvms_or_disks"
DEBUG "num_lvm: $num_lvm, lvm_suggest: ${lvm_suggest[*]}, num_devices: $num_devices, devices_suggest: ${devices_suggest[*]}"
# Create an associative array to store the suggested LVMs and their paths
declare -A lvms_array
# Loop through the suggested LVMs and add them to the array
for lvm in ${lvm_suggest[@]}; do
lvms_array["$lvm"]=$lvm
done
# Get the number of suggested LVMs
num_lvms=${#lvms_array[@]}
if [ "$num_lvms" -gt 1 ]; then
DEBUG "Multiple LVMs found: ${lvm_suggest[*]}"
selected_lvms_not_existing=1
# Create an array to store the selected LVMs
declare -a key_lvms_array
while [ $selected_lvms_not_existing -ne 0 ]; do
{
# Read the user input and store it in a variable
read \
-p "Encrypted LVMs? (choose between/all: ${lvm_suggest[*]}): " \
key_lvms
# Split the user input by spaces and add each element to the array
IFS=' ' read -r -a key_lvms_array <<<"$key_lvms"
# Loop through the array and check if each element is in the lvms_array
valid=1
for lvm in "${key_lvms_array[@]}"; do
if [[ ! ${lvms_array[$lvm]+_} ]]; then
# If not found, set the flag to indicate invalid input
valid=0
break
fi
done
# If valid, set the flag to indicate valid input
if [[ $valid -eq 1 ]]; then
selected_lvms_not_existing=0
fi
}
done
elif [ "$num_lvms" -eq 1 ]; then
echo "Single Encrypted LVM found at ${lvm_suggest[*]}."
key_lvms=("${lvm_suggest[@]}")
else
echo "No encrypted LVMs found."
fi
# Create an associative array to store the suggested devices and their paths
declare -A devices_array
# Loop through the suggested devices and add them to the array
for device in ${devices_suggest[@]}; do
devices_array["$device"]=$device
done
DEBUG "LUKS num_devices before array: $num_devices, devices_array: ${devices_array[*]}"
num_devices=${#devices_array[@]}
DEBUG "LUKS num_devices after array: $num_devices, devices_array: ${devices_array[*]}"
if [ "$num_devices" -gt 1 ]; then
DEBUG "Multiple LUKS devices found: ${devices_suggest[*]}"
selected_luksdevs_not_existing=1
# Create an array to store the selected devices
declare -a key_devices_array
while [ $selected_luksdevs_not_existing -ne 0 ]; do
{
# Read the user input and store it in a variable
read \
-p "Encrypted devices? (choose between/all: ${devices_suggest[*]}): " \
key_devices
# Split the user input by spaces and add each element to the array
IFS=' ' read -r -a key_devices_array <<<"$key_devices"
# Loop through the array and check if each element is in the devices_array
valid=1
for device in "${key_devices_array[@]}"; do
if [[ ! ${devices_array[$device]+_} ]]; then
# If not found, set the flag to indicate invalid input
valid=0
break
fi
done
# If valid, set the flag to indicate valid input
if [[ $valid -eq 1 ]]; then
selected_luksdevs_not_existing=0
fi
}
done
DEBUG "devices_suggest: ${devices_suggest[*]}, key_devices: $key_devices, key_devices_array: ${key_devices_array[*]}"
DEBUG "Multiple LUKS devices selected: $key_devices"
elif [ "$num_devices" -eq 1 ]; then
echo "Single Encrypted Disk found at ${devices_suggest[*]}."
key_devices=("${devices_suggest[@]}")
else
echo "No encrypted devices found."
fi
}
# get all LVM volume groups
lvm_suggest=($(lvm vgscan | awk -F '"' '{print $1}' | tail -n +2))
num_lvm=${#lvm_suggest[@]}
if [ "$num_lvm" -eq 1 ] && [ -n "${lvm_suggest[*]}" ]; then
lvm_volume_group=("${lvm_suggest[@]}")
elif [ -z "${lvm_suggest[*]}" ]; then
num_lvm=0
fi
DEBUG "LVM num_lvm: $num_lvm, lvm_suggest: ${lvm_suggest[*]}"
# get all LUKS container devices
devices_suggest=($(blkid | cut -d ':' -f 1 | while read device; do
if cryptsetup isLuks "$device"; then echo "$device"; fi
done))
num_devices=${#devices_suggest[@]}
if [ "$num_devices" -eq 1 ] && [ -s "${devices_suggest[*]}" ]; then
key_devices=("${devices_suggest[@]}")
elif [ -z "${devices_suggest[*]}" ]; then
num_devices=0
fi
# Create an array to store the suggested devices and their paths
declare -A devices_array
# Loop through the suggested devices and add them to the array
for device in "${devices_suggest[@]}"; do
devices_array["$device"]=$device
done
# $devices_suggest is a multiline string, we need to convert it to a space separated string
devices_suggest=$(echo "${devices_suggest[*]}" | tr '\n' ' ')
DEBUG "LUKS num_devices: $num_devices, devices_suggest: $devices_suggest"
if [ "$num_lvm" -eq 0 ] && [ "$num_devices" -eq 0 ]; then
#No encrypted partition found.
no_encrypted_partition=1
fi
if [ ! -r "$TMP_MENU_FILE" ]; then
die "No menu options available, please run kexec-select-boot"
fi
entry=$(head -n $index $TMP_MENU_FILE | tail -1)
if [ -z "$entry" ]; then
die "Invalid menu index $index"
fi
save_key="n"
if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ "$CONFIG_BASIC" != y ]; then
DEBUG "TPM is enabled and TPM_NO_LUKS_DISK_UNLOCK is not set"
DEBUG "Checking if a a TPM Disk Unlock Key was previously set up from $KEY_DEVICES"
#check if $KEY_DEVICES file exists and is not empty
if [ -r "$KEY_DEVICES" ] && [ -s "$KEY_DEVICES" ]; then
DEBUG "A TPM Disk Unlock Key was previously set up from $KEY_DEVICES"
#TODO: nobody complains about encrypted lvms missing, we might want to deprecate encrypted lvm logic: not aware of anyone using that anymore
#Extract key devices from $KEY_DEVICES file
key_devices=$(cat "$KEY_DEVICES" |
cut -d\ -f1 | xargs) || true
warn "Reseal a TPM Disk Unlock Key only if a new key/passphrase is desired for $key_devices"
read \
-n 1 \
-p "Do you want to reseal a Disk Unlock Key for $key_devices to the TPM [y/N]: " \
change_key_confirm
echo
if [ "$change_key_confirm" = "y" \
-o "$change_key_confirm" = "Y" ]; then
old_lvm_volume_group=""
if [ -r "$KEY_LVM" ]; then
old_lvm_volume_group=$(cat "$KEY_LVM") || true
old_key_devices=$(cat "$KEY_DEVICES" |
cut -d\ -f1 |
grep -v "$old_lvm_volume_group" |
xargs) || true
else
old_key_devices=$(cat "$KEY_DEVICES" |
cut -d\ -f1 | xargs) || true
fi
lvm_suggest=("$old_lvm_volume_group")
devices_suggest=("$old_key_devices")
save_key="y"
fi
else
DEBUG "No previous TPM Disk Unlock Key was set up for LUKS devices, confirming to add a Disk Encryption Key to the TPM"
read \
-n 1 \
-p "Do you wish to add a disk encryption to the TPM [y/N]: " \
add_key_confirm
echo
if [ "$add_key_confirm" = "y" \
-o "$add_key_confirm" = "Y" ]; then
DEBUG "User confirmed desire to add a Disk Encryption Key to the TPM"
save_key="y"
fi
fi
if [ "$save_key" = "y" ]; then
if [ -n "$old_key_devices" ] || [ -n "$old_lvm_volume_group" ]; then
DEBUG "Previous TPM Disk Unlock Key was set up for LUKS devices ${old_key_devices[*]} ${old_lvm_volume_group[*]}"
read \
-n 1 \
-p "Do you want to reuse configured Encrypted LVM groups/Block devices? (Y/n):" \
reuse_past_devices
echo
if [ "$reuse_past_devices" = "y" ] || [ "$reuse_past_devices" = "Y" ] || [ -z "$reuse_past_devices" ]; then
if [ -z "${key_devices[*]}" ] && [ -n "$old_key_devices" ]; then
key_devices=("${old_key_devices[*]}")
fi
if [ -z "${lvm_volume_group[*]}" ] && [ -n "$old_lvm_volume_group" ]; then
lvm_volume_group=("${old_lvm_volume_group[*]}")
fi
#User doesn't want to reuse past devices, so we need to prompt him from devices_suggest and lvm_suggest
else
prompt_for_existing_encrypted_lvms_or_disks
fi
else
DEBUG "No previous TPM Disk Unlock Key was set up for LUKS devices, setting up new one"
prompt_for_existing_encrypted_lvms_or_disks
fi
save_key_params=("-s" "-p" "$paramsdev")
if [ -n "${lvm_volume_group[*]}" ]; then
save_key_params+=("-l" "${lvm_volume_group[*]}" "${key_devices[*]}")
else
save_key_params+=("${key_devices[*]}")
fi
kexec-save-key "${save_key_params[@]}" ||
die "Failed to save the TPM Disk Unlock Key"
fi
fi
# try to switch to rw mode
mount -o rw,remount "$paramsdev"
if [ ! -d "$paramsdir" ]; then
mkdir -p "$paramsdir" ||
die "Failed to create params directory"
fi
if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then
sha256sum /tmp/secret/primary.handle >"$PRIMHASH_FILE" ||
die "ERROR: Failed to Hash TPM2 primary key handle!"
DEBUG "TPM2 primary key handle hash saved to $PRIMHASH_FILE"
fi
rm "$paramsdir/kexec_default."*.txt 2>/dev/null || true
echo "$entry" >"$ENTRY_FILE"
(
cd "$bootdir" && kexec-boot -b "$bootdir" -e "$entry" -f |
xargs sha256sum >"$HASH_FILE"
) || die "Failed to create hashes of boot files"
if [ ! -r "$ENTRY_FILE" -o ! -r "$HASH_FILE" ]; then
die "Failed to write default config"
fi
if [ "$save_key" = "y" ]; then
# logic to parse OS initrd to extract crypttab, its filepaths and its OS defined options
initrd_decompressed="/tmp/initrd_extract"
mkdir -p "$initrd_decompressed"
# Get initrd filename selected to be default initrd that OS could be using to configure LUKS on boot by deploying crypttab files
current_default_initrd=$(cat /boot/kexec_default_hashes.txt | grep initr | awk -F " " {'print $NF'} | sed 's/\.\//\/boot\//g')
echo "+++ Extracting current selected default boot's $current_default_initrd to find crypttab files..."
unpack_initramfs.sh "$current_default_initrd" "$initrd_decompressed"
crypttab_files=$(find "$initrd_decompressed" | grep crypttab 2>/dev/null) || true
if [ ! -z "$crypttab_files" ]; then
DEBUG "Found crypttab files in $current_default_initrd"
rm -f "$bootdir/kexec_initrd_crypttab_overrides.txt" || true
#Parsing each crypttab file found
echo "$crypttab_files" | while read -r crypttab_file; do
# Change crypttab file path to be relative to initrd for string manipulation
final_initrd_filepath=${crypttab_file#/tmp/initrd_extract}
DEBUG "Final initramfs crypttab path:$final_initrd_filepath"
# Keep only non-commented lines for crypttab entries
current_crypttab_entries=$(cat "$crypttab_file" | grep -v "^#")
DEBUG "Found initrd crypttab entries $final_initrd_filepath:$current_crypttab_entries"
# Modify each retained crypttab line for /secret.key under intramfs to be considered as a keyfile
modified_crypttab_entries=$(echo "$current_crypttab_entries" | sed 's/none/\/secret.key/g')
DEBUG "Modified crypttab entries $final_initrd_filepath:$modified_crypttab_entries"
echo "$modified_crypttab_entries" | while read -r modified_crypttab_entry; do
echo "$final_initrd_filepath:$modified_crypttab_entry" >>"$bootdir/kexec_initrd_crypttab_overrides.txt"
done
done
#insert current default boot's initrd crypttab locations into tracking file to be overwritten into initramfs at kexec-inject-key
echo "+++ The following OS crypttab file:entry were modified from default boot's initrd:"
cat "$bootdir/kexec_initrd_crypttab_overrides.txt"
echo "+++ Heads added /secret.key in those entries and saved them under $bootdir/kexec_initrd_crypttab_overrides.txt"
echo "+++ Those overrides will be part of detached signed digests and used to prepare cpio injected at kexec of selected default boot entry."
else
echo "+++ No crypttab file found in extracted initrd. A generic crypttab will be generated"
if [ -e "$bootdir/kexec_initrd_crypttab_overrides.txt" ]; then
echo "+++ Removing $bootdir/kexec_initrd_crypttab_overrides.txt"
rm -f "$bootdir/kexec_initrd_crypttab_overrides.txt"
fi
fi
# Cleanup
cd /
rm -rf /tmp/initrd_extract || true
fi
# sign and auto-roll config counter
extparam=
if [ "$CONFIG_TPM" = "y" ]; then
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
extparam=-r
fi
fi
if [ "$CONFIG_BASIC" != "y" ]; then
kexec-sign-config -p "$paramsdir" $extparam ||
die "Failed to sign default config"
fi
# switch back to ro mode
mount -o ro,remount "$paramsdev"