Re: [Qemu-devel] [PATCH v2 2/7] block/qcow2-refcount: avoid eating RAM

2018-10-08 Thread Max Reitz
On 08.10.18 22:22, Vladimir Sementsov-Ogievskiy wrote:
> 
> 
> On 10/08/2018 06:31 PM, Max Reitz wrote:
>> On 17.08.18 14:22, Vladimir Sementsov-Ogievskiy wrote:
>>> qcow2_inc_refcounts_imrt() (through realloc_refcount_array()) can eat
>>> an unpredictable amount of memory on corrupted table entries, which are
>>> referencing regions far beyond the end of file.
>>>
>>> Prevent this, by skipping such regions from further processing.
>>>
>>> Signed-off-by: Vladimir Sementsov-Ogievskiy 
>>> ---
>>>   block/qcow2-refcount.c | 14 ++
>>>   1 file changed, 14 insertions(+)
>>>
>>> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
>>> index 615847eb09..566c19fbfa 100644
>>> --- a/block/qcow2-refcount.c
>>> +++ b/block/qcow2-refcount.c
>>> @@ -1499,12 +1499,26 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, 
>>> BdrvCheckResult *res,
>>>   {
>>>   BDRVQcow2State *s = bs->opaque;
>>>   uint64_t start, last, cluster_offset, k, refcount;
>>> +int64_t file_len;
>>>   int ret;
>>>   
>>>   if (size <= 0) {
>>>   return 0;
>>>   }
>>>   
>>> +file_len = bdrv_getlength(bs->file->bs);
>>> +if (file_len < 0) {
>>> +return file_len;
>>> +}
>>
>> Doesn't this slow things down?  Can we not cache the length somewhere
>> and update it whenever the image is modified?
> 
> 
> hmm. bdrv_getlength is used everywhere in Qemu, and I don't think it is 
> good idea to improve it locally for these series. If we can improve it 
> somehow with a cache or something like this, it should be done for all 
> users and therefore it is outside of these series..

I wanted to write: Sure it's used everywhere, but usually that is before
someone performs some I/O, so it isn't too bad.  But this is a function
that's suppose to just increment a couple of values in memory, which is
different.

However, I put the "wanted to write" prefix there, because: I knew that
we already have a central cache for bdrv_getlength(), but it isn't used
when the block driver reports has_variable_length as true.  I thought
file-posix did that.  But it only does so for CD-ROM devices.

So I think it should be OK to call the function here, yes.

>>> +
>>> +if (offset + size - file_len > s->cluster_size) {
>>> +fprintf(stderr, "ERROR: counting reference for region exceeding 
>>> the "
>>> +"end of the file by more than one cluster: offset 0x%" 
>>> PRIx64
>>> +" size 0x%" PRIx64 "\n", offset, size);
>>
>> Why is one cluster OK?  Is there a specific case you're trying to catch
>> here?
> 
> raw file under qcow2 may be not aligned in real size to qcow2 cluster, 
> as I understand, it's normal for the last cluster to be semi-allocated

Ah, that's true, thanks.  I'd appreciate a comment here, though, and in
that case I think we don't need to check whether the reference is off by
more than a cluster, but whether it's off by a cluster or more (so >=).

Max



signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [PATCH v2 2/7] block/qcow2-refcount: avoid eating RAM

2018-10-08 Thread Vladimir Sementsov-Ogievskiy


On 10/08/2018 06:31 PM, Max Reitz wrote:
> On 17.08.18 14:22, Vladimir Sementsov-Ogievskiy wrote:
>> qcow2_inc_refcounts_imrt() (through realloc_refcount_array()) can eat
>> an unpredictable amount of memory on corrupted table entries, which are
>> referencing regions far beyond the end of file.
>>
>> Prevent this, by skipping such regions from further processing.
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy 
>> ---
>>   block/qcow2-refcount.c | 14 ++
>>   1 file changed, 14 insertions(+)
>>
>> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
>> index 615847eb09..566c19fbfa 100644
>> --- a/block/qcow2-refcount.c
>> +++ b/block/qcow2-refcount.c
>> @@ -1499,12 +1499,26 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, 
>> BdrvCheckResult *res,
>>   {
>>   BDRVQcow2State *s = bs->opaque;
>>   uint64_t start, last, cluster_offset, k, refcount;
>> +int64_t file_len;
>>   int ret;
>>   
>>   if (size <= 0) {
>>   return 0;
>>   }
>>   
>> +file_len = bdrv_getlength(bs->file->bs);
>> +if (file_len < 0) {
>> +return file_len;
>> +}
> 
> Doesn't this slow things down?  Can we not cache the length somewhere
> and update it whenever the image is modified?


hmm. bdrv_getlength is used everywhere in Qemu, and I don't think it is 
good idea to improve it locally for these series. If we can improve it 
somehow with a cache or something like this, it should be done for all 
users and therefore it is outside of these series..

> 
>> +
>> +if (offset + size - file_len > s->cluster_size) {
>> +fprintf(stderr, "ERROR: counting reference for region exceeding the 
>> "
>> +"end of the file by more than one cluster: offset 0x%" 
>> PRIx64
>> +" size 0x%" PRIx64 "\n", offset, size);
> 
> Why is one cluster OK?  Is there a specific case you're trying to catch
> here?

raw file under qcow2 may be not aligned in real size to qcow2 cluster, 
as I understand, it's normal for the last cluster to be semi-allocated

> 
> Max
> 
>> +res->corruptions++;
>> +return 0;
>> +}
>> +
>>   start = start_of_cluster(s, offset);
>>   last = start_of_cluster(s, offset + size - 1);
>>   for(cluster_offset = start; cluster_offset <= last;
>>
> 
> 


Re: [Qemu-devel] [PATCH v2 2/7] block/qcow2-refcount: avoid eating RAM

2018-10-08 Thread Vladimir Sementsov-Ogievskiy


On 10/08/2018 06:31 PM, Max Reitz wrote:
> On 17.08.18 14:22, Vladimir Sementsov-Ogievskiy wrote:
>> qcow2_inc_refcounts_imrt() (through realloc_refcount_array()) can eat
>> an unpredictable amount of memory on corrupted table entries, which are
>> referencing regions far beyond the end of file.
>>
>> Prevent this, by skipping such regions from further processing.
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy 
>> ---
>>   block/qcow2-refcount.c | 14 ++
>>   1 file changed, 14 insertions(+)
>>
>> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
>> index 615847eb09..566c19fbfa 100644
>> --- a/block/qcow2-refcount.c
>> +++ b/block/qcow2-refcount.c
>> @@ -1499,12 +1499,26 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, 
>> BdrvCheckResult *res,
>>   {
>>   BDRVQcow2State *s = bs->opaque;
>>   uint64_t start, last, cluster_offset, k, refcount;
>> +int64_t file_len;
>>   int ret;
>>   
>>   if (size <= 0) {
>>   return 0;
>>   }
>>   
>> +file_len = bdrv_getlength(bs->file->bs);
>> +if (file_len < 0) {
>> +return file_len;
>> +}
> 
> Doesn't this slow things down?  Can we not cache the length somewhere
> and update it whenever the image is modified?


hmm. bdrv_getlength is used everywhere in Qemu, and I don't think it is 
good idea to improve it locally for these series. If we can improve it 
somehow with a cache or something like this, it should be done for all 
users and therefore it is outside of these series..

> 
>> +
>> +if (offset + size - file_len > s->cluster_size) {
>> +fprintf(stderr, "ERROR: counting reference for region exceeding the 
>> "
>> +"end of the file by more than one cluster: offset 0x%" 
>> PRIx64
>> +" size 0x%" PRIx64 "\n", offset, size);
> 
> Why is one cluster OK?  Is there a specific case you're trying to catch
> here?

raw file under qcow2 may be not aligned in real size to qcow2 cluster, 
as I understand, it's normal for the last cluster to be semi-allocated

> 
> Max
> 
>> +res->corruptions++;
>> +return 0;
>> +}
>> +
>>   start = start_of_cluster(s, offset);
>>   last = start_of_cluster(s, offset + size - 1);
>>   for(cluster_offset = start; cluster_offset <= last;
>>
> 
> 


Re: [Qemu-devel] [PATCH v2 2/7] block/qcow2-refcount: avoid eating RAM

2018-10-08 Thread Max Reitz
On 17.08.18 14:22, Vladimir Sementsov-Ogievskiy wrote:
> qcow2_inc_refcounts_imrt() (through realloc_refcount_array()) can eat
> an unpredictable amount of memory on corrupted table entries, which are
> referencing regions far beyond the end of file.
> 
> Prevent this, by skipping such regions from further processing.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy 
> ---
>  block/qcow2-refcount.c | 14 ++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
> index 615847eb09..566c19fbfa 100644
> --- a/block/qcow2-refcount.c
> +++ b/block/qcow2-refcount.c
> @@ -1499,12 +1499,26 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, 
> BdrvCheckResult *res,
>  {
>  BDRVQcow2State *s = bs->opaque;
>  uint64_t start, last, cluster_offset, k, refcount;
> +int64_t file_len;
>  int ret;
>  
>  if (size <= 0) {
>  return 0;
>  }
>  
> +file_len = bdrv_getlength(bs->file->bs);
> +if (file_len < 0) {
> +return file_len;
> +}

Doesn't this slow things down?  Can we not cache the length somewhere
and update it whenever the image is modified?

> +
> +if (offset + size - file_len > s->cluster_size) {
> +fprintf(stderr, "ERROR: counting reference for region exceeding the "
> +"end of the file by more than one cluster: offset 0x%" PRIx64
> +" size 0x%" PRIx64 "\n", offset, size);

Why is one cluster OK?  Is there a specific case you're trying to catch
here?

Max

> +res->corruptions++;
> +return 0;
> +}
> +
>  start = start_of_cluster(s, offset);
>  last = start_of_cluster(s, offset + size - 1);
>  for(cluster_offset = start; cluster_offset <= last;
> 




signature.asc
Description: OpenPGP digital signature


[Qemu-devel] [PATCH v2 2/7] block/qcow2-refcount: avoid eating RAM

2018-08-17 Thread Vladimir Sementsov-Ogievskiy
qcow2_inc_refcounts_imrt() (through realloc_refcount_array()) can eat
an unpredictable amount of memory on corrupted table entries, which are
referencing regions far beyond the end of file.

Prevent this, by skipping such regions from further processing.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block/qcow2-refcount.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 615847eb09..566c19fbfa 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1499,12 +1499,26 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, 
BdrvCheckResult *res,
 {
 BDRVQcow2State *s = bs->opaque;
 uint64_t start, last, cluster_offset, k, refcount;
+int64_t file_len;
 int ret;
 
 if (size <= 0) {
 return 0;
 }
 
+file_len = bdrv_getlength(bs->file->bs);
+if (file_len < 0) {
+return file_len;
+}
+
+if (offset + size - file_len > s->cluster_size) {
+fprintf(stderr, "ERROR: counting reference for region exceeding the "
+"end of the file by more than one cluster: offset 0x%" PRIx64
+" size 0x%" PRIx64 "\n", offset, size);
+res->corruptions++;
+return 0;
+}
+
 start = start_of_cluster(s, offset);
 last = start_of_cluster(s, offset + size - 1);
 for(cluster_offset = start; cluster_offset <= last;
-- 
2.11.1