diff options
Diffstat (limited to 'libpod/container_internal.go')
-rw-r--r-- | libpod/container_internal.go | 99 |
1 files changed, 44 insertions, 55 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go index fd451f9ef..3b01ee6c8 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -21,6 +21,7 @@ import ( "github.com/containers/common/pkg/cgroups" "github.com/containers/common/pkg/chown" "github.com/containers/common/pkg/config" + cutil "github.com/containers/common/pkg/util" "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/libpod/events" "github.com/containers/podman/v4/pkg/ctime" @@ -219,7 +220,7 @@ func (c *Container) handleExitFile(exitFile string, fi os.FileInfo) error { // Write an event for the container's death c.newContainerExitedEvent(c.state.ExitCode) - return nil + return c.runtime.state.AddContainerExitCode(c.ID(), c.state.ExitCode) } func (c *Container) shouldRestart() bool { @@ -290,7 +291,7 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr err return false, err } - // setup slirp4netns again because slirp4netns will die when conmon exits + // set up slirp4netns again because slirp4netns will die when conmon exits if c.config.NetMode.IsSlirp4netns() { err := c.runtime.setupSlirp4netns(c, c.state.NetNS) if err != nil { @@ -298,7 +299,7 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr err } } - // setup rootlesskit port forwarder again since it dies when conmon exits + // set up rootlesskit port forwarder again since it dies when conmon exits // we use rootlesskit port forwarder only as rootless and when bridge network is used if rootless.IsRootless() && c.config.NetMode.IsBridge() && len(c.config.PortMappings) > 0 { err := c.runtime.setupRootlessPortMappingViaRLK(c, c.state.NetNS.Path(), c.state.NetworkStatus) @@ -589,7 +590,7 @@ func (c *Container) teardownStorage() error { } if err := c.cleanupStorage(); err != nil { - return errors.Wrapf(err, "failed to cleanup container %s storage", c.ID()) + return errors.Wrapf(err, "failed to clean up container %s storage", c.ID()) } if err := c.runtime.storageService.DeleteContainer(c.ID()); err != nil { @@ -784,20 +785,6 @@ func (c *Container) getArtifactPath(name string) string { return filepath.Join(c.config.StaticDir, artifactsDir, name) } -// Used with Wait() to determine if a container has exited -func (c *Container) isStopped() (bool, int32, error) { - if !c.batched { - c.lock.Lock() - defer c.lock.Unlock() - } - err := c.syncContainer() - if err != nil { - return true, -1, err - } - - return !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopping), c.state.ExitCode, nil -} - // save container state to the database func (c *Container) save() error { if err := c.runtime.state.SaveContainer(c); err != nil { @@ -1282,13 +1269,6 @@ func (c *Container) stop(timeout uint) error { } } - // Check if conmon is still alive. - // If it is not, we won't be getting an exit file. - conmonAlive, err := c.ociRuntime.CheckConmonRunning(c) - if err != nil { - return err - } - // Set the container state to "stopping" and unlock the container // before handing it over to conmon to unblock other commands. #8501 // demonstrates nicely that a high stop timeout will block even simple @@ -1309,8 +1289,9 @@ func (c *Container) stop(timeout uint) error { if err := c.syncContainer(); err != nil { switch errors.Cause(err) { // If the container has already been removed (e.g., via - // the cleanup process), there's nothing left to do. + // the cleanup process), set the container state to "stopped". case define.ErrNoSuchCtr, define.ErrCtrRemoved: + c.state.State = define.ContainerStateStopped return stopErr default: if stopErr != nil { @@ -1341,21 +1322,18 @@ func (c *Container) stop(timeout uint) error { } c.newContainerEvent(events.Stop) - - c.state.PID = 0 - c.state.ConmonPID = 0 c.state.StoppedByUser = true + conmonAlive, err := c.ociRuntime.CheckConmonRunning(c) + if err != nil { + return err + } if !conmonAlive { - // Conmon is dead, so we can't expect an exit code. - c.state.ExitCode = -1 - c.state.FinishedTime = time.Now() - c.state.State = define.ContainerStateStopped - if err := c.save(); err != nil { - logrus.Errorf("Saving container %s status: %v", c.ID(), err) + if err := c.checkExitFile(); err != nil { + return err } - return errors.Wrapf(define.ErrConmonDead, "container %s conmon process missing, cannot retrieve exit code", c.ID()) + return c.save() } if err := c.save(); err != nil { @@ -1663,30 +1641,16 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string) if err := vol.update(); err != nil { return nil, err } - if vol.state.NeedsCopyUp { + _, hasNoCopy := vol.config.Options["nocopy"] + if vol.state.NeedsCopyUp && !cutil.StringInSlice("nocopy", v.Options) && !hasNoCopy { logrus.Debugf("Copying up contents from container %s to volume %s", c.ID(), vol.Name()) - // If the volume is not empty, we should not copy up. - volMount := vol.mountPoint() - contents, err := ioutil.ReadDir(volMount) - if err != nil { - return nil, errors.Wrapf(err, "error listing contents of volume %s mountpoint when copying up from container %s", vol.Name(), c.ID()) - } - if len(contents) > 0 { - // The volume is not empty. It was likely modified - // outside of Podman. For safety, let's not copy up into - // it. Fixes CVE-2020-1726. - return vol, nil - } - srcDir, err := securejoin.SecureJoin(mountpoint, v.Dest) if err != nil { return nil, errors.Wrapf(err, "error calculating destination path to copy up container %s volume %s", c.ID(), vol.Name()) } // Do a manual stat on the source directory to verify existence. // Skip the rest if it exists. - // TODO: Should this be stat or lstat? I'm using lstat because I - // think copy-up doesn't happen when the source is a link. srcStat, err := os.Lstat(srcDir) if err != nil { if os.IsNotExist(err) { @@ -1712,6 +1676,19 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string) return vol, nil } + // If the volume is not empty, we should not copy up. + volMount := vol.mountPoint() + contents, err := ioutil.ReadDir(volMount) + if err != nil { + return nil, errors.Wrapf(err, "error listing contents of volume %s mountpoint when copying up from container %s", vol.Name(), c.ID()) + } + if len(contents) > 0 { + // The volume is not empty. It was likely modified + // outside of Podman. For safety, let's not copy up into + // it. Fixes CVE-2020-1726. + return vol, nil + } + // Set NeedsCopyUp to false since we are about to do first copy // Do not copy second time. vol.state.NeedsCopyUp = false @@ -1784,7 +1761,7 @@ func (c *Container) cleanupStorage() error { overlayBasePath := filepath.Dir(c.state.Mountpoint) if err := overlay.Unmount(overlayBasePath); err != nil { if cleanupErr != nil { - logrus.Errorf("Failed to cleanup overlay mounts for %s: %v", c.ID(), err) + logrus.Errorf("Failed to clean up overlay mounts for %s: %v", c.ID(), err) } cleanupErr = err } @@ -1801,7 +1778,7 @@ func (c *Container) cleanupStorage() error { if err := c.cleanupOverlayMounts(); err != nil { // If the container can't remove content report the error - logrus.Errorf("Failed to cleanup overlay mounts for %s: %v", c.ID(), err) + logrus.Errorf("Failed to clean up overlay mounts for %s: %v", c.ID(), err) cleanupErr = err } @@ -1880,7 +1857,7 @@ func (c *Container) cleanup(ctx context.Context) error { // we cannot use the dependency container lock due ABBA deadlocks if lock, err := lockfile.GetLockfile(hoststFile); err == nil { lock.Lock() - // make sure to ignore ENOENT error in case the netns container was cleanup before this one + // make sure to ignore ENOENT error in case the netns container was cleaned up before this one if err := etchosts.Remove(hoststFile, getLocalhostHostEntry(c)); err != nil && !errors.Is(err, os.ErrNotExist) { // this error is not fatal we still want to do proper cleanup logrus.Errorf("failed to remove hosts entry from the netns containers /etc/hosts: %v", err) @@ -1939,6 +1916,18 @@ func (c *Container) cleanup(ctx context.Context) error { } } + // Prune the exit codes of other container during clean up. + // Since Podman is no daemon, we have to clean them up somewhere. + // Cleanup seems like a good place as it's not performance + // critical. + if err := c.runtime.state.PruneContainerExitCodes(); err != nil { + if lastError == nil { + lastError = err + } else { + logrus.Errorf("Pruning container exit codes: %v", err) + } + } + return lastError } |