Skip to content

Commit 4e5a261

Browse files
espadolinigopherbot
authored andcommitted
ssh: close net.Conn on all NewServerConn errors
This PR ensures that the net.Conn passed to ssh.NewServerConn is closed on all error return paths, not just after a failed handshake. This matches the behavior of ssh.NewClientConn. Change-Id: Id8a51d10ae8d575cbbe26f2ef6b37de7cca840ec GitHub-Last-Rev: 81bb2e5 GitHub-Pull-Request: #279 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/549095 Run-TryBot: Nicola Murino <[email protected]> Auto-Submit: Nicola Murino <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-by: Nicola Murino <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Michael Pratt <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 152cdb1 commit 4e5a261

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

Diff for: ssh/server.go

+2
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,15 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
213213
} else {
214214
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
215215
if !contains(supportedPubKeyAuthAlgos, algo) {
216+
c.Close()
216217
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
217218
}
218219
}
219220
}
220221
// Check if the config contains any unsupported key exchanges
221222
for _, kex := range fullConf.KeyExchanges {
222223
if _, ok := serverForbiddenKexAlgos[kex]; ok {
224+
c.Close()
223225
return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
224226
}
225227
}

Diff for: ssh/server_test.go

+64-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
package ssh
66

77
import (
8+
"io"
9+
"net"
10+
"sync/atomic"
811
"testing"
12+
"time"
913
)
1014

1115
func TestClientAuthRestrictedPublicKeyAlgos(t *testing.T) {
@@ -59,27 +63,78 @@ func TestClientAuthRestrictedPublicKeyAlgos(t *testing.T) {
5963
}
6064

6165
func TestNewServerConnValidationErrors(t *testing.T) {
62-
c1, c2, err := netPipe()
63-
if err != nil {
64-
t.Fatalf("netPipe: %v", err)
65-
}
66-
defer c1.Close()
67-
defer c2.Close()
68-
6966
serverConf := &ServerConfig{
7067
PublicKeyAuthAlgorithms: []string{CertAlgoRSAv01},
7168
}
72-
_, _, _, err = NewServerConn(c1, serverConf)
69+
c := &markerConn{}
70+
_, _, _, err := NewServerConn(c, serverConf)
7371
if err == nil {
7472
t.Fatal("NewServerConn with invalid public key auth algorithms succeeded")
7573
}
74+
if !c.isClosed() {
75+
t.Fatal("NewServerConn with invalid public key auth algorithms left connection open")
76+
}
77+
if c.isUsed() {
78+
t.Fatal("NewServerConn with invalid public key auth algorithms used connection")
79+
}
80+
7681
serverConf = &ServerConfig{
7782
Config: Config{
7883
KeyExchanges: []string{kexAlgoDHGEXSHA256},
7984
},
8085
}
81-
_, _, _, err = NewServerConn(c1, serverConf)
86+
c = &markerConn{}
87+
_, _, _, err = NewServerConn(c, serverConf)
8288
if err == nil {
8389
t.Fatal("NewServerConn with unsupported key exchange succeeded")
8490
}
91+
if !c.isClosed() {
92+
t.Fatal("NewServerConn with unsupported key exchange left connection open")
93+
}
94+
if c.isUsed() {
95+
t.Fatal("NewServerConn with unsupported key exchange used connection")
96+
}
97+
}
98+
99+
type markerConn struct {
100+
closed uint32
101+
used uint32
85102
}
103+
104+
func (c *markerConn) isClosed() bool {
105+
return atomic.LoadUint32(&c.closed) != 0
106+
}
107+
108+
func (c *markerConn) isUsed() bool {
109+
return atomic.LoadUint32(&c.used) != 0
110+
}
111+
112+
func (c *markerConn) Close() error {
113+
atomic.StoreUint32(&c.closed, 1)
114+
return nil
115+
}
116+
117+
func (c *markerConn) Read(b []byte) (n int, err error) {
118+
atomic.StoreUint32(&c.used, 1)
119+
if atomic.LoadUint32(&c.closed) != 0 {
120+
return 0, net.ErrClosed
121+
} else {
122+
return 0, io.EOF
123+
}
124+
}
125+
126+
func (c *markerConn) Write(b []byte) (n int, err error) {
127+
atomic.StoreUint32(&c.used, 1)
128+
if atomic.LoadUint32(&c.closed) != 0 {
129+
return 0, net.ErrClosed
130+
} else {
131+
return 0, io.ErrClosedPipe
132+
}
133+
}
134+
135+
func (*markerConn) LocalAddr() net.Addr { return nil }
136+
func (*markerConn) RemoteAddr() net.Addr { return nil }
137+
138+
func (*markerConn) SetDeadline(t time.Time) error { return nil }
139+
func (*markerConn) SetReadDeadline(t time.Time) error { return nil }
140+
func (*markerConn) SetWriteDeadline(t time.Time) error { return nil }

0 commit comments

Comments
 (0)