From 97dc3056c6d293014e71af1ad3e94c82a82b299d Mon Sep 17 00:00:00 2001 From: Tadeusz Dudkiewicz Date: Tue, 7 Jan 2025 15:13:07 +0100 Subject: [PATCH] Clear RWLayer reference under container lock Previously the RWLayer reference was cleared without holding the container lock. This could lead to goroutine panics in various places that use the container.RWLayer because nil checks introduced in #36242 where not sufficient as the reference could change right before the use. Fixes #49227 Signed-off-by: Tadeusz Dudkiewicz --- daemon/delete.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/daemon/delete.go b/daemon/delete.go index f93a89aa18..244f7acfa9 100644 --- a/daemon/delete.go +++ b/daemon/delete.go @@ -125,6 +125,10 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, config ba container.Lock() container.Dead = true + // Copy RWLayer for releasing and clear the reference while holding the container lock. + rwLayer := container.RWLayer + container.RWLayer = nil + // Save container state to disk. So that if error happens before // container meta file got removed from disk, then a restart of // docker should not make a dead container alive. @@ -135,13 +139,17 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, config ba // When container creation fails and `RWLayer` has not been created yet, we // do not call `ReleaseRWLayer` - if container.RWLayer != nil { - if err := daemon.imageService.ReleaseLayer(container.RWLayer); err != nil { + if rwLayer != nil { + if err := daemon.imageService.ReleaseLayer(rwLayer); err != nil { + // Restore the reference on error as it possibly was not released. + container.Lock() + container.RWLayer = rwLayer + container.Unlock() + err = errors.Wrapf(err, "container %s", container.ID) container.SetRemovalError(err) return err } - container.RWLayer = nil } else { if daemon.UsesSnapshotter() { ls := daemon.containerdClient.LeasesService()