Subject: bin/28473: telnetd loses data and corrupts crypto state due to typo in use of poll()
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <jld@panix.com>
List: netbsd-bugs
Date: 11/30/2004 02:51:01
>Number:         28473
>Category:       bin
>Synopsis:       telnetd loses data and corrupts crypto state due to typo in use of poll()
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Nov 30 02:51:01 +0000 2004
>Originator:     Jed Davis [staff]
>Release:        NetBSD 2.0_RC4
>Organization:
	Panix
>Environment:
	
	
System: NetBSD panix6.panix.com 2.0_RC4 NetBSD 2.0_RC4 (PANIX-USER) #0: Sat Nov 6 19:39:39 EST 2004 root@trinity.nyc.access.net:/devel/netbsd/release-2.0-20041022/src/sys/arch/i386/compile/PANIX-USER i386
Architecture: i386
Machine: i386
>Description:

When someone is connected to a 2.0/CURRENT telnetd and inputs a lot of
text at once -- copy/paste, for example -- some of it may be lost.  If
the telnet session is encrypted, this causes the two sides' keystreams
to desynchronize, so anything typed afterwards decrypts to random
characters.

This was reproduced using both NetBSD's telnet client and C-Kermit.

>How-To-Repeat:

Use encrypted telnet and paste a large (>1024 chars) block of text
into the session; this may need to be repeated several times.

Alternately, without encryption, cat the pasted text to a file and
diff that with the original.

We also have a report that using ZMODEM or similar over an affected
telnet connection results in large numbers of checksum errors.

>Fix:

--- src/libexec/telnetd/telnetd.c.orig  Mon Nov 29 21:16:14 2004
+++ src/libexec/telnetd/telnetd.c       Mon Nov 29 21:16:28 2004
@@ -999,7 +999,7 @@
                /*
                 * Something to read from the network...
                 */
-               if (set[0].revents && POLLIN) {
+               if (set[0].revents & POLLIN) {
                    ncc = read(f, netibuf, sizeof (netibuf));
                    if (ncc < 0 && errno == EWOULDBLOCK)
                        ncc = 0;

When there's still unused data in netibuf, POLLIN is not set in
set[0].events, so the if-statement's body should not be executed in that
case.  But, because of the mistyped condition, it is, and the previous
buffer contents are discarded.

For example, a telnetd run with "-D report" gives this:

td: netread 1024 chars
td: netread 546 chars
td: netflush 47 chars
td: ptyflush 1023 chars
td: netread 0 chars
td: netflush 46 chars
td: ptyflush 1 chars

Note that sizeof netibuf == 1024, and observe that all 546 characters of
the second netread, and possibly the last one of the first netread (see
state.c:95), are dropped in this manner.

>Unformatted: