Return to BSD News archive
Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!nntp.coast.net!howland.reston.ans.net!swrinde!newsfeed.internetmci.com!bloom-beacon.mit.edu!jik.datasrv.co.il!jik.datasrv.co.il!jik From: jik@annex-1-slip-jik.cam.ov.com (Jonathan Kamens) Newsgroups: comp.protocols.kerberos,comp.bugs.4bsd Subject: krlogin/krlogind usage of OOB data is broken Date: 10 Feb 1996 18:32:09 GMT Organization: jik's Linux box Lines: 99 Sender: jik@jik.datasrv.co.il (Jonathan Kamens) Message-ID: <4fiobt$590@jik.datasrv.co.il> NNTP-Posting-Host: jik.datasrv.co.il Xref: euryale.cc.adfa.oz.au comp.protocols.kerberos:5405 comp.bugs.4bsd:2093 (Comp.bugs.4bsd folks: This posting relates to a problem in how the Kerberos rlogin and rlogind programs use out-of-band data. However, I believe that the problem I'm describing here is shared by the stock BSD rlogin and rlogind programs, which is why I'm cross-posting to comp.bugs.4bsd.) I understand that Sam Hartman has done a considerable amount of work on rlogin and rlogind, trying to get their handling of out-of-band data to work properly. I've done similar work independently of Sam, and I suspect that my changes are quite different from the ones he's implemented; nevertheless, I've come to the conclusion that the way the protocl uses OOB data is broken in at least on way that simply cannot be fixed without changing the protocol. The basic problem I'm encountering is this: What happens if krlogind sends an OOB message to krlogin, and then it sends a *second* OOB message before krlogin has processed the first one? This *can* and *does* happen. For example, when I krlogin from my Linux box at home to an AIX box at work over a SLIP link, the AIX box sends three different OOB messages as part of the initial initialization of the connection, and network congestion can easily cause all of them to get to my Linux box in consecutive packets, too quickly for it to deal with each of them before the next one arrives. Unfortunately, the way OOB data is implemented in the Linux kernel (and I believe in many other UNIX kernels as well) is that only one OOB message is allowed at a time. If a second message is received while the first one is still pending, the first one becomes part of the normal data stream, and the OOB mark is moved to the second one. This does appear to be legal, according to the BSD documentation about OOB data. Consider what occurs if this happens with krlogin/krlogind -- if krlogind sends multiple OOB messages consecutively, then krlogin will process one of them, but the rest will simply be part of the data stream, thus causing one or more garbage characters to appear on the user's screen. If the connection is being encrypted, the results are much worse -- the OOB messages that enter the normal data stream corrupt it, which usually causes krlogin to complain and close the connection. I came up with three hacks to reduce the likelihood of this problem, but they're all real hacks, and even all of them together don't work 100% of the time. First of all, I modified the protocol() function in krlogind so that any single run through the protocol() loop only causes a single OOB byte to be sent, with all the commands that need to be sent OR'd together in it. This appears to be OK since (a) krlogin treats the OOB byte as a mask, and checks it to see which bits are set, and (b) the various commands sent as OOB bytes are bit-wise exlusive of each other. I confess that of the three hacks I came up with, this is the one I'm least sure about, so if anyone can confirm or deny that this is a reasonable thing to do, I'd love to hear it. For the Linux -> AIX case I mentioned above, this reduces the number of OOB bytes sent by the AIX box from three to two. Second, I modified krlogind so that it never sends two OOB messages less than five seconds apart. In *most* cases, this gives the client time to process the first OOB message before the second one is sent. But of course, it introduces delays when initiating some connections. Sometimes network congestion or whatever makes the five-second pause by krlogind meaningless, and besides, sometimes krlogin will have to talk to a krlogind which hasn't been modified in this way. So I put a third hack hack in des_read() in krlogin. When des_read() reads the length of the next encrypted data block off the net, and that length is absurd, it checks to see if the first byte of the length contains a valid OOB message. If it does, it processes it as an OOB message, shifts the three remaining bytes of the length up one, and then reads a new byte to replace the one that was treated as OOB. In the case of the Linux -> AIX connection I mentioned above, it ends up doing this twice, since the Linux box gets three OOB messages in quick succession and only ends up dealing with one of them as OOB data. I figured that this doesn't really pose a thread to the encrypted data stream, since if there's really a problem with it the problem will turn up later anyway. However, that second hack in krlogin will only work when an encrypted session is being used. Non-encrypted sessions will still end up with some OOB messages not getting processed and ending up as garbage in the data stream. Furthermore, even with these hacks, I've still seen instances where des_read() gets unexpected values when it tries to read the length off the net, or where the encrypted data is not available for some reason when it tries to read it. As far as I can tell, the only way to make this work reliably is to require hand-shaking -- when krlogind sends OOB data to krlogin, krlogin needs to send OOB data back to krlogind to tell it when it has processed the data, and krlogind needs to wait for that ACK before sending any more OOB data. This is, I believe, how telnet/telnetd handle their OOB data. Unfortunately, this would require changing the krlogin/krlogind protocol (and I realize that "protocol" is a strong word) in a way that would make the new krlogin incompatible with the old krlogind and vice versa. The closest thing that I can come up with to modifying the protocol in a backward-compatible way is to have krlogind set a bit in the first OOB byte it sends, to tell krlogin, "I know how to deal with OOB ACK messages, so you should ACK every OOB message you receive." Unfortunately, I can't figure out a protocol-compatible way for krlogin to tell krlogind that it knows how to deal with this bit, so after sending this bit to krlogin, krlogind has no way of knowing whether it should wait for the ACK from krlogin. I would appreciate any input that people might have into this problem. Am I right that there's a problem? Has it always been there? Is there any way to solve it, short of either (a) modifying the protocol in a way that isn't backward-compatible, or (b) ditching krlogin/krlogind altogether and using ktelnet/ktelnetd instead (yes, I'd love to do that, but first of all, some of our customers demand krlogin/krlogind, and second, I've heard rumors that the security negotiation in ktelnet/ktelnetd is vulnerable). Thanks.