look_for_link() used to return 0 both when it found the closing </MAP> tag, and when it hit the end of the file. In the first case, it also added *menu to the memory_list; in the second case, it did not. The caller get_image_map() supposedly distinguished between these cases by checking whether pos >= eof, and freed *menu separately if so.
However, if the </MAP> was at the very end of the HTML file, so that not even a newline followed it, then look_for_link() left pos == eof even though it had found the </MAP> and added *menu to the memory_list. This made get_image_map() misinterpret the result and mem_free(*menu) even though *menu had already been freed as part of the memory_list; thus the crash. To fix this, make look_for_link() return -1 instead of 0 if it hits EOF without finding the </MAP>. Then make get_image_map() check the return value instead of comparing pos to eof. Alternatively, look_for_link() could have been changed to decrement pos between finding the </MAP> and returning 0. Then, the pos >= eof comparison in get_image_map() would have been false. That scheme would however have been a bit more difficult to understand and maintain, I think. Reported by Paul B. Mahol. --- NEWS | 1 + src/document/html/parser.c | 17 ++++++++++++----- test/imgmap2.html | 5 +++++ 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 test/imgmap2.html diff --git a/NEWS b/NEWS index ab36a8e..ebd7c80 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ ELinks 0.12pre2.GIT now: To be released as 0.12pre3, 0.12rc1, or even 0.12.0. This branch also includes the changes listed under ``ELinks 0.11.5.GIT'' below. +* critical: Fix double-free crash if EOF immediately follows </MAP>. * Preserve newlines in hidden input fields, and submit them as CRLF. Previously, they could turn into spaces or disappear entirely. * Perl scripts can use modules that dynamically load C libraries, like diff --git a/src/document/html/parser.c b/src/document/html/parser.c index 4d8c111..d9e911a 100644 --- a/src/document/html/parser.c +++ b/src/document/html/parser.c @@ -615,6 +615,9 @@ look_for_tag(unsigned char **pos, unsigned char *eof, return 0; } +/** @return -1 if EOF is hit without the closing tag; 0 if the closing + * tag is found (in which case this also adds *...@a menu to *...@a ml); or + * 1 if this should be called again. */ static int look_for_link(unsigned char **pos, unsigned char *eof, struct menu_item **menu, struct memory_list **ml, struct uri *href_base, @@ -632,7 +635,7 @@ look_for_link(unsigned char **pos, unsigned char *eof, struct menu_item **menu, (*pos)++; } - if (*pos >= eof) return 0; + if (*pos >= eof) return -1; if (*pos + 2 <= eof && ((*pos)[1] == '!' || (*pos)[1] == '?')) { *pos = skip_comment(*pos, eof); @@ -647,7 +650,7 @@ look_for_link(unsigned char **pos, unsigned char *eof, struct menu_item **menu, if (!c_strlcasecmp(name, namelen, "A", 1)) { while (look_for_tag(pos, eof, name, namelen, &label)); - if (*pos >= eof) return 0; + if (*pos >= eof) return -1; } else if (!c_strlcasecmp(name, namelen, "AREA", 4)) { /* FIXME (bug 784): options->cp is the terminal charset; @@ -765,6 +768,7 @@ get_image_map(unsigned char *head, unsigned char *pos, unsigned char *eof, { struct conv_table *ct; struct string hd; + int look_result; if (!init_string(&hd)) return -1; @@ -785,10 +789,13 @@ get_image_map(unsigned char *head, unsigned char *pos, unsigned char *eof, *ml = NULL; - while (look_for_link(&pos, eof, menu, ml, uri, target_base, ct, options)) - ; + do { + /* This call can modify both *ml and *menu. */ + look_result = look_for_link(&pos, eof, menu, ml, uri, + target_base, ct, options); + } while (look_result > 0); - if (pos >= eof) { + if (look_result < 0) { freeml(*ml); mem_free(*menu); return -1; diff --git a/test/imgmap2.html b/test/imgmap2.html new file mode 100644 index 0000000..e96e184 --- /dev/null +++ b/test/imgmap2.html @@ -0,0 +1,5 @@ +<TITLE>Double-free crash in USEMAP</TITLE> +<P><IMG src="/dev/null" usemap="#crasher"></P> +<MAP name="crasher"> +<AREA shape="rect" coords="42,42,69,69" href="http://elinks.cz/" alt="see this?"> +<!-- no newline at the end of this line --></MAP> \ No newline at end of file -- 1.6.0.6.4.g22c5
pgpW7qNKcoq7t.pgp
Description: PGP signature
_______________________________________________ elinks-dev mailing list elinks-dev@linuxfromscratch.org http://linuxfromscratch.org/mailman/listinfo/elinks-dev