]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Prevent relocator of overwriting itself
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 26 Nov 2009 15:52:10 +0000 (16:52 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 26 Nov 2009 15:52:10 +0000 (16:52 +0100)
lib/relocator.c

index bebf7ada96c205a7dca31d269bd0c3ee82f4009c..68260b1974610ae0bdd6248a1b01efc8662f81f5 100644 (file)
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define MAX_OVERHEAD ((RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) \
+                     + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) \
+                     + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN)  \
+                     + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN))
+
 void *
 PREFIX (alloc) (grub_size_t size)
 {
   char *playground;
 
-  playground = grub_malloc ((RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN)
-                           + size
-                           + (RELOCATOR_SIZEOF (backward) +
-                              RELOCATOR_ALIGN));
+  playground = grub_malloc (size + MAX_OVERHEAD);
   if (!playground)
     return 0;
 
@@ -40,10 +42,7 @@ PREFIX (realloc) (void *relocator, grub_size_t size)
 
   playground = (char *) relocator - RELOCATOR_SIZEOF (forward);
 
-  playground = grub_realloc (playground,
-                            (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN)
-                            + size
-                            + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN));
+  playground = grub_realloc (playground, size + MAX_OVERHEAD);
   if (!playground)
     return 0;
 
@@ -73,6 +72,25 @@ PREFIX (boot) (void *relocator, grub_uint32_t dest,
                "Relocator: source: %p, destination: 0x%x, size: 0x%x\n",
                relocator, dest, size);
 
+  /* Very unlikely condition: Relocator may risk overwrite itself.
+     Just move it a bit up.  */
+  if ((grub_uint8_t *) UINT_TO_PTR (dest) - (grub_uint8_t *) relocator
+      < RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN
+      && (grub_uint8_t *) UINT_TO_PTR (dest) - (grub_uint8_t *) relocator
+      > -(RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN))
+    {
+      void *relocator_new = ((grub_uint8_t *) relocator)
+       + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN)
+       + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN);
+      grub_dprintf ("relocator", "Overwrite condition detected moving "
+                   "relocator from %p to %p\n", relocator, relocator_new);
+      grub_memmove (relocator_new, relocator,
+                   (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN)
+                   + size
+                   + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN));
+      relocator = relocator_new;
+    }
+
   if (UINT_TO_PTR (dest) >= relocator)
     {
       int overhead;