mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 05:07:33 +00:00
ssh/tailssh: close tty on session close
We were only closing on side of the pty/tty pair. Close the other side too. Thanks to @fritterhoff for reporting and debugging the issue! Fixes #8119 Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
gossh "github.com/tailscale/golang-x-crypto/ssh"
|
||||
@@ -811,6 +812,7 @@ type sshSession struct {
|
||||
stdout io.ReadCloser
|
||||
stderr io.Reader // nil for pty sessions
|
||||
ptyReq *ssh.Pty // non-nil for pty sessions
|
||||
tty *os.File // non-nil for pty sessions, must be closed after process exits
|
||||
|
||||
// We use this sync.Once to ensure that we only terminate the process once,
|
||||
// either it exits itself or is terminated
|
||||
@@ -1087,6 +1089,7 @@ func (ss *sshSession) run() {
|
||||
}
|
||||
go ss.killProcessOnContextDone()
|
||||
|
||||
var processDone atomic.Bool
|
||||
go func() {
|
||||
defer ss.stdin.Close()
|
||||
if _, err := io.Copy(rec.writer("i", ss.stdin), ss); err != nil {
|
||||
@@ -1104,8 +1107,11 @@ func (ss *sshSession) run() {
|
||||
defer ss.stdout.Close()
|
||||
_, err := io.Copy(rec.writer("o", ss), ss.stdout)
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
logf("stdout copy: %v", err)
|
||||
ss.cancelCtx(err)
|
||||
isErrBecauseProcessExited := processDone.Load() && errors.Is(err, syscall.EIO)
|
||||
if !isErrBecauseProcessExited {
|
||||
logf("stdout copy: %v, %T", err)
|
||||
ss.cancelCtx(err)
|
||||
}
|
||||
}
|
||||
if openOutputStreams.Add(-1) == 0 {
|
||||
ss.CloseWrite()
|
||||
@@ -1124,7 +1130,12 @@ func (ss *sshSession) run() {
|
||||
}()
|
||||
}
|
||||
|
||||
if ss.tty != nil {
|
||||
// If running a tty session, close the tty when the session is done.
|
||||
defer ss.tty.Close()
|
||||
}
|
||||
err = ss.cmd.Wait()
|
||||
processDone.Store(true)
|
||||
// This will either make the SSH Termination goroutine be a no-op,
|
||||
// or itself will be a no-op because the process was killed by the
|
||||
// aforementioned goroutine.
|
||||
|
Reference in New Issue
Block a user