* 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;
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;
"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;