Skip to content

Commit

Permalink
Fix some bugs in processing of line directives
Browse files Browse the repository at this point in the history
In order to work with preprocessed dts files more easily, dts will parse
line number information in the form emitted by cpp.

Anton Blanchard (using a fuzzer) reported that including a line number
directive with a nul character (a literal nul in the input file, not a \0
sequence) would cause dtc to SEGV.  I spotted several more problems on
examining the code:
    * It modified yytext in place which seems to work, but is ugly and I'm
      not sure if it's safe on all lex/flex versions
    * The regexp used in the lexer to recognize line number information
      accepts strings with escape characters, but it won't process these
      escapes.
        - GNU cpp at least, will generate \ escapes in line number
          information, at least with files containing " or \ in the name

This patch reworks the handling of line number information to address
these problems.  \ escapes should now be handled directly.  nuls in file
names (either with a literal nul in the input file, or with a \0 escape
sequence) are still not permitted, but will now result in a lexical error
rather than a SEGV.

Reported-by: Anton Blanchard <[email protected]>
Signed-off-by: David Gibson <[email protected]>
  • Loading branch information
dgibson committed Jan 4, 2016
1 parent d728ad5 commit b433450
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 13 deletions.
34 changes: 21 additions & 13 deletions dtc-lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,32 @@ static void lexical_error(const char *fmt, ...);
}

<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
char *line, *tmp, *fn;
char *line, *fnstart, *fnend;
struct data fn;
/* skip text before line # */
line = yytext;
while (!isdigit((unsigned char)*line))
line++;
/* skip digits in line # */
tmp = line;
while (!isspace((unsigned char)*tmp))
tmp++;
/* "NULL"-terminate line # */
*tmp = '\0';
/* start of filename */
fn = strchr(tmp + 1, '"') + 1;
/* strip trailing " from filename */
tmp = strchr(fn, '"');
*tmp = 0;

/* regexp ensures that first and list "
* in the whole yytext are those at
* beginning and end of the filename string */
fnstart = memchr(yytext, '"', yyleng);
for (fnend = yytext + yyleng - 1;
*fnend != '"'; fnend--)
;
assert(fnstart && fnend && (fnend > fnstart));

fn = data_copy_escape_string(fnstart + 1,
fnend - fnstart - 1);

/* Don't allow nuls in filenames */
if (memchr(fn.val, '\0', fn.len - 1))
lexical_error("nul in line number directive");

/* -1 since #line is the number of the next line */
srcpos_set_line(xstrdup(fn), atoi(line) - 1);
srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
data_free(fn);
}

<*><<EOF>> {
Expand Down
5 changes: 5 additions & 0 deletions tests/line_directives.dts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@
# 10 "qux.dts"
0x12345678
>;
/*
* Check processing of escapes in filenames
*/
# 100 "\".dts"
# 200 "\\.dts"
};
Binary file added tests/nul-in-line-info1.dts
Binary file not shown.
1 change: 1 addition & 0 deletions tests/nul-in-line-info2.dts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# 0 "\0"
2 changes: 2 additions & 0 deletions tests/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ libfdt_tests () {
run_wrap_error_test $DTC division-by-zero.dts
run_wrap_error_test $DTC bad-octal-literal.dts
run_dtc_test -I dts -O dtb nul-in-escape.dts
run_wrap_error_test $DTC nul-in-line-info1.dts
run_wrap_error_test $DTC nul-in-line-info2.dts
}

dtc_tests () {
Expand Down

0 comments on commit b433450

Please sign in to comment.