Fix CVE-2017-10684 and CVE-2017-10685: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-10684 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-10685 Bug reports included proof of concept reproducer inputs: https://bugzilla.redhat.com/show_bug.cgi?id=1464684 https://bugzilla.redhat.com/show_bug.cgi?id=1464685 https://bugzilla.redhat.com/show_bug.cgi?id=1464686 https://bugzilla.redhat.com/show_bug.cgi?id=1464687 https://bugzilla.redhat.com/show_bug.cgi?id=1464688 https://bugzilla.redhat.com/show_bug.cgi?id=1464691 https://bugzilla.redhat.com/show_bug.cgi?id=1464692 Patches copied from ncurses patch release 20170701: ftp://invisible-island.net/ncurses/6.0/ncurses-6.0-20170701.patch.gz Excerpt from patch release announcement: + add/improve checks in tic's parser to address invalid input (Redhat #1464684, #1464685, #1464686, #1464691). + alloc_entry.c, add a check for a null-pointer. + parse_entry.c, add several checks for valid pointers as well as one check to ensure that a single character on a line is not treated as the 2-character termcap short-name. + the fixes for Redhat #1464685 obscured a problem subsequently reported in Redhat #1464687; the given test-case was no longer reproducible. Testing without the fixes for the earlier reports showed a problem with buffer overflow in dump_entry.c, which is addressed by reducing the use of a fixed-size buffer. https://lists.gnu.org/archive/html/bug-ncurses/2017-07/msg00001.html --- ncurses-6.0-20170624+/ncurses/tinfo/alloc_entry.c 2017-04-09 23:33:51.000000000 +0000 +++ ncurses-6.0-20170701/ncurses/tinfo/alloc_entry.c 2017-06-27 23:48:55.000000000 +0000 @@ -96,7 +96,11 @@ { char *result = 0; size_t old_next_free = next_free; - size_t len = strlen(string) + 1; + size_t len; + + if (string == 0) + return _nc_save_str(""); + len = strlen(string) + 1; if (len == 1 && next_free != 0) { /* --- ncurses-6.0-20170624+/ncurses/tinfo/parse_entry.c 2017-06-24 22:59:46.000000000 +0000 +++ ncurses-6.0-20170701/ncurses/tinfo/parse_entry.c 2017-06-28 00:53:12.000000000 +0000 @@ -236,13 +236,14 @@ * implemented it. Note that the resulting terminal type was never the * 2-character name, but was instead the first alias after that. */ +#define ok_TC2(s) (isgraph(UChar(s)) && (s) != '|') ptr = _nc_curr_token.tk_name; if (_nc_syntax == SYN_TERMCAP #if NCURSES_XNAMES && !_nc_user_definable #endif ) { - if (ptr[2] == '|') { + if (ok_TC2(ptr[0]) && ok_TC2(ptr[1]) && (ptr[2] == '|')) { ptr += 3; _nc_curr_token.tk_name[2] = '\0'; } @@ -284,9 +285,11 @@ if (is_use || is_tc) { entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring); entryp->uses[entryp->nuses].line = _nc_curr_line; - entryp->nuses++; - if (entryp->nuses > 1 && is_tc) { - BAD_TC_USAGE + if (VALID_STRING(entryp->uses[entryp->nuses].name)) { + entryp->nuses++; + if (entryp->nuses > 1 && is_tc) { + BAD_TC_USAGE + } } } else { /* normal token lookup */ @@ -588,7 +591,7 @@ static void append_acs(string_desc * dst, int code, char *src) { - if (src != 0 && strlen(src) == 1) { + if (VALID_STRING(src) && strlen(src) == 1) { append_acs0(dst, code, *src); } } @@ -849,15 +852,14 @@ } if (tp->Strings[to_ptr->nte_index]) { + const char *s = tp->Strings[from_ptr->nte_index]; + const char *t = tp->Strings[to_ptr->nte_index]; /* There's no point in warning about it if it's the same * string; that's just an inefficiency. */ - if (strcmp( - tp->Strings[from_ptr->nte_index], - tp->Strings[to_ptr->nte_index]) != 0) + if (VALID_STRING(s) && VALID_STRING(t) && strcmp(s, t) != 0) _nc_warning("%s (%s) already has an explicit value %s, ignoring ko", - ap->to, ap->from, - _nc_visbuf(tp->Strings[to_ptr->nte_index])); + ap->to, ap->from, t); continue; } --- ncurses-6.0-20170624+/progs/dump_entry.c 2017-06-23 22:47:43.000000000 +0000 +++ ncurses-6.0-20170701/progs/dump_entry.c 2017-07-01 11:27:29.000000000 +0000 @@ -841,9 +841,10 @@ PredIdx num_strings = 0; bool outcount = 0; -#define WRAP_CONCAT \ - wrap_concat(buffer); \ - outcount = TRUE +#define WRAP_CONCAT1(s) wrap_concat(s); outcount = TRUE +#define WRAP_CONCAT2(a,b) wrap_concat(a); WRAP_CONCAT1(b) +#define WRAP_CONCAT3(a,b,c) wrap_concat(a); WRAP_CONCAT2(b,c) +#define WRAP_CONCAT WRAP_CONCAT1(buffer) len = 12; /* terminfo file-header */ @@ -1007,9 +1008,9 @@ set_attributes = save_sgr; trimmed_sgr0 = _nc_trim_sgr0(tterm); - if (strcmp(capability, trimmed_sgr0)) + if (strcmp(capability, trimmed_sgr0)) { capability = trimmed_sgr0; - else { + } else { if (trimmed_sgr0 != exit_attribute_mode) free(trimmed_sgr0); } @@ -1046,13 +1047,21 @@ _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) "%s=!!! %s WILL NOT CONVERT !!!", name, srccap); + WRAP_CONCAT; } else if (suppress_untranslatable) { continue; } else { char *s = srccap, *d = buffer; - _nc_SPRINTF(d, _nc_SLIMIT(sizeof(buffer)) "..%s=", name); - d += strlen(d); + WRAP_CONCAT3("..", name, "="); while ((*d = *s++) != 0) { + if ((d - buffer - 1) >= (int) sizeof(buffer)) { + fprintf(stderr, + "%s: value for %s is too long\n", + _nc_progname, + name); + *d = '\0'; + break; + } if (*d == ':') { *d++ = '\\'; *d = ':'; @@ -1061,13 +1070,12 @@ } d++; } + WRAP_CONCAT; } } else { - _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) - "%s=%s", name, cv); + WRAP_CONCAT3(name, "=", cv); } len += (int) strlen(capability) + 1; - WRAP_CONCAT; } else { char *src = _nc_tic_expand(capability, outform == F_TERMINFO, numbers); @@ -1083,8 +1091,7 @@ strcpy_DYN(&tmpbuf, src); } len += (int) strlen(capability) + 1; - wrap_concat(tmpbuf.text); - outcount = TRUE; + WRAP_CONCAT1(tmpbuf.text); } } /* e.g., trimmed_sgr0 */ @@ -1526,7 +1533,8 @@ } if (len > critlen) { (void) fprintf(stderr, - "warning: %s entry is %d bytes long\n", + "%s: %s entry is %d bytes long\n", + _nc_progname, _nc_first_name(tterm->term_names), len); SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",