From c1cce67cff49ce77187aea9dc14dcd404a4ccb56 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Mon, 28 Aug 2023 17:24:31 +0000 Subject: [PATCH 1/2] fix: avoid derp-map updates endpoint leak --- coderd/workspaceagents.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index c127b2342d4a3..3581074285dd4 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -878,13 +878,15 @@ func (api *API) derpMapUpdates(rw http.ResponseWriter, r *http.Request) { }) return } - nconn := websocket.NetConn(ctx, ws, websocket.MessageBinary) + ctx, nconn := websocketNetConn(ctx, ws, websocket.MessageBinary) defer nconn.Close() // Slurp all packets from the connection into io.Discard so pongs get sent - // by the websocket package. + // by the websocket package. We don't do any reads ourselves so this is + // necessary. go func() { _, _ = io.Copy(io.Discard, nconn) + _ = nconn.Close() }() go func(ctx context.Context) { @@ -899,13 +901,11 @@ func (api *API) derpMapUpdates(rw http.ResponseWriter, r *http.Request) { return } - // We don't need a context that times out here because the ping will - // eventually go through. If the context times out, then other - // websocket read operations will receive an error, obfuscating the - // actual problem. + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) err := ws.Ping(ctx) + cancel() if err != nil { - _ = ws.Close(websocket.StatusInternalError, err.Error()) + _ = nconn.Close() return } } From 564cfe3057086fdfcd54c15773086056794bdf66 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Mon, 28 Aug 2023 17:25:36 +0000 Subject: [PATCH 2/2] fixup! fix: avoid derp-map updates endpoint leak --- coderd/workspaceagents.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 3581074285dd4..d921bbfa72bd7 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -920,7 +920,7 @@ func (api *API) derpMapUpdates(rw http.ResponseWriter, r *http.Request) { if lastDERPMap == nil || !tailnet.CompareDERPMaps(lastDERPMap, derpMap) { err := json.NewEncoder(nconn).Encode(derpMap) if err != nil { - _ = ws.Close(websocket.StatusInternalError, err.Error()) + _ = nconn.Close() return } lastDERPMap = derpMap