Author: Sven Joachim <svenjoac@gmx.de>
Description: Fixes for six CVEs in the tic library
 Fixes for CVE-2017-13728, CVE-2017-13729, CVE-2017-13730,
 CVE-2017-13731, CVE-2017-13732 and CVE-2017-13734 cherry-picked from
 upstream patchlevel 20170826.
Bug-Debian: https://bugs.debian.org/873723
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=1484274
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=1484276
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=1484284
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=1484285
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=1484287
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=1484291
Forwarded: not-needed
Last-Update: 2017-09-04

---
 ncurses/tinfo/alloc_entry.c |    2 
 ncurses/tinfo/comp_parse.c  |    8 +--
 ncurses/tinfo/comp_scan.c   |    4 +
 ncurses/tinfo/parse_entry.c |   89 +++++++++++++++++++++++++++++---------------
 ncurses/tinfo/strings.c     |    5 +-
 ncurses/tinfo/trim_sgr0.c   |    2 
 6 files changed, 71 insertions(+), 39 deletions(-)

--- a/ncurses/tinfo/alloc_entry.c
+++ b/ncurses/tinfo/alloc_entry.c
@@ -98,7 +98,7 @@ _nc_save_str(const char *const string)
     size_t old_next_free = next_free;
     size_t len;
 
-    if (string == 0)
+    if (!VALID_STRING(string))
 	return _nc_save_str("");
     len = strlen(string) + 1;
 
--- a/ncurses/tinfo/comp_parse.c
+++ b/ncurses/tinfo/comp_parse.c
@@ -522,9 +522,9 @@ static void
 fixup_acsc(TERMTYPE *tp, int literal)
 {
     if (!literal) {
-	if (acs_chars == 0
-	    && enter_alt_charset_mode != 0
-	    && exit_alt_charset_mode != 0)
+	if (acs_chars == ABSENT_STRING
+	    && PRESENT(enter_alt_charset_mode)
+	    && PRESENT(exit_alt_charset_mode))
 	    acs_chars = strdup(VT_ACSC);
     }
 }
@@ -580,9 +580,7 @@ sanity_check2(TERMTYPE *tp, bool literal
     PAIRED(enter_xon_mode, exit_xon_mode);
     PAIRED(enter_am_mode, exit_am_mode);
     ANDMISSING(label_off, label_on);
-#ifdef remove_clock
     PAIRED(display_clock, remove_clock);
-#endif
     ANDMISSING(set_color_pair, initialize_pair);
 }
 
--- a/ncurses/tinfo/comp_scan.c
+++ b/ncurses/tinfo/comp_scan.c
@@ -168,6 +168,8 @@ next_char(void)
 	if (result != 0) {
 	    FreeAndNull(result);
 	    FreeAndNull(pushname);
+	    bufptr = 0;
+	    bufstart = 0;
 	    allocated = 0;
 	}
 	/*
@@ -222,6 +224,8 @@ next_char(void)
 		}
 		if ((bufptr = bufstart) != 0) {
 		    used = strlen(bufptr);
+		    if (used == 0)
+			return (EOF);
 		    while (iswhite(*bufptr)) {
 			if (*bufptr == '\t') {
 			    _nc_curr_col = (_nc_curr_col | 7) + 1;
--- a/ncurses/tinfo/parse_entry.c
+++ b/ncurses/tinfo/parse_entry.c
@@ -180,6 +180,20 @@ _nc_extend_names(ENTRY * entryp, char *n
 }
 #endif /* NCURSES_XNAMES */
 
