From 99afdd5ecd787e40f06473304125eee93139031a Mon Sep 17 00:00:00 2001
From: Michal Ruprich <michalruprich@gmail.com>
Date: Sun, 12 Apr 2020 22:41:50 +0200
Subject: [PATCH 53/60] telnetd: Fix arbitrary remote code execution via short
 writes or urgent data

Fixes: CVE-2020-10188
Closes: #956084
Bug-RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2020-10188
Patch-Origin: Fedora / RedHat
Patch-URL: https://src.fedoraproject.org/rpms/telnet/raw/master/f/telnet-0.17-overflow-exploit.patch
---
 telnetd/telnetd.h |  2 +-
 telnetd/utility.c | 35 ++++++++++++++++++++++-------------
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/telnetd/telnetd.h b/telnetd/telnetd.h
index 044025d2..fa970e24 100644
--- a/telnetd/telnetd.h
+++ b/telnetd/telnetd.h
@@ -271,7 +271,7 @@ void io_drain (void);
 
 int stilloob (int s);
 void ptyflush (void);
-char *nextitem (char *current);
+char *nextitem (char *current, const char *endp);
 void netclear (void);
 void netflush (void);
 
diff --git a/telnetd/utility.c b/telnetd/utility.c
index db93c205..c9df8a79 100644
--- a/telnetd/utility.c
+++ b/telnetd/utility.c
@@ -484,10 +484,14 @@ stilloob (int s)
  * character.
  */
 char *
-nextitem (char *current)
+nextitem (char *current, const char *endp)
 {
+  if (current >= endp)
+    return NULL;
   if ((*current & 0xff) != IAC)
     return current + 1;
+  if (current + 1 >= endp)
+    return NULL;
 
   switch (*(current + 1) & 0xff)
     {
@@ -495,19 +499,20 @@ nextitem (char *current)
     case DONT:
     case WILL:
     case WONT:
-      return current + 3;
+      return current + 3 <= endp ? current + 3 : NULL;
 
     case SB:			/* loop forever looking for the SE */
       {
 	char *look = current + 2;
 
-	for (;;)
-	  if ((*look++ & 0xff) == IAC && (*look++ & 0xff) == SE)
+	while (look < endp)
+	  if ((*look++ & 0xff) == IAC && look < endp && (*look++ & 0xff) == SE)
 	    return look;
 
-      default:
-	return current + 2;
+	return NULL;
       }
+    default:
+      return current + 2 <= endp ? current + 2 : NULL;
     }
 }				/* end of nextitem */
 
@@ -529,8 +534,9 @@ nextitem (char *current)
  * us in any case.
  */
 #define wewant(p)					\
-  ((nfrontp > p) && ((*p&0xff) == IAC) &&		\
-   ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
+  ((nfrontp > p) && ((*p & 0xff) == IAC) &&		\
+   (nfrontp > p + 1 && (((*(p + 1) & 0xff) != EC) &&	\
+                        ((*(p + 1)&0xff) != EL))))
 
 
 void
@@ -545,7 +551,7 @@ netclear (void)
   thisitem = netobuf;
 #endif /* ENCRYPTION */
 
-  while ((next = nextitem (thisitem)) <= nbackp)
+  while ((next = nextitem (thisitem, nbackp)) != NULL && next <= nbackp)
     thisitem = next;
 
   /* Now, thisitem is first before/at boundary. */
@@ -556,15 +562,18 @@ netclear (void)
   good = netobuf;		/* where the good bytes go */
 #endif /* ENCRYPTION */
 
-  while (nfrontp > thisitem)
+  while (thisitem != NULL && nfrontp > thisitem)
     {
       if (wewant (thisitem))
 	{
 	  int length;
 
-	  for (next = thisitem; wewant (next) && nfrontp > next;
-	       next = nextitem (next))
+	  for (next = thisitem;
+	       next != NULL && wewant (next) && nfrontp > next;
+	       next = nextitem (next, nfrontp))
 	    ;
+	  if (next == NULL)
+	    next = nfrontp;
 
 	  length = next - thisitem;
 	  memmove (good, thisitem, length);
@@ -573,7 +582,7 @@ netclear (void)
 	}
       else
 	{
-	  thisitem = nextitem (thisitem);
+	  thisitem = nextitem (thisitem, nfrontp);
 	}
     }
 
-- 
2.26.0.292.g33ef6b2f38

