diff mbox series

[v4,04/24] memory-device: handle integer overflows properly

Message ID 20180926094219.20322-5-david@redhat.com
State New
Headers show
Series memory-device: complete refactoring + virtio-pmem | expand

Commit Message

David Hildenbrand Sept. 26, 2018, 9:41 a.m. UTC
Although unlikely in practice, we could have integer overflows on some
calculations based on addresses and sizes, leading to error checks not
triggering.

Let's properly handle this whenever we do an addition. Make
address_space_end point at the real end, instead of end + 1, so we don't
have to handle special cases like it being 0. This will allow us to
place a memory device at the very end of the guest physical 64bit address
space (if ever possible).

Also, QEMU_ALIGN_UP(md_addr + md_size, align) could (theoretically) wrap to
address 0, so add a final check for 0.

Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: David Hildenbrand <david@redhat.com>
---
 hw/mem/memory-device.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

Comments

Igor Mammedov Sept. 27, 2018, 8:02 a.m. UTC | #1
On Wed, 26 Sep 2018 11:41:59 +0200
David Hildenbrand <david@redhat.com> wrote:

> Make address_space_end point at the real end, instead of end + 1, so we don't
> have to handle special cases like it being 0. This will allow us to
> place a memory device at the very end of the guest physical 64bit address
> space (if ever possible).

[...]

> @@ -115,7 +116,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
>      }
>      address_space_start = ms->device_memory->base;
>      address_space_end = address_space_start +
> -                        memory_region_size(&ms->device_memory->mr);
> +                        memory_region_size(&ms->device_memory->mr) - 1;
I'm terrible at math, lets assume size = 1 so after this
'real end' would end up at 'address_space_start', which makes
it rather confusing beside not matching variable name anymore.

I'd drop it and maybe extend the following assert to abort
on overflow condition.