+static bool
+valid_entryname(const char *name)
+{
+    bool result = TRUE;
+    int ch;
+    while ((ch = UChar(*name++)) != '\0') {
+	if (ch <= ' ' || ch > '~' || ch == '/') {
+	    result = FALSE;
+	    break;
+	}
+    }
+    return result;
+}
+
 /*
  *	int
  *	_nc_parse_entry(entry, literal, silent)
@@ -211,6 +225,7 @@ _nc_parse_entry(struct entry *entryp, in
     int token_type;
     struct name_table_entry const *entry_ptr;
     char *ptr, *base;
+    const char *name;
     bool bad_tc_usage = FALSE;
 
     token_type = _nc_get_token(silent);
@@ -261,7 +276,12 @@ _nc_parse_entry(struct entry *entryp, in
      * results in the terminal type getting prematurely set to correspond
      * to that of the next entry.
      */
-    _nc_set_type(_nc_first_name(entryp->tterm.term_names));
+    name = _nc_first_name(entryp->tterm.term_names);
+    if (!valid_entryname(name)) {
+	_nc_warning("invalid entry name \"%s\"", name);
+	name = "invalid";
+    }
+    _nc_set_type(name);
 
     /* check for overly-long names and aliases */
     for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0;
@@ -283,13 +303,24 @@ _nc_parse_entry(struct entry *entryp, in
 	bool is_use = (strcmp(_nc_curr_token.tk_name, "use") == 0);
 	bool is_tc = !is_use && (strcmp(_nc_curr_token.tk_name, "tc") == 0);
 	if (is_use || is_tc) {
+	    if (!VALID_STRING(_nc_curr_token.tk_valstring)
+		|| _nc_curr_token.tk_valstring[0] == '\0') {
+		_nc_warning("missing name for use-clause");
+		continue;
+	    } else if (!valid_entryname(_nc_curr_token.tk_valstring)) {
+		_nc_warning("invalid name for use-clause \"%s\"",
+			    _nc_curr_token.tk_valstring);
+		continue;
+	    } else if (entryp->nuses >= MAX_USES) {
+		_nc_warning("too many use-clauses, ignored \"%s\"",
+			    _nc_curr_token.tk_valstring);
+		continue;
+	    }
 	    entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring);
 	    entryp->uses[entryp->nuses].line = _nc_curr_line;
-	    if (VALID_STRING(entryp->uses[entryp->nuses].name)) {
-		entryp->nuses++;
-		if (entryp->nuses > 1 && is_tc) {
-		    BAD_TC_USAGE
-		}
+	    entryp->nuses++;
+	    if (entryp->nuses > 1 && is_tc) {
+		BAD_TC_USAGE
 	    }
 	} else {
 	    /* normal token lookup */
@@ -625,13 +656,6 @@ static const char C_BS[] = "\b";
 static const char C_HT[] = "\t";
 
 /*
- * Note that WANTED and PRESENT are not simple inverses!  If a capability
- * has been explicitly cancelled, it's not considered WANTED.
- */
-#define WANTED(s)	((s) == ABSENT_STRING)
-#define PRESENT(s)	(((s) != ABSENT_STRING) && ((s) != CANCELLED_STRING))
-
-/*
  * This bit of legerdemain turns all the terminfo variable names into
  * references to locations in the arrays Booleans, Numbers, and Strings ---
  * precisely what's needed.
@@ -656,10 +680,10 @@ postprocess_termcap(TERMTYPE *tp, bool h
 
     /* if there was a tc entry, assume we picked up defaults via that */
     if (!has_base) {
-	if (WANTED(init_3string) && termcap_init2)
+	if (WANTED(init_3string) && PRESENT(termcap_init2))
 	    init_3string = _nc_save_str(termcap_init2);
 
-	if (WANTED(reset_2string) && termcap_reset)
+	if (WANTED(reset_2string) && PRESENT(termcap_reset))
 	    reset_2string = _nc_save_str(termcap_reset);
 
 	if (WANTED(carriage_return)) {
@@ -774,7 +798,7 @@ postprocess_termcap(TERMTYPE *tp, bool h
 	if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC)
 	    _nc_warning("hardware tabs with a width other than 8: %d", init_tabs);
 	else {
-	    if (tab && _nc_capcmp(tab, C_HT))
+	    if (PRESENT(tab) && _nc_capcmp(tab, C_HT))
 		_nc_warning("hardware tabs with a non-^I tab string %s",
 			    _nc_visbuf(tab));
 	    else {
@@ -851,17 +875,22 @@ postprocess_termcap(TERMTYPE *tp, bool h
 	     * The magic moment -- copy the mapped key string over,
 	     * stripping out padding.
 	     */
-	    for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) {
-		if (bp[0] == '$' && bp[1] == '<') {
-		    while (*bp && *bp != '>') {
-			++bp;
-		    }
-		} else
-		    *dp++ = *bp;
-	    }
-	    *dp = '\0';
+	    bp = tp->Strings[from_ptr->nte_index];
+	    if (VALID_STRING(bp)) {
+		for (dp = buf2; *bp; bp++) {
+		    if (bp[0] == '$' && bp[1] == '<') {
+			while (*bp && *bp != '>') {
+			    ++bp;
+			}
+		    } else
+			*dp++ = *bp;
+		}
+		*dp = '\0';
 
-	    tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
+		tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
+	    } else {
+		tp->Strings[to_ptr->nte_index] = bp;
+	    }
 	}
 
 	/*
@@ -870,7 +899,7 @@ postprocess_termcap(TERMTYPE *tp, bool h
 	 * got mapped to kich1 and im to kIC to avoid a collision.
 	 * If the description has im but not ic, hack kIC back to kich1.
 	 */
-	if (foundim && WANTED(key_ic) && key_sic) {
+	if (foundim && WANTED(key_ic) && PRESENT(key_sic)) {
 	    key_ic = key_sic;
 	    key_sic = ABSENT_STRING;
 	}
@@ -922,9 +951,9 @@ postprocess_termcap(TERMTYPE *tp, bool h
 	    acs_chars = _nc_save_str(buf2);
 	    _nc_warning("acsc string synthesized from XENIX capabilities");
 	}
-    } else if (acs_chars == 0
-	       && enter_alt_charset_mode != 0
-	       && exit_alt_charset_mode != 0) {
+    } else if (acs_chars == ABSENT_STRING
+	       && PRESENT(enter_alt_charset_mode)
+	       && PRESENT(exit_alt_charset_mode)) {
 	acs_chars = _nc_save_str(VT_ACSC);
     }
 }
--- a/ncurses/tinfo/strings.c
+++ b/ncurses/tinfo/strings.c
@@ -35,6 +35,7 @@
 **/
 
 #include <curses.priv.h>
+#include <tic.h>
 
 MODULE_ID("$Id: strings.c,v 1.8 2012/02/22 22:34:31 tom Exp $")
 
@@ -105,7 +106,7 @@ _nc_str_copy(string_desc * dst, string_d
 NCURSES_EXPORT(bool)
 _nc_safe_strcat(string_desc * dst, const char *src)
 {
-    if (src != 0) {
+    if (PRESENT(src)) {
 	size_t len = strlen(src);
 
 	if (len < dst->s_size) {
@@ -126,7 +127,7 @@ _nc_safe_strcat(string_desc * dst, const
 NCURSES_EXPORT(bool)
 _nc_safe_strcpy(string_desc * dst, const char *src)
 {
-    if (src != 0) {
+    if (PRESENT(src)) {
 	size_t len = strlen(src);
 
 	if (len < dst->s_size) {
--- a/ncurses/tinfo/trim_sgr0.c
+++ b/ncurses/tinfo/trim_sgr0.c
@@ -263,7 +263,7 @@ _nc_trim_sgr0(TERMTYPE *tp)
 	    /*
 	     * If rmacs is a substring of sgr(0), remove that chunk.
 	     */
-	    if (exit_alt_charset_mode != 0) {
+	    if (PRESENT(exit_alt_charset_mode)) {
 		TR(TRACE_DATABASE, ("scan for rmacs %s", _nc_visbuf(exit_alt_charset_mode)));
 		j = strlen(off);
 		k = strlen(exit_alt_charset_mode);
