Bug 1976109

Summary: Improper conversion of large numbers in virConnectDomainEventBlockThresholdCallback handler
Product: Red Hat Enterprise Linux Advanced Virtualization Reporter: Peter Krempa <pkrempa>
Component: libvirt-pythonAssignee: Peter Krempa <pkrempa>
Status: CLOSED ERRATA QA Contact: lcheng
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: ---CC: hhan, jdenemar, lmen, virt-maint, xuzhang
Target Milestone: rcKeywords: Triaged
Target Release: 8.5Flags: pm-rhel: mirror+
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: libvirt-python-7.5.0-1.el8 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2021-11-16 07:54:28 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: 7.5.0
Embargoed:
Bug Depends On:    
Bug Blocks: 1948177    

Description Peter Krempa 2021-06-25 08:30:38 UTC
Description of problem:
When sufficiently large numbers are reported by the virConnectDomainEventBlockThresholdCallback, they passed to the python handlers as negative numbers due to an overflow happening in the wrapper code:

The event callback has the following prototype:

void
virConnectDomainEventBlockThresholdCallback(virConnectPtr conn, 
					    virDomainPtr dom, 
					    const char * dev, 
					    const char * path, 
					    unsigned long long threshold, 
					    unsigned long long excess, 
					    void * opaque)

I think the problem is in the dispatching code in the python bindings, where we use:

    /* Call the Callback Dispatcher */
    pyobj_ret = PyObject_CallMethod(pyobj_conn,
                                    (char*)"_dispatchDomainEventBlockThresholdCallback",
                                    (char*)"OssiiO",
                                    pyobj_dom, dev, path, threshold, excess,
                                    pyobj_cbData);

The meaning of characters in the third argument is:

i (int) [int]

    Convert a plain C int to a Python integer object.


K (int) [unsigned long long]

    Convert a C unsigned long long to a Python integer object.


Version-Release number of selected component (if applicable):
All versions in existance which support virConnectDomainEventBlockThresholdCallback

How reproducible:
always

Steps to Reproduce:
1. Register threshold callback
2. Exceed it by a large amount
3.

Actual results:


Expected results:


Additional info:

Comment 2 Peter Krempa 2021-06-25 11:57:19 UTC
Fixed upstream:

commit b5cd547bfd7e9dd566de672f76a17aa9229b7c52
Author: Peter Krempa <pkrempa>
Date:   Fri Jun 25 10:46:06 2021 +0200

    Fix BlockThreshold Callback argument conversion once more
    
    The conversion was changed from "OssiiO" to "OssLLO". Unfortunately the
    arguments are unsigned long long, where the proper coversion character
    is 'K'.
    
    Fixes: https://gitlab.com/libvirt/libvirt-python/-/merge_requests/40
    Fixes: fd069ac85c8cf1593587dc9287a3d5eb6bd4bdb9
    Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1976109
    Signed-off-by: Peter Krempa <pkrempa>

Comment 5 Han Han 2021-07-26 07:02:20 UTC
rhel.cpu.iothread.negative_test.disk_attach.delete_without_detach  PASSED on libvirt-7.5.0-1.el9.x86_64

Comment 6 Han Han 2021-07-26 07:05:16 UTC
Sorry for comment5. Restore the previous status...

Comment 7 lcheng 2021-08-04 17:56:49 UTC
Steps to reproduce:

1. Prepare a image.
# qemu-img create -f raw /var/lib/libvirt/images/test-api-block.img 5G

2. Start a guest with a raw disk.
# cat /root/disk.xml 
<disk device="disk" type="file">
    <driver name="qemu" type="raw"/>
    <source file="/var/lib/libvirt/images/test-api-block.img"/>
    <target bus="virtio" dev="vdb"/>
</disk>


3. Set threshold to 3221225472.
# python
Python 3.6.8 (default, Mar 18 2021, 08:58:41) 
[GCC 8.4.1 20200928 (Red Hat 8.4.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import libvirt
>>> conn = libvirt.open()
>>> dom = conn.lookupByName("test")
>>> dom.setBlockThreshold('vdb', 3221225472,0)
0
>>>

4. Run "/usr/share/doc/python3-libvirt/examples/event-test.py" on one terminal to capture event. 
# python /usr/share/doc/python3-libvirt/examples/event-test.py
Using uri 'qemu:///system' and event loop 'poll'

5. Run "mkfs /dev/vdb" command in guest.

6. And then get a negative value.
# python /usr/share/doc/python3-libvirt/examples/event-test.py
Using uri 'qemu:///system' and event loop 'poll'
myDomainEventBlockThresholdCallback: Domain test(7) block device vdb(/var/lib/libvirt/images/test-api-block.img) threshold -1073741824 exceeded by -2147483648
myDomainEventBlockThresholdCallback: Domain test(7) block device vdb[2](/var/lib/libvirt/images/test-api-block.img) threshold -1073741824 exceeded by -2147483648


Verified on python3-libvirt-7.5.0-1.module+el8.5.0+11677+542c8d77.x86_64.
For 6 step,
# python /usr/share/doc/python3-libvirt/examples/event-test.py
Using uri 'qemu:///system' and event loop 'poll'
myDomainEventBlockThresholdCallback: Domain test(3) block device vdb(/var/lib/libvirt/images/test-api-block.img) threshold 3221225472 exceeded by 2147483648
myDomainEventBlockThresholdCallback: Domain test(3) block device vdb[2](/var/lib/libvirt/images/test-api-block.img) threshold 3221225472 exceeded by 2147483648


So move to VERIFIED.

Comment 9 errata-xmlrpc 2021-11-16 07:54:28 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 (virt:av bug fix and enhancement update), 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/RHBA-2021:4684