From 4d9899a6753bc355b2e835c7c726891125b5b243 Mon Sep 17 00:00:00 2001
From: Mats Erik Andersson <gnu@gisladisker.se>
Date: Wed, 29 Jan 2020 21:07:10 +0100
Subject: [PATCH 31/60] More work on CVE-2019-0053.

Telnet protocol messages must remain sane at all costs, instead of
being truncated because indata was oversized.  Some additional cases
of insufficient buffer declaration are corrected.
---
 ChangeLog         | 14 ++++++++++++++
 telnet/telnet.c   | 36 ++++++++++++++++++++++++++++--------
 telnetd/utility.c |  3 ++-
 3 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2d4e603a..77e6a615 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2020-01-29  Mats Erik Andersson  <gnu@gisladisker.se>
+
+	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.
+
+	Insufficiently declared length of string variable.
+
+	* telnetd/utility.c (printsub): Declare TBUF with maximal extent.
+
 2020-01-11  Mats Erik Andersson  <gnu@gisladisker.se>
 
 	The glibc manual page for ether address specifies <netinet/ether.h>.
diff --git a/telnet/telnet.c b/telnet/telnet.c
index 6e00513a..574bef83 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/utility.c b/telnetd/utility.c
index 8227775d..5b8bd50a 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" : "",
-- 
2.26.0.292.g33ef6b2f38

