Bug 1087104 - [Storage][vol-download] virsh cmd vol-download works with option offset and length by passing a negative integer
Summary: [Storage][vol-download] virsh cmd vol-download works with option offset and l...
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: libvirt
Version: 7.1
Hardware: x86_64
OS: Linux
medium
medium
Target Milestone: rc
: ---
Assignee: John Ferlan
QA Contact: Virtualization Bugs
URL:
Whiteboard: storage
Depends On:
Blocks: CVE-2014-8135
TreeView+ depends on / blocked
 
Reported: 2014-04-14 01:32 UTC by Yang Yang
Modified: 2015-03-05 07:33 UTC (History)
9 users (show)

Fixed In Version: libvirt-1.2.8-11.el7
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2015-03-05 07:33:59 UTC
Target Upstream Version:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2015:0323 0 normal SHIPPED_LIVE Low: libvirt security, bug fix, and enhancement update 2015-03-05 12:10:54 UTC

Description Yang Yang 2014-04-14 01:32:13 UTC
Description:
Running virsh command vol-download with the option offset and length by passing a negative integer, it succeeded and return without any error.

Product Version:
libvirt-1.1.1-29.el7.x86_64
qemu-kvm-rhev-1.5.3-60.el7ev.x86_64

How producible:
Always

Steps:
1. Create a qcow3 format volume in default pool
# cat qcow3-vol2.xml
<volume>
  <name>qcow3-vol2</name>
  <source>
  </source>
  <capacity unit='bytes'>1024000000</capacity>
  <allocation unit='bytes'>204000</allocation>
  <target>
    <format type='qcow2'/>
    <compat>1.1</compat>
    <features>
    <lazy_refcounts/>
    </features>
  </target>
</volume>

# virsh vol-create default qcow3-vol2.xml
Vol qcow3-vol2 created from qcow3-vol2.xml

# ll /var/lib/libvirt/images/qcow3-vol2
-rw-------. 1 root root 197120 Apr  9  2014 /var/lib/libvirt/images/qcow3-vol2

2. Create a raw format volume in default pool
# cat raw.xml
<volume>
<name>raw</name>
  <source>
  </source>
   <capacity unit='bytes'>589934592</capacity>
  <allocation unit='bytes'>56063232</allocation>
  <target>
    <format type='raw'/>
  </target>
</volume>

# virsh vol-create default raw.xml
Vol raw created from raw.xml

# ll /var/lib/libvirt/images/raw
-rw-------. 1 root root 589934592 Apr  9  2014 /var/lib/libvirt/images/raw


3. Download qcow3-vol2 to raw by passing negative integer to offset and length
# virsh vol-download --pool default qcow3-vol2 /var/lib/libvirt/images/raw --offset -1 --length -1000

4. check the volume raw
# ll /var/lib/libvirt/images/raw
-rw-------. 1 root root 197120 Apr  9  2014 /var/lib/libvirt/images/raw

Actual results:
in step 3: Successfully download volume to local file

Expected results:
in step 3: Virsh command vol-download should return with error like this:
error: invalid value for offset and length

Additional Info:
In manual page:
vol-download [--pool pool-or-uuid] [--offset bytes] [--length bytes]
      
 --offset is the position in the storage volume
           at which to start reading the data. --length is an upper bound of
           the amount of data to be downloaded.

It is said that offset is the position in the storage volume at which to start reading the data, so I think the value of offset should be no smaller than 0, option length as well.

Comment 2 John Ferlan 2014-07-15 11:41:06 UTC
There are those that would argue that "-1" could be used to imply the largest value allowed. The libvirt code reads input from virsh generally as an unsigned long long value and then makes decisions based on "expectations" of how the caller wishes to interpret the data.

For "offset" the eventual lseek() allows a -1 value to mean the end of the file, although other negative values are interpreted as their unsigned long long values which generally results in an error since files are generally not that large (yet).  Whether it's realistic to expect copying from the end of the file means anything is left to the interpretation of the user and the implementation of the OS. See the lstat man page for details on -1 for the offset argument.

For "length" a -1 could/should be interpretted as the "whole" file. In your example all 197120 bytes. Other negative values are less obvious, but would be converted to their unsigned long long equivalent and used. In your case -1000 would be more than enough to copy the whole file.

For a short time during May 2014 it seems the use of -1 would have been prohibited due to other changes (listed below) in the underlying code called by the virsh routines (in particular vshCommandOptULongLong()). The following is a bit of history going backwards through time...

For vol-{upload|download} in particular, a change made as a result of the patches restored the ability to use -1 as a pseudonym for everything:

http://www.redhat.com/archives/libvir-list/2014-June/msg00184.html

Those changes were based on a pass where the vcpuinfo parameter to allow/use -1:

http://www.redhat.com/archives/libvir-list/2014-May/msg01013.html

was questioned and led to a list of various virsh commands that may or may not want to allow -1:

