source: patches/grub-0.97-use_mmap-2.patch@ 8867e46

clfs-1.2 clfs-2.1 clfs-3.0.0-systemd clfs-3.0.0-sysvinit systemd sysvinit
Last change on this file since 8867e46 was a1811b6, checked in by Joe Ciccone <jciccone@…>, 14 years ago

Update the grub patches.

  • Property mode set to 100644
File size: 19.1 KB
  • grub/asmstub.c

    Submitted By: Jim Gifford <clfs at cross-lfs dot org>
    Date: 07-15-2009
    Initial Package Version: 0.97
    Upstream Status: Unknown
    Origin: Grub Bug Report - http://savannah.gnu.org/bugs/?func=detailitem&item_id=11312
    Description: This patch fixes the following issues on x86_64
    	1) malloc'd pages seem to lack the execute bit on x86_64;
    	2) grub seems to use some stack pointer diversion to malloc'd pages;
    	3) nested functions execute data on the stack;
    	4) this causes a segfault (at least on my machine)
    
    diff -Naur grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c
    old new  
    4242#include <sys/time.h>
    4343#include <termios.h>
    4444#include <signal.h>
     45#include <sys/mman.h>
    4546
    4647#ifdef __linux__
    4748# include <sys/ioctl.h>         /* ioctl */
     
    7980struct apm_info apm_bios_info;
    8081
    8182/* Emulation requirements. */
    82 char *grub_scratch_mem = 0;
     83void *grub_scratch_mem = 0;
    8384
    8485struct geometry *disks = 0;
    8586
     
    103104static unsigned int serial_speed;
    104105#endif /* SIMULATE_SLOWNESS_OF_SERIAL */
    105106
     107/* This allocates page-aligned storage of the specified size, which must be
     108 * a multiple of the page size as determined by calling sysconf(_SC_PAGESIZE)
     109 */
     110#ifdef __linux__
     111static void *
     112grub_mmap_alloc(size_t len)
     113{
     114  int mmap_flags = MAP_ANONYMOUS|MAP_PRIVATE;
     115
     116#ifdef MAP_32BIT
     117  mmap_flags |= MAP_32BIT;
     118#endif
     119  /* Mark the simulated stack executable, as GCC uses stack trampolines
     120   * to implement nested functions. */
     121  return mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC, mmap_flags, -1, 0);
     122}
     123#else /* !defined(__linux__) */
     124static void *
     125grub_mmap_alloc(size_t len)
     126{
     127  int fd = 0, offset = 0, ret = 0;
     128  void *pa = MAP_FAILED;
     129  char template[] = "/tmp/grub_mmap_alloc_XXXXXX";
     130  int e;
     131
     132  fd = mkstemp(template);
     133  if (fd < 0)
     134    return pa;
     135
     136  unlink(template);
     137
     138  ret = ftruncate(fd, len);
     139  if (ret < 0)
     140    return pa;
     141
     142  /* Mark the simulated stack executable, as GCC uses stack trampolines
     143   * to implement nested functions. */
     144  pa = mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC,
     145                  MAP_PRIVATE, fd, offset);
     146
     147  e = errno;
     148  close(fd);
     149  errno = e;
     150  return pa;
     151}
     152#endif /* defined(__linux__) */
     153
    106154/* The main entry point into this mess. */
    107155int
    108156grub_stage2 (void)
    109157{
    110158  /* These need to be static, because they survive our stack transitions. */
    111159  static int status = 0;
    112   static char *realstack;
    113   char *scratch, *simstack;
     160  static void *realstack;
     161  void *simstack_alloc_base, *simstack;
     162  size_t simstack_size, page_size;
    114163  int i;
    115164
    116165  auto void doit (void);
     
    142191    }
    143192
    144193  assert (grub_scratch_mem == 0);
    145   scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
    146   assert (scratch);
    147   grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4);
     194
     195  /* Allocate enough pages for 0x100000 + EXTENDED_SIZE + 15, and
     196   * make sure the memory is aligned to a multiple of the system's
     197   * page size */
     198  page_size = sysconf (_SC_PAGESIZE);
     199  simstack_size = ( 0x100000 + EXTENDED_MEMSIZE + 15);
     200  if (simstack_size % page_size)
     201    {
     202      /* If we're not on a page_size boundary, round up to the next one */
     203      simstack_size &= ~(page_size-1);
     204      simstack_size += page_size;
     205    }
     206
     207  /* Add one for a PROT_NONE boundary page at each end. */
     208  simstack_size += 2 * page_size;
     209
     210  simstack_alloc_base = grub_mmap_alloc(simstack_size);
     211  assert (simstack_alloc_base != MAP_FAILED);
     212
     213  /* mark pages above and below our simstack area as innaccessable.
     214   * If the implementation we're using doesn't support that, then the
     215   * new protection modes are undefined.  It's safe to just ignore
     216   * them, though.  It'd be nice if we knew that we'd get a SEGV for
     217   * touching the area, but that's all.  it'd be nice to have. */
     218  mprotect (simstack_alloc_base, page_size, PROT_NONE);
     219  mprotect ((void *)((unsigned long)simstack_alloc_base +
     220                         simstack_size - page_size),  page_size, PROT_NONE);
     221
     222  grub_scratch_mem = (void *)((unsigned long)simstack_alloc_base + page_size);
    148223
    149224  /* FIXME: simulate the memory holes using mprot, if available. */
    150225
     
    217292  device_map = 0;
    218293  free (disks);
    219294  disks = 0;
    220   free (scratch);
     295  munmap(simstack_alloc_base, simstack_size);
    221296  grub_scratch_mem = 0;
    222297
    223298  if (serial_device)
  • stage2/builtins.c

    diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c
    old new  
    130130  grub_printf ("[%d,%d,%d]", sector, offset, length);
    131131}
    132132
    133 
    134133
     134/* blocklist_read_helper nee disk_read_blocklist_func was a nested
     135 * function, to which pointers were taken and exposed globally.  Even
     136 * in the GNU-C nested functions extension, they have local linkage,
     137 * and aren't guaranteed to be accessable *at all* outside of their
     138 * containing scope.
     139 *
     140 * Above and beyond all of that, the variables within blocklist_func_context
     141 * are originally local variables, with local (not even static) linkage,
     142 * from within blocklist_func.  These were each referenced by
     143 * disk_read_blocklist_func, which is only called from other functions
     144 * through a globally scoped pointer.
     145 *
     146 * The documentation in GCC actually uses the words "all hell will break
     147 * loose" to describe this scenario.
     148 *
     149 * Also, "start_sector" was also used uninitialized, but gcc doesn't warn
     150 * about it (possibly because of the scoping madness?)
     151 */
     152   
     153static struct {
     154       int start_sector;
     155       int num_sectors;
     156       int num_entries;
     157       int last_length;
     158} blocklist_func_context = {
     159       .start_sector = 0,
     160       .num_sectors = 0,
     161       .num_entries = 0,
     162       .last_length = 0
     163};
     164
     165/* Collect contiguous blocks into one entry as many as possible,
     166   and print the blocklist notation on the screen.  */
     167static void
     168blocklist_read_helper (int sector, int offset, int length)
     169{
     170  int *start_sector = &blocklist_func_context.start_sector;
     171  int *num_sectors = &blocklist_func_context.num_sectors;
     172  int *num_entries = &blocklist_func_context.num_entries;
     173  int *last_length = &blocklist_func_context.last_length;
     174
     175  if (*num_sectors > 0)
     176  {
     177    if (*start_sector + *num_sectors == sector
     178      && offset == 0 && *last_length == SECTOR_SIZE)
     179    {
     180      *num_sectors++;
     181      *last_length = length;
     182      return;
     183    }
     184    else
     185    {
     186      if (*last_length == SECTOR_SIZE)
     187        grub_printf ("%s%d+%d", *num_entries ? "," : "",
     188          *start_sector - part_start, *num_sectors);
     189      else if (*num_sectors > 1)
     190        grub_printf ("%s%d+%d,%d[0-%d]", *num_entries ? "," : "",
     191          *start_sector - part_start, *num_sectors-1,
     192          *start_sector + *num_sectors-1 - part_start,
     193          *last_length);
     194      else
     195        grub_printf ("%s%d[0-%d]", *num_entries ? "," : "",
     196          *start_sector - part_start, *last_length);
     197      *num_entries++;
     198      *num_sectors = 0;
     199    }
     200  }
     201
     202  if (offset > 0)
     203  {
     204    grub_printf("%s%d[%d-%d]", *num_entries ? "," : "",
     205          sector-part_start, offset, offset+length);
     206    *num_entries++;
     207  }
     208  else
     209  {
     210    *start_sector = sector;
     211    *num_sectors = 1;
     212    *last_length = length;
     213  }
     214}
     215
    135216/* blocklist */
    136217static int
    137218blocklist_func (char *arg, int flags)
    138219{
    139220  char *dummy = (char *) RAW_ADDR (0x100000);
    140   int start_sector;
    141   int num_sectors = 0;
    142   int num_entries = 0;
    143   int last_length = 0;
    144221
    145   auto void disk_read_blocklist_func (int sector, int offset, int length);
    146  
    147   /* Collect contiguous blocks into one entry as many as possible,
    148      and print the blocklist notation on the screen.  */
    149   auto void disk_read_blocklist_func (int sector, int offset, int length)
    150     {
    151       if (num_sectors > 0)
    152         {
    153           if (start_sector + num_sectors == sector
    154               && offset == 0 && last_length == SECTOR_SIZE)
    155             {
    156               num_sectors++;
    157               last_length = length;
    158               return;
    159             }
    160           else
    161             {
    162               if (last_length == SECTOR_SIZE)
    163                 grub_printf ("%s%d+%d", num_entries ? "," : "",
    164                              start_sector - part_start, num_sectors);
    165               else if (num_sectors > 1)
    166                 grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
    167                              start_sector - part_start, num_sectors-1,
    168                              start_sector + num_sectors-1 - part_start,
    169                              last_length);
    170               else
    171                 grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
    172                              start_sector - part_start, last_length);
    173               num_entries++;
    174               num_sectors = 0;
    175             }
    176         }
    177 
    178       if (offset > 0)
    179         {
    180           grub_printf("%s%d[%d-%d]", num_entries ? "," : "",
    181                       sector-part_start, offset, offset+length);
    182           num_entries++;
    183         }
    184       else
    185         {
    186           start_sector = sector;
    187           num_sectors = 1;
    188           last_length = length;
    189         }
    190     }
     222  int *start_sector = &blocklist_func_context.start_sector;
     223  int *num_sectors = &blocklist_func_context.num_sectors;
     224  int *num_entries = &blocklist_func_context.num_entries;
    191225
    192226  /* Open the file.  */
  • stage2/shared.h

       if (! grub_open (arg))
    @@ -206,15 +240,15 @@
       grub_printf (")");
     
       /* Read in the whole file to DUMMY.  */
    -  disk_read_hook = disk_read_blocklist_func;
    +  disk_read_hook = blocklist_read_helper;
       if (! grub_read (dummy, -1))
         goto fail;
     
       /* The last entry may not be printed yet.  Don't check if it is a
        * full sector, since it doesn't matter if we read too much. */
    -  if (num_sectors > 0)
    -    grub_printf ("%s%d+%d", num_entries ? "," : "",
    -		 start_sector - part_start, num_sectors);
    +  if (*num_sectors > 0)
    +	grub_printf ("%s%d+%d", *num_entries ? "," : "",
    +                *start_sector - part_start, *num_sectors);
     
       grub_printf ("\n");
       
    @@ -1740,6 +1774,77 @@
     
     
    
     /* install */
    +static struct {
    +       int saved_sector;
    +       int installaddr;
    +       int installlist;
    +       char *stage2_first_buffer;
    +} install_func_context = {
    +       .saved_sector = 0,
    +       .installaddr = 0,
    +       .installlist = 0,
    +       .stage2_first_buffer = NULL,
    +};
    +
    +/* Save the first sector of Stage2 in STAGE2_SECT.  */
    +/* Formerly disk_read_savesect_func with local scope inside install_func */
    +static void
    +install_savesect_helper(int sector, int offset, int length)
    +{
    +  if (debug)
    +    printf ("[%d]", sector);
    +
    +  /* ReiserFS has files which sometimes contain data not aligned
    +     on sector boundaries.  Returning an error is better than
    +     silently failing. */
    +  if (offset != 0 || length != SECTOR_SIZE)
    +    errnum = ERR_UNALIGNED;
    +
    +  install_func_context.saved_sector = sector;
    +}
    +
    +/* Write SECTOR to INSTALLLIST, and update INSTALLADDR and  INSTALLSECT.  */
    +/* Formerly disk_read_blocklist_func with local scope inside install_func */
    +static void
    +install_blocklist_helper (int sector, int offset, int length)
    +{
    +  int *installaddr = &install_func_context.installaddr;
    +  int *installlist = &install_func_context.installlist;
    +  char **stage2_first_buffer = &install_func_context.stage2_first_buffer;
    +  /* Was the last sector full? */
    +  static int last_length = SECTOR_SIZE;
    +
    +  if (debug)
    +    printf("[%d]", sector);
    +
    +  if (offset != 0 || last_length != SECTOR_SIZE)
    +    {
    +      /* We found a non-sector-aligned data block. */
    +      errnum = ERR_UNALIGNED;
    +      return;
    +    }
    +
    +  last_length = length;
    +
    +  if (*((unsigned long *) (*installlist - 4))
    +      + *((unsigned short *) *installlist) != sector
    +      || *installlist == (int) *stage2_first_buffer + SECTOR_SIZE + 4)
    +    {
    +      *installlist -= 8;
    +
    +      if (*((unsigned long *) (*installlist - 8)))
    +        errnum = ERR_WONT_FIT;
    +      else
    +        {
    +          *((unsigned short *) (*installlist + 2)) = (*installaddr >> 4);
    +          *((unsigned long *) (*installlist - 4)) = sector;
    +        }
    +    }
    +
    +  *((unsigned short *) *installlist) += 1;
    +  *installaddr += 512;
    +}
    +
     static int
     install_func (char *arg, int flags)
     {
    @@ -1747,8 +1852,12 @@
       char *stage1_buffer = (char *) RAW_ADDR (0x100000);
       char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
       char *old_sect = stage2_buffer + SECTOR_SIZE;
    -  char *stage2_first_buffer = old_sect + SECTOR_SIZE;
    -  char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
    +  /* stage2_first_buffer used to be defined as:
    +   * char *stage2_first_buffer = old_sect + SECTOR_SIZE;  */
    +  char **stage2_first_buffer = &install_func_context.stage2_first_buffer;
    +  /* and stage2_second_buffer was:
    +   * char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; */
    +  char *stage2_second_buffer = old_sect + SECTOR_SIZE + SECTOR_SIZE;
       /* XXX: Probably SECTOR_SIZE is reasonable.  */
       char *config_filename = stage2_second_buffer + SECTOR_SIZE;
       char *dummy = config_filename + SECTOR_SIZE;
    @@ -1757,10 +1866,11 @@
       int src_drive, src_partition, src_part_start;
       int i;
       struct geometry dest_geom, src_geom;
    -  int saved_sector;
    +  int *saved_sector = &install_func_context.saved_sector;
       int stage2_first_sector, stage2_second_sector;
       char *ptr;
    -  int installaddr, installlist;
    +  int *installaddr = &install_func_context.installaddr;
    +  int *installlist = &install_func_context.installlist;
       /* Point to the location of the name of a configuration file in Stage 2.  */
       char *config_file_location;
       /* If FILE is a Stage 1.5?  */
    @@ -1769,67 +1879,13 @@
       int is_open = 0;
       /* If LBA is forced?  */
       int is_force_lba = 0;
    -  /* Was the last sector full? */
    -  int last_length = SECTOR_SIZE;
    -  
    +
    +  *stage2_first_buffer = old_sect + SECTOR_SIZE;
     #ifdef GRUB_UTIL
       /* If the Stage 2 is in a partition mounted by an OS, this will store
          the filename under the OS.  */
       char *stage2_os_file = 0;
     #endif /* GRUB_UTIL */
    -  
    -  auto void disk_read_savesect_func (int sector, int offset, int length);
    -  auto void disk_read_blocklist_func (int sector, int offset, int length);
    -  
    -  /* Save the first sector of Stage2 in STAGE2_SECT.  */
    -  auto void disk_read_savesect_func (int sector, int offset, int length)
    -    {
    -      if (debug)
    -	printf ("[%d]", sector);
    -
    -      /* ReiserFS has files which sometimes contain data not aligned
    -         on sector boundaries.  Returning an error is better than
    -         silently failing. */
    -      if (offset != 0 || length != SECTOR_SIZE)
    -	errnum = ERR_UNALIGNED;
    -
    -      saved_sector = sector;
    -    }
    -
    -  /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
    -     INSTALLSECT.  */
    -  auto void disk_read_blocklist_func (int sector, int offset, int length)
    -    {
    -      if (debug)
    -	printf("[%d]", sector);
    -
    -      if (offset != 0 || last_length != SECTOR_SIZE)
    -	{
    -	  /* We found a non-sector-aligned data block. */
    -	  errnum = ERR_UNALIGNED;
    -	  return;
    -	}
    -
    -      last_length = length;
    -
    -      if (*((unsigned long *) (installlist - 4))
    -	  + *((unsigned short *) installlist) != sector
    -	  || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
    -	{
    -	  installlist -= 8;
    -
    -	  if (*((unsigned long *) (installlist - 8)))
    -	    errnum = ERR_WONT_FIT;
    -	  else
    -	    {
    -	      *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
    -	      *((unsigned long *) (installlist - 4)) = sector;
    -	    }
    -	}
    -
    -      *((unsigned short *) installlist) += 1;
    -      installaddr += 512;
    -    }
     
       /* First, check the GNU-style long option.  */
       while (1)
    @@ -1862,10 +1918,10 @@
       addr = skip_to (0, file);
     
       /* Get the installation address.  */
    -  if (! safe_parse_maxint (&addr, &installaddr))
    +  if (! safe_parse_maxint (&addr, installaddr))
         {
           /* ADDR is not specified.  */
    -      installaddr = 0;
    +      *installaddr = 0;
           ptr = addr;
           errnum = 0;
         }
    @@ -1961,17 +2017,17 @@
           = 0x9090;
       
       /* Read the first sector of Stage 2.  */
    -  disk_read_hook = disk_read_savesect_func;
    -  if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
    +  disk_read_hook = install_savesect_helper;
    +  if (grub_read (*stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
         goto fail;
     
    -  stage2_first_sector = saved_sector;
    +  stage2_first_sector = *saved_sector;
       
       /* Read the second sector of Stage 2.  */
       if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
         goto fail;
     
    -  stage2_second_sector = saved_sector;
    +  stage2_second_sector = *saved_sector;
       
       /* Check for the version of Stage 2.  */
       if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
    @@ -1987,27 +2043,27 @@
     
       /* If INSTALLADDR is not specified explicitly in the command-line,
          determine it by the Stage 2 id.  */
    -  if (! installaddr)
    +  if (! *installaddr)
         {
           if (! is_stage1_5)
     	/* Stage 2.  */
    -	installaddr = 0x8000;
    +	*installaddr = 0x8000;
           else
     	/* Stage 1.5.  */
    -	installaddr = 0x2000;
    +	*installaddr = 0x2000;
         }
     
       *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
         = stage2_first_sector;
       *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
    -    = installaddr;
    +    = *installaddr;
       *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
    -    = installaddr >> 4;
    +    = *installaddr >> 4;
     
    -  i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
    +  i = (int) *stage2_first_buffer + SECTOR_SIZE - 4;
       while (*((unsigned long *) i))
         {
    -      if (i < (int) stage2_first_buffer
    +      if (i < (int) *stage2_first_buffer
     	  || (*((int *) (i - 4)) & 0x80000000)
     	  || *((unsigned short *) i) >= 0xA00
     	  || *((short *) (i + 2)) == 0)
    @@ -2021,13 +2077,13 @@
           i -= 8;
         }
     
    -  installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
    -  installaddr += SECTOR_SIZE;
    +  *installlist = (int) *stage2_first_buffer + SECTOR_SIZE + 4;
    +  *installaddr += SECTOR_SIZE;
       
       /* Read the whole of Stage2 except for the first sector.  */
       grub_seek (SECTOR_SIZE);
     
    -  disk_read_hook = disk_read_blocklist_func;
    +  disk_read_hook = install_blocklist_helper;
       if (! grub_read (dummy, -1))
         goto fail;
       
    @@ -2110,7 +2166,7 @@
     	  /* Skip the first sector.  */
     	  grub_seek (SECTOR_SIZE);
     	  
    -	  disk_read_hook = disk_read_savesect_func;
    +	  disk_read_hook = install_savesect_helper;
     	  if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
     	    goto fail;
     	  
    @@ -2180,7 +2236,7 @@
     	  else
     #endif /* GRUB_UTIL */
     	    {
    -	      if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
    +	      if (! devwrite (*saved_sector - part_start, 1, stage2_buffer))
     		goto fail;
     	    }
     	}
    @@ -2202,7 +2258,7 @@
     	  goto fail;
     	}
     
    -      if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
    +      if (fwrite (*stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
     	{
     	  fclose (fp);
     	  errnum = ERR_WRITE;
    @@ -2229,7 +2285,7 @@
     	goto fail;
     
           if (! devwrite (stage2_first_sector - src_part_start, 1,
    -		      stage2_first_buffer))
    +		      *stage2_first_buffer))
     	goto fail;
     
           if (! devwrite (stage2_second_sector - src_part_start, 1,
    diff -Naur grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h
    old new  
    3636
    3737/* Maybe redirect memory requests through grub_scratch_mem. */
    3838#ifdef GRUB_UTIL
    39 extern char *grub_scratch_mem;
    40 # define RAW_ADDR(x) ((x) + (int) grub_scratch_mem)
     39extern void *grub_scratch_mem;
     40# define RAW_ADDR(x) ((x) + (unsigned long) grub_scratch_mem)
    4141# define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4)
    4242#else
    4343# define RAW_ADDR(x) (x)
Note: See TracBrowser for help on using the repository browser.