Skip to content

Commit a0943c0

Browse files
authored
Merge pull request moby#3848 from sipsma/close-ssh-conn
ssh: add fallback to ensure conn is closed in all cases.
2 parents 9d35774 + 30ea419 commit a0943c0

File tree

3 files changed

+80
-3
lines changed

3 files changed

+80
-3
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ COPY --link --from=dnsname /usr/bin/dnsname /opt/cni/bin/
235235

236236
FROM buildkit-base AS integration-tests-base
237237
ENV BUILDKIT_INTEGRATION_ROOTLESS_IDPAIR="1000:1000"
238-
RUN apk add --no-cache shadow shadow-uidmap sudo vim iptables ip6tables dnsmasq fuse curl git-daemon \
238+
RUN apk add --no-cache shadow shadow-uidmap sudo vim iptables ip6tables dnsmasq fuse curl git-daemon openssh-client \
239239
&& useradd --create-home --home-dir /home/user --uid 1000 -s /bin/sh user \
240240
&& echo "XDG_RUNTIME_DIR=/run/user/1000; export XDG_RUNTIME_DIR" >> /home/user/.profile \
241241
&& mkdir -m 0700 -p /run/user/1000 \

frontend/dockerfile/dockerfile_ssh_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package dockerfile
22

33
import (
4+
"bytes"
45
"crypto/rand"
56
"crypto/rsa"
67
"crypto/x509"
78
"encoding/pem"
89
"os"
10+
"os/exec"
911
"path/filepath"
1012
"testing"
13+
"time"
1114

1215
"github.com/containerd/continuity/fs/fstest"
1316
"github.com/moby/buildkit/client"
@@ -20,6 +23,7 @@ import (
2023

2124
var sshTests = integration.TestFuncs(
2225
testSSHSocketParams,
26+
testSSHFileDescriptorsClosed,
2327
)
2428

2529
func init() {
@@ -73,3 +77,74 @@ RUN --mount=type=ssh,mode=741,uid=100,gid=102 [ "$(stat -c "%u %g %f" $SSH_AUTH_
7377
}, nil)
7478
require.NoError(t, err)
7579
}
80+
81+
func testSSHFileDescriptorsClosed(t *testing.T, sb integration.Sandbox) {
82+
f := getFrontend(t, sb)
83+
84+
dockerfile := []byte(`
85+
FROM alpine
86+
RUN --mount=type=ssh apk update \
87+
&& apk add openssh-client-default \
88+
&& mkdir -p -m 0600 ~/.ssh \
89+
&& ssh-keyscan github.com >> ~/.ssh/known_hosts \
90+
&& for i in $(seq 1 3); do \
91+
92+
done; \
93+
exit 0;
94+
`)
95+
96+
dir, err := integration.Tmpdir(
97+
t,
98+
fstest.CreateFile("Dockerfile", dockerfile, 0600),
99+
)
100+
require.NoError(t, err)
101+
102+
c, err := client.New(sb.Context(), sb.Address())
103+
require.NoError(t, err)
104+
defer c.Close()
105+
106+
// not using t.TempDir() here because the path ends up longer than the unix socket max length
107+
tmpDir, err := os.MkdirTemp("", "buildkit-ssh-test-")
108+
require.NoError(t, err)
109+
t.Cleanup(func() {
110+
os.RemoveAll(tmpDir)
111+
})
112+
sockPath := filepath.Join(tmpDir, "ssh-agent.sock")
113+
114+
sshAgentCmd := exec.CommandContext(sb.Context(), "ssh-agent", "-s", "-d", "-a", sockPath)
115+
sshAgentOutputBuf := &bytes.Buffer{}
116+
sshAgentCmd.Stderr = sshAgentOutputBuf
117+
require.NoError(t, sshAgentCmd.Start())
118+
var found bool
119+
for i := 0; i < 100; i++ {
120+
_, err := os.Stat(sockPath)
121+
if err == nil {
122+
found = true
123+
break
124+
}
125+
time.Sleep(100 * time.Millisecond)
126+
}
127+
if !found {
128+
sshAgentOutput := sshAgentOutputBuf.String()
129+
t.Fatalf("ssh-agent failed to start: %s", sshAgentOutput)
130+
}
131+
132+
ssh, err := sshprovider.NewSSHAgentProvider([]sshprovider.AgentConfig{{
133+
Paths: []string{sockPath},
134+
}})
135+
require.NoError(t, err)
136+
137+
_, err = f.Solve(sb.Context(), c, client.SolveOpt{
138+
LocalDirs: map[string]string{
139+
dockerui.DefaultLocalNameDockerfile: dir,
140+
dockerui.DefaultLocalNameContext: dir,
141+
},
142+
Session: []session.Attachable{ssh},
143+
}, nil)
144+
require.NoError(t, err)
145+
146+
sshAgentOutput := sshAgentOutputBuf.String()
147+
require.Contains(t, sshAgentOutput, "process_message: socket 1")
148+
require.NotContains(t, sshAgentOutput, "process_message: socket 2")
149+
require.NotContains(t, sshAgentOutput, "process_message: socket 3")
150+
}

session/sshforward/copy.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ func Copy(ctx context.Context, conn io.ReadWriteCloser, stream Stream, closeStre
2424
if err == io.EOF {
2525
// indicates client performed CloseSend, but they may still be
2626
// reading data
27-
if conn, ok := conn.(interface {
27+
if closeWriter, ok := conn.(interface {
2828
CloseWrite() error
2929
}); ok {
30-
conn.CloseWrite()
30+
closeWriter.CloseWrite()
31+
} else {
32+
conn.Close()
3133
}
3234
return nil
3335
}

0 commit comments

Comments
 (0)