diff --git a/ChangeLog b/ChangeLog index 843fbf69..6dbb150f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2020-01-29 Mats Erik Andersson + + More work on CVE-2019-0053. + Telnet protocol messages must not be corrupted when buffer + overflows are detected, but should be reported as errors. + + * telnet/telnet.c (suboption): Check that prepared protocol + message in fact fits in intermediary buffer without truncation. + Tweak indentation for visibility of protocol elements in snprintf. + + Allocate space also for final NUL-character. + + * telnetd/telnetd.c (telnetdrun): Increase DATA string size by one. + * telnetd/termstat.c (localstat, flowstat, clientstat): Likewise. + + Insufficiently declared length of string variable. + + * telnetd/utility.c (printsub): Declare TBUF with maximal extent. + 2020-01-28 Mats Erik Andersson Better test coverage, mostly IPv6. diff --git a/telnet/telnet.c b/telnet/telnet.c index f42957e4..297ae0e4 100644 --- a/telnet/telnet.c +++ b/telnet/telnet.c @@ -859,10 +859,13 @@ suboption (void) #endif /* defined(TN3270) */ name = gettermname (); len = strlen (name) + 4 + 2; - if (len < NETROOM ()) + + if ((len < NETROOM ()) && (len <= sizeof (temp))) { - snprintf ((char *) temp, sizeof (temp), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, - TELQUAL_IS, name, IAC, SE); + snprintf ((char *) temp, sizeof (temp), "%c%c%c%c%s%c%c", + IAC, SB, TELOPT_TTYPE, TELQUAL_IS, + name, + IAC, SE); ring_supply_data (&netoring, temp, len); printsub ('>', &temp[2], len - 2); } @@ -880,13 +883,15 @@ suboption (void) if (SB_GET () == TELQUAL_SEND) { long ospeed, ispeed; - unsigned char temp[50]; + unsigned char temp[50]; /* Two six-digit integers plus 7. */ int len; TerminalSpeeds (&ispeed, &ospeed); - snprintf ((char *) temp, sizeof (temp), "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, - TELQUAL_IS, (int) ospeed, (int) ispeed, IAC, SE); + snprintf ((char *) temp, sizeof (temp), "%c%c%c%c%d,%d%c%c", + IAC, SB, TELOPT_TSPEED, TELQUAL_IS, + (int) ospeed, (int) ispeed, + IAC, SE); len = strlen ((char *) temp + 4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM ()) @@ -999,8 +1004,23 @@ suboption (void) send_wont (TELOPT_XDISPLOC, 1); break; } - snprintf ((char *) temp, sizeof (temp), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, - TELQUAL_IS, dp, IAC, SE); + + /* Remote host, and display server must not be corrupted + * by truncation. In addition, every character of telnet + * protocol must remain unsevered. Check that DP fits in + * full within TEMP. Otherwise report buffer error. + */ + if (strlen (dp) > sizeof (temp) - 4 - 2) + { + printf ("lm_will: not enough room in buffer\n"); + break; + } + + /* Go ahead safely. */ + snprintf ((char *) temp, sizeof (temp), "%c%c%c%c%s%c%c", + IAC, SB, TELOPT_XDISPLOC, TELQUAL_IS, + dp, + IAC, SE); len = strlen ((char *) temp + 4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM ()) diff --git a/telnetd/telnetd.c b/telnetd/telnetd.c index a3badbee..048ed136 100644 --- a/telnetd/telnetd.c +++ b/telnetd/telnetd.c @@ -704,7 +704,7 @@ telnetd_run (void) int newflow = (c & TIOCPKT_DOSTOP) ? 1 : 0; if (newflow != flowmode) { - char data[6]; + char data[7]; sprintf (data, "%c%c%c%c%c%c", IAC, SB, TELOPT_LFLOW, diff --git a/telnetd/termstat.c b/telnetd/termstat.c index daeea00b..6f94da09 100644 --- a/telnetd/termstat.c +++ b/telnetd/termstat.c @@ -304,7 +304,7 @@ localstat (void) } else if (lmodetype == REAL_LINEMODE) { - char data[7]; + char data[8]; send_do (TELOPT_LINEMODE, 1); /* send along edit modes */ @@ -339,7 +339,7 @@ localstat (void) /* * Send along appropriate edit mode mask. */ - char data[7]; + char data[8]; sprintf (data, "%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, @@ -391,7 +391,7 @@ flowstat (void) { if (his_state_is_will (TELOPT_LFLOW)) { - char data[6]; + char data[7]; if (tty_flowmode () != flowmode) { @@ -476,7 +476,7 @@ clientstat (register int code, register int parm1, register int parm2) if (lmodetype == REAL_LINEMODE && uselinemode) if (uselinemode) { - char data[7]; + char data[8]; useeditmode = 0; if (tty_isediting ()) @@ -553,7 +553,7 @@ clientstat (register int code, register int parm1, register int parm2) if (!ack) { - char data[7]; + char data[8]; sprintf (data, "%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, diff --git a/telnetd/utility.c b/telnetd/utility.c index dc87e9af..42f624e7 100644 --- a/telnetd/utility.c +++ b/telnetd/utility.c @@ -1225,7 +1225,8 @@ printsub (int direction, unsigned char *pointer, int length) break; } { - char tbuf[32]; + char tbuf[sizeof ("|EDIT|TRAPSIG|SOFT_TAB|LIT_ECHO|ACK")]; + snprintf (tbuf, sizeof (tbuf), "%s%s%s%s%s", pointer[2] & MODE_EDIT ? "|EDIT" : "", pointer[2] & MODE_TRAPSIG ? "|TRAPSIG" : "",