>      g_assert(address_space_end >= address_space_start);
>  
>      /* address_space_start indicates the maximum alignment we expect */
> @@ -149,7 +150,8 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
>                         "] before 0x%" PRIx64, new_addr, size,
>                         address_space_start);
>              return 0;
> -        } else if ((new_addr + size) > address_space_end) {
> +        } else if (new_addr + size - 1 < new_addr ||
> +                   new_addr + size - 1 > address_space_end) {
>              error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64
>                         "] beyond 0x%" PRIx64, new_addr, size,
>                         address_space_end);
> @@ -182,7 +184,8 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
>          }
>      }
>  
> -    if (new_addr + size > address_space_end) {
> +    if (new_addr + size - 1 < new_addr || !new_addr ||
> +        new_addr + size - 1 > address_space_end) {
>          error_setg(errp, "could not find position in guest address space for "
>                     "memory device - memory fragmented due to alignments");
>          goto out;
I strongly suggest replace non obvious math with several
plain <>= conditions even if adds more conditions compared
to math variant.
At least reader doesn't have to do calculations manually
to figure out what's going on
David Hildenbrand Sept. 27, 2018, 8:13 a.m. UTC | #2
On 27/09/2018 10:02, Igor Mammedov wrote:
> On Wed, 26 Sep 2018 11:41:59 +0200
> David Hildenbrand <david@redhat.com> wrote:
> 
>> Make address_space_end point at the real end, instead of end + 1, so we don't
>> have to handle special cases like it being 0. This will allow us to
>> place a memory device at the very end of the guest physical 64bit address
>> space (if ever possible).
> 
> [...]
> 
>> @@ -115,7 +116,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
>>      }
>>      address_space_start = ms->device_memory->base;
>>      address_space_end = address_space_start +
>> -                        memory_region_size(&ms->device_memory->mr);
>> +                        memory_region_size(&ms->device_memory->mr) - 1;
> I'm terrible at math, lets assume size = 1 so after this
> 'real end' would end up at 'address_space_start', which makes
> it rather confusing beside not matching variable name anymore.

(very simply and unrealistic) counter example as given in the
description. You should get the idea.

address_space_start = 0xffffffffffffffffull;
size = 1;

-> address_space_end = 0;

While this would be perfectly valid, we would have to handle
address_space_end potentially being 0 in the code below, because this
would be a valid overflow. This, I avoid.

And form my POV, the variable name here matches perfectly. It points at
the last address of the address space. (yes people have different
opinions on this)

> 
> I'd drop it and maybe extend the following assert to abort
> on overflow condition.

I'll leave it like this, handling address_space_end = 0 is ugly.

I'll add a comment like

/* address_space_end points at the last valid address */

> 
>>      g_assert(address_space_end >= address_space_start);
>>  
>>      /* address_space_start indicates the maximum alignment we expect */
>> @@ -149,7 +150,8 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
>>                         "] before 0x%" PRIx64, new_addr, size,
>>                         address_space_start);
>>              return 0;
>> -        } else if ((new_addr + size) > address_space_end) {
>> +        } else if (new_addr + size - 1 < new_addr ||
>> +                   new_addr + size - 1 > address_space_end) {
>>              error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64
>>                         "] beyond 0x%" PRIx64, new_addr, size,
>>                         address_space_end);
>> @@ -182,7 +184,8 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
>>          }
>>      }
>>  
>> -    if (new_addr + size > address_space_end) {
>> +    if (new_addr + size - 1 < new_addr || !new_addr ||
>> +        new_addr + size - 1 > address_space_end) {
>>          error_setg(errp, "could not find position in guest address space for "
>>                     "memory device - memory fragmented due to alignments");
>>          goto out;
> I strongly suggest replace non obvious math with several
> plain <>= conditions even if adds more conditions compared
> to math variant.
> At least reader doesn't have to do calculations manually
> to figure out what's going on
> 

Right, maybe adding a new temporary variable new_region_end will help.
Igor Mammedov Sept. 27, 2018, 8:47 a.m. UTC | #3
On Thu, 27 Sep 2018 10:13:07 +0200
David Hildenbrand <david@redhat.com> wrote:

> On 27/09/2018 10:02, Igor Mammedov wrote:
> > On Wed, 26 Sep 2018 11:41:59 +0200
> > David Hildenbrand <david@redhat.com> wrote:
> >   
> >> Make address_space_end point at the real end, instead of end + 1, so we don't
> >> have to handle special cases like it being 0. This will allow us to
> >> place a memory device at the very end of the guest physical 64bit address
> >> space (if ever possible).  
> > 
> > [...]
> >   
> >> @@ -115,7 +116,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
> >>      }
> >>      address_space_start = ms->device_memory->base;
> >>      address_space_end = address_space_start +
> >> -                        memory_region_size(&ms->device_memory->mr);
> >> +                        memory_region_size(&ms->device_memory->mr) - 1;  
> > I'm terrible at math, lets assume size = 1 so after this
> > 'real end' would end up at 'address_space_start', which makes
> > it rather confusing beside not matching variable name anymore.  
> 
> (very simply and unrealistic) counter example as given in the
> description. You should get the idea.
> 
> address_space_start = 0xffffffffffffffffull;
that should never happen, nor valid in any conditions
just add assert so we would catch error if some patch would introduce it

> size = 1;
> 
> -> address_space_end = 0;  
> 
> While this would be perfectly valid, we would have to handle
> address_space_end potentially being 0 in the code below, because this
> would be a valid overflow. This, I avoid.
assert(address_space_end > address_space_start)
would be much better for unrealistic values without messing up with
meaning of variables.
 
> And form my POV, the variable name here matches perfectly. It points at
> the last address of the address space. (yes people have different
> opinions on this)
start,end pair is a range, there shouldn't be any other interpretations to
this variables.

> > 
> > I'd drop it and maybe extend the following assert to abort
> > on overflow condition.  
> 
> I'll leave it like this, handling address_space_end = 0 is ugly.
Looks like I have to insist on dropping this hunk.

> 
> I'll add a comment like
> 
> /* address_space_end points at the last valid address */
> 
> >   
> >>      g_assert(address_space_end >= address_space_start);
> >>  
> >>      /* address_space_start indicates the maximum alignment we expect */
> >> @@ -149,7 +150,8 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
> >>                         "] before 0x%" PRIx64, new_addr, size,
> >>                         address_space_start);
> >>              return 0;
> >> -        } else if ((new_addr + size) > address_space_end) {
> >> +        } else if (new_addr + size - 1 < new_addr ||
> >> +                   new_addr + size - 1 > address_space_end) {
> >>              error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64
> >>                         "] beyond 0x%" PRIx64, new_addr, size,
> >>                         address_space_end);
> >> @@ -182,7 +184,8 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
> >>          }
> >>      }
> >>  
> >> -    if (new_addr + size > address_space_end) {
> >> +    if (new_addr + size - 1 < new_addr || !new_addr ||
> >> +        new_addr + size - 1 > address_space_end) {
> >>          error_setg(errp, "could not find position in guest address space for "
> >>                     "memory device - memory fragmented due to alignments");
> >>          goto out;  
> > I strongly suggest replace non obvious math with several
> > plain <>= conditions even if adds more conditions compared
> > to math variant.
> > At least reader doesn't have to do calculations manually
> > to figure out what's going on
> >   
> 
> Right, maybe adding a new temporary variable new_region_end will help.
what I was meaning is avoid -1 and rather use and additional range border check
David Hildenbrand Sept. 27, 2018, 8:58 a.m. UTC | #4
On 27/09/2018 10:47, Igor Mammedov wrote:
> On Thu, 27 Sep 2018 10:13:07 +0200
> David Hildenbrand <david@redhat.com> wrote:
> 
>> On 27/09/2018 10:02, Igor Mammedov wrote:
>>> On Wed, 26 Sep 2018 11:41:59 +0200
>>> David Hildenbrand <david@redhat.com> wrote:
>>>   
>>>> Make address_space_end point at the real end, instead of end + 1, so we don't
>>>> have to handle special cases like it being 0. This will allow us to
>>>> place a memory device at the very end of the guest physical 64bit address
>>>> space (if ever possible).  
>>>
>>> [...]
>>>   
>>>> @@ -115,7 +116,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
>>>>      }
>>>>      address_space_start = ms->device_memory->base;
>>>>      address_space_end = address_space_start +
>>>> -                        memory_region_size(&ms->device_memory->mr);
>>>> +                        memory_region_size(&ms->device_memory->mr) - 1;  
>>> I'm terrible at math, lets assume size = 1 so after this
>>> 'real end' would end up at 'address_space_start', which makes
>>> it rather confusing beside not matching variable name anymore.  
>>
>> (very simply and unrealistic) counter example as given in the
>> description. You should get the idea.
>>
>> address_space_start = 0xffffffffffffffffull;
> that should never happen, nor valid in any conditions
> just add assert so we would catch error if some patch would introduce it
> 
>> size = 1;
>>
>> -> address_space_end = 0;  
>>
>> While this would be perfectly valid, we would have to handle
>> address_space_end potentially being 0 in the code below, because this
>> would be a valid overflow. This, I avoid.
> assert(address_space_end > address_space_start)
> would be much better for unrealistic values without messing up with
> meaning of variables.
>  
>> And form my POV, the variable name here matches perfectly. It points at
>> the last address of the address space. (yes people have different
>> opinions on this)
> start,end pair is a range, there shouldn't be any other interpretations to
> this variables.
> 

Please see include/qemu/range.h:struct Range;

So I am using _the definition_.


>>>
>>> I'd drop it and maybe extend the following assert to abort
>>> on overflow condition.  
>>
>> I'll leave it like this, handling address_space_end = 0 is ugly.
> Looks like I have to insist on dropping this hunk.

You're going from "I'd" to "I have to insist". Please make up your mind.

I have a R-b from David. But I am willing to change it if you can give
me a good reason why we should add asserts instead of fixing the code
(== making it work in all possibly valid scenarios, especially end of
address space).


With the new local variable new_end, the code looks pretty clean.
Igor Mammedov Sept. 27, 2018, 11:53 a.m. UTC | #5
On Thu, 27 Sep 2018 10:58:47 +0200
David Hildenbrand <david@redhat.com> wrote:

> On 27/09/2018 10:47, Igor Mammedov wrote:
> > On Thu, 27 Sep 2018 10:13:07 +0200
> > David Hildenbrand <david@redhat.com> wrote:
> >   
> >> On 27/09/2018 10:02, Igor Mammedov wrote:  
> >>> On Wed, 26 Sep 2018 11:41:59 +0200
> >>> David Hildenbrand <david@redhat.com> wrote:
> >>>     
> >>>> Make address_space_end point at the real end, instead of end + 1, so we don't
> >>>> have to handle special cases like it being 0. This will allow us to
> >>>> place a memory device at the very end of the guest physical 64bit address
> >>>> space (if ever possible).    
> >>>
> >>> [...]
> >>>     
> >>>> @@ -115,7 +116,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
> >>>>      }
> >>>>      address_space_start = ms->device_memory->base;
> >>>>      address_space_end = address_space_start +
> >>>> -                        memory_region_size(&ms->device_memory->mr);
> >>>> +                        memory_region_size(&ms->device_memory->mr) - 1;    
> >>> I'm terrible at math, lets assume size = 1 so after this
> >>> 'real end' would end up at 'address_space_start', which makes
> >>> it rather confusing beside not matching variable name anymore.    
> >>
> >> (very simply and unrealistic) counter example as given in the
> >> description. You should get the idea.
> >>
> >> address_space_start = 0xffffffffffffffffull;  
> > that should never happen, nor valid in any conditions
> > just add assert so we would catch error if some patch would introduce it
> >   
> >> size = 1;
> >>  
> >> -> address_space_end = 0;    
> >>
> >> While this would be perfectly valid, we would have to handle
> >> address_space_end potentially being 0 in the code below, because this
> >> would be a valid overflow. This, I avoid.  
> > assert(address_space_end > address_space_start)
> > would be much better for unrealistic values without messing up with
> > meaning of variables.
> >    
> >> And form my POV, the variable name here matches perfectly. It points at
> >> the last address of the address space. (yes people have different
> >> opinions on this)  
> > start,end pair is a range, there shouldn't be any other interpretations to
> > this variables.
> >   
> 
> Please see include/qemu/range.h:struct Range;
> 
> So I am using _the definition_.
> >>>
> >>> I'd drop it and maybe extend the following assert to abort
> >>> on overflow condition.    
> >>
> >> I'll leave it like this, handling address_space_end = 0 is ugly.  
> > Looks like I have to insist on dropping this hunk.  
> 
> You're going from "I'd" to "I have to insist". Please make up your mind.
my suggestions heavily influenced by the fact that the code should
be easy (for me and hopefully for others) to maintain in future,
when I have to review related code later down the road when original
author is not reachable/care anymore. (i.e. by pure selfishness)

