Bug 1491217

Summary: blockPeek() return wrong contents of a domain's disk device.
Product: Red Hat Enterprise Linux 7 Reporter: lcheng
Component: libvirtAssignee: Peter Krempa <pkrempa>
Status: CLOSED ERRATA QA Contact: Han Han <hhan>
Severity: medium Docs Contact:
Priority: medium    
Version: 7.5CC: dyuan, dzheng, gsun, lmen, pkrempa, rbalakri, xuzhang
Target Milestone: rcKeywords: Automation, Regression
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: libvirt-3.8.0-1.el7 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2018-04-10 10:57:19 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:

Description lcheng 2017-09-13 10:41:41 UTC
Description:
blockPeek() return wrong contents of a domain's disk device.


Version:
libvirt-python-3.7.0-1.el7.x86_64
libvirt-3.7.0-2.el7.x86_64
qemu-kvm-rhev-2.9.0-16.el7_4.6.x86_64


How reproduced:
100%

Steps:
1. Prepare a running domain.

2. Execute following steps.
>>> import os
>>> import libvirt
>>> conn = libvirt.open()
>>> dom = conn.lookupByName("test")
>>> dom.isActive()
1
>>> dom.blockPeek("vda", 0, 16, 0)
'\x80\n\x00D;\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> dom.blockPeek("vda", 0, 16, 0)
'\x80\n\x00H;\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> dom.blockPeek("vda", 0, 16, 0)
'\x80\n\x00L;\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> dom.blockPeek("vda", 0, 16, 0)
'\xb0\n\x00@;\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> dom.blockPeek("vda", 0, 16, 0)
'0A\x00P;\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'



3. Using hexdump command to check the contents of the domain's disk device.
# hexdump /var/lib/libvirt/images/libvirt-test-api -n 16 -s 0
0000000 63eb 1090 d08e 00bc b8b0 0000 d88e c08e
0000010


Actual result:
In step 2, when blockPeek() is called many times, we get different contents every time.

Expected result:
We can get the same contents every time.


Additional info:
We can get the same contents on rhel 7.4.


libvirt-3.2.0-14.el7_4.3.x86_64
libvirt-python-3.2.0-3.el7.x86_64
qemu-kvm-rhev-2.9.0-16.el7_4.5.x86_64

>>> import libvirt
>>> conn = libvirt.open()
>>> dom = conn.lookupByName("test")
>>> dom.blockPeek("vda", 0, 16, 0)
'QFI\xfb\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00'
>>> dom.blockPeek("vda", 0, 16, 0)
'QFI\xfb\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00'
>>> dom.blockPeek("vda", 0, 16, 0)
'QFI\xfb\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00'
>>> quit()

Comment 2 Peter Krempa 2017-09-13 14:32:11 UTC
I probably broke it by commit:

commit 3956af495ecb84dc79f6c1c23d221e868aaf3ab5
Author: Peter Krempa <pkrempa>
Date:   Fri May 12 15:33:33 2017 +0200

    qemu: Use storage driver APIs in qemuDomainBlockPeek
    
    Refactor the access to storage driver usage along with
    qemuDomainStorageFileInit which ensures that we access the file with
    correct DAC uid/gid.


I'll investigate.

Comment 3 Peter Krempa 2017-09-18 14:08:29 UTC
Yes, the commit broke it. Moving to the 'libvirt' component since it's a bug in libvirtd.

Comment 4 Peter Krempa 2017-09-19 15:33:35 UTC
Fixed upstream:

commit f767d53dbe484f33d71c173b3fa890515a91103b
Author: Peter Krempa <pkrempa>
Date:   Mon Sep 18 16:03:58 2017 +0200

    qemu: blockPeek: Fix filling of the return buffer
    
    Commit 3956af495e broke the blockPeek API since virStorageFileRead
    allocates a return buffer and fills it with the data, while the API
    fills a user-provided buffer. This did not get caught by the compiler
    since the API prototype uses a 'void *'.
    
    Fix it by transferring the data from the allocated buffer to the user
    provided buffer.

Comment 7 Han Han 2017-11-01 08:52:40 UTC
Verify it on qemu-kvm-rhev-2.10.0-3.el7.x86_64 libvirt-3.8.0-1.el7.x86_64.
As we know, in an VM with OS, the sectors before first partition usuallly are not written. So I will verify this bug by blockpeek from the first 2048 sectors.

Check the disk in VM:
# fdisk -l /dev/vda                                                

Disk /dev/vda: 10.7 GB, 10737418240 bytes, 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000b77dd

   Device Boot      Start         End      Blocks   Id  System
/dev/vda1   *        2048     2099199     1048576   83  Linux
/dev/vda2         2099200    20971519     9436160   8e  Linux LVM

I write a script to check the hash digest of data from the first 2048 sectors by blockpeek for 9 times. Then check if all hash digests are the same. If yes, bug fixed while no means bug unfixed.

The script:
```
#!/usr/bin/env python
import libvirt
import hashlib
import time
# The target device
DISK_TARGET = "vda"
# Data size of blockpeek
PEEK_SIZE = 2048
# Interval between blockpeek operations
SLEEP_TIME = 2
conn = libvirt.open("qemu:///system")
dom = conn.lookupByName("V-raw")
hexdigest_list = []
for i in range(1,9):
    sha1 = hashlib.sha1()
# Calculate the sha1 digest of data from blockpeek
    sha1.update(dom.blockPeek("vda", 0, PEEK_SIZE, 0))
    hexdigest_list.append(sha1.hexdigest())
    time.sleep(SLEEP_TIME)
# Check if all hash digests are the same
print set(hexdigest_list)
```

Result:
set(['8e6067cc31ccc0b52440a16d711695ca9dac08c6'])

All hash digests are 8e6067cc31ccc0b52440a16d711695ca9dac08c6. Bug fixed.

Comment 11 errata-xmlrpc 2018-04-10 10:57:19 UTC
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-2018:0704