http://www.redhat.com/archives/libvir-list/2014-May/msg01029.html

The set of changes was based upon a new API that was developed to handle those -1 special cases based on the following patches:

https://www.redhat.com/archives/libvir-list/2014-May/msg00000.html

which were based on the rejection of:

http://www.redhat.com/archives/libvir-list/2014-April/msg01132.html

The early May patches would have caused -1 to be rejected as an invalid value, while the later May patches restored the former functionality based on the auditing done of the callers of the API's to convert input values.

I have reopened (with any luck) the discussion surrounding vol-{upload|download} with the upstream community and will see what the thoughts there are.  I personally think an 'offset' of -1 is useless, although a negative value for length does have value to mean everything.

The man page will be adjusted accordingly based on the results of the renewed discussion.  If that doesn't work - I'll send patches which will most certainly cause someone to think about it again

Comment 3 John Ferlan 2014-07-17 17:29:44 UTC
Patch sent upstream:

http://www.redhat.com/archives/libvir-list/2014-July/msg00865.html


Code pushed:

commit 570d0f6387038a6d7651b22fd555de603f07ab3b
Author: John Ferlan <jferlan@redhat.com>
Date:   Tue Jul 15 08:26:28 2014 -0400

    virsh vol-upload/download disallow negative offset
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1087104
    
    Commit id 'c6212539' explicitly allowed a negative value to be used for
    offset and length as a shorthand for the largest value after commit id
    'f18c02ec' modified virStrToLong_ui() to essentially disallow a negative
    value.
    
    However, allowing a negative value for offset ONLY worked if the negative
    value was -1 since the eventual lseek() does allow a -1 to mean the end
    of the file.  Providing other negative values resulted in errors such as:
    
    $ virsh vol-download --pool default qcow3-vol2 /home/vm-images/raw \
      --offset -2 --length -1000
    error: cannot download from volume qcow3-vol2
    error: Unable to seek /home/vm-images/qcow3-vol2 to 18446744073709551614: In
    
    $
    
    Thus, it seems unreasonable to expect or allow a negative value for offset
    since the only benefit is to lseek() to the end of the file and then only
    take advantage of how the OS would handle such a seek. For the purposes of
    upload or download of volume data, that seems to be a no-op.  Therefore,
    disallow a negative value for offset.
    
    Additionally, modify the man page for vol-upload and vol-download to provide
    more details regarding the valid values for both offset and length.



git describe: v1.2.6-184-g570d0f6

Comment 5 Pei Zhang 2014-12-03 06:10:18 UTC
According to the title and content of the patch in comment 3 ,
and the description of vol-upload / vol-download about --offset ,--length option in the man page :
......
--offset is the position in the storage volume at which to start writing the data. The value must be 0 or larger
--length is an upper bound of the amount of data to be uploaded. A negative value is interpreted as an unsigned long long value to essentially include everything from the offset to the end of the volume. 
......
 
verifying it as following steps , it seems that it doesn't work well for vol-upload :

steps:
1> 
try to do vol-upload with a negative value of --offset as -1 and --length as -1 , upload successfully

# virsh vol-upload --pool default --vol vol1.xml uploadfile --offset -1 --length -1

2>
try to do vol-upload with a negative value of --offset as -1 and --length as -10000 , upload successfully
# virsh vol-upload --pool default --vol vol1.xml uploadfile --offset -1 --length -10000

3>
try to do vol-upload with a negative value of --offset as -2 and --length as -1 , fail to upload , give error message .

# virsh vol-upload --pool default --vol vol1.xml uploadfile --offset -2 --length -1
error: cannot upload to volume vol1.xml
error: End of file while reading data: Input/output error
error: Failed to reconnect to the hypervisor

4>
try to do vol-upload with a negative value of --offset as -1000 and --length as -1000 , fail to upload , give error message .

# virsh vol-upload --pool default --vol vol1.xml uploadfile --offset -1000 --length -1000
error: cannot upload to volume vol1.xml
error: End of file while reading data: Input/output error
error: Failed to reconnect to the hypervisor

5>try to do vol-download with a negative value of --offset  and --length , unable to parse offset value

# virsh vol-download --pool default --vol vol1.xml downloadfile --offset -2 --length -1
error: Unable to parse offset value

# virsh vol-download --pool default --vol vol1.xml downloadfile --offset -1 --length -1
error: Unable to parse offset value


As above ,for command vol-upload in the step 1 and step 2 , if the negative value of offset is -1 , it will be wrapped the largest value then upload successfully.
in the step 3 and step 4 , using another negative value which is not -1 , fail to upload and it  will give a confused error message.
should it use the same error handling as well as vol-download . 
thanks.

Comment 6 John Ferlan 2014-12-03 12:22:10 UTC
yes - although it's been 5 months since I made the change and I have no recollection how I forgot the -upload check as well even though I mentioned it in the commit (sigh!)... Must've been the myopia and short term memory loss.

