golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.02k stars 17.68k forks source link

x/crypto: SSH swallows first character in second connection #41390

Open jkohen opened 4 years ago

jkohen commented 4 years ago

What version of Go are you using (go version)?

$ go version
go version go1.15 linux/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/usr/local/google/home/jkohen/.cache/go-build"
GOENV="/usr/local/google/home/jkohen/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/usr/local/google/home/jkohen/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/usr/local/google/home/jkohen/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/google-golang"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/google-golang/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build079540723=/tmp/go-build -gno-record-gcc-switches"

What did you do?

The following assumes a ssh server in localhost set up with SSH_AUTH_SOCK, which is what my environment provides. It should be trivial for you all to adjust it for a different host and hardcoded password as needed:

  1. go run xcrypto-bug.txt
  2. Once you see the "type something" prompt, enter a string and press enter. Note the output.
  3. Repeat for the second attempt.

What did you expect to see?

The output from the second session is exactly what I entered on the keyboard.

What did you see instead?

The output from the second session is missing the first character. If I add more executions of runTest(), I see the same effect in all but the first session.

For instance, in the session below I typed "hi" both times, but the second time only the "i" was registered:

Type something: hi
0000000   h   i  nl
         68  69  0a
0000003
Type something: i
0000000   i  nl
         69  0a
0000002

I tried a few things to no avail:

I also tried a couple different versions of the SSH code in the snippet, and always got the same result. I was unable to reproduce this with a local shell, or with the ssh command-line tool (OpenSSH).

toothrot commented 4 years ago

/cc @FiloSottile @hanwen

hanwen commented 3 years ago

can you reproduce this if you don't use the ssh/terminal package?

jkohen commented 3 years ago

@hanwen How do you mean? If I remove the terminal.MakeRaw call or the entire block protected by terminal.IsTerminal, then I still see a similar bug, though it manifests slightly differently: I need to press enter one more time between runs of sshTest. I'm not an expert in terminals, but I think the enter is the only acceptable "separator" because the terminal is no longer in raw mode.

Without extra enter:

Type something: hi
0000000   h   i  nl
         68  69  0a
0000003
Type something: hi

0000000  nl
         0a
0000001

With an extra enter before the second "hi":

Type something: hi
0000000   h   i  nl
         68  69  0a
0000003
Type something:
hi
0000000   h   i  nl
         68  69  0a
0000003

In the end, I need everything in the current version:

The same workflow works perfectly with the OpenSSH client, as far as I can come close to reproduce this.

hanwen commented 3 years ago

the question is whether the SSH package swallows a byte somewhere at the transport level (unlikely), or if there is a problem with the terminal layering that runs on top of the SSH package.

jkohen commented 3 years ago

As per my last comment, I believe I was able to reproduce a variation of the bug without using the terminal module. This is the code I used: xcrypto-noterm-bug.txt

silviucm commented 3 years ago

@jkohen @hanwen I posted a "working" / not-working scenario here: https://play.golang.org/p/mK1UJ-BNMkV In case it helps debugging this one. The only way I made it "work" is by opening an alternate /dev/stdin *os.File, then close it at each iteration. The terminal still initializes with the os.Stdin fd 0 assumption though.

cybertramp commented 1 year ago

Hi! I'm making an SSH shell manager program, but I'm facing the same problem. Is this issue still pending? Is there any other way to open stdin through a path on the Linux filesystem?

My symptoms are: If input after connecting with ssh shell(), the key is randomly chewed(swallowed).

I'd like to know how to fix it, but there is only one reference here related to the issue. 😥