So far I'm not convinced that this change is for a better hence we stuck
without consensus.

> I have a R-b from David. But I am willing to change it if you can give
> me a good reason why we should add asserts instead of fixing the code
> (== making it work in all possibly valid scenarios, especially end of
> address space).
if it's about valid cases then it's worth fixing,
but how many of the cases targeted here are in need of fixing in practice?

I'd keep it simple so it would be readable and do the job
but not clutter it with not necessary logic.

If we =actually= need to handle every possible permutation, it might
be better to reuse range_foo() helpers you've mentioned, instead of
open coding conditions over again. But only if we really need it or
if it makes current code simpler to read.

> With the new local variable new_end, the code looks pretty clean.
>
David Hildenbrand Sept. 27, 2018, 11:58 a.m. UTC | #6
On 27/09/2018 13:53, Igor Mammedov wrote:
> On Thu, 27 Sep 2018 10:58:47 +0200
> David Hildenbrand <david@redhat.com> wrote:
> 
>> On 27/09/2018 10:47, Igor Mammedov wrote:
>>> On Thu, 27 Sep 2018 10:13:07 +0200
>>> David Hildenbrand <david@redhat.com> wrote:
>>>   
>>>> On 27/09/2018 10:02, Igor Mammedov wrote:  
>>>>> On Wed, 26 Sep 2018 11:41:59 +0200
>>>>> David Hildenbrand <david@redhat.com> wrote:
>>>>>     
>>>>>> Make address_space_end point at the real end, instead of end + 1, so we don't
>>>>>> have to handle special cases like it being 0. This will allow us to
>>>>>> place a memory device at the very end of the guest physical 64bit address
>>>>>> space (if ever possible).    
>>>>>
>>>>> [...]
>>>>>     
>>>>>> @@ -115,7 +116,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
>>>>>>      }
>>>>>>      address_space_start = ms->device_memory->base;
>>>>>>      address_space_end = address_space_start +
>>>>>> -                        memory_region_size(&ms->device_memory->mr);
>>>>>> +                        memory_region_size(&ms->device_memory->mr) - 1;    
>>>>> I'm terrible at math, lets assume size = 1 so after this
>>>>> 'real end' would end up at 'address_space_start', which makes
>>>>> it rather confusing beside not matching variable name anymore.    
>>>>
>>>> (very simply and unrealistic) counter example as given in the
>>>> description. You should get the idea.
>>>>
>>>> address_space_start = 0xffffffffffffffffull;  
>>> that should never happen, nor valid in any conditions
>>> just add assert so we would catch error if some patch would introduce it
>>>   
>>>> size = 1;
>>>>  
>>>> -> address_space_end = 0;    
>>>>
>>>> While this would be perfectly valid, we would have to handle
>>>> address_space_end potentially being 0 in the code below, because this
>>>> would be a valid overflow. This, I avoid.  
>>> assert(address_space_end > address_space_start)
>>> would be much better for unrealistic values without messing up with
>>> meaning of variables.
>>>    
>>>> And form my POV, the variable name here matches perfectly. It points at
>>>> the last address of the address space. (yes people have different
>>>> opinions on this)  
>>> start,end pair is a range, there shouldn't be any other interpretations to
>>> this variables.
>>>   
>>
>> Please see include/qemu/range.h:struct Range;
>>
>> So I am using _the definition_.
>>>>>
>>>>> I'd drop it and maybe extend the following assert to abort
>>>>> on overflow condition.    
>>>>
>>>> I'll leave it like this, handling address_space_end = 0 is ugly.  
>>> Looks like I have to insist on dropping this hunk.  
>>
>> You're going from "I'd" to "I have to insist". Please make up your mind.
> my suggestions heavily influenced by the fact that the code should
> be easy (for me and hopefully for others) to maintain in future,
> when I have to review related code later down the road when original
> author is not reachable/care anymore. (i.e. by pure selfishness)
> 
> So far I'm not convinced that this change is for a better hence we stuck
> without consensus.
> 
>> I have a R-b from David. But I am willing to change it if you can give
>> me a good reason why we should add asserts instead of fixing the code
>> (== making it work in all possibly valid scenarios, especially end of
>> address space).
> if it's about valid cases then it's worth fixing,
> but how many of the cases targeted here are in need of fixing in practice?
> 
> I'd keep it simple so it would be readable and do the job
> but not clutter it with not necessary logic.
> 
> If we =actually= need to handle every possible permutation, it might
> be better to reuse range_foo() helpers you've mentioned, instead of
> open coding conditions over again. But only if we really need it or
> if it makes current code simpler to read.