I see Shanzhi Yu has submitted a patch to the upstream list - I will return this bz back to POST once I push that and repost to the downstream list

Comment 9 Pei Zhang 2014-12-23 01:35:35 UTC
verify version:

libvirt-1.2.8-11.el7.x86_64
qemu-kvm-rhev-2.1.2-17.el7.x86_64
kernel-3.10.0-217.el7.x86_64

verify steps:

1.create two volumes in the default pool

# cat default-volume.xml 
<volume>
  <name>qcow2-vol</name>
  <source>
  </source>
  <capacity unit='bytes'>1024000000</capacity>
  <allocation unit='bytes'>204000</allocation>
  <target>
    <format type='qcow2'/>
   <features>
    <lazy_refcounts/>
    </features>
  </target>
</volume>

 
# virsh vol-create default default-volume.xml 
Vol qcow2-vol created from default-volume.xml


# cat raw-vol.xml 
<volume>
<name>raw-vol</name>
  <source>
  </source>
   <capacity unit='bytes'>589934592</capacity>
  <allocation unit='bytes'>56063232</allocation>
  <target>
    <format type='raw'/>
  </target>
</volume>

# virsh vol-create default raw-vol.xml 
Vol raw-vol created from raw-vol.xml

check volumes in default pool 

# virsh vol-list default
 Name                 Path                                    
------------------------------------------------------------------------------
 qcow2-vol            /var/lib/libvirt/images/qcow2-vol       
 raw-vol              /var/lib/libvirt/images/raw-vol         


2. verify vol-upload/download disallow negative offset

2.1  try to download qcow2-vol to raw by passing negative integer to offset and length 

# virsh vol-download --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset -1 --length -1000
error: Unable to parse offset value

# virsh vol-download --pool default qcow2-vol  /var/lib/libvirt/images/raw-vol --offset -2 --length -10
error: Unable to parse offset value

2.2  try to upload qcow2 to raw by passing negative integer to offset and length 

# virsh vol-upload --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset -1 --length -1000
error: Unable to parse offset value

# virsh vol-upload --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset -2 --length -100
error: Unable to parse offset value 


3.verify using vol-upload/download with an offset that was "too large" 

3.1  try to download qcow2-vol to raw by passing an offset with too large value 
 
# virsh vol-download --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset 18446744073709551614 --length 18446744073709551614
error: cannot download to volume qcow2-vol
error: Unable to seek /var/lib/libvirt/images/qcow2-vol to 18446744073709551614: Invalid argument

NOTE : if set an offset that was 18446744073709551615 ,it will download successfully.
# virsh vol-download --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset 18446744073709551615 --length 18446744073709551615

# virsh vol-download --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset 18446744073709551616 --length 18446744073709551616
error: Unable to parse offset value

3.2   try to upload qcow2 to raw by passing an offset with too large value 

# virsh vol-upload --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset 18446744073709551614 --length 18446744073709551615
error: cannot upload to volume qcow2-vol
error: Unable to seek /var/lib/libvirt/images/qcow2-vol to 18446744073709551614: Invalid argument

NOTE : if set an offset that was 18446744073709551615 ,it will upload successfully.
# virsh vol-upload --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset 18446744073709551615 --length 18446744073709551615

# virsh vol-upload --pool default qcow2-vol /var/lib/libvirt/images/raw-vol --offset 18446744073709551616 --length 18446744073709551616
error: Unable to parse offset value


Is it OK to verify this bug and the CVE issue according to all above steps .

And another issue in steps 3.1 and 3.2  when i try to set a too large offset .It will upload / download successfully if set an offset which was 18446744073709551615 .
but the value 18446744073709551614 (or a little less than 18446744073709551614  or 18446744073709551616) was invalid  and will give the error message. If that is expected result or may be another question.
Thanks a lot .

Comment 10 John Ferlan 2014-12-23 13:47:32 UTC
From the aspect of whether the bug described is fixed - I would say, sure this is verified (e.g. -1 as offset results in failures).

From the aspect of whether the *1614, *1615, and *1616 work - I think perhaps a new bug report should be created and tracked separately, but be sure it gets the rhel-7.2.0 flag (not 7.1.0).  The *1615 value is also known as UINT64_MAX and it's worth the time to chase into the code to see if that magic value has special meaning...  It might end up being nothing but the *equivalent* of passing -1 to *seek to indicate "the whole file" or "the end of the file".

Comment 11 Pei Zhang 2014-12-25 08:20:58 UTC
Thanks for your response . 
According to comment 9 and comment 10 , move this bug to verified .
A new bug to trace "too large" value issue .
https://bugzilla.redhat.com/show_bug.cgi?id=1177219

Comment 13 errata-xmlrpc 2015-03-05 07:33:59 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://rhn.redhat.com/errata/RHSA-2015-0323.html


Note You need to log in before you can comment on or make changes to this bug.