All of lore.kernel.org
 help / color / mirror / Atom feed
* calculation overflow in grub_mm_init_region
@ 2013-08-29 17:26 Leif Lindholm
  2013-09-10 12:13 ` calculation overflow in grub_mm_init_region (patch) Leif Lindholm
  0 siblings, 1 reply; 8+ messages in thread
From: Leif Lindholm @ 2013-08-29 17:26 UTC (permalink / raw)
  To: grub-devel

When allocating memory for the heap on ARMv7 UEFI, the init code
pretty much just allocates a chunk from the top of available RAM.

This means that when grub_mm_init_region is called for a region
extending to the top of the 32-bit address space, addr + size == 0.
However, this is not taken into account by arithmetic in this
function, causing Grub to fail on one of my platforms[1] before
"Welcome to GRUB".

Having some trouble getting my head around the grub_mm_init_region
code right now (where is grub_mm_base initialised?), so don't have
a patch.

/
    Leif

[1] Versatile Express V2P-CA15_A7, also known as TC2, has 2GB of RAM
    starting at 0x80000000.  


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: calculation overflow in grub_mm_init_region (patch)
  2013-08-29 17:26 calculation overflow in grub_mm_init_region Leif Lindholm
@ 2013-09-10 12:13 ` Leif Lindholm
  2013-09-10 21:46   ` Seth Goldberg
  2013-09-11  1:00   ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 2 replies; 8+ messages in thread
From: Leif Lindholm @ 2013-09-10 12:13 UTC (permalink / raw)
  To: grub-devel

On Thu, Aug 29, 2013 at 07:26:03PM +0200, Leif Lindholm wrote:
> When allocating memory for the heap on ARMv7 UEFI, the init code
> pretty much just allocates a chunk from the top of available RAM.
> 
> This means that when grub_mm_init_region is called for a region
> extending to the top of the 32-bit address space, addr + size == 0.
> However, this is not taken into account by arithmetic in this
> function, causing Grub to fail on one of my platforms[1] before
> "Welcome to GRUB".
> 
> Having some trouble getting my head around the grub_mm_init_region
> code right now (where is grub_mm_base initialised?), so don't have
> a patch.

So, sat down to dissect the code a bit, and turns out that apart from
a debug message (which is #ifdef 0 by default), grub_mm_init_region()
is actually innocent.

The error lies in get_header_from_pointer() (also kern/mm.c), and its
comparisons regarding whether a pointer lies within the current
region or not.

My suggested fix is as follows (with a little bit of refactoring to
help my brain).

/
    Leif

=== modified file 'grub-core/kern/mm.c'
--- grub-core/kern/mm.c 2013-04-20 15:39:49 +0000
+++ grub-core/kern/mm.c 2013-09-10 11:13:36 +0000
@@ -86,13 +86,20 @@
 static void
 get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
 {
+  grub_addr_t block_start = (grub_addr_t) ptr;
+
   if ((grub_addr_t) ptr & (GRUB_MM_ALIGN - 1))
     grub_fatal ("unaligned pointer %p", ptr);
 
   for (*r = grub_mm_base; *r; *r = (*r)->next)
-    if ((grub_addr_t) ptr > (grub_addr_t) ((*r) + 1)
-       && (grub_addr_t) ptr <= (grub_addr_t) ((*r) + 1) + (*r)->size)
-      break;
+    {
+      grub_addr_t region_start = (grub_addr_t) ((*r) + 1);
+      grub_addr_t region_end = (grub_addr_t) ((*r) + 1) + (*r)->size;
+
+      if (block_start > region_start)
+       if ((block_start <= region_end) || (region_end == 0))
+         break;
+    }
 
   if (! *r)
     grub_fatal ("out of range pointer %p", ptr);



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: calculation overflow in grub_mm_init_region (patch)
  2013-09-10 12:13 ` calculation overflow in grub_mm_init_region (patch) Leif Lindholm
