Mercurial > hg > index.cgi
view lwlink/script.c @ 342:12e2453f8417
Fix potential memory access after free in lw_expr_simplify_go()
Thanks to Erik Gavriluk (erik@bombfactory.com) for spotting a missing "else"
when attempting to resolve a "special" reference. This could have led to
access to memory that had already been freed if a "special" resolved to an
expression that also referenced the same special (a circular reference).
Whether that can actually happen is questionable but the check must have
been added for a reason so it follows that it should be done correctly.
This also brings the code in line with similar code resolving symbol
references which makes a similar check.
author | William Astle <lost@l-w.ca> |
---|---|
date | Sat, 14 Mar 2015 14:06:13 -0600 |
parents | fcd103148aa6 |
children | 55c1f9a321e9 |
line wrap: on
line source
/* script.c Copyright © 2009 William Astle This file is part of LWLINK. LWLINK is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Read and parse linker scripts */ #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <lw_alloc.h> #include <lw_string.h> #include "lwlink.h" // the built-in OS9 script // the 000D bit is to handle the module header! static char *os9_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "section code load 000D\n" "section .text\n" "section data\n" "section .data\n" "section bss,bss load 0000\n" "section .bss,bss\n" "stacksize 32\n" "entry __start\n" ; // the built-in DECB target linker script static char *decb_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "section init load 2000\n" "section code\n" "section *,!bss\n" "section *,bss\n" "entry 2000\n" ; // the built-in RAW target linker script static char *raw_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "section init load 0000\n" "section code\n" "section *,!bss\n" "section *,bss\n" ; static char *lwex0_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "sectopt .ctors padafter 00,00\n" "sectopt .dtors padafter 00,00\n" "section init load 0100\n" "section .text\n" "section .data\n" "section .ctors_start\n" "section .ctors\n" "section .ctors_end\n" "section .dtors_start\n" "section .dtors\n" "section .dtors_end\n" "section *,!bss\n" "section *,bss\n" "entry __start\n" "stacksize 0100\n" // default 256 byte stack ; // the "simple" script static char *simple_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "section *,!bss\n" "section *,bss\n" ; linkscript_t linkscript = { 0, NULL, -1 }; void setup_script() { char *script, *oscript; long size; // read the file if needed if (scriptfile) { FILE *f; long bread; f = fopen(scriptfile, "rb"); if (!f) { fprintf(stderr, "Can't open file %s:", scriptfile); perror(""); exit(1); } fseek(f, 0, SEEK_END); size = ftell(f); rewind(f); script = lw_alloc(size + 2); bread = fread(script, 1, size, f); if (bread < size) { fprintf(stderr, "Short read on file %s (%ld/%ld):", scriptfile, bread, size); perror(""); exit(1); } fclose(f); script[size] = '\n'; script[size + 1] = '\0'; } else { // fetch defaults based on output mode switch (outformat) { case OUTPUT_RAW: script = raw_script; break; case OUTPUT_DECB: script = decb_script; break; case OUTPUT_LWEX0: script = lwex0_script; break; case OUTPUT_OS9: script = os9_script; break; default: script = simple_script; break; } size = strlen(script); if (nscriptls) { char *rscript; int i; // prepend the "extra" script lines for (i = 0; i < nscriptls; i++) size += strlen(scriptls[i]) + 1; rscript = lw_alloc(size + 1); oscript = rscript; for (i = 0; i < nscriptls; i++) { oscript += sprintf(oscript, "%s\n", scriptls[i]); } strcpy(oscript, script); script = rscript; } } if (outformat == OUTPUT_LWEX0) linkscript.stacksize = 0x100; if (outformat == OUTPUT_OS9) { linkscript.modtype = 0x01; linkscript.modlang = 0x01; linkscript.modattr = 0x08; linkscript.modrev = 0x00; linkscript.edition = -1; linkscript.name = NULL; } oscript = script; // now parse the script file while (*script) { char *ptr, *ptr2, *line; for (ptr = script; *ptr && *ptr != '\n' && *ptr != '\r'; ptr++) /* do nothing */ ; line = lw_alloc(ptr - script + 1); memcpy(line, script, ptr - script); line[ptr - script] = '\0'; // skip line terms for (script = ptr + 1; *script == '\n' || *script == '\r'; script++) /* do nothing */ ; // ignore leading whitespace for (ptr = line; *ptr && isspace(*ptr); ptr++) /* do nothing */ ; // ignore blank lines and comments if (!*ptr || *ptr == '#' || *ptr == ';') continue; for (ptr = line; *ptr && !isspace(*ptr); ptr++) /* do nothing */ ; // now ptr points to the char past the first word // NUL it out if (*ptr) *ptr++ = '\0'; // skip spaces after the first word for ( ; *ptr && isspace(*ptr); ptr++) /* do nothing */ ; if (!strcmp(line, "sectopt")) { char *sn; char *ptr3; sectopt_t *so; for (ptr2 = ptr; *ptr && !isspace(*ptr2); ptr2++) /* do nothing */ ; if (*ptr2) *ptr2++ = '\0'; while (*ptr2 && isspace(*ptr2)) ptr2++; // section name is at ptr // ptr2 is the option type sn = ptr; // now ptr2 points to the section option name for (ptr3 = ptr2; *ptr3 && !isspace(*ptr3); ptr3++) /* do nothing */ ; if (*ptr3) *ptr3++ = 0; while (*ptr3 && isspace(*ptr3)) ptr3++; // now ptr3 points to option value for (so = section_opts; so; so = so -> next) { if (!strcmp(so -> name, sn)) break; } if (!so) { so = lw_alloc(sizeof(sectopt_t)); so -> name = lw_strdup(sn); so -> aftersize = 0; so -> afterbytes = NULL; so -> next = section_opts; section_opts = so; } if (!strcmp(ptr2, "padafter")) { if (so -> afterbytes) lw_free(so -> afterbytes); so -> aftersize = 0; for (;;) { int v; char *ptr4; while (*ptr3 && isspace(*ptr3)) ptr3++; if (!ptr3) break; v = strtoul(ptr3, &ptr4, 16); if (ptr3 == ptr4) break; so -> afterbytes = lw_realloc(so -> afterbytes, so -> aftersize + 1); so -> afterbytes[so -> aftersize] = v; so -> aftersize++; ptr3 = ptr4; while (*ptr3 && isspace(*ptr3)) ptr3++; if (*ptr3 != ',') break; ptr3++; } } else { fprintf(stderr, "%s: bad script line: %s %s\n", scriptfile, line, ptr2); exit(1); } } else if (!strcmp(line, "define")) { // parse out the definition type for (ptr2 = ptr; *ptr2 && !isspace(*ptr2); ptr2++) /* do nothing */ ; if (*ptr2) *ptr2++ = '\0'; while (*ptr2 && isspace(*ptr2)) ptr2++; // now ptr points to the define type if (!strcmp(ptr, "basesympat")) { /* section base symbol pattern */ lw_free(linkscript.basesympat); linkscript.basesympat = lw_strdup(ptr2); } else if (!strcmp(ptr, "lensympat")) { /* section length symbol pattern */ lw_free(linkscript.lensympat); linkscript.lensympat = lw_strdup(ptr2); } else { } } else if (!strcmp(line, "pad")) { // padding // parse the hex number and stow it linkscript.padsize = strtol(ptr, NULL, 16); if (linkscript.padsize < 0) linkscript.padsize = 0; } else if (!strcmp(line, "stacksize")) { // stack size for targets that support it // parse the hex number and stow it linkscript.padsize = strtol(ptr, NULL, 16); if (linkscript.stacksize < 0) linkscript.stacksize = 0x100; } else if (!strcmp(line, "entry")) { int eaddr; eaddr = strtol(ptr, &ptr2, 16); if (*ptr2) { linkscript.execaddr = -1; linkscript.execsym = lw_strdup(ptr); } else { linkscript.execaddr = eaddr; linkscript.execsym = NULL; } } else if (!strcmp(line, "section")) { int growsdown = 0; // section // parse out the section name and flags for (ptr2 = ptr; *ptr2 && !isspace(*ptr2); ptr2++) /* do nothing */ ; if (*ptr2) *ptr2++ = '\0'; while (*ptr2 && isspace(*ptr2)) ptr2++; // ptr now points to the section name and flags and ptr2 // to the first non-space character following // then look for "load <addr>" clause if (*ptr2) { if (!strncmp(ptr2, "load", 4)) { ptr2 += 4; while (*ptr2 && isspace(*ptr2)) ptr2++; } else if (!strncmp(ptr2, "high", 4)) { ptr2 += 4; while (*ptr2 && isspace(*ptr2)) ptr2++; growsdown = 1; } else { fprintf(stderr, "%s: bad script\n", scriptfile); exit(1); } } else { if (linkscript.nlines > 0) growsdown = linkscript.lines[linkscript.nlines - 1].growsdown; } // now ptr2 points to the load address if there is one // or NUL if not linkscript.lines = lw_realloc(linkscript.lines, sizeof(struct scriptline_s) * (linkscript.nlines + 1)); linkscript.lines[linkscript.nlines].noflags = 0; linkscript.lines[linkscript.nlines].yesflags = 0; linkscript.lines[linkscript.nlines].growsdown = growsdown; if (*ptr2) linkscript.lines[linkscript.nlines].loadat = strtol(ptr2, NULL, 16); else linkscript.lines[linkscript.nlines].loadat = -1; for (ptr2 = ptr; *ptr2 && *ptr2 != ','; ptr2++) /* do nothing */ ; if (*ptr2) { *ptr2++ = '\0'; if (!strcmp(ptr2, "!bss")) { linkscript.lines[linkscript.nlines].noflags = SECTION_BSS; } else if (!strcmp(ptr2, "bss")) { linkscript.lines[linkscript.nlines].yesflags = SECTION_BSS; } else { fprintf(stderr, "%s: bad script\n", scriptfile); exit(1); } } if (ptr[0] == '*' && ptr[1] == '\0') linkscript.lines[linkscript.nlines].sectname = NULL; else linkscript.lines[linkscript.nlines].sectname = lw_strdup(ptr); linkscript.nlines++; } else { fprintf(stderr, "%s: bad script line: %s\n", scriptfile, line); exit(1); } lw_free(line); } if (scriptfile || nscriptls) lw_free(oscript); if (entrysym) { int eaddr; char *ptr2; lw_free(linkscript.execsym); eaddr = strtol(entrysym, &ptr2, 0); if (*ptr2) { linkscript.execaddr = -1; linkscript.execsym = lw_strdup(entrysym); } else { linkscript.execaddr = eaddr; linkscript.execsym = NULL; } } }