1 |
commit: 9e7b41cda3df648b509a0f8a2af29a683100a46f |
2 |
Author: Thomas Deutschmann <whissi <AT> gentoo <DOT> org> |
3 |
AuthorDate: Fri Jan 10 16:07:20 2020 +0000 |
4 |
Commit: Thomas Deutschmann <whissi <AT> gentoo <DOT> org> |
5 |
CommitDate: Sat Jan 11 19:54:40 2020 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/genkernel.git/commit/?id=9e7b41cd |
7 |
|
8 |
Rework ZFS unlock |
9 |
|
10 |
- Prompt for key when key is unavailable, not when key is available. |
11 |
|
12 |
- Check ZFS' keystatus property instead of return value to allow |
13 |
remote unlock. |
14 |
|
15 |
- Add unlock-zfs command to remote rescue shell. |
16 |
|
17 |
Closes: https://bugs.gentoo.org/705032 |
18 |
Signed-off-by: Thomas Deutschmann <whissi <AT> gentoo.org> |
19 |
|
20 |
defaults/initrd.defaults | 3 ++ |
21 |
defaults/initrd.scripts | 38 +++++++++++++++----- |
22 |
defaults/linuxrc | 42 +++++++++++++++------- |
23 |
defaults/login-remote.sh | 5 +++ |
24 |
defaults/unlock-zfs.sh | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ |
25 |
gen_initramfs.sh | 6 ++++ |
26 |
6 files changed, 165 insertions(+), 20 deletions(-) |
27 |
|
28 |
diff --git a/defaults/initrd.defaults b/defaults/initrd.defaults |
29 |
index 198800b..15326dd 100644 |
30 |
--- a/defaults/initrd.defaults |
31 |
+++ b/defaults/initrd.defaults |
32 |
@@ -103,6 +103,9 @@ CRYPT_KEYFILE_SWAP='/tmp/swap.key' |
33 |
CRYPT_ROOT_OPENED_LOCKFILE='/tmp/ROOT.opened' |
34 |
CRYPT_SWAP_OPENED_LOCKFILE='/tmp/SWAP.opened' |
35 |
|
36 |
+ZFS_ENC_ENV_FILE='/etc/ZFS_ENC_ENV.conf' |
37 |
+ZFS_ENC_OPENED_LOCKFILE='/tmp/ZFS.opened' |
38 |
+ |
39 |
# Flag for if ok when using CDROOT |
40 |
got_good_root='0' |
41 |
# if LOOP found on root before mount, trigger Unpacking additional packages |
42 |
|
43 |
diff --git a/defaults/initrd.scripts b/defaults/initrd.scripts |
44 |
index 73cd94c..6c7d72b 100644 |
45 |
--- a/defaults/initrd.scripts |
46 |
+++ b/defaults/initrd.scripts |
47 |
@@ -1087,6 +1087,20 @@ warn_msg() { |
48 |
[ "$2" != '1' ] && printf "%b\n" "${WARN}**${NORMAL}${BOLD} ${msg_string} ${NORMAL}" |
49 |
} |
50 |
|
51 |
+write_env_file() { |
52 |
+ local env_file=${1} |
53 |
+ shift |
54 |
+ |
55 |
+ run touch "${env_file}" |
56 |
+ |
57 |
+ local varname= varvalue= |
58 |
+ for varname in $* |
59 |
+ do |
60 |
+ eval varvalue=\$${varname} |
61 |
+ echo "${varname}=${varvalue}" >> "${env_file}" |
62 |
+ done |
63 |
+} |
64 |
+ |
65 |
crypt_filter() { |
66 |
if [ "${CRYPT_SILENT}" = '1' ] |
67 |
then |
68 |
@@ -2265,14 +2279,15 @@ start_sshd() { |
69 |
return |
70 |
fi |
71 |
|
72 |
- # setup environment variables for the ssh login shell |
73 |
- local varname= varvalue= |
74 |
- run touch "${CRYPT_ENV_FILE}" |
75 |
- for varname in CRYPT_ROOT CRYPT_ROOT_TRIM CRYPT_SILENT CRYPT_SWAP |
76 |
- do |
77 |
- eval varvalue=\$${varname} |
78 |
- echo "${varname}=${varvalue}" >> "${CRYPT_ENV_FILE}" |
79 |
- done |
80 |
+ # setup environment variables for the remote rescue shell |
81 |
+ # ZFS will use a different file because $REAL_ROOT for ZFS |
82 |
+ # isn't known yet. |
83 |
+ write_env_file \ |
84 |
+ "${CRYPT_ENV_FILE}" \ |
85 |
+ CRYPT_ROOT \ |
86 |
+ CRYPT_ROOT_TRIM \ |
87 |
+ CRYPT_SILENT \ |
88 |
+ CRYPT_SWAP |
89 |
|
90 |
run touch /var/log/lastlog |
91 |
|
92 |
@@ -2679,6 +2694,13 @@ get_mount_device() { |
93 |
' ${NEW_ROOT}/etc/fstab |
94 |
} |
95 |
|
96 |
+get_zfs_property() { |
97 |
+ local device=${1} |
98 |
+ local propertyname=${2} |
99 |
+ |
100 |
+ echo "$(zfs get -H -o value ${propertyname} "${device}" 2>/dev/null)" |
101 |
+} |
102 |
+ |
103 |
# If the kernel is handed a mount option is does not recognize, it WILL fail to |
104 |
# mount. util-linux handles auto/noauto, but busybox passes it straight to the kernel |
105 |
# which then rejects the mount. |
106 |
|
107 |
diff --git a/defaults/linuxrc b/defaults/linuxrc |
108 |
index f585017..7fbd0ad 100644 |
109 |
--- a/defaults/linuxrc |
110 |
+++ b/defaults/linuxrc |
111 |
@@ -491,7 +491,7 @@ then |
112 |
if [ ! -x ${i} ] |
113 |
then |
114 |
USE_ZFS=0 |
115 |
- bad_msg 'Aborting use of zfs because ${i} not found!' |
116 |
+ bad_msg "Aborting use of ZFS because ${i} not found!" |
117 |
break |
118 |
fi |
119 |
done |
120 |
@@ -740,7 +740,7 @@ do |
121 |
ROOT_DEV="${REAL_ROOT#*=}" |
122 |
if [ "${ROOT_DEV}" != 'ZFS' ] |
123 |
then |
124 |
- if [ "$(zfs get type -o value -H ${ROOT_DEV} 2>/dev/null)" = 'filesystem' ] |
125 |
+ if [ "$(get_zfs_property "${ROOT_DEV}" type)" = 'filesystem' ] |
126 |
then |
127 |
got_good_root=1 |
128 |
REAL_ROOT=${ROOT_DEV} |
129 |
@@ -753,7 +753,7 @@ do |
130 |
continue |
131 |
fi |
132 |
else |
133 |
- BOOTFS=$(/sbin/zpool list -H -o bootfs 2>/dev/null) |
134 |
+ BOOTFS=$(zpool list -H -o bootfs 2>/dev/null) |
135 |
if [ "${BOOTFS}" != '-' ] |
136 |
then |
137 |
for i in ${BOOTFS} |
138 |
@@ -801,6 +801,14 @@ do |
139 |
echo |
140 |
fi |
141 |
|
142 |
+ if [ "${USE_ZFS}" = '1' ] |
143 |
+ then |
144 |
+ write_env_file \ |
145 |
+ "${ZFS_ENC_ENV_FILE}" \ |
146 |
+ REAL_ROOT \ |
147 |
+ ROOTFSTYPE |
148 |
+ fi |
149 |
+ |
150 |
# Check for a block device or /dev/nfs or zfs encryption |
151 |
if [ -n "${REAL_ROOT}" ] && [ "${REAL_ROOT}" = "/dev/nfs" ] || [ "${ROOTFSTYPE}" = "zfs" ] || [ -b "${REAL_ROOT}" ] |
152 |
then |
153 |
@@ -810,20 +818,30 @@ do |
154 |
# let's check if this dataset is encrypted and ask for passphrase |
155 |
if [ "$(zpool list -H -o feature@encryption "${REAL_ROOT%%/*}" 2>/dev/null)" = 'active' ] |
156 |
then |
157 |
- ZFS_KEYSTATUS="$(zfs get -H -o value keystatus "${REAL_ROOT}" 2>/dev/null)" |
158 |
- ZFS_ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${REAL_ROOT}" 2>/dev/null)" |
159 |
- if ! [ "${ZFS_ENCRYPTIONROOT}" = '-' ] || [ "${ZFS_KEYSTATUS}" = 'available' ] |
160 |
+ ZFS_KEYSTATUS="$(get_zfs_property "${REAL_ROOT}" keystatus)" |
161 |
+ ZFS_ENCRYPTIONROOT="$(get_zfs_property "${REAL_ROOT}" encryptionroot)" |
162 |
+ if [ "${ZFS_ENCRYPTIONROOT}" != '-' ] && [ "${ZFS_KEYSTATUS}" = 'unavailable' ] |
163 |
then |
164 |
good_msg "Detected ZFS encryption, asking for key" |
165 |
- zfs load-key "${ZFS_ENCRYPTIONROOT}" |
166 |
- retval=$? |
167 |
- # if the key loaded fine, confirm got_good_root to exit second while loop |
168 |
- if [ ${retval} -ne 0 ] |
169 |
+ run zfs load-key "${ZFS_ENCRYPTIONROOT}" |
170 |
+ |
171 |
+ # Get new key status to check if load-key was successful |
172 |
+ # or dataset has been opened by someone else in the meantime (through SSH for instance) |
173 |
+ ZFS_KEYSTATUS="$(get_zfs_property "${REAL_ROOT}" keystatus)" |
174 |
+ |
175 |
+ if [ "${ZFS_KEYSTATUS}" != 'available' ] |
176 |
then |
177 |
- bad_msg "${ROOT_DEV} is encrypted and not mountable without key" |
178 |
+ bad_msg "${REAL_ROOT} is encrypted and not mountable without key" |
179 |
got_good_root=0 |
180 |
break |
181 |
fi |
182 |
+ |
183 |
+ if [ -f "${ZFS_ENC_OPENED_LOCKFILE}" ] |
184 |
+ then |
185 |
+ good_msg "${REAL_ROOT} device meanwhile was opened by someone else." |
186 |
+ else |
187 |
+ run touch "${ZFS_ENC_OPENED_LOCKFILE}" |
188 |
+ fi |
189 |
fi |
190 |
fi |
191 |
else |
192 |
@@ -849,7 +867,7 @@ do |
193 |
|
194 |
if [ "${ROOTFSTYPE}" = 'zfs' ] |
195 |
then |
196 |
- if [ "$(zfs get -H -o value mountpoint "${REAL_ROOT}")" = 'legacy' ] |
197 |
+ if [ "$(get_zfs_property "${REAL_ROOT}" mountpoint)" = 'legacy' ] |
198 |
then |
199 |
MOUNT_STATE=rw |
200 |
else |
201 |
|
202 |
diff --git a/defaults/login-remote.sh b/defaults/login-remote.sh |
203 |
index 588504f..94ee014 100644 |
204 |
--- a/defaults/login-remote.sh |
205 |
+++ b/defaults/login-remote.sh |
206 |
@@ -105,6 +105,11 @@ else |
207 |
good_msg "${NORMAL}To remote unlock LUKS-encrypted swap device, run '${BOLD}unlock-luks swap${NORMAL}'." |
208 |
fi |
209 |
|
210 |
+ if [ -e "${ZFS_ENC_ENV_FILE}" ] && [ ! -f "${ZFS_ENC_OPENED_LOCKFILE}" ] |
211 |
+ then |
212 |
+ good_msg "${NORMAL}To remote unlock ZFS root device, run '${BOLD}unlock-zfs${NORMAL}'." |
213 |
+ fi |
214 |
+ |
215 |
echo |
216 |
|
217 |
[ -x /bin/sh ] && SH=/bin/sh || SH=/bin/ash |
218 |
|
219 |
diff --git a/defaults/unlock-zfs.sh b/defaults/unlock-zfs.sh |
220 |
new file mode 100644 |
221 |
index 0000000..c22a214 |
222 |
--- /dev/null |
223 |
+++ b/defaults/unlock-zfs.sh |
224 |
@@ -0,0 +1,91 @@ |
225 |
+#!/bin/sh |
226 |
+ |
227 |
+. /etc/initrd.defaults |
228 |
+. /etc/initrd.scripts |
229 |
+ |
230 |
+GK_INIT_LOG_PREFIX=${0} |
231 |
+if [ -n "${SSH_CLIENT_IP}" ] && [ -n "${SSH_CLIENT_PORT}" ] |
232 |
+then |
233 |
+ GK_INIT_LOG_PREFIX="${0}[${SSH_CLIENT_IP}:${SSH_CLIENT_PORT}]" |
234 |
+fi |
235 |
+ |
236 |
+if [ -f "${ZFS_ENC_ENV_FILE}" ] |
237 |
+then |
238 |
+ . "${ZFS_ENC_ENV_FILE}" |
239 |
+else |
240 |
+ bad_msg "${ZFS_ENC_ENV_FILE} does not exist! Did you boot without 'dozfs' kernel command-line parameter?" |
241 |
+ exit 1 |
242 |
+fi |
243 |
+ |
244 |
+main() { |
245 |
+ if ! hash zfs >/dev/null 2>&1 |
246 |
+ then |
247 |
+ bad_msg "zfs program is missing. Was initramfs built without --zfs parameter?" |
248 |
+ exit 1 |
249 |
+ elif ! hash zpool >/dev/null 2>&1 |
250 |
+ then |
251 |
+ bad_msg "zpool program is missing. Was initramfs built without --zfs parameter?" |
252 |
+ exit 1 |
253 |
+ elif [ -z "${ROOTFSTYPE}" ] |
254 |
+ then |
255 |
+ bad_msg "Something went wrong. ROOTFSTYPE is not set!" |
256 |
+ exit 1 |
257 |
+ elif [ "${ROOTFSTYPE}" != "zfs" ] |
258 |
+ then |
259 |
+ bad_msg "ROOTFSTYPE of 'zfs' required but '${ROOTFSTYPE}' detected!" |
260 |
+ exit 1 |
261 |
+ elif [ -z "${REAL_ROOT}" ] |
262 |
+ then |
263 |
+ bad_msg "Something went wrong. REAL_ROOT is not set!" |
264 |
+ exit 1 |
265 |
+ fi |
266 |
+ |
267 |
+ if [ "$(zpool list -H -o feature@encryption "${REAL_ROOT%%/*}" 2>/dev/null)" != 'active' ] |
268 |
+ then |
269 |
+ bad_msg "Root device ${REAL_ROOT} is not encrypted!" |
270 |
+ exit 1 |
271 |
+ fi |
272 |
+ |
273 |
+ local ZFS_ENCRYPTIONROOT="$(get_zfs_property "${REAL_ROOT}" encryptionroot)" |
274 |
+ if [ "${ZFS_ENCRYPTIONROOT}" = '-' ] |
275 |
+ then |
276 |
+ bad_msg "Failed to determine encryptionroot for ${REAL_ROOT}!" |
277 |
+ exit 1 |
278 |
+ fi |
279 |
+ |
280 |
+ local ZFS_KEYSTATUS= |
281 |
+ while true |
282 |
+ do |
283 |
+ if [ -e "${ZFS_ENC_OPENED_LOCKFILE}" ] |
284 |
+ then |
285 |
+ good_msg "${REAL_ROOT} device meanwhile was opened by someone else." |
286 |
+ break |
287 |
+ fi |
288 |
+ |
289 |
+ zfs load-key "${ZFS_ENCRYPTIONROOT}" |
290 |
+ |
291 |
+ ZFS_KEYSTATUS="$(get_zfs_property "${REAL_ROOT}" keystatus)" |
292 |
+ if [ "${ZFS_KEYSTATUS}" = 'available' ] |
293 |
+ then |
294 |
+ run touch "${ZFS_ENC_OPENED_LOCKFILE}" |
295 |
+ good_msg "ZFS device ${REAL_ROOT} opened" |
296 |
+ break |
297 |
+ else |
298 |
+ bad_msg "Failed to open ZFS device ${REAL_ROOT}" |
299 |
+ |
300 |
+ # We need to stop here with a non-zero exit code to prevent |
301 |
+ # a loop when invalid keyfile was sent. |
302 |
+ exit 1 |
303 |
+ fi |
304 |
+ done |
305 |
+ |
306 |
+ if [ "${ZFS_KEYSTATUS}" = 'available' ] |
307 |
+ then |
308 |
+ # Kill any running load-key prompt. |
309 |
+ run pkill -f "load-key" >/dev/null 2>&1 |
310 |
+ fi |
311 |
+} |
312 |
+ |
313 |
+main |
314 |
+ |
315 |
+exit 0 |
316 |
|
317 |
diff --git a/gen_initramfs.sh b/gen_initramfs.sh |
318 |
index 676b86d..8620414 100755 |
319 |
--- a/gen_initramfs.sh |
320 |
+++ b/gen_initramfs.sh |
321 |
@@ -1342,6 +1342,9 @@ append_dropbear() { |
322 |
cp -a "${GK_SHARE}"/defaults/unlock-luks.sh "${TDIR}"/usr/sbin/unlock-luks \ |
323 |
|| gen_die "Failed to copy '${GK_SHARE}/defaults/unlock-luks.sh' to '${TDIR}/usr/sbin/unlock-luks'" |
324 |
|
325 |
+ cp -a "${GK_SHARE}"/defaults/unlock-zfs.sh "${TDIR}"/usr/sbin/unlock-zfs \ |
326 |
+ || gen_die "Failed to copy '${GK_SHARE}/defaults/unlock-zfs.sh' to '${TDIR}/usr/sbin/unlock-zfs'" |
327 |
+ |
328 |
cp -aL "${DROPBEAR_AUTHORIZED_KEYS_FILE}" "${TDIR}"/root/.ssh/ \ |
329 |
|| gen_die "Failed to copy '${DROPBEAR_AUTHORIZED_KEYS_FILE}'!" |
330 |
|
331 |
@@ -1369,6 +1372,9 @@ append_dropbear() { |
332 |
chmod 0755 "${TDIR}"/usr/sbin/unlock-luks \ |
333 |
|| gen_die "Failed to chmod of '${TDIR}/usr/sbin/unlock-luks'!" |
334 |
|
335 |
+ chmod 0755 "${TDIR}"/usr/sbin/unlock-zfs \ |
336 |
+ || gen_die "Failed to chmod of '${TDIR}/usr/sbin/unlock-zfs'!" |
337 |
+ |
338 |
chmod 0640 "${TDIR}"/etc/shadow \ |
339 |
|| gen_die "Failed to chmod of '${TDIR}/etc/shadow'!" |