@ 2013-09-10 21:46   ` Seth Goldberg
  2013-09-10 22:36     ` Leif Lindholm
  2013-09-11  1:00   ` Vladimir 'φ-coder/phcoder' Serbinenko
  1 sibling, 1 reply; 8+ messages in thread
From: Seth Goldberg @ 2013-09-10 21:46 UTC (permalink / raw)
  To: The development of GNU GRUB


Quoting Leif Lindholm, who wrote the following on Tue, 10 Sep 2013:

> On Thu, Aug 29, 2013 at 07:26:03PM +0200, Leif Lindholm wrote:
>> When allocating memory for the heap on ARMv7 UEFI, the init code
>> pretty much just allocates a chunk from the top of available RAM.
>>
>> This means that when grub_mm_init_region is called for a region
>> extending to the top of the 32-bit address space, addr + size == 0.
>> However, this is not taken into account by arithmetic in this
>> function, causing Grub to fail on one of my platforms[1] before
>> "Welcome to GRUB".
>>
>> Having some trouble getting my head around the grub_mm_init_region
>> code right now (where is grub_mm_base initialised?), so don't have
>> a patch.
>
> So, sat down to dissect the code a bit, and turns out that apart from
> a debug message (which is #ifdef 0 by default), grub_mm_init_region()
> is actually innocent.
>
> The error lies in get_header_from_pointer() (also kern/mm.c), and its
> comparisons regarding whether a pointer lies within the current
> region or not.
>
> My suggested fix is as follows (with a little bit of refactoring to
> help my brain).
>
> /
>    Leif
>
> === modified file 'grub-core/kern/mm.c'
> --- grub-core/kern/mm.c 2013-04-20 15:39:49 +0000
> +++ grub-core/kern/mm.c 2013-09-10 11:13:36 +0000
> @@ -86,13 +86,20 @@
> static void
> get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
> {
> +  grub_addr_t block_start = (grub_addr_t) ptr;
> +
>   if ((grub_addr_t) ptr & (GRUB_MM_ALIGN - 1))
>     grub_fatal ("unaligned pointer %p", ptr);
>
>   for (*r = grub_mm_base; *r; *r = (*r)->next)
> -    if ((grub_addr_t) ptr > (grub_addr_t) ((*r) + 1)
> -       && (grub_addr_t) ptr <= (grub_addr_t) ((*r) + 1) + (*r)->size)
> -      break;
> +    {
> +      grub_addr_t region_start = (grub_addr_t) ((*r) + 1);
> +      grub_addr_t region_end = (grub_addr_t) ((*r) + 1) + (*r)->size;
> +
> +      if (block_start > region_start)
> +       if ((block_start <= region_end) || (region_end == 0))


   Why would region_end be zero?  That sounds like an invalid value.

  --S


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: calculation overflow in grub_mm_init_region (patch)
  2013-09-10 21:46   ` Seth Goldberg
@ 2013-09-10 22:36     ` Leif Lindholm
  2013-09-10 22:39       ` Leif Lindholm
  2013-09-11 17:01       ` Seth Goldberg
  0 siblings, 2 replies; 8+ messages in thread
From: Leif Lindholm @ 2013-09-10 22:36 UTC (permalink / raw)
  To: The development of GNU GRUB

On 10 September 2013 22:46, Seth Goldberg <seth.goldberg@oracle.com> wrote:
>   Why would region_end be zero?  That sounds like an invalid value.

Because when a heap region sits at the top of RAM, region base +
region size == 0.

/
    Leif


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: calculation overflow in grub_mm_init_region (patch)
  2013-09-10 22:36     ` Leif Lindholm
@ 2013-09-10 22:39       ` Leif Lindholm
  2013-09-11 17:01       ` Seth Goldberg
  1 sibling, 0 replies; 8+ messages in thread
From: Leif Lindholm @ 2013-09-10 22:39 UTC (permalink / raw)
  To: The development of GNU GRUB

