Skip to content

Commit 4951432

Browse files
committed
fix exit status race condition
1 parent 75f2002 commit 4951432

1 file changed

Lines changed: 17 additions & 6 deletions

File tree

packages/pam/handlers/ssh/proxy.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,16 +213,13 @@ func (p *SSHProxy) handleChannel(ctx context.Context, newChannel ssh.NewChannel,
213213
newChannel.Reject(ssh.ConnectionFailed, fmt.Sprintf("failed to open channel: %v", err))
214214
return
215215
}
216-
defer serverChannel.Close()
217-
218216
// Accept the channel from client
219217
clientChannel, clientRequests, err := newChannel.Accept()
220218
if err != nil {
221219
log.Error().Err(err).Str("sessionID", sessionID).Msg("Failed to accept client channel")
222220
serverChannel.Close()
223221
return
224222
}
225-
defer clientChannel.Close()
226223

227224
log.Info().
228225
Str("sessionID", sessionID).
@@ -232,9 +229,17 @@ func (p *SSHProxy) handleChannel(ctx context.Context, newChannel ssh.NewChannel,
232229
// Create per-channel state for tracking binary sessions (SFTP/SCP)
233230
chState := &channelState{}
234231

235-
// Handle requests for this channel (pty-req, shell, exec, etc.)
236-
go p.handleChannelRequests(clientRequests, serverChannel, sessionID, channelType, chState)
237-
go p.handleChannelRequests(serverRequests, clientChannel, sessionID, channelType, chState)
232+
// Separate done channels to ensure exit-status is forwarded before channel teardown.
233+
serverReqDone := make(chan struct{})
234+
clientReqDone := make(chan struct{})
235+
go func() {
236+
defer close(clientReqDone)
237+
p.handleChannelRequests(clientRequests, serverChannel, sessionID, channelType, chState)
238+
}()
239+
go func() {
240+
defer close(serverReqDone)
241+
p.handleChannelRequests(serverRequests, clientChannel, sessionID, channelType, chState)
242+
}()
238243

239244
// Proxy data bidirectionally with logging
240245
errChan := make(chan error, 2)
@@ -261,6 +266,12 @@ func (p *SSHProxy) handleChannel(ctx context.Context, newChannel ssh.NewChannel,
261266
log.Info().Str("sessionID", sessionID).Msg("Channel cancelled by context")
262267
}
263268

269+
// Let exit-status be forwarded before closing channels.
270+
<-serverReqDone
271+
clientChannel.Close()
272+
serverChannel.Close()
273+
<-clientReqDone
274+
264275
log.Debug().
265276
Str("sessionID", sessionID).
266277
Str("channelType", channelType).

0 commit comments

Comments
 (0)