From a9152ebf895b03f9be4eb00624b0f4aff92396ed Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Thu, 11 May 2023 15:44:24 +0100 Subject: [PATCH] copy: prevent potential deadlock if close before fully written We also need an additional check to avoid setting both the error and response which can create a race where they can arrive in the receiving thread in either order. If we hit an error, we don't need to send the response. > There is a condition where the registry (unexpectedly, not to spec) > returns 201 or 204 on the put before the body is fully written. I would > expect that the http library would issue close and could fall into a > deadlock here. We could just read respC and call setResponse. In that > case ErrClosedPipe would get returned and Commit shouldn't be called > anyway. Signed-off-by: Justin Chadwell --- core/remotes/docker/pusher.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/remotes/docker/pusher.go b/core/remotes/docker/pusher.go index 128d2fd03..f994fff5a 100644 --- a/core/remotes/docker/pusher.go +++ b/core/remotes/docker/pusher.go @@ -297,6 +297,7 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str err := remoteserrors.NewUnexpectedStatusErr(resp) log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") pushw.setError(err) + return } pushw.setResponse(resp) }() @@ -432,6 +433,8 @@ func (pw *pushWriter) Write(p []byte) (n int, err error) { pw.Close() case p := <-pw.pipeC: return 0, pw.replacePipe(p) + case resp := <-pw.respC: + pw.setResponse(resp) } } status.Offset += int64(n)