source: patches/grub-0.97-use_mmap-2.patch@ 8fed28a

clfs-1.2 clfs-2.1 clfs-3.0.0-systemd clfs-3.0.0-sysvinit systemd sysvinit
Last change on this file since 8fed28a 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
RevLine 
[a1811b6]1Submitted By: Jim Gifford <clfs at cross-lfs dot org>
2Date: 07-15-2009
3Initial Package Version: 0.97
4Upstream Status: Unknown
5Origin: Grub Bug Report - http://savannah.gnu.org/bugs/?func=detailitem&item_id=11312
6Description: This patch fixes the following issues on x86_64
7 1) malloc'd pages seem to lack the execute bit on x86_64;
8 2) grub seems to use some stack pointer diversion to malloc'd pages;
9 3) nested functions execute data on the stack;
10 4) this causes a segfault (at least on my machine)
11
12diff -Naur grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c
13--- grub-0.97.orig/grub/asmstub.c 2005-02-16 12:45:14.000000000 -0800
14+++ grub-0.97/grub/asmstub.c 2009-07-05 23:32:43.000000000 -0700
15@@ -42,6 +42,7 @@
16 #include <sys/time.h>
17 #include <termios.h>
18 #include <signal.h>
19+#include <sys/mman.h>
20
21 #ifdef __linux__
22 # include <sys/ioctl.h> /* ioctl */
23@@ -79,7 +80,7 @@
24 struct apm_info apm_bios_info;
25
26 /* Emulation requirements. */
27-char *grub_scratch_mem = 0;
28+void *grub_scratch_mem = 0;
29
30 struct geometry *disks = 0;
31
32@@ -103,14 +104,62 @@
33 static unsigned int serial_speed;
34 #endif /* SIMULATE_SLOWNESS_OF_SERIAL */
35
36+/* This allocates page-aligned storage of the specified size, which must be
37+ * a multiple of the page size as determined by calling sysconf(_SC_PAGESIZE)
38+ */
39+#ifdef __linux__
40+static void *
41+grub_mmap_alloc(size_t len)
42+{
43+ int mmap_flags = MAP_ANONYMOUS|MAP_PRIVATE;
44+
45+#ifdef MAP_32BIT
46+ mmap_flags |= MAP_32BIT;
47+#endif
48+ /* Mark the simulated stack executable, as GCC uses stack trampolines
49+ * to implement nested functions. */
50+ return mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC, mmap_flags, -1, 0);
51+}
52+#else /* !defined(__linux__) */
53+static void *
54+grub_mmap_alloc(size_t len)
55+{
56+ int fd = 0, offset = 0, ret = 0;
57+ void *pa = MAP_FAILED;
58+ char template[] = "/tmp/grub_mmap_alloc_XXXXXX";
59+ int e;
60+
61+ fd = mkstemp(template);
62+ if (fd < 0)
63+ return pa;
64+
65+ unlink(template);
66+
67+ ret = ftruncate(fd, len);
68+ if (ret < 0)
69+ return pa;
70+
71+ /* Mark the simulated stack executable, as GCC uses stack trampolines
72+ * to implement nested functions. */
73+ pa = mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC,
74+ MAP_PRIVATE, fd, offset);
75+
76+ e = errno;
77+ close(fd);
78+ errno = e;
79+ return pa;
80+}
81+#endif /* defined(__linux__) */
82+
83 /* The main entry point into this mess. */
84 int
85 grub_stage2 (void)
86 {
87 /* These need to be static, because they survive our stack transitions. */
88 static int status = 0;
89- static char *realstack;
90- char *scratch, *simstack;
91+ static void *realstack;
92+ void *simstack_alloc_base, *simstack;
93+ size_t simstack_size, page_size;
94 int i;
95
96 auto void doit (void);
97@@ -142,9 +191,35 @@
98 }
99
100 assert (grub_scratch_mem == 0);
101- scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
102- assert (scratch);
103- grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4);
104+
105+ /* Allocate enough pages for 0x100000 + EXTENDED_SIZE + 15, and
106+ * make sure the memory is aligned to a multiple of the system's
107+ * page size */
108+ page_size = sysconf (_SC_PAGESIZE);
109+ simstack_size = ( 0x100000 + EXTENDED_MEMSIZE + 15);
110+ if (simstack_size % page_size)
111+ {
112+ /* If we're not on a page_size boundary, round up to the next one */
113+ simstack_size &= ~(page_size-1);
114+ simstack_size += page_size;
115+ }
116+
117+ /* Add one for a PROT_NONE boundary page at each end. */
118+ simstack_size += 2 * page_size;
119+
120+ simstack_alloc_base = grub_mmap_alloc(simstack_size);
121+ assert (simstack_alloc_base != MAP_FAILED);
122+
123+ /* mark pages above and below our simstack area as innaccessable.
124+ * If the implementation we're using doesn't support that, then the
125+ * new protection modes are undefined. It's safe to just ignore
126+ * them, though. It'd be nice if we knew that we'd get a SEGV for
127+ * touching the area, but that's all. it'd be nice to have. */
128+ mprotect (simstack_alloc_base, page_size, PROT_NONE);
129+ mprotect ((void *)((unsigned long)simstack_alloc_base +
130+ simstack_size - page_size), page_size, PROT_NONE);
131+
132+ grub_scratch_mem = (void *)((unsigned long)simstack_alloc_base + page_size);
133
134 /* FIXME: simulate the memory holes using mprot, if available. */
135
136@@ -217,7 +292,7 @@
137 device_map = 0;
138 free (disks);
139 disks = 0;
140- free (scratch);
141+ munmap(simstack_alloc_base, simstack_size);
142 grub_scratch_mem = 0;
143
144 if (serial_device)
145diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c
146--- grub-0.97.orig/stage2/builtins.c 2005-02-15 13:58:23.000000000 -0800
147+++ grub-0.97/stage2/builtins.c 2009-07-05 23:42:45.000000000 -0700
148@@ -130,63 +130,97 @@
149 grub_printf ("[%d,%d,%d]", sector, offset, length);
150 }
151
152-
153
154+/* blocklist_read_helper nee disk_read_blocklist_func was a nested
155+ * function, to which pointers were taken and exposed globally. Even
156+ * in the GNU-C nested functions extension, they have local linkage,
157+ * and aren't guaranteed to be accessable *at all* outside of their
158+ * containing scope.
159+ *
160+ * Above and beyond all of that, the variables within blocklist_func_context
161+ * are originally local variables, with local (not even static) linkage,
162+ * from within blocklist_func. These were each referenced by
163+ * disk_read_blocklist_func, which is only called from other functions
164+ * through a globally scoped pointer.
165+ *
166+ * The documentation in GCC actually uses the words "all hell will break
167+ * loose" to describe this scenario.
168+ *
169+ * Also, "start_sector" was also used uninitialized, but gcc doesn't warn
170+ * about it (possibly because of the scoping madness?)
171+ */
172+
173+static struct {
174+ int start_sector;
175+ int num_sectors;
176+ int num_entries;
177+ int last_length;
178+} blocklist_func_context = {
179+ .start_sector = 0,
180+ .num_sectors = 0,
181+ .num_entries = 0,
182+ .last_length = 0
183+};
184+
185+/* Collect contiguous blocks into one entry as many as possible,
186+ and print the blocklist notation on the screen. */
187+static void
188+blocklist_read_helper (int sector, int offset, int length)
189+{
190+ int *start_sector = &blocklist_func_context.start_sector;
191+ int *num_sectors = &blocklist_func_context.num_sectors;
192+ int *num_entries = &blocklist_func_context.num_entries;
193+ int *last_length = &blocklist_func_context.last_length;
194+
195+ if (*num_sectors > 0)
196+ {
197+ if (*start_sector + *num_sectors == sector
198+ && offset == 0 && *last_length == SECTOR_SIZE)
199+ {
200+ *num_sectors++;
201+ *last_length = length;
202+ return;
203+ }
204+ else
205+ {
206+ if (*last_length == SECTOR_SIZE)
207+ grub_printf ("%s%d+%d", *num_entries ? "," : "",
208+ *start_sector - part_start, *num_sectors);
209+ else if (*num_sectors > 1)
210+ grub_printf ("%s%d+%d,%d[0-%d]", *num_entries ? "," : "",
211+ *start_sector - part_start, *num_sectors-1,
212+ *start_sector + *num_sectors-1 - part_start,
213+ *last_length);
214+ else
215+ grub_printf ("%s%d[0-%d]", *num_entries ? "," : "",
216+ *start_sector - part_start, *last_length);
217+ *num_entries++;
218+ *num_sectors = 0;
219+ }
220+ }
221+
222+ if (offset > 0)
223+ {
224+ grub_printf("%s%d[%d-%d]", *num_entries ? "," : "",
225+ sector-part_start, offset, offset+length);
226+ *num_entries++;
227+ }
228+ else
229+ {
230+ *start_sector = sector;
231+ *num_sectors = 1;
232+ *last_length = length;
233+ }
234+}
235+
236 /* blocklist */
237 static int
238 blocklist_func (char *arg, int flags)
239 {
240 char *dummy = (char *) RAW_ADDR (0x100000);
241- int start_sector;
242- int num_sectors = 0;
243- int num_entries = 0;
244- int last_length = 0;
245
246- auto void disk_read_blocklist_func (int sector, int offset, int length);
247-
248- /* Collect contiguous blocks into one entry as many as possible,
249- and print the blocklist notation on the screen. */
250- auto void disk_read_blocklist_func (int sector, int offset, int length)
251- {
252- if (num_sectors > 0)
253- {
254- if (start_sector + num_sectors == sector
255- && offset == 0 && last_length == SECTOR_SIZE)
256- {
257- num_sectors++;
258- last_length = length;
259- return;
260- }
261- else
262- {
263- if (last_length == SECTOR_SIZE)
264- grub_printf ("%s%d+%d", num_entries ? "," : "",
265- start_sector - part_start, num_sectors);
266- else if (num_sectors > 1)
267- grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
268- start_sector - part_start, num_sectors-1,
269- start_sector + num_sectors-1 - part_start,
270- last_length);
271- else
272- grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
273- start_sector - part_start, last_length);
274- num_entries++;
275- num_sectors = 0;
276- }
277- }
278-
279- if (offset > 0)
280- {
281- grub_printf("%s%d[%d-%d]", num_entries ? "," : "",
282- sector-part_start, offset, offset+length);
283- num_entries++;
284- }
285- else
286- {
287- start_sector = sector;
288- num_sectors = 1;
289- last_length = length;
290- }
291- }
292+ int *start_sector = &blocklist_func_context.start_sector;
293+ int *num_sectors = &blocklist_func_context.num_sectors;
294+ int *num_entries = &blocklist_func_context.num_entries;
295
296 /* Open the file. */
297 if (! grub_open (arg))
298@@ -206,15 +240,15 @@
299 grub_printf (")");
300
301 /* Read in the whole file to DUMMY. */
302- disk_read_hook = disk_read_blocklist_func;
303+ disk_read_hook = blocklist_read_helper;
304 if (! grub_read (dummy, -1))
305 goto fail;
306
307 /* The last entry may not be printed yet. Don't check if it is a
308 * full sector, since it doesn't matter if we read too much. */
309- if (num_sectors > 0)
310- grub_printf ("%s%d+%d", num_entries ? "," : "",
311- start_sector - part_start, num_sectors);
312+ if (*num_sectors > 0)
313+ grub_printf ("%s%d+%d", *num_entries ? "," : "",
314+ *start_sector - part_start, *num_sectors);
315
316 grub_printf ("\n");
317
318@@ -1740,6 +1774,77 @@
319
320
321
322 /* install */
323+static struct {
324+ int saved_sector;
325+ int installaddr;
326+ int installlist;
327+ char *stage2_first_buffer;
328+} install_func_context = {
329+ .saved_sector = 0,
330+ .installaddr = 0,
331+ .installlist = 0,
332+ .stage2_first_buffer = NULL,
333+};
334+
335+/* Save the first sector of Stage2 in STAGE2_SECT. */
336+/* Formerly disk_read_savesect_func with local scope inside install_func */
337+static void
338+install_savesect_helper(int sector, int offset, int length)
339+{
340+ if (debug)
341+ printf ("[%d]", sector);
342+
343+ /* ReiserFS has files which sometimes contain data not aligned
344+ on sector boundaries. Returning an error is better than
345+ silently failing. */
346+ if (offset != 0 || length != SECTOR_SIZE)
347+ errnum = ERR_UNALIGNED;
348+
349+ install_func_context.saved_sector = sector;
350+}
351+
352+/* Write SECTOR to INSTALLLIST, and update INSTALLADDR and INSTALLSECT. */
353+/* Formerly disk_read_blocklist_func with local scope inside install_func */
354+static void
355+install_blocklist_helper (int sector, int offset, int length)
356+{
357+ int *installaddr = &install_func_context.installaddr;
358+ int *installlist = &install_func_context.installlist;
359+ char **stage2_first_buffer = &install_func_context.stage2_first_buffer;
360+ /* Was the last sector full? */
361+ static int last_length = SECTOR_SIZE;
362+
363+ if (debug)
364+ printf("[%d]", sector);
365+
366+ if (offset != 0 || last_length != SECTOR_SIZE)
367+ {
368+ /* We found a non-sector-aligned data block. */
369+ errnum = ERR_UNALIGNED;
370+ return;
371+ }
372+
373+ last_length = length;
374+
375+ if (*((unsigned long *) (*installlist - 4))
376+ + *((unsigned short *) *installlist) != sector
377+ || *installlist == (int) *stage2_first_buffer + SECTOR_SIZE + 4)
378+ {
379+ *installlist -= 8;
380+
381+ if (*((unsigned long *) (*installlist - 8)))
382+ errnum = ERR_WONT_FIT;
383+ else
384+ {
385+ *((unsigned short *) (*installlist + 2)) = (*installaddr >> 4);
386+ *((unsigned long *) (*installlist - 4)) = sector;
387+ }
388+ }
389+
390+ *((unsigned short *) *installlist) += 1;
391+ *installaddr += 512;
392+}
393+
394 static int
395 install_func (char *arg, int flags)
396 {
397@@ -1747,8 +1852,12 @@
398 char *stage1_buffer = (char *) RAW_ADDR (0x100000);
399 char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
400 char *old_sect = stage2_buffer + SECTOR_SIZE;
401- char *stage2_first_buffer = old_sect + SECTOR_SIZE;
402- char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
403+ /* stage2_first_buffer used to be defined as:
404+ * char *stage2_first_buffer = old_sect + SECTOR_SIZE; */
405+ char **stage2_first_buffer = &install_func_context.stage2_first_buffer;
406+ /* and stage2_second_buffer was:
407+ * char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; */
408+ char *stage2_second_buffer = old_sect + SECTOR_SIZE + SECTOR_SIZE;
409 /* XXX: Probably SECTOR_SIZE is reasonable. */
410 char *config_filename = stage2_second_buffer + SECTOR_SIZE;
411 char *dummy = config_filename + SECTOR_SIZE;
412@@ -1757,10 +1866,11 @@
413 int src_drive, src_partition, src_part_start;
414 int i;
415 struct geometry dest_geom, src_geom;
416- int saved_sector;
417+ int *saved_sector = &install_func_context.saved_sector;
418 int stage2_first_sector, stage2_second_sector;
419 char *ptr;
420- int installaddr, installlist;
421+ int *installaddr = &install_func_context.installaddr;
422+ int *installlist = &install_func_context.installlist;
423 /* Point to the location of the name of a configuration file in Stage 2. */
424 char *config_file_location;
425 /* If FILE is a Stage 1.5? */
426@@ -1769,67 +1879,13 @@
427 int is_open = 0;
428 /* If LBA is forced? */
429 int is_force_lba = 0;
430- /* Was the last sector full? */
431- int last_length = SECTOR_SIZE;
432-
433+
434+ *stage2_first_buffer = old_sect + SECTOR_SIZE;
435 #ifdef GRUB_UTIL
436 /* If the Stage 2 is in a partition mounted by an OS, this will store
437 the filename under the OS. */
438 char *stage2_os_file = 0;
439 #endif /* GRUB_UTIL */
440-
441- auto void disk_read_savesect_func (int sector, int offset, int length);
442- auto void disk_read_blocklist_func (int sector, int offset, int length);
443-
444- /* Save the first sector of Stage2 in STAGE2_SECT. */
445- auto void disk_read_savesect_func (int sector, int offset, int length)
446- {
447- if (debug)
448- printf ("[%d]", sector);
449-
450- /* ReiserFS has files which sometimes contain data not aligned
451- on sector boundaries. Returning an error is better than
452- silently failing. */
453- if (offset != 0 || length != SECTOR_SIZE)
454- errnum = ERR_UNALIGNED;
455-
456- saved_sector = sector;
457- }
458-
459- /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
460- INSTALLSECT. */
461- auto void disk_read_blocklist_func (int sector, int offset, int length)
462- {
463- if (debug)
464- printf("[%d]", sector);
465-
466- if (offset != 0 || last_length != SECTOR_SIZE)
467- {
468- /* We found a non-sector-aligned data block. */
469- errnum = ERR_UNALIGNED;
470- return;
471- }
472-
473- last_length = length;
474-
475- if (*((unsigned long *) (installlist - 4))
476- + *((unsigned short *) installlist) != sector
477- || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
478- {
479- installlist -= 8;
480-
481- if (*((unsigned long *) (installlist - 8)))
482- errnum = ERR_WONT_FIT;
483- else
484- {
485- *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
486- *((unsigned long *) (installlist - 4)) = sector;
487- }
488- }
489-
490- *((unsigned short *) installlist) += 1;
491- installaddr += 512;
492- }
493
494 /* First, check the GNU-style long option. */
495 while (1)
496@@ -1862,10 +1918,10 @@
497 addr = skip_to (0, file);
498
499 /* Get the installation address. */
500- if (! safe_parse_maxint (&addr, &installaddr))
501+ if (! safe_parse_maxint (&addr, installaddr))
502 {
503 /* ADDR is not specified. */
504- installaddr = 0;
505+ *installaddr = 0;
506 ptr = addr;
507 errnum = 0;
508 }
509@@ -1961,17 +2017,17 @@
510 = 0x9090;
511
512 /* Read the first sector of Stage 2. */
513- disk_read_hook = disk_read_savesect_func;
514- if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
515+ disk_read_hook = install_savesect_helper;
516+ if (grub_read (*stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
517 goto fail;
518
519- stage2_first_sector = saved_sector;
520+ stage2_first_sector = *saved_sector;
521
522 /* Read the second sector of Stage 2. */
523 if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
524 goto fail;
525
526- stage2_second_sector = saved_sector;
527+ stage2_second_sector = *saved_sector;
528
529 /* Check for the version of Stage 2. */
530 if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
531@@ -1987,27 +2043,27 @@
532
533 /* If INSTALLADDR is not specified explicitly in the command-line,
534 determine it by the Stage 2 id. */
535- if (! installaddr)
536+ if (! *installaddr)
537 {
538 if (! is_stage1_5)
539 /* Stage 2. */
540- installaddr = 0x8000;
541+ *installaddr = 0x8000;
542 else
543 /* Stage 1.5. */
544- installaddr = 0x2000;
545+ *installaddr = 0x2000;
546 }
547
548 *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
549 = stage2_first_sector;
550 *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
551- = installaddr;
552+ = *installaddr;
553 *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
554- = installaddr >> 4;
555+ = *installaddr >> 4;
556
557- i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
558+ i = (int) *stage2_first_buffer + SECTOR_SIZE - 4;
559 while (*((unsigned long *) i))
560 {
561- if (i < (int) stage2_first_buffer
562+ if (i < (int) *stage2_first_buffer
563 || (*((int *) (i - 4)) & 0x80000000)
564 || *((unsigned short *) i) >= 0xA00
565 || *((short *) (i + 2)) == 0)
566@@ -2021,13 +2077,13 @@
567 i -= 8;
568 }
569
570- installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
571- installaddr += SECTOR_SIZE;
572+ *installlist = (int) *stage2_first_buffer + SECTOR_SIZE + 4;
573+ *installaddr += SECTOR_SIZE;
574
575 /* Read the whole of Stage2 except for the first sector. */
576 grub_seek (SECTOR_SIZE);
577
578- disk_read_hook = disk_read_blocklist_func;
579+ disk_read_hook = install_blocklist_helper;
580 if (! grub_read (dummy, -1))
581 goto fail;
582
583@@ -2110,7 +2166,7 @@
584 /* Skip the first sector. */
585 grub_seek (SECTOR_SIZE);
586
587- disk_read_hook = disk_read_savesect_func;
588+ disk_read_hook = install_savesect_helper;
589 if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
590 goto fail;
591
592@@ -2180,7 +2236,7 @@
593 else
594 #endif /* GRUB_UTIL */
595 {
596- if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
597+ if (! devwrite (*saved_sector - part_start, 1, stage2_buffer))
598 goto fail;
599 }
600 }
601@@ -2202,7 +2258,7 @@
602 goto fail;
603 }
604
605- if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
606+ if (fwrite (*stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
607 {
608 fclose (fp);
609 errnum = ERR_WRITE;
610@@ -2229,7 +2285,7 @@
611 goto fail;
612
613 if (! devwrite (stage2_first_sector - src_part_start, 1,
614- stage2_first_buffer))
615+ *stage2_first_buffer))
616 goto fail;
617
618 if (! devwrite (stage2_second_sector - src_part_start, 1,
619diff -Naur grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h
620--- grub-0.97.orig/stage2/shared.h 2004-06-19 09:40:09.000000000 -0700
621+++ grub-0.97/stage2/shared.h 2009-07-05 23:32:43.000000000 -0700
622@@ -36,8 +36,8 @@
623
624 /* Maybe redirect memory requests through grub_scratch_mem. */
625 #ifdef GRUB_UTIL
626-extern char *grub_scratch_mem;
627-# define RAW_ADDR(x) ((x) + (int) grub_scratch_mem)
628+extern void *grub_scratch_mem;
629+# define RAW_ADDR(x) ((x) + (unsigned long) grub_scratch_mem)
630 # define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4)
631 #else
632 # define RAW_ADDR(x) (x)
Note: See TracBrowser for help on using the repository browser.