We would probably have to add some new range_* helpers for that,
something I like to avoid now. So to make some progress, I will keep the
changes in this file minimal for now (e.g. specifying a device with a
huge size is IMHO possible, so we should fix that).

Maybe we can instead focus our energy on the more important parts
(namely Patch 18, 23, and 24) - I would really like to hear your opinion
about these. Thanks!
Igor Mammedov Sept. 27, 2018, 12:21 p.m. UTC | #7
On Thu, 27 Sep 2018 13:58:45 +0200
David Hildenbrand <david@redhat.com> wrote:

> On 27/09/2018 13:53, Igor Mammedov wrote:
> > On Thu, 27 Sep 2018 10:58:47 +0200
> > David Hildenbrand <david@redhat.com> wrote:
> >   
> >> On 27/09/2018 10:47, Igor Mammedov wrote:  
> >>> On Thu, 27 Sep 2018 10:13:07 +0200
> >>> David Hildenbrand <david@redhat.com> wrote:
> >>>     
> >>>> On 27/09/2018 10:02, Igor Mammedov wrote:    
> >>>>> On Wed, 26 Sep 2018 11:41:59 +0200
> >>>>> David Hildenbrand <david@redhat.com> wrote:
> >>>>>       
> >>>>>> Make address_space_end point at the real end, instead of end + 1, so we don't
> >>>>>> have to handle special cases like it being 0. This will allow us to
> >>>>>> place a memory device at the very end of the guest physical 64bit address
> >>>>>> space (if ever possible).      
> >>>>>
> >>>>> [...]
> >>>>>       
> >>>>>> @@ -115,7 +116,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
> >>>>>>      }
> >>>>>>      address_space_start = ms->device_memory->base;
> >>>>>>      address_space_end = address_space_start +
> >>>>>> -                        memory_region_size(&ms->device_memory->mr);
> >>>>>> +                        memory_region_size(&ms->device_memory->mr) - 1;      
> >>>>> I'm terrible at math, lets assume size = 1 so after this
> >>>>> 'real end' would end up at 'address_space_start', which makes
> >>>>> it rather confusing beside not matching variable name anymore.      
> >>>>
> >>>> (very simply and unrealistic) counter example as given in the
> >>>> description. You should get the idea.
> >>>>
> >>>> address_space_start = 0xffffffffffffffffull;    
> >>> that should never happen, nor valid in any conditions
> >>> just add assert so we would catch error if some patch would introduce it
> >>>     
> >>>> size = 1;
> >>>>    
> >>>> -> address_space_end = 0;      
> >>>>
> >>>> While this would be perfectly valid, we would have to handle
> >>>> address_space_end potentially being 0 in the code below, because this
> >>>> would be a valid overflow. This, I avoid.    
> >>> assert(address_space_end > address_space_start)
> >>> would be much better for unrealistic values without messing up with
> >>> meaning of variables.
> >>>      
> >>>> And form my POV, the variable name here matches perfectly. It points at
> >>>> the last address of the address space. (yes people have different
> >>>> opinions on this)    
> >>> start,end pair is a range, there shouldn't be any other interpretations to
> >>> this variables.
> >>>     
> >>
> >> Please see include/qemu/range.h:struct Range;
> >>
> >> So I am using _the definition_.  
> >>>>>
> >>>>> I'd drop it and maybe extend the following assert to abort
> >>>>> on overflow condition.      
> >>>>
> >>>> I'll leave it like this, handling address_space_end = 0 is ugly.    
> >>> Looks like I have to insist on dropping this hunk.    
> >>
> >> You're going from "I'd" to "I have to insist". Please make up your mind.  
> > my suggestions heavily influenced by the fact that the code should
> > be easy (for me and hopefully for others) to maintain in future,
> > when I have to review related code later down the road when original
> > author is not reachable/care anymore. (i.e. by pure selfishness)
> > 
> > So far I'm not convinced that this change is for a better hence we stuck
> > without consensus.
> >   
> >> I have a R-b from David. But I am willing to change it if you can give
> >> me a good reason why we should add asserts instead of fixing the code
> >> (== making it work in all possibly valid scenarios, especially end of
> >> address space).  
> > if it's about valid cases then it's worth fixing,
> > but how many of the cases targeted here are in need of fixing in practice?
> > 
> > I'd keep it simple so it would be readable and do the job
> > but not clutter it with not necessary logic.
> > 
> > If we =actually= need to handle every possible permutation, it might
> > be better to reuse range_foo() helpers you've mentioned, instead of
> > open coding conditions over again. But only if we really need it or
> > if it makes current code simpler to read.  
> 
> We would probably have to add some new range_* helpers for that,
> something I like to avoid now. So to make some progress, I will keep the
> changes in this file minimal for now (e.g. specifying a device with a
> huge size is IMHO possible, so we should fix that).
It's not a rush time before release where patch fixing something is
good enough reason to convince me even if it's not the way it should be
written.

