Module Name:    src
Committed By:   shm
Date:           Fri Sep 22 15:28:36 UTC 2023

Modified Files:
        src/libexec/telnetd: state.c

Log Message:
Fix off by one in telrcv()

In case of "\r" in the data buffer, the code was unconditionally looking ahead
to next character, even if "\r" was last character in the buffer. That
condition leads to read outside of the data (one byte after the array)

Thanks christos@ for the review


To generate a diff of this commit:
cvs rdiff -u -r1.32 -r1.33 src/libexec/telnetd/state.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/libexec/telnetd/state.c
diff -u src/libexec/telnetd/state.c:1.32 src/libexec/telnetd/state.c:1.33
--- src/libexec/telnetd/state.c:1.32	Mon Aug  9 21:38:04 2021
+++ src/libexec/telnetd/state.c	Fri Sep 22 15:28:36 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: state.c,v 1.32 2021/08/09 21:38:04 andvar Exp $	*/
+/*	$NetBSD: state.c,v 1.33 2023/09/22 15:28:36 shm Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)state.c	8.5 (Berkeley) 5/30/95";
 #else
-__RCSID("$NetBSD: state.c,v 1.32 2021/08/09 21:38:04 andvar Exp $");
+__RCSID("$NetBSD: state.c,v 1.33 2023/09/22 15:28:36 shm Exp $");
 #endif
 #endif /* not lint */
 
@@ -100,9 +100,33 @@ telrcv(void)
 
 		case TS_CR:
 			state = TS_DATA;
-			/* Strip off \n or \0 after a \r */
-			if ((c == 0) || (c == '\n')) {
-				break;
+
+#ifdef	LINEMODE
+			/*
+			 * If we are operating in linemode,
+			 * convert to local end-of-line.
+			 */
+			if (linemode && (ncc > 0) && ((c == '\n') ||
+				 ((c == 0) && tty_iscrnl())) )
+				c = '\n';
+			else
+#endif
+			{
+				/*
+				 * We now map \r\n ==> \r for pragmatic reasons.
+				 * Many client implementations send \r\n when
+				 * the user hits the CarriageReturn key.
+				 *
+				 * We USED to map \r\n ==> \n, since \r\n says
+				 * that we want to be in column 1 of the next
+				 * printable line, and \n is the standard
+				 * unix way of saying that (\r is only good
+				 * if CRMOD is set, which it normally is).
+				 */
+
+				/* Strip off \n or \0 after a \r */
+				if ((c == 0) || (c == '\n'))
+					break;
 			}
 			/* FALL THROUGH */
 
@@ -111,42 +135,10 @@ telrcv(void)
 				state = TS_IAC;
 				break;
 			}
-			/*
-			 * We now map \r\n ==> \r for pragmatic reasons.
-			 * Many client implementations send \r\n when
-			 * the user hits the CarriageReturn key.
-			 *
-			 * We USED to map \r\n ==> \n, since \r\n says
-			 * that we want to be in column 1 of the next
-			 * printable line, and \n is the standard
-			 * unix way of saying that (\r is only good
-			 * if CRMOD is set, which it normally is).
-			 */
-			if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
-				int nc = *netip;
-#ifdef	ENCRYPTION
-				if (decrypt_input)
-					nc = (*decrypt_input)(nc & 0xff);
-#endif	/* ENCRYPTION */
-#ifdef	LINEMODE
-				/*
-				 * If we are operating in linemode,
-				 * convert to local end-of-line.
-				 */
-				if (linemode && (ncc > 0) && (('\n' == nc) ||
-					 ((0 == nc) && tty_iscrnl())) ) {
-					netip++; ncc--;
-					c = '\n';
-				} else
-#endif
-				{
-#ifdef	ENCRYPTION
-					if (decrypt_input)
-						(void)(*decrypt_input)(-1);
-#endif	/* ENCRYPTION */
-					state = TS_CR;
-				}
-			}
+
+			if ((c == '\r') && his_state_is_wont(TELOPT_BINARY))
+				state = TS_CR;
+
 			*pfrontp++ = c;
 			break;
 

Reply via email to