From c16b6c124496e03d1f6da1b442a56f76a9a2fa57 Mon Sep 17 00:00:00 2001 From: Tiago Silva Date: Mon, 5 May 2025 20:46:30 +0100 Subject: [PATCH] fix: fixes a possible deadlock in kube moderator joining (#54500) * fix: fixes a possible deadlock in kube moderator joining This PR addresses a bug in the Kubernetes session join logic where a joined session could hang under specific conditions. The issue occurred when one or more peers triggered multiple terminal resize events in rapid succession. The client handling the resize was only performing a single resize operation and failing to respond to subsequent events, resulting in the terminal becoming unresponsive. This led to a state where session data was no longer displayed to moderators or observers, effectively freezing the shared session view. The fix ensures proper handling of repeated resize events to maintain session responsiveness and continuity. Signed-off-by: Tiago Silva * Update lib/client/kubesession.go Co-authored-by: Zac Bergquist --------- Signed-off-by: Tiago Silva Co-authored-by: Zac Bergquist --- lib/client/kubesession.go | 44 +++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/lib/client/kubesession.go b/lib/client/kubesession.go index b55a9d79155..1037caf6226 100644 --- a/lib/client/kubesession.go +++ b/lib/client/kubesession.go @@ -136,8 +136,7 @@ func NewKubeSession(ctx context.Context, cfg KubeSessionConfig) (*KubeSession, e stdout := utils.NewSyncWriter(term.Stdout()) - go handleOutgoingResizeEvents(ctx, stream, term) - go handleIncomingResizeEvents(ctx, stream, term) + go handleResizeEvents(ctx, stream, term) s := &KubeSession{stream, term, ctx, cancel, cfg.Tracker, sync.WaitGroup{}} if err := s.handleMFA(ctx, cfg.AuthClient, cfg.Ceremony, cfg.Mode, stdout); err != nil { @@ -170,29 +169,28 @@ func kubeSessionNetDialer(ctx context.Context, cfg KubeSessionConfig) client.Con ) } -func handleOutgoingResizeEvents(ctx context.Context, stream *streamproto.SessionStream, term *terminal.Terminal) { - queue := stream.ResizeQueue() - - select { - case <-ctx.Done(): - return - case size := <-queue: - if size == nil { - return - } - - term.Resize(int16(size.Width), int16(size.Height)) - } -} - -func handleIncomingResizeEvents(ctx context.Context, stream *streamproto.SessionStream, term *terminal.Terminal) { - events := term.Subscribe() - +func handleResizeEvents(ctx context.Context, stream *streamproto.SessionStream, term *terminal.Terminal) { + streamResizes := stream.ResizeQueue() + terminalResizes := term.Subscribe() + defer stream.Close() for { select { case <-ctx.Done(): return - case event, more := <-events: + case size, more := <-streamResizes: + if !more { + return + } + if size == nil { + continue + } + if err := term.Resize(int16(size.Width), int16(size.Height)); err != nil { + fmt.Printf("Error attempting to resize terminal: %v\n\r", err) + } + case event, more := <-terminalResizes: + if !more { + return + } _, ok := event.(terminal.ResizeEvent) if ok { w, h, err := term.Size() @@ -205,10 +203,6 @@ func handleIncomingResizeEvents(ctx context.Context, stream *streamproto.Session fmt.Printf("Error attempting to resize terminal: %v\n\r", err) } } - - if !more { - return - } } } }