To minimize changes it's fine to just drop this patch.
If you can reproduce real problem it's fine to fix it in this series
or separately and do simplification later.

> Maybe we can instead focus our energy on the more important parts
> (namely Patch 18, 23, and 24) - I would really like to hear your opinion
> about these. Thanks!
>
diff mbox series

Patch

diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c
index 7c706fadfc..8f0b9a9898 100644
--- a/hw/mem/memory-device.c
+++ b/hw/mem/memory-device.c
@@ -85,7 +85,8 @@  static void memory_device_check_addable(MachineState *ms, uint64_t size,
 
     /* will we exceed the total amount of memory specified */
     memory_device_used_region_size(OBJECT(ms), &used_region_size);
-    if (used_region_size + size > ms->maxram_size - ms->ram_size) {
+    if (used_region_size + size < used_region_size ||
+        used_region_size + size > ms->maxram_size - ms->ram_size) {
         error_setg(errp, "not enough space, currently 0x%" PRIx64
                    " in use of total hot pluggable 0x" RAM_ADDR_FMT,
                    used_region_size, ms->maxram_size - ms->ram_size);
@@ -115,7 +116,7 @@  uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
     }
     address_space_start = ms->device_memory->base;
     address_space_end = address_space_start +
-                        memory_region_size(&ms->device_memory->mr);
+                        memory_region_size(&ms->device_memory->mr) - 1;
     g_assert(address_space_end >= address_space_start);
 
     /* address_space_start indicates the maximum alignment we expect */
@@ -149,7 +150,8 @@  uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
                        "] before 0x%" PRIx64, new_addr, size,
                        address_space_start);
             return 0;
-        } else if ((new_addr + size) > address_space_end) {
+        } else if (new_addr + size - 1 < new_addr ||
+                   new_addr + size - 1 > address_space_end) {
             error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64
                        "] beyond 0x%" PRIx64, new_addr, size,
                        address_space_end);
@@ -182,7 +184,8 @@  uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint,
         }
     }
 
-    if (new_addr + size > address_space_end) {
+    if (new_addr + size - 1 < new_addr || !new_addr ||
+        new_addr + size - 1 > address_space_end) {
         error_setg(errp, "could not find position in guest address space for "
                    "memory device - memory fragmented due to alignments");
         goto out;