From owner-freebsd-bugs@FreeBSD.ORG Mon Dec 29 10:00:32 2003 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 63FA616A4CE for ; Mon, 29 Dec 2003 10:00:32 -0800 (PST) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 6C1B143D53 for ; Mon, 29 Dec 2003 10:00:29 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) hBTI0TFR034945 for ; Mon, 29 Dec 2003 10:00:29 -0800 (PST) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.10/8.12.10/Submit) id hBTI0TX7034944; Mon, 29 Dec 2003 10:00:29 -0800 (PST) (envelope-from gnats) Resent-Date: Mon, 29 Dec 2003 10:00:29 -0800 (PST) Resent-Message-Id: <200312291800.hBTI0TX7034944@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Peter Edwards Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id B7D2716A4CE for ; Mon, 29 Dec 2003 09:53:14 -0800 (PST) Received: from www.freebsd.org (www.freebsd.org [216.136.204.117]) by mx1.FreeBSD.org (Postfix) with ESMTP id 1EAC743D67 for ; Mon, 29 Dec 2003 09:52:57 -0800 (PST) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.12.10/8.12.10) with ESMTP id hBTHqudL021157 for ; Mon, 29 Dec 2003 09:52:56 -0800 (PST) (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.12.10/8.12.10/Submit) id hBTHqujY021156; Mon, 29 Dec 2003 09:52:56 -0800 (PST) (envelope-from nobody) Message-Id: <200312291752.hBTHqujY021156@www.freebsd.org> Date: Mon, 29 Dec 2003 09:52:56 -0800 (PST) From: Peter Edwards To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-2.0 Subject: misc/60697: [patch] pseudo-tty hack versus telnet race causes data loss. X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 29 Dec 2003 18:00:32 -0000 >Number: 60697 >Category: misc >Synopsis: [patch] pseudo-tty hack versus telnet race causes data loss. >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon Dec 29 10:00:29 PST 2003 >Closed-Date: >Last-Modified: >Originator: Peter Edwards >Release: 5.2 -CURRENT as of Dec 23, 2003 >Organization: >Environment: FreeBSD hippo 5.2-CURRENT FreeBSD 5.2-CURRENT #2: Tue Dec 23 12:46:05 GMT 2003 petere@hippo:/scratch/obj/scratch/src/sys/HIPPO i386 >Description: The pty driver appears to have a hack that prevents a deadlock at the cost of discarding data: In the event that certain ioctls are invoked on the master side of the pty, it'll drop any "unsent" data. This can be seen at line 702 of kern/tty_pty.c > > switch (cmd) { > #ifdef COMPAT_43 > case TIOCSETP: > case TIOCSETN: > #endif > case TIOCSETD: > case TIOCSETA: > case TIOCSETAW: > case TIOCSETAF: > /* > * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. > * ttywflush(tp) will hang if there are characters in > * the outq. > */ > ndflush(&tp->t_outq, tp->t_outq.c_cc); > break; > I believe this is here to avoid having the master process waiting until all the data written to the slave side is drained for some operations, because its that process itself that needs to do the draining. However, this can cause problems with the telnet server. Here's an example: 1: Telnetd answers an incoming call, grabs the master side of a pseudo-terminal, and sends a bunch of telnet commands, one of which is a "WILL ECHO" request. 2a: Just after this, it launches a new process to run "login": This is given the slave side of the pseudo-terminal for its std(in|out|err) 2b: Meanwhile, the remote telnet client sends a response to the WILL echo: In this case, a "DONT" ECHO. 2c: Meanwhile, the login process writes the phrase: "login: " to the slave side of the terminal 3: If the telnetd process sees the network response before it sees the pty data, the echo response causes a call to "tcsetattr(..., TCSANOW, ...)". This ends up as an ioctl(..., TIOCSETA, ...) which gets handled by ptyioctl(), and exercises the code quoted above. This, unfortunately, causes the "login:" written by the login process to be discarded sometimes. For a human interacting with the telnet server, this is merely an annoyance, but for automated tools, it can be more of an issue, and just adds to the hackery that such evil programs need to perform. I'm sure there are other occaisons where the same data loss can rear its head beyond the initial flurry of telnet option processing. I'm sure a more sophisticated hack can work around this issue, but the "TIOCSETA" operation that telnetd invokes does not actually cause a blocking operation to occur: I think the check against TIOCSETA is unneccessary. i.e., I propose the patch below. >How-To-Repeat: Write a dumb telnet client that responds negatively to any telnet option requests. If you want to make it more reproducable, add a sleep into the telnetd code in sys_term.c:startslave() for the parent (10ms is plenty) If someone's interested, I can spend some time ripping a minimal example from my code. >Fix: Index: kern/tty_pty.c =================================================================== RCS file: /usr/cvs/FreeBSD-CVS/src/sys/kern/tty_pty.c,v retrieving revision 1.112 diff -u -r1.112 tty_pty.c --- kern/tty_pty.c 9 Nov 2003 09:17:24 -0000 1.112 +++ kern/tty_pty.c 29 Dec 2003 17:17:42 -0000 @@ -705,7 +705,6 @@ case TIOCSETN: #endif case TIOCSETD: - case TIOCSETA: case TIOCSETAW: case TIOCSETAF: /* >Release-Note: >Audit-Trail: >Unformatted: