Bug 1405269
| Summary: | libvirtd crashes when attaching raw LUKS volumes | |||
|---|---|---|---|---|
| Product: | Red Hat Enterprise Linux 7 | Reporter: | Eric Wheeler <rh-bugzilla> | |
| Component: | libvirt | Assignee: | John Ferlan <jferlan> | |
| Status: | CLOSED ERRATA | QA Contact: | yisun | |
| Severity: | urgent | Docs Contact: | ||
| Priority: | high | |||
| Version: | 7.3 | CC: | dyuan, jdenemar, jsuchane, maurizio.antillon, rbalakri, snagar, xuzhang | |
| Target Milestone: | rc | Keywords: | Regression, ZStream | |
| Target Release: | --- | |||
| Hardware: | x86_64 | |||
| OS: | Linux | |||
| Whiteboard: | ||||
| Fixed In Version: | libvirt-3.0.0-1.el7 | Doc Type: | Bug Fix | |
| Doc Text: |
Cause: The libvirt code assumed that for any domain disk device found to be LUKS encrypted, the device would have a libvirt secret associated with the device in order to provide the key to unlock the device.
Consequence: When attempting to access the secret libvirt would core.
Fix: Add a check to ensure that not only is there encryption, but there is a secret before trying to access the secret object in order to pass the secret along with the disk.
Result: After the patch, it is possible to attach a LUKS encrypted disk and no libvirt secret associated with the disk. This would force the application to perform the unlock.
|
Story Points: | --- | |
| Clone Of: | ||||
| : | 1411394 (view as bug list) | Environment: | ||
| Last Closed: | 2017-08-01 17:19:14 UTC | Type: | Bug | |
| Regression: | --- | Mount Type: | --- | |
| Documentation: | --- | CRM: | ||
| Verified Versions: | Category: | --- | ||
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | ||
| Cloudforms Team: | --- | Target Upstream Version: | ||
| Embargoed: | ||||
| Bug Depends On: | ||||
| Bug Blocks: | 1411394 | |||
|
Description
Eric Wheeler
2016-12-16 01:51:28 UTC
It's reproduced in my env
3.10.0-514.el7.x86_64
qemu-kvm-rhev-2.6.0-29.el7.x86_64
qemu-img-rhev-2.6.0-29.el7.x86_64
3.10.0-514.el7.x86_64
# lvdisplay
...
--- Logical volume ---
LV Path /dev/rhel_bootp-73-75-161/lvol0
LV Name lvol0
VG Name rhel_bootp-73-75-161
LV UUID 0ENvVT-vnxU-U6lZ-Wt7c-Ldrs-pc03-Bwhq2o
LV Write Access read/write
LV Creation host, time bootp-73-75-161.lab.eng.pek2.redhat.com, 2016-12-16 18:27:36 +0800
LV Status available
# open 1
LV Size 20.00 MiB
Current LE 5
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:6
# cryptsetup luksFormat /dev/rhel_bootp-73-75-161/lvol0
WARNING!
========
This will overwrite data on /dev/rhel_bootp-73-75-161/lvol0 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
# cat disk.xml
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='none' io='native' discard='unmap'/>
<source dev='/dev/rhel_bootp-73-75-161/lvol0'/>
<target dev='sdb' bus='virtio'/>
<serial>drive-scsi0-0-0-1</serial>
<alias name='drive-scsi0-0-0-1'/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
# virsh attach-device vm1 disk.xml
error: Disconnected from qemu:///system due to I/O error
error: Failed to attach device from disk.xml
error: End of file while reading data: Input/output error
This is probably caused because this is implicit now with disk attachments: <disk> ... <encryption format="default"/> </disk> Of course it should fail more gracefully than a segfault, but a proper backward compatible update might introduce the format of "none" and let that be the default, instead of letting "default" be the default which tries to autodetect the disk format. Perhaps "default" should be renamed "detect". Fallback to passthrough if no key is loaded would be acceptable too. It might be best if libvirt doesn't (by default) attempt to detect anything about volumes that are attached. They should be opaque to the hypervisor unless a non-default setting like format="luks" or perhaps, hypothetically, format="detect". Thank you for your help! It looks like format=default is only for creation according to this https://libvirt.org/formatstorageencryption.html so perhaps the <encryption> tag isn't implicit---but it should still gracefully passthrough if no secret is loaded into libvirt. There is a workaround - of sorts - create the secret and add it to your XML. It worked for me...
Assume 'new_vol' has had cryptsetup luksFormat run on it.
# cat secret.xml
<secret ephemeral='no' private='yes'>
<description>secret libvirt for /dev/LVM_Test/new_vol</description>
<usage type='volume'>
<volume>/dev/LVM_Test/new_vol</volume>
</usage>
</secret>
# virsh secret-define secret.xml
Secret aa3f2251-4506-4d72-9a59-b17ea9d0ffef created
# MYSECRET=`printf %s "libvirt" | base64`
# virsh secret-set-value aa3f2251-4506-4d72-9a59-b17ea9d0ffef $MYSECRET
Secret value set
# cat disk-secret.xml
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='none' io='native' discard='unmap'/>
<source dev='/dev/LVM_Test/new_vol'/>
<target dev='sda' bus='scsi'/>
<encryption format='luks'>
<secret type='passphrase' uuid='aa3f2251-4506-4d72-9a59-b17ea9d0ffef'/>
</encryption>
</disk>
# virsh attach-device f23 disk-secret.xml
Device attached successfully
#
So yes, the code shouldn't core and that can be fixed; however, removing automatic recognition of local storage that encrypted using LUKS would remove functionality, so the final solution could be a bit tricky.
I'll have to keep digging a bit more, but I wanted to at least provide some feedback.
FWIW:
The core in question is because there is no secret defined:
#0 qemuDomainSecretDiskPrepare (conn=conn@entry=0x7fffb4000ad0,
priv=priv@entry=0x7fffc016c920, disk=disk@entry=0x7fffc04aff60)
at qemu/qemu_domain.c:1218
code path:
if (!virStorageSourceIsEmpty(src) && src->encryption &&
src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
if (VIR_ALLOC(secinfo) < 0)
return -1;
1218: if (qemuDomainSecretSetup(conn, priv, secinfo, disk->info.alias,
VIR_SECRET_USAGE_TYPE_VOLUME, NULL,
&src->encryption->secrets[0]->seclookupdef,
true) < 0)
where
(gdb) p *disk
$2 = {src = 0x7fffc04665c0, privateData = 0x7fffc00effd0, device = 0, bus = 2,
dst = 0x7fffc01a6240 "sda", tray_status = 0, removable = 0, mirror = 0x0,
mirrorState = 0, mirrorJob = 0, geometry = {cylinders = 0, heads = 0,
sectors = 0, trans = 0}, blockio = {logical_block_size = 0,
physical_block_size = 0}, blkdeviotune = {total_bytes_sec = 0,
read_bytes_sec = 0, write_bytes_sec = 0, total_iops_sec = 0,
read_iops_sec = 0, write_iops_sec = 0, total_bytes_sec_max = 0,
read_bytes_sec_max = 0, write_bytes_sec_max = 0, total_iops_sec_max = 0,
read_iops_sec_max = 0, write_iops_sec_max = 0, size_iops_sec = 0,
group_name = 0x0, total_bytes_sec_max_length = 0,
read_bytes_sec_max_length = 0, write_bytes_sec_max_length = 0,
total_iops_sec_max_length = 0, read_iops_sec_max_length = 0,
write_iops_sec_max_length = 0}, serial = 0x0, wwn = 0x0, vendor = 0x0,
product = 0x0, cachemode = 1, error_policy = 0, rerror_policy = 0,
iomode = 1, ioeventfd = 0, event_idx = 0, copy_on_read = 0, snapshot = 0,
startupPolicy = 0, transient = false, info = {
alias = 0x7fffc02a36c0 "scsi0-0-0", type = 2, addr = {pci = {domain = 0,
bus = 0, slot = 0, function = 0, multi = 0}, drive = {controller = 0,
bus = 0, target = 0, unit = 0}, vioserial = {controller = 0, bus = 0,
port = 0}, ccid = {controller = 0, slot = 0}, usb = {bus = 0, port = {
0, 0, 0, 0}}, spaprvio = {reg = 0, has_reg = false}, ccw = {
cssid = 0, ssid = 0, devno = 0, assigned = false}, isa = {iobase = 0,
irq = 0}, dimm = {slot = 0, base = 0}}, mastertype = 0, master = {
usb = {startport = 0}}, rombar = 0, romfile = 0x0, bootIndex = 0,
pciConnectFlags = 0}, rawio = 0, sgio = 0, discard = 1, iothread = 0,
detect_zeroes = 0, domain_name = 0x0}
(gdb) p src->encryption
$3 = (virStorageEncryptionPtr) 0x7fffc00ed570
(gdb) p *src->encryption
$4 = {format = 2, nsecrets = 0, secrets = 0x0, encinfo = {cipher_size = 0,
cipher_name = 0x0, cipher_mode = 0x0, cipher_hash = 0x0, ivgen_name = 0x0,
ivgen_hash = 0x0}}
The 'nsecrets = 0' and 'secrets = 0x0' where the deference in the call is "src->encryption->secrets[0]->seclookupdef"
This issue is limited to hotplug of a disk device for which libvirt has determined the "on disk" format has LUKS encryption. The determination of the format is part of the processing of live disk attachment that doesn't occur during domain startup/code plug processing. I have posted a patch upstream that will resolve the issue. http://www.redhat.com/archives/libvir-list/2016-December/msg01114.html Awesome, thank you! For the work-around in #5, does an incorrect key still pass the disk through unlocked, or is the example above assuming the correct key is being used? -Eric You'd need a valid secret; otherwise, qemu won't add the disk and the drive_add from libvirt receives an error: # MYSECRET=`printf %s "badsecret" | base64` # virsh secret-set-value aa3f2251-4506-4d72-9a59-b17ea9d0ffef $MYSECRET # virsh attach-device f23 disk-secret.xml error: Failed to attach device from disk-secret.xml error: internal error: unable to execute QEMU command 'device_add': Property 'scsi-hd.drive' can't find value 'drive-scsi0-0-0-0' # Understood. Your patch in c#6 slated for inclusion into the next libvirt package? It blocks our adoption of el7.3 until then. Thanks! -Eric Typically the process is - get it reviewed/ACK'd to be included in an upstream version... Then once there I can create a downstream patch for inclusion in a 7.3.z release. I don't have any idea "when" that 7.3.z release is generated, but I will look to get this included for that. The change has been pushed upstream for 7.4. Moving to POST, but a rhel 7.3.z cloned bz still needs to be created.
$ git show
commit 7f7d99048350935a394d07b98a13d7da9c4b0502
Author: John Ferlan <jferlan>
Date: Thu Dec 22 07:12:49 2016 -0500
qemu: Don't assume secret provided for LUKS encryption
...
If a secret was not provided for what was determined to be a LUKS
encrypted disk (during virStorageFileGetMetadata processing when
called from qemuDomainDetermineDiskChain as a result of hotplug
attach qemuDomainAttachDeviceDiskLive), then do not attempt to
look it up (avoiding a libvirtd crash) and do not alter the format
to "luks" when adding the disk; otherwise, the device_add would
fail with a message such as:
"unable to execute QEMU command 'device_add': Property 'scsi-hd.drive'
can't find value 'drive-scsi0-0-0-0'"
because of assumptions that when the format=luks that libvirt would have
provided the secret to decrypt the volume.
Access to unlock the volume will thus be left to the application.
$ git describe 7f7d99048350935a394d07b98a13d7da9c4b0502
v2.5.0-284-g7f7d990
$
tested with patch and passed, wait for new build, just record the test steps here.
# pvcreate /dev/sdb
# vgcreate vg1 /dev/sdb
# lvcreate vg1 /dev/sdb --size 10M
# lvdisplay
--- Logical volume ---
LV Path /dev/vg1/lvol0
...
# cryptsetup luksFormat /dev/vg1/lvol0
# cat /tmp/disk.xml
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='none' io='native' discard='unmap'/>
<source dev='/dev/vg1/lvol0'/>
<backingStore/>
<target dev='sdb' bus='virtio'/>
<serial>drive-scsi0-0-0-1</serial>
<alias name='virtio-disk1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</disk>
# virsh attach-device avocado-vt-vm1 /tmp/disk.xml
Device attached successfully
# virsh dumpxml avocado-vt-vm1
...
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='none' io='native' discard='unmap'/>
<source dev='/dev/vg1/lvol0'/>
<backingStore/>
<target dev='sdb' bus='virtio'/>
<serial>drive-scsi0-0-0-1</serial>
**<encryption format='luks'>**
**</encryption>**
<alias name='virtio-disk1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</disk>
...
# virsh console avocado-vt-vm1
Connected to domain avocado-vt-vm1
Escape character is ^]
# lsblk
...
vdb 252:16 0 12M 0 disk
# mount /dev/vdb /mnt
mount: unknown filesystem type 'crypto_LUKS'
# virsh detach-device avocado-vt-vm1 /tmp/disk.xml
Device detached successfully
# virsh domblklist avocado-vt-vm1
Target Source
------------------------------------------------
vda /var/lib/libvirt/images/jeos-21-64.qcow2
Verified with:
libvirt-3.0.0-2.el7.x86_64
qemu-kvm-rhev-2.8.0-4.el7.x86_64
## pvcreate /dev/sdd
## vgcreate vg_luks /dev/sdd
Volume group "vg_luks" successfully created
## lvcreate vg_luks /dev/sdd --size 10M
Rounding up size to full physical extent 12.00 MiB
Logical volume "lvol0" created.
## cryptsetup luksFormat /dev/vg_luks/lvol0
WARNING!
========
This will overwrite data on /dev/vg_luks/lvol0 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
## cat /tmp/luks.disk
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='none' io='native' discard='unmap'/>
<source dev='/dev/vg_luks/lvol0'/>
<backingStore/>
<target dev='vdb' bus='virtio'/>
<serial>drive-scsi0-0-0-1</serial>
<alias name='virtio-disk1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</disk>
## virsh start avocado-vt-vm1
Domain avocado-vt-vm1 started
## virsh attach-device avocado-vt-vm1 /tmp/luks.disk
Device attached successfully
## virsh console avocado-vt-vm1
Connected to domain avocado-vt-vm1
[root@yisun_vm1 ~]# lsblk
...
vdb 252:16 0 12M 0 disk
[root@yisun_vm1 ~]# mount /dev/vdb /mnt
mount: unknown filesystem type 'crypto_LUKS'
Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory, and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://access.redhat.com/errata/RHEA-2017:1846 Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory, and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://access.redhat.com/errata/RHEA-2017:1846 |