[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#451535: Bug#529343: debian-installer: physical volume for encryption: doesnt care if already encrypted and kills data



On Wed, Sep 07, 2011 at 03:59:16PM +0100, Colin Watson wrote:
> Here's a first pass at this.  What do people think?

I meant to send my previous version to the first of the merged bug set,
#451535.  I'll send further mails only there rather than to #529343 as
well.

> The one thing I don't think I've got right yet is writing out
> /etc/crypttab at the end of installation.  This needs a bit more work to
> write out the correct files in the partman device directory without
> causing partman to reinitialise the encrypted volume.

Well.  Yes.  That turned out to be the second 90% of the work!  After
trying a few alternatives, I ended up with a new 'crypto_keep' method
and then tried to let init.d/crypto do as much of the work as possible,
while still being careful to avoid reinitialising the contents of
encrypted volumes.

In the process, I also decided that it was better to always have the
Activate option present, without trying to detect existing volumes
first.  That way, we can actively warn people that this method only
works with LUKS where we have a useful encrypted volume header and that
they should back up their data before attempting an installation, rather
than having them get confused into destroying their data as before.

I'm fairly happy with this now, and am inclined to commit it if there
are no objections.  The one problem I've found is that the check for an
unencrypted /boot doesn't work properly when activating existing
LVM-on-crypto volumes, but I think that's actually a pre-existing bug so
I'm not going to let that block this change.

  * Add an "Activate existing encrypted volumes" option to the
    partman-crypto main menu.  If selected, this searches for existing
    volumes, and for each one prompts for its passphrase and attempts to
    open it; it then returns directly to the partitioning menu (closes:
    #451535, LP: #420080).

=== modified file 'check.d/crypto_check_mountpoints'
--- check.d/crypto_check_mountpoints	2008-03-14 19:25:59 +0000
+++ check.d/crypto_check_mountpoints	2011-09-08 19:20:22 +0000
@@ -43,7 +43,7 @@ for dev in $DEVICES/*; do
 		[ -f $realdevdir/method ] || continue
 		method=$(cat $realdevdir/method)
 		type=$(cat $realdevdir/crypto_type)
-		[ $method = crypto ] || continue
+		[ $method = crypto ] || [ $method = crypto_keep ] || continue
 
 		# Check 1 - Is cryptoroot possible?
 		if [ "$mnt" = / ]; then

=== modified file 'choose_partition/crypto/do_option'
--- choose_partition/crypto/do_option	2009-11-10 14:20:25 +0000
+++ choose_partition/crypto/do_option	2011-09-09 11:30:35 +0000
@@ -12,6 +12,118 @@
 
 . /lib/partman/lib/crypto-base.sh
 
+get_passphrase () {
+	db_set partman-crypto/activate/passphrase-existing ""
+	db_fset partman-crypto/activate/passphrase-existing seen false
+	db_subst partman-crypto/activate/passphrase-existing DEVICE "$1"
+	db_input critical partman-crypto/activate/passphrase-existing
+
+	db_go || return 1
+
+	db_get partman-crypto/activate/passphrase-existing || RET=''
+	echo -n "$RET"
+}
+
+do_cryptsetup () {
+	local dev num id size path
+	local dump cipher keysize ivalgorithm keytype keyhash
+	local cryptdev pass
+
+	dev=$1
+	num=$2
+	id=$3
+	size=$4
+	path=$5
+
+	dump="$(cryptsetup luksDump "$path")"
+	cipher="$(echo "$dump" | sed -n '/^Cipher name:/s/.*[[:space:]]//p')"
+	if [ "$cipher" ]; then
+		crypto_load_udebs "cdebconf-$DEBIAN_FRONTEND-entropy" \
+				  partman-crypto-dm
+		crypto_check_required_tools dm-crypt
+		crypto_load_modules dm-crypt "$cipher"
+	fi
+	keysize="$(echo "$dump" | sed -n '/^MK bits:/s/.*[[:space:]]//p')"
+	ivalgorithm="$(echo "$dump" | sed -n '/^Cipher mode:/s/.*[[:space:]]//p')"
+	keytype=passphrase
+	keyhash="$(echo "$dump" | sed -n '/^Hash spec:/s/.*[[:space:]]//p')"
+
+	cryptdev="${path##*/}_crypt"
+	if ! cryptsetup status "$cryptdev" >/dev/null 2>&1; then
+		while :; do
+			pass="$(get_passphrase "$path")" || return 1
+			if [ -z "$pass" ]; then
+				return 1
+			fi
+			echo -n "$pass" | log-output -t partman-crypto \
+				cryptsetup -d - luksOpen "$path" "$cryptdev" \
+				&& break
+		done
+
+		cryptdev="/dev/mapper/$cryptdev"
+		echo dm-crypt > $id/crypto_type
+		echo "$keysize" > $id/keysize
+		echo "$ivalgorithm" > $id/ivalgorithm
+		echo "$keytype" > $id/keytype
+		echo "$keyhash" > $id/keyhash
+		echo cipher > $id/cipher
+		echo crypto_keep > $id/method
+		echo "$cryptdev" > $id/crypt_active
+
+		db_subst partman-crypto/text/in_use DEV "${cryptdev##*/}"
+		db_metaget partman-crypto/text/in_use description
+		partman_lock_unit "$(mapdevfs "$path")" "$RET"
+	fi
+}
+
+do_activate () {
+	local found_luks dev partitions num id size type fs path name part
+
+	found_luks=0
+	for dev in $DEVICES/*; do
+		[ -d "$dev" ] || continue
+		cd "$dev"
+
+		partitions=
+		open_dialog PARTITIONS
+		while { read_line num id size type fs path name; [ "$id" ]; }; do
+			[ "$fs" != free ] || continue
+			partitions="$partitions $id,$path"
+		done
+		close_dialog
+
+		for part in $partitions; do
+			id="${part%%,*}"
+			path="${part#*,}"
+
+			if cryptsetup isLuks "$path" 2>/dev/null; then
+				found_luks=1
+				do_cryptsetup "$dev" "$num" "$id" "$size" \
+					"$path" || continue
+			fi
+		done
+	done
+
+	if [ "$found_luks" = 0 ]; then
+		db_input critical partman-crypto/activate/no_luks
+		db_go || true
+		return
+	fi
+
+	# Encrypted devices as configured by d-i usually contain LVM PVs
+	export LVM_SUPPRESS_FD_WARNINGS=1
+	log-output -t partman-crypto pvscan
+	log-output -t partman-crypto vgscan
+	log-output -t partman-crypto vgchange -a y
+
+	# Tell partman to detect filesystems again.
+	rm -f /var/lib/partman/filesystems_detected
+
+	stop_parted_server
+	restart_partman
+	exit 0
+}
+
 do_create () {
 	local parts line pv output vg pathmap
 	parts=""
@@ -93,6 +231,7 @@ while :; do
 	db_go || exit 10
 	db_get partman-crypto/mainmenu
 	case $RET in
+	    activate)	do_activate ;; # exits if any volumes were activated
 	    create)	do_create ;;
 	    finish)	break ;;
 	    *)

=== modified file 'debian/control'
--- debian/control	2011-05-03 16:05:09 +0000
+++ debian/control	2011-09-09 12:06:37 +0000
@@ -12,7 +12,7 @@ Vcs-Bzr: http://bazaar.launchpad.net/~ub
 Package: partman-crypto
 XC-Package-Type: udeb
 Architecture: any
-Depends: partman-base (>= 134), cdebconf-udeb (>= 0.133), di-utils (>= 1.68), ${shlibs:Depends}, ${misc:Depends}
+Depends: partman-base (>= 134), partman-lvm (>= 62), cdebconf-udeb (>= 0.133), di-utils (>= 1.68), ${shlibs:Depends}, ${misc:Depends}
 Description: Add to partman support for block device encryption
 
 Package: partman-crypto-dm

=== modified file 'debian/partman-crypto.templates'
--- debian/partman-crypto.templates	2009-12-05 22:29:36 +0000
+++ debian/partman-crypto.templates	2011-09-08 11:16:40 +0000
@@ -430,12 +430,12 @@ _Description: Proceed to install crypto
 
 Template: partman-crypto/mainmenu
 Type: select
-Choices-C: create, finish
+Choices-C: activate, create, finish
 # Note to translators : Please keep your translations of the choices
 # below a 65 columns limit (which means 65 characters
 # in single-byte languages)
 # :sl3:
-__Choices: Create encrypted volumes, Finish
+__Choices: Activate existing encrypted volumes, Create encrypted volumes, Finish
 # :sl3:
 _Description: Encryption configuration actions
  This menu allows you to configure encrypted volumes.
@@ -454,3 +454,20 @@ Type: error
 # :sl3:
 _Description: No devices selected
  No devices were selected for encryption.
+
+Template: partman-crypto/activate/no_luks
+Type: error
+# :sl3:
+_Description: No LUKS devices found
+ This partitioning program can only activate existing encrypted volumes that
+ use the LUKS format (dm-crypt with a passphrase). No such volumes were
+ found. If you have encrypted volumes using other formats, you may need to
+ back up your data before continuing with installation.
+
+Template: partman-crypto/activate/passphrase-existing
+Type: password
+# :sl3:
+_Description: Passphrase for ${DEVICE}:
+ Please enter the passphrase for the encrypted volume ${DEVICE}.
+ .
+ If you don't enter anything, the volume will not be activated.

=== modified file 'finish.d/crypto_aptinstall'
--- finish.d/crypto_aptinstall	2008-03-20 21:06:33 +0000
+++ finish.d/crypto_aptinstall	2011-09-07 22:17:00 +0000
@@ -39,7 +39,7 @@ for dev in $DEVICES/*; do
 		[ -f $id/crypto_type ] || continue
 
 		method=$(cat $id/method)
-		[ $method = crypto ] || continue
+		[ $method = crypto ] || [ $method = crypto_keep ] || continue
 
 		type=$(cat $id/crypto_type)
 		case $type in

=== modified file 'init.d/crypto'
--- init.d/crypto	2010-05-27 09:44:55 +0000
+++ init.d/crypto	2011-09-09 12:36:17 +0000
@@ -4,6 +4,17 @@
 # setup in choose_partition/crypto/do_option.
 
 . /lib/partman/lib/base.sh
+. /lib/partman/lib/lvm-base.sh
+
+# Avoid warnings from lvm2 tools about open file descriptors
+export LVM_SUPPRESS_FD_WARNINGS=1
+
+if [ -x /sbin/vgdisplay ]; then
+	vgroups=$(/sbin/vgdisplay 2>/dev/null | grep '^[ ]*VG Name' | \
+		sed -e 's/.*[[:space:]]\(.*\)$/\1/' | sort)
+else
+	vgroups=''
+fi
 
 dev_to_devdir () {
 	echo $DEVICES/$(echo $1 | tr / =)
@@ -72,7 +83,7 @@ create_partition () {
 }
 
 create_cryptdisk () {
-	local dev id num size path cryptdev cipher
+	local dev id num size path cryptdev cipher file vg vgs
 	dev=$1
 	id=$2
 	num=$3
@@ -81,6 +92,7 @@ create_cryptdisk () {
 
 	cipher=$(cat $id/cipher)
 	keytype=$(cat $id/keytype)
+	method=$(cat $id/method)
 
 	templ="partman-crypto/text/cryptdev_description"
 	db_subst $templ CIPHER $cipher
@@ -128,17 +140,47 @@ create_cryptdisk () {
 	case $filesystem in
 		linux-swap)
 			echo swap > $cryptpart/method
-			>$cryptpart/format
+			if [ "$method" = crypto ]; then
+				>$cryptpart/format
+			else
+				rm -f $cryptpart/format
+			fi
 			;;
 
 		$default_fs)
-			echo format > $cryptpart/method
-			>$cryptpart/format
-			>$cryptpart/use_filesystem
-			echo $filesystem > $cryptpart/filesystem
+			if [ "$method" = crypto ]; then
+				echo format > $cryptpart/method
+				>$cryptpart/format
+				>$cryptpart/use_filesystem
+				echo $filesystem > $cryptpart/filesystem
+			else
+				echo keep > $cryptpart/method
+				rm -f $cryptpart/format
+			fi
 			;;
 	esac
 
+	# To avoid ordering problems between init.d/crypto and init.d/lvm,
+	# we need to duplicate a bit of the latter here, in case an existing
+	# crypto device contains an LVM PV.
+	if [ "$method" = crypto_keep ]; then
+		if pvdisplay "$cryptdev" >/dev/null 2>&1; then
+			for file in acting_filesystem filesystem format \
+				    formatable use_filesystem; do
+				rm -f $cryptpart/$file
+			done
+			echo lvm > $cryptpart/method
+			if [ ! -e $cryptpart/locked ]; then
+				vg="$(pv_get_vg "$cryptdev")"
+				for vgs in $vgroups; do
+					if [ "$vg" = "$vgs" ]; then
+						vg_lock_pvs "$vg" "$cryptdev"
+					fi
+				done
+			fi
+		fi
+	fi
+
 	update_partition $cryptdir $cryptid
 
 	echo $path:$num:$dev/$id > $cryptdir/crypt_realdev
@@ -174,7 +216,7 @@ for dev in /var/lib/partman/devices/*; d
 		[ -f $id/crypt_active ] || continue
 
 		method=$(cat $id/method)
-		[ $method = crypto ] || continue
+		[ $method = crypto ] || [ $method = crypto_keep ] || continue
 
 		if ! create_cryptdisk $dev $id $num $size $path; then
 			db_fset partman-crypto/init_failed seen false

=== modified file 'lib/crypto-base.sh'
--- lib/crypto-base.sh	2011-08-26 12:20:00 +0000
+++ lib/crypto-base.sh	2011-09-07 22:27:14 +0000
@@ -82,7 +82,7 @@ crypto_prepare () {
 	if [ "$method" = swap ]; then
 		disable_swap "$dev" "$id"
 	fi
-	if [ "$method" != crypto ]; then
+	if [ "$method" != crypto ] && [ "$method" != crypto_keep ]; then
 		crypto_prepare_method "$id" dm-crypt || return 1
 		rm -f "$id/use_filesystem"
 		rm -f "$id/format"
@@ -820,7 +820,8 @@ crypto_check_setup() {
 			[ -f $id/crypto_type ] || continue
 
 			method=$(cat $id/method)
-			if [ $method != crypto ]; then
+			if [ $method != crypto ] && \
+			   [ $method != crypto_keep ]; then
 				continue
 			fi
 			type=$(cat $id/crypto_type)

=== modified file 'update.d/crypto_visuals'
--- update.d/crypto_visuals	2007-12-05 20:18:24 +0000
+++ update.d/crypto_visuals	2011-09-07 22:16:23 +0000
@@ -37,8 +37,9 @@ cryptdev_shortname ()
 	esac
 }
 
-if [ $method = crypto ]; then
-	db_metaget partman/method_short/$method description || RET=''
+case $method in
+    crypto|crypto_keep)
+	db_metaget partman/method_short/crypto description || RET=''
 	echo ${RET:-crypto} >$id/visual_filesystem
 
 	if [ -f $id/crypt_active ]; then
@@ -52,5 +53,6 @@ if [ $method = crypto ]; then
 
 	# open_dialog CHANGE_FILE_SYSTEM $id linux-swap
 	# close_dialog
-fi
+	;;
+esac
 
-- 
Colin Watson                                       [cjwatson@ubuntu.com]



Reply to: