From 4bf72cb8f1d3aa5f33c31eb817a5f0338f4aaf6f Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Wed, 20 Sep 2017 05:02:00 +0000 Subject: [PATCH] Import upstream patch 20170826 20170826 + fixes for "iterm2" (report by Leonardo Brondani Schenkel) -TD + corrected a warning from tic about keys which are the same, to skip over missing/cancelled values. + add check in tic for unnecessary use of "2" to denote a shifted special key. + improve checks in trim_sgr0, comp_parse.c and parse_entry.c, for cancelled string capabilities. + add check in _nc_parse_entry() for invalid entry name, setting the name to "invalid" to avoid problems storing entries. + add/improve checks in tic's parser to address invalid input + add a check in comp_scan.c to handle the special case where a nontext file ending with a NUL rather than newline is given to tic as input (Redhat #1484274). + allow for cancelled capabilities in _nc_save_str (Redhat #1484276). + add validity checks for "use=" target in _nc_parse_entry (Redhat #1484284). + check for invalid strings in postprocess_termcap (Redhat #1484285) + reset secondary pointers on EOF in next_char() (Redhat #1484287). + guard _nc_safe_strcpy() and _nc_safe_strcat() against calls using cancelled strings (Redhat #1484291). + correct typo in curs_memleaks.3x (Sven Joachim). + improve test/configure checks for some curses variants not based on X/Open Curses. + add options for test/configure to disable checks for form, menu and panel libraries. Upstream-Status: Backport CVE: CVE-2017-13732, CVE-2017-13734, CVE-2017-13730, CVE-2017-13729, CVE-2017-13728, CVE-2017-13731 Author: Sven Joachim Signed-off-by: Ovidiu Panait --- dist.mk | 4 +- include/ncurses_defs | 4 +- ncurses/tinfo/alloc_entry.c | 4 +- ncurses/tinfo/comp_parse.c | 10 ++--- ncurses/tinfo/comp_scan.c | 6 ++- ncurses/tinfo/parse_entry.c | 91 ++++++++++++++++++++++++++++++--------------- ncurses/tinfo/strings.c | 9 +++-- ncurses/tinfo/trim_sgr0.c | 4 +- progs/tic.c | 75 ++++++++++++++++++++++++++++++++++++- 9 files changed, 157 insertions(+), 50 deletions(-) diff --git a/dist.mk b/dist.mk index 9af2699..2c70472 100644 --- a/dist.mk +++ b/dist.mk @@ -25,7 +25,7 @@ # use or other dealings in this Software without prior written # # authorization. # ############################################################################## -# $Id: dist.mk,v 1.1172 2017/07/13 00:15:27 tom Exp $ +# $Id: dist.mk,v 1.1179 2017/08/20 15:33:41 tom Exp $ # Makefile for creating ncurses distributions. # # This only needs to be used directly as a makefile by developers, but @@ -37,7 +37,7 @@ SHELL = /bin/sh # These define the major/minor/patch versions of ncurses. NCURSES_MAJOR = 6 NCURSES_MINOR = 0 -NCURSES_PATCH = 20170715 +NCURSES_PATCH = 20170826 # We don't append the patch to the version, since this only applies to releases VERSION = $(NCURSES_MAJOR).$(NCURSES_MINOR) diff --git a/include/ncurses_defs b/include/ncurses_defs index e6611b7..d237db1 100644 --- a/include/ncurses_defs +++ b/include/ncurses_defs @@ -1,4 +1,4 @@ -# $Id: ncurses_defs,v 1.73 2017/06/24 14:20:57 tom Exp $ +# $Id: ncurses_defs,v 1.75 2017/08/20 16:50:04 tom Exp $ ############################################################################## # Copyright (c) 2000-2016,2017 Free Software Foundation, Inc. # # # @@ -50,7 +50,9 @@ HAVE_BSD_STRING_H HAVE_BTOWC HAVE_BUILTIN_H HAVE_CHGAT 1 +HAVE_COLOR_CONTENT 1 HAVE_COLOR_SET 1 +HAVE_CURSCR 1 HAVE_DIRENT_H HAVE_ERRNO HAVE_FCNTL_H diff --git a/ncurses/tinfo/alloc_entry.c b/ncurses/tinfo/alloc_entry.c index 5de09f1..09374d6 100644 --- a/ncurses/tinfo/alloc_entry.c +++ b/ncurses/tinfo/alloc_entry.c @@ -47,7 +47,7 @@ #include -MODULE_ID("$Id: alloc_entry.c,v 1.60 2017/06/27 23:48:55 tom Exp $") +MODULE_ID("$Id: alloc_entry.c,v 1.61 2017/08/25 09:09:08 tom Exp $") #define ABSENT_OFFSET -1 #define CANCELLED_OFFSET -2 @@ -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; diff --git a/ncurses/tinfo/comp_parse.c b/ncurses/tinfo/comp_parse.c index 34e6216..580d4df 100644 --- a/ncurses/tinfo/comp_parse.c +++ b/ncurses/tinfo/comp_parse.c @@ -47,7 +47,7 @@ #include -MODULE_ID("$Id: comp_parse.c,v 1.96 2017/04/15 15:36:58 tom Exp $") +MODULE_ID("$Id: comp_parse.c,v 1.99 2017/08/26 16:15:50 tom Exp $") static void sanity_check2(TERMTYPE2 *, bool); NCURSES_IMPEXP void NCURSES_API(*_nc_check_termtype2) (TERMTYPE2 *, bool) = sanity_check2; @@ -510,9 +510,9 @@ static void fixup_acsc(TERMTYPE2 *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); } } @@ -568,9 +568,7 @@ sanity_check2(TERMTYPE2 *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); } diff --git a/ncurses/tinfo/comp_scan.c b/ncurses/tinfo/comp_scan.c index 40d7f6a..b207257 100644 --- a/ncurses/tinfo/comp_scan.c +++ b/ncurses/tinfo/comp_scan.c @@ -50,7 +50,7 @@ #include #include -MODULE_ID("$Id: comp_scan.c,v 1.106 2017/04/22 11:41:12 tom Exp $") +MODULE_ID("$Id: comp_scan.c,v 1.108 2017/08/25 22:57:21 tom Exp $") /* * Maximum length of string capability we'll accept before raising an error. @@ -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; diff --git a/ncurses/tinfo/parse_entry.c b/ncurses/tinfo/parse_entry.c index 3fa2f25..bbbfcb2 100644 --- a/ncurses/tinfo/parse_entry.c +++ b/ncurses/tinfo/parse_entry.c @@ -47,7 +47,7 @@ #include #include -MODULE_ID("$Id: parse_entry.c,v 1.86 2017/06/28 00:53:12 tom Exp $") +MODULE_ID("$Id: parse_entry.c,v 1.91 2017/08/26 16:13:34 tom Exp $") #ifdef LINT static short const parametrized[] = @@ -180,6 +180,20 @@ _nc_extend_names(ENTRY * entryp, char *name, int token_type) } #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(ENTRY * entryp, int literal, bool silent) 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(ENTRY * entryp, int literal, bool silent) * 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(ENTRY * entryp, int literal, bool silent) 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 */ @@ -641,13 +672,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. @@ -672,10 +696,10 @@ postprocess_termcap(TERMTYPE2 *tp, bool has_base) /* 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)) { @@ -790,7 +814,7 @@ postprocess_termcap(TERMTYPE2 *tp, bool has_base) 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 { @@ -867,17 +891,22 @@ postprocess_termcap(TERMTYPE2 *tp, bool has_base) * 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; + } } /* @@ -886,7 +915,7 @@ postprocess_termcap(TERMTYPE2 *tp, bool has_base) * 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; } @@ -938,9 +967,9 @@ postprocess_termcap(TERMTYPE2 *tp, bool has_base) 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); } } diff --git a/ncurses/tinfo/strings.c b/ncurses/tinfo/strings.c index 393d8e7..10ec6c8 100644 --- a/ncurses/tinfo/strings.c +++ b/ncurses/tinfo/strings.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 2000-2007,2012 Free Software Foundation, Inc. * + * Copyright (c) 2000-2012,2017 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -35,8 +35,9 @@ **/ #include +#include -MODULE_ID("$Id: strings.c,v 1.8 2012/02/22 22:34:31 tom Exp $") +MODULE_ID("$Id: strings.c,v 1.9 2017/08/26 13:16:11 tom Exp $") /**************************************************************************** * Useful string functions (especially for mvcur) @@ -105,7 +106,7 @@ _nc_str_copy(string_desc * dst, string_desc * src) 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 char *src) 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) { diff --git a/ncurses/tinfo/trim_sgr0.c b/ncurses/tinfo/trim_sgr0.c index 4cbcb65..4d92d15 100644 --- a/ncurses/tinfo/trim_sgr0.c +++ b/ncurses/tinfo/trim_sgr0.c @@ -36,7 +36,7 @@ #include -MODULE_ID("$Id: trim_sgr0.c,v 1.16 2017/04/05 22:33:07 tom Exp $") +MODULE_ID("$Id: trim_sgr0.c,v 1.17 2017/08/26 14:54:16 tom Exp $") #undef CUR #define CUR tp-> @@ -263,7 +263,7 @@ _nc_trim_sgr0(TERMTYPE2 *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); diff --git a/progs/tic.c b/progs/tic.c index c5d78e5..6dd4678 100644 --- a/progs/tic.c +++ b/progs/tic.c @@ -48,7 +48,7 @@ #include #include -MODULE_ID("$Id: tic.c,v 1.233 2017/07/15 17:40:19 tom Exp $") +MODULE_ID("$Id: tic.c,v 1.243 2017/08/26 20:56:55 tom Exp $") #define STDIN_NAME "" @@ -62,6 +62,10 @@ static bool showsummary = FALSE; static char **namelst = 0; static const char *to_remove; +#if NCURSES_XNAMES +static bool using_extensions = FALSE; +#endif + static void (*save_check_termtype) (TERMTYPE2 *, bool); static void check_termtype(TERMTYPE2 *tt, bool); @@ -850,6 +854,7 @@ main(int argc, char *argv[]) /* FALLTHRU */ case 'x': use_extended_names(TRUE); + using_extensions = TRUE; break; #endif default: @@ -2405,10 +2410,17 @@ check_conflict(TERMTYPE2 *tp) const char *a = given[j].value; bool first = TRUE; + if (!VALID_STRING(a)) + continue; + for (k = j + 1; given[k].keycode; k++) { const char *b = given[k].value; + + if (!VALID_STRING(b)) + continue; if (check[k]) continue; + if (!_nc_capcmp(a, b)) { check[j] = 1; check[k] = 1; @@ -2431,6 +2443,67 @@ check_conflict(TERMTYPE2 *tp) if (!first) fprintf(stderr, "\n"); } +#if NCURSES_XNAMES + if (using_extensions) { + /* *INDENT-OFF* */ + static struct { + const char *xcurses; + const char *shifted; + } table[] = { + { "kDC", NULL }, + { "kDN", "kind" }, + { "kEND", NULL }, + { "kHOM", NULL }, + { "kLFT", NULL }, + { "kNXT", NULL }, + { "kPRV", NULL }, + { "kRIT", NULL }, + { "kUP", "kri" }, + { NULL, NULL }, + }; + /* *INDENT-ON* */ + + /* + * SVr4 curses defines the "xcurses" names listed above except for + * the special cases in the "shifted" column. When using these + * names for xterm's extensions, that was confusing, and resulted + * in adding extended capabilities with "2" (shift) suffix. This + * check warns about unnecessary use of extensions for this quirk. + */ + for (j = 0; given[j].keycode; ++j) { + const char *find = given[j].name; + int value; + char ch; + + if (!VALID_STRING(given[j].value)) + continue; + + for (k = 0; table[k].xcurses; ++k) { + const char *test = table[k].xcurses; + size_t size = strlen(test); + + if (!strncmp(find, test, size) && strcmp(find, test)) { + switch (sscanf(find + size, "%d%c", &value, &ch)) { + case 1: + if (value == 2) { + _nc_warning("expected '%s' rather than '%s'", + (table[k].shifted + ? table[k].shifted + : test), find); + } else if (value < 2 || value > 15) { + _nc_warning("expected numeric 2..15 '%s'", find); + } + break; + default: + _nc_warning("expected numeric suffix for '%s'", find); + break; + } + break; + } + } + } + } +#endif free(given); free(check); } -- 2.10.2