On 10 September 2013 23:36, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On 10 September 2013 22:46, Seth Goldberg <seth.goldberg@oracle.com> wrote:
>>   Why would region_end be zero?  That sounds like an invalid value.
>
> Because when a heap region sits at the top of RAM, region base +
> region size == 0.

(On that specific platform. In general, when it sits at the top of
addressable memory.)

/
    Leif


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: calculation overflow in grub_mm_init_region (patch)
  2013-09-10 12:13 ` calculation overflow in grub_mm_init_region (patch) Leif Lindholm
  2013-09-10 21:46   ` Seth Goldberg
@ 2013-09-11  1:00   ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-11  6:43     ` Leif Lindholm
  1 sibling, 1 reply; 8+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-11  1:00 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 839 bytes --]


>    for (*r = grub_mm_base; *r; *r = (*r)->next)
> -    if ((grub_addr_t) ptr > (grub_addr_t) ((*r) + 1)
> -       && (grub_addr_t) ptr <= (grub_addr_t) ((*r) + 1) + (*r)->size)
> -      break;
> +    {
> +      grub_addr_t region_start = (grub_addr_t) ((*r) + 1);
> +      grub_addr_t region_end = (grub_addr_t) ((*r) + 1) + (*r)->size;
> +
> +      if (block_start > region_start)
> +       if ((block_start <= region_end) || (region_end == 0))
> +         break;
> +    }
This fix looks correct but as indicated by us not having discovered this
bug earlier, this is a very unusual case and it's difficult to ensure
that similar bug doesn't pop up in another place or that we don't suffer
a regression. I'd prefer to exclude top 4K of adressable memory from
heap as safety measure. Are you ok with this approach?



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: calculation overflow in grub_mm_init_region (patch)
  2013-09-11  1:00   ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-09-11  6:43     ` Leif Lindholm
  0 siblings, 0 replies; 8+ messages in thread
From: Leif Lindholm @ 2013-09-11  6:43 UTC (permalink / raw)
  To: The development of GNU GRUB

On 11 September 2013 02:00, Vladimir 'φ-coder/phcoder' Serbinenko
<phcoder@gmail.com> wrote:
> This fix looks correct but as indicated by us not having discovered this
> bug earlier, this is a very unusual case and it's difficult to ensure
> that similar bug doesn't pop up in another place or that we don't suffer
> a regression. I'd prefer to exclude top 4K of adressable memory from
> heap as safety measure. Are you ok with this approach?

I am happy with that.

/
    Leif


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: calculation overflow in grub_mm_init_region (patch)
  2013-09-10 22:36     ` Leif Lindholm
  2013-09-10 22:39       ` Leif Lindholm
@ 2013-09-11 17:01       ` Seth Goldberg
  1 sibling, 0 replies; 8+ messages in thread
From: Seth Goldberg @ 2013-09-11 17:01 UTC (permalink / raw)
  To: The development of GNU GRUB



On Sep 10, 2013, at 3:36 PM, Leif Lindholm <leif.lindholm@linaro.org> wrote:

> On 10 September 2013 22:46, Seth Goldberg <seth.goldberg@oracle.com> wrote:
>>  Why would region_end be zero?  That sounds like an invalid value.
> 
> Because when a heap region sits at the top of RAM, region base +
> region size == 0.

  So, an overflow.  Ugh.  Reserving the last 4k would be fine, too, yes.

  --S


> 
> /
>    Leif
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-09-11 17:02 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-29 17:26 calculation overflow in grub_mm_init_region Leif Lindholm
2013-09-10 12:13 ` calculation overflow in grub_mm_init_region (patch) Leif Lindholm
2013-09-10 21:46   ` Seth Goldberg
2013-09-10 22:36     ` Leif Lindholm
2013-09-10 22:39       ` Leif Lindholm
2013-09-11 17:01       ` Seth Goldberg
2013-09-11  1:00   ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-09-11  6:43     ` Leif Lindholm

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.