From f47bc1e86e7e91cfeea4c1c21bc924afec387882 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Feb 14 2022 17:07:41 +0000 Subject: import docker-1.13.1-209.git7d71120.el7_9 --- diff --git a/.docker.metadata b/.docker.metadata index 09aeb6b..e840f26 100644 --- a/.docker.metadata +++ b/.docker.metadata @@ -1,10 +1,10 @@ d89e744b00b8ba2f3b45784a2a443670e05f9db3 SOURCES/7d71120b1f31f8bb4da733b5f1e5960b434696de.tar.gz e21d6c1b9e04650915499946bb4e6a01727c7d54 SOURCES/container-storage-setup-413b408.tar.gz -0ab6f850918d4bca8b11a06d067e37e6a146d9a0 SOURCES/containerd-9c53e35.tar.gz +65d744db00d7bce0b61933932fcab7e73b6914d9 SOURCES/containerd-46b69ea.tar.gz c5e6169ea101c97d94257f48fa227f5ff0501454 SOURCES/docker-lvm-plugin-20a1f68.tar.gz 0beb6283e30f1e87e907576f4571ccb0a48b6be5 SOURCES/docker-novolume-plugin-385ec70.tar.gz 656b1d1605dc43d7f5c00cedadd686dbd418d285 SOURCES/libnetwork-c5d66a0.tar.gz 965d64f5a81c3a428ca3b29495ecf66748c67c1f SOURCES/rhel-push-plugin-af9107b.tar.gz -76c0a865f850368f23bbb8e862e8b7aff171fbcc SOURCES/runc-66aedde.tar.gz +c5320ac925069f9007b93b2296fafbbcf0edea6f SOURCES/runc-8891bca.tar.gz 7941233b1ed34afdc074e74ab26a86dea20ee7d4 SOURCES/tini-fec3683.tar.gz 496f9927f4254508ea1cd94f473b5b9321d41245 SOURCES/v1.10-migrator-c417a6a.tar.gz diff --git a/.gitignore b/.gitignore index d6c68ef..3821448 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ SOURCES/7d71120b1f31f8bb4da733b5f1e5960b434696de.tar.gz SOURCES/container-storage-setup-413b408.tar.gz -SOURCES/containerd-9c53e35.tar.gz +SOURCES/containerd-46b69ea.tar.gz SOURCES/docker-lvm-plugin-20a1f68.tar.gz SOURCES/docker-novolume-plugin-385ec70.tar.gz SOURCES/libnetwork-c5d66a0.tar.gz SOURCES/rhel-push-plugin-af9107b.tar.gz -SOURCES/runc-66aedde.tar.gz +SOURCES/runc-8891bca.tar.gz SOURCES/tini-fec3683.tar.gz SOURCES/v1.10-migrator-c417a6a.tar.gz diff --git a/SOURCES/1.patch b/SOURCES/1.patch deleted file mode 100644 index c4f8e4c..0000000 --- a/SOURCES/1.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 40fd67a5303214be8a6aeb30e4f30735dcaf3094 Mon Sep 17 00:00:00 2001 -From: y00316549 -Date: Thu, 11 Jan 2018 20:16:18 +0800 -Subject: [PATCH] Security: fix mem leak in containerd - -Change-Id: I79df63093835a28ff23074ebc0f75fffac592e66 -Signed-off-by: Shukui Yang -(cherry picked from commit 64456eccb7443ab68b1b5cf0c33be51fdfe5e346) -Signed-off-by: Kir Kolyshkin ---- - supervisor/delete.go | 7 +++++-- - supervisor/exit.go | 1 + - supervisor/supervisor.go | 8 ++++++-- - 3 files changed, 12 insertions(+), 4 deletions(-) - -diff --git a/supervisor/delete.go b/supervisor/delete.go -index 26cf1bb..9cf517f 100644 ---- a/containerd-9c53e35c39f214b128beed3dfb670ccf751c4173/supervisor/delete.go -+++ b/containerd-9c53e35c39f214b128beed3dfb670ccf751c4173/supervisor/delete.go -@@ -27,11 +27,14 @@ func (s *Supervisor) delete(t *DeleteTask) error { - t.Process.Wait() - } - if !t.NoEvent { -- execMap := s.getExecSyncMap(t.ID) - go func() { - // Wait for all exec processe events to be sent (we seem - // to sometimes receive them after the init event) -- for _, ch := range execMap { -+ for { -+ ch := s.getExecSyncOneChannel(t.ID) -+ if ch == nil { -+ break -+ } - <-ch - } - s.deleteExecSyncMap(t.ID) -diff --git a/supervisor/exit.go b/supervisor/exit.go -index 2bce31e..537927b 100644 ---- a/containerd-9c53e35c39f214b128beed3dfb670ccf751c4173/supervisor/exit.go -+++ b/containerd-9c53e35c39f214b128beed3dfb670ccf751c4173/supervisor/exit.go -@@ -89,6 +89,7 @@ func (s *Supervisor) execExit(t *ExecExitTask) error { - PID: t.PID, - Status: t.Status, - }) -+ s.deleteExecSyncChannel(t.ID, t.PID) - close(synCh) - }() - return nil -diff --git a/supervisor/supervisor.go b/supervisor/supervisor.go -index e21ae7b..bbb001c 100644 ---- a/containerd-9c53e35c39f214b128beed3dfb670ccf751c4173/supervisor/supervisor.go -+++ b/containerd-9c53e35c39f214b128beed3dfb670ccf751c4173/supervisor/supervisor.go -@@ -479,10 +479,14 @@ func (s *Supervisor) getExecSyncChannel(containerID, pid string) chan struct{} { - return ch - } - --func (s *Supervisor) getExecSyncMap(containerID string) map[string]chan struct{} { -+func (s *Supervisor) getExecSyncOneChannel(containerID string) chan struct{} { - s.containerExecSyncLock.Lock() - defer s.containerExecSyncLock.Unlock() -- return s.containerExecSync[containerID] -+ -+ for _, ch := range s.containerExecSync[containerID] { -+ return ch -+ } -+ return nil - } - - func (s *Supervisor) deleteExecSyncMap(containerID string) { diff --git a/SOURCES/30.patch b/SOURCES/30.patch deleted file mode 100644 index db8fee1..0000000 --- a/SOURCES/30.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 44f6033c48968945353109af69114b5d0a1700de Mon Sep 17 00:00:00 2001 -From: Jhon Honce -Date: Fri, 11 Oct 2019 16:08:59 -0700 -Subject: [PATCH] Check for both nil and zero length - -Signed-off-by: Jhon Honce ---- - libcontainer/generic_error.go | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/libcontainer/generic_error.go b/libcontainer/generic_error.go -index de37715c..0f90369b 100644 ---- a/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/generic_error.go -+++ b/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/generic_error.go -@@ -93,6 +93,10 @@ func (e *genericError) Error() string { - if e.Cause == "" { - return e.Message - } -+ -+ if len(e.Stack.Frames) == 0 { -+ return fmt.Sprintf(":: %s caused %q", e.Cause, e.Message) -+ } - frame := e.Stack.Frames[0] - return fmt.Sprintf("%s:%d: %s caused %q", frame.File, frame.Line, e.Cause, e.Message) - } diff --git a/SOURCES/54.patch b/SOURCES/54.patch deleted file mode 100644 index 0af3708..0000000 --- a/SOURCES/54.patch +++ /dev/null @@ -1,397 +0,0 @@ -From 2a572d2d825735493a981b03b48877940ea2c17a Mon Sep 17 00:00:00 2001 -From: Kir Kolyshkin -Date: Mon, 17 May 2021 14:11:35 -0700 -Subject: [PATCH] rootfs: add mount destination validation - -This is a manual backport of the CVE-2021-30465 fix. Original -description follows. - ---- - -Because the target of a mount is inside a container (which may be a -volume that is shared with another container), there exists a race -condition where the target of the mount may change to a path containing -a symlink after we have sanitised the path -- resulting in us -inadvertently mounting the path outside of the container. - -This is not immediately useful because we are in a mount namespace with -MS_SLAVE mount propagation applied to "/", so we cannot mount on top of -host paths in the host namespace. However, if any subsequent mountpoints -in the configuration use a subdirectory of that host path as a source, -those subsequent mounts will use an attacker-controlled source path -(resolved within the host rootfs) -- allowing the bind-mounting of "/" -into the container. - -While arguably configuration issues like this are not entirely within -runc's threat model, within the context of Kubernetes (and possibly -other container managers that provide semi-arbitrary container creation -privileges to untrusted users) this is a legitimate issue. Since we -cannot block mounting from the host into the container, we need to block -the first stage of this attack (mounting onto a path outside the -container). - -The long-term plan to solve this would be to migrate to libpathrs, but -as a stop-gap we implement libpathrs-like path verification through -readlink(/proc/self/fd/$n) and then do mount operations through the -procfd once it's been verified to be inside the container. The target -could move after we've checked it, but if it is inside the container -then we can assume that it is safe for the same reason that libpathrs -operations would be safe. - -A slight wrinkle is the "copyup" functionality we provide for tmpfs, -which is the only case where we want to do a mount on the host -filesystem. To facilitate this, I split out the copy-up functionality -entirely so that the logic isn't interspersed with the regular tmpfs -logic. In addition, all dependencies on m.Destination being overwritten -have been removed since that pattern was just begging to be a source of -more mount-target bugs (we do still have to modify m.Destination for -tmpfs-copyup but we only do it temporarily). - -Fixes: CVE-2021-30465 -Reported-by: Etienne Champetier -Co-authored-by: Noah Meyerhans -Reviewed-by: Samuel Karp -Reviewed-by: Akihiro Suda -Signed-off-by: Aleksa Sarai - -Signed-off-by: Kir Kolyshkin ---- - libcontainer/rootfs_linux.go | 154 +++++++++++++++++++---------------- - libcontainer/utils/utils.go | 56 +++++++++++++ - 2 files changed, 139 insertions(+), 71 deletions(-) - -diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go -index 42b66141..984fe289 100644 ---- a/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/rootfs_linux.go -+++ b/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/rootfs_linux.go -@@ -14,6 +14,7 @@ import ( - "syscall" - "time" - -+ "github.com/Sirupsen/logrus" - securejoin "github.com/cyphar/filepath-securejoin" - "github.com/docker/docker/pkg/mount" - "github.com/mrunalp/fileutils" -@@ -145,8 +146,6 @@ func prepareBindMount(m *configs.Mount, rootfs string) error { - if err := checkProcMount(rootfs, dest, m.Source); err != nil { - return err - } -- // update the mount with the correct dest after symlinks are resolved. -- m.Destination = dest - if err := createIfNotExists(dest, stat.IsDir()); err != nil { - return err - } -@@ -154,12 +153,50 @@ func prepareBindMount(m *configs.Mount, rootfs string) error { - return nil - } - -+func doTmpfsCopyUp(m *configs.Mount, rootfs, mountLabel string) (Err error) { -+ // Set up a scratch dir for the tmpfs on the host. -+ tmpDir, err := ioutil.TempDir("/tmp", "runctmpdir") -+ if err != nil { -+ return newSystemErrorWithCause(err, "tmpcopyup: failed to create tmpdir") -+ } -+ defer os.RemoveAll(tmpDir) -+ -+ // Configure the *host* tmpdir as if it's the container mount. We change -+ // m.Destination since we are going to mount *on the host*. -+ oldDest := m.Destination -+ m.Destination = tmpDir -+ err = mountPropagate(m, "/", mountLabel) -+ m.Destination = oldDest -+ if err != nil { -+ return err -+ } -+ defer func() { -+ if Err != nil { -+ if err := syscall.Unmount(tmpDir, syscall.MNT_DETACH); err != nil { -+ logrus.Warnf("tmpcopyup: failed to unmount tmpdir on error: %v", err) -+ } -+ } -+ }() -+ -+ return libcontainerUtils.WithProcfd(rootfs, m.Destination, func(procfd string) (Err error) { -+ // Copy the container data to the host tmpdir. We append "/" to force -+ // CopyDirectory to resolve the symlink rather than trying to copy the -+ // symlink itself. -+ if err := fileutils.CopyDirectory(procfd+"/", tmpDir); err != nil { -+ return fmt.Errorf("tmpcopyup: failed to copy %s to %s (%s): %v", m.Destination, procfd, tmpDir, err) -+ } -+ // Now move the mount into the container. -+ if err := syscall.Mount(tmpDir, procfd, "", syscall.MS_MOVE, ""); err != nil { -+ return fmt.Errorf("tmpcopyup: failed to move mount %s to %s (%s): %v", tmpDir, procfd, m.Destination, err) -+ } -+ return nil -+ }) -+} -+ - func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { -- var ( -- dest = m.Destination -- ) -- if !strings.HasPrefix(dest, rootfs) { -- dest = filepath.Join(rootfs, dest) -+ dest, err := securejoin.SecureJoin(rootfs, m.Destination) -+ if err != nil { -+ return err - } - - switch m.Device { -@@ -182,41 +219,20 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { - } - return nil - case "tmpfs": -- copyUp := m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP -- tmpDir := "" - stat, err := os.Stat(dest) - if err != nil { - if err := os.MkdirAll(dest, 0755); err != nil { - return err - } - } -- if copyUp { -- tmpDir, err = ioutil.TempDir("/tmp", "runctmpdir") -- if err != nil { -- return newSystemErrorWithCause(err, "tmpcopyup: failed to create tmpdir") -- } -- defer os.RemoveAll(tmpDir) -- m.Destination = tmpDir -+ if m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP { -+ err = doTmpfsCopyUp(m, rootfs, mountLabel) -+ } else { -+ err = mountPropagate(m, rootfs, mountLabel) - } -- if err := mountPropagate(m, rootfs, mountLabel); err != nil { -+ if err != nil { - return err - } -- if copyUp { -- if err := fileutils.CopyDirectory(dest, tmpDir); err != nil { -- errMsg := fmt.Errorf("tmpcopyup: failed to copy %s to %s: %v", dest, tmpDir, err) -- if err1 := syscall.Unmount(tmpDir, syscall.MNT_DETACH); err1 != nil { -- return newSystemErrorWithCausef(err1, "tmpcopyup: %v: failed to unmount", errMsg) -- } -- return errMsg -- } -- if err := syscall.Mount(tmpDir, dest, "", syscall.MS_MOVE, ""); err != nil { -- errMsg := fmt.Errorf("tmpcopyup: failed to move mount %s to %s: %v", tmpDir, dest, err) -- if err1 := syscall.Unmount(tmpDir, syscall.MNT_DETACH); err1 != nil { -- return newSystemErrorWithCausef(err1, "tmpcopyup: %v: failed to unmount", errMsg) -- } -- return errMsg -- } -- } - if stat != nil { - if err = os.Chmod(dest, stat.Mode()); err != nil { - return err -@@ -299,19 +315,9 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { - } - } - default: -- // ensure that the destination of the mount is resolved of symlinks at mount time because -- // any previous mounts can invalidate the next mount's destination. -- // this can happen when a user specifies mounts within other mounts to cause breakouts or other -- // evil stuff to try to escape the container's rootfs. -- var err error -- if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { -- return err -- } - if err := checkProcMount(rootfs, dest, m.Source); err != nil { - return err - } -- // update the mount with the correct dest after symlinks are resolved. -- m.Destination = dest - if err := os.MkdirAll(dest, 0755); err != nil { - return err - } -@@ -485,7 +491,7 @@ func createDevices(config *configs.Config) error { - return nil - } - --func bindMountDeviceNode(dest string, node *configs.Device) error { -+func bindMountDeviceNode(rootfs, dest string, node *configs.Device) error { - f, err := os.Create(dest) - if err != nil && !os.IsExist(err) { - return err -@@ -493,24 +499,29 @@ func bindMountDeviceNode(dest string, node *configs.Device) error { - if f != nil { - f.Close() - } -- return syscall.Mount(node.Path, dest, "bind", syscall.MS_BIND, "") -+ return libcontainerUtils.WithProcfd(rootfs, dest, func(procfd string) error { -+ return syscall.Mount(node.Path, procfd, "bind", syscall.MS_BIND, "") -+ }) - } - - // Creates the device node in the rootfs of the container. - func createDeviceNode(rootfs string, node *configs.Device, bind bool) error { -- dest := filepath.Join(rootfs, node.Path) -+ dest, err := securejoin.SecureJoin(rootfs, node.Path) -+ if err != nil { -+ return err -+ } - if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil { - return err - } - - if bind { -- return bindMountDeviceNode(dest, node) -+ return bindMountDeviceNode(rootfs, dest, node) - } - if err := mknodDevice(dest, node); err != nil { - if os.IsExist(err) { - return nil - } else if os.IsPermission(err) { -- return bindMountDeviceNode(dest, node) -+ return bindMountDeviceNode(rootfs, dest, node) - } - return err - } -@@ -807,43 +818,44 @@ func writeSystemProperty(key, value string) error { - } - - func remount(m *configs.Mount, rootfs string) error { -- var ( -- dest = m.Destination -- ) -- if !strings.HasPrefix(dest, rootfs) { -- dest = filepath.Join(rootfs, dest) -- } -- if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags|syscall.MS_REMOUNT), ""); err != nil { -- return err -- } -- return nil -+ return libcontainerUtils.WithProcfd(rootfs, m.Destination, func(procfd string) error { -+ return syscall.Mount(m.Source, procfd, m.Device, uintptr(m.Flags|syscall.MS_REMOUNT), "") -+ }) - } - - // Do the mount operation followed by additional mounts required to take care --// of propagation flags. -+// of propagation flags. This will always be scoped inside the container rootfs. - func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error { - var ( -- dest = m.Destination - data = label.FormatMountLabel(m.Data, mountLabel) - flags = m.Flags - ) -- if libcontainerUtils.CleanPath(dest) == "/dev" { -+ if libcontainerUtils.CleanPath(m.Destination) == "/dev" { - flags &= ^syscall.MS_RDONLY - } - -- copyUp := m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP -- if !(copyUp || strings.HasPrefix(dest, rootfs)) { -- dest = filepath.Join(rootfs, dest) -+ // Because the destination is inside a container path which might be -+ // mutating underneath us, we verify that we are actually going to mount -+ // inside the container with WithProcfd() -- mounting through a procfd -+ // mounts on the target. -+ if err := libcontainerUtils.WithProcfd(rootfs, m.Destination, func(procfd string) error { -+ return syscall.Mount(m.Source, procfd, m.Device, uintptr(flags), data) -+ }); err != nil { -+ return fmt.Errorf("mount through procfd: %v", err) - } - -- if err := syscall.Mount(m.Source, dest, m.Device, uintptr(flags), data); err != nil { -- return err -- } -- -- for _, pflag := range m.PropagationFlags { -- if err := syscall.Mount("", dest, "", uintptr(pflag), ""); err != nil { -- return err -+ // We have to apply mount propagation flags in a separate WithProcfd() call -+ // because the previous call invalidates the passed procfd -- the mount -+ // target needs to be re-opened. -+ if err := libcontainerUtils.WithProcfd(rootfs, m.Destination, func(procfd string) error { -+ for _, pflag := range m.PropagationFlags { -+ if err := syscall.Mount("", procfd, "", uintptr(pflag), ""); err != nil { -+ return err -+ } - } -+ return nil -+ }); err != nil { -+ return fmt.Errorf("change mount propagation through procfd: %v", err) - } - return nil - } -diff --git a/libcontainer/utils/utils.go b/libcontainer/utils/utils.go -index 2b35b9a7..a89fc6a2 100644 ---- a/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/utils/utils.go -+++ b/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/utils/utils.go -@@ -4,12 +4,17 @@ import ( - "crypto/rand" - "encoding/hex" - "encoding/json" -+ "fmt" - "io" - "os" - "path/filepath" -+ "strconv" - "strings" - "syscall" - "unsafe" -+ -+ securejoin "github.com/cyphar/filepath-securejoin" -+ "golang.org/x/sys/unix" - ) - - const ( -@@ -87,6 +92,57 @@ func CleanPath(path string) string { - return filepath.Clean(path) - } - -+// stripRoot returns the passed path, stripping the root path if it was -+// (lexicially) inside it. Note that both passed paths will always be treated -+// as absolute, and the returned path will also always be absolute. In -+// addition, the paths are cleaned before stripping the root. -+func stripRoot(root, path string) string { -+ // Make the paths clean and absolute. -+ root, path = CleanPath("/"+root), CleanPath("/"+path) -+ switch { -+ case path == root: -+ path = "/" -+ case root == "/": -+ // do nothing -+ case strings.HasPrefix(path, root+"/"): -+ path = strings.TrimPrefix(path, root+"/") -+ } -+ return CleanPath("/" + path) -+} -+ -+// WithProcfd runs the passed closure with a procfd path (/proc/self/fd/...) -+// corresponding to the unsafePath resolved within the root. Before passing the -+// fd, this path is verified to have been inside the root -- so operating on it -+// through the passed fdpath should be safe. Do not access this path through -+// the original path strings, and do not attempt to use the pathname outside of -+// the passed closure (the file handle will be freed once the closure returns). -+func WithProcfd(root, unsafePath string, fn func(procfd string) error) error { -+ // Remove the root then forcefully resolve inside the root. -+ unsafePath = stripRoot(root, unsafePath) -+ path, err := securejoin.SecureJoin(root, unsafePath) -+ if err != nil { -+ return fmt.Errorf("resolving path inside rootfs failed: %v", err) -+ } -+ -+ // Open the target path. -+ fh, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC, 0) -+ if err != nil { -+ return fmt.Errorf("open o_path procfd: %v", err) -+ } -+ defer fh.Close() -+ -+ // Double-check the path is the one we expected. -+ procfd := "/proc/self/fd/" + strconv.Itoa(int(fh.Fd())) -+ if realpath, err := os.Readlink(procfd); err != nil { -+ return fmt.Errorf("procfd verification failed: %v", err) -+ } else if realpath != path { -+ return fmt.Errorf("possibly malicious path detected -- refusing to operate on %s", realpath) -+ } -+ -+ // Run the closure. -+ return fn(procfd) -+} -+ - // SearchLabels searches a list of key-value pairs for the provided key and - // returns the corresponding value. The pairs must be separated with '='. - func SearchLabels(labels []string, query string) string { diff --git a/SOURCES/69518f0bbdb1f11113f46a4d794e09e2f21f5e91.patch b/SOURCES/69518f0bbdb1f11113f46a4d794e09e2f21f5e91.patch deleted file mode 100644 index 90ce818..0000000 --- a/SOURCES/69518f0bbdb1f11113f46a4d794e09e2f21f5e91.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 69518f0bbdb1f11113f46a4d794e09e2f21f5e91 Mon Sep 17 00:00:00 2001 -From: Ulrich Obergfell -Date: Thu, 10 Oct 2019 11:59:44 +0200 -Subject: [PATCH] fix error handling in restore() function - version 2 - -If runtime.Load() returns an error, the restore() function removes the -/run/docker/libcontainerd/containerd/CONTAINERID directory recursively. -However, this is wrong if the error is not related to the init process -of the container. - -This patch introduces the following changes to the runtime.Load() function: - -- runtime.Load() handles errors from readProcessState() autonomously. The - /run/docker/libcontainerd/containerd/CONTAINERID/PROCESSID directory will - be removed recursively, and a warning message will be logged. - -- Errors returned by runtime.Load() are always related to the init process, - so restore() may remove /run/docker/libcontainerd/containerd/CONTAINERID. - -Signed-off-by: Ulrich Obergfell ---- - runtime/container.go | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/runtime/container.go b/runtime/container.go -index 2e9e663..489e407 100644 ---- a/runtime/container.go -+++ b/runtime/container.go -@@ -182,11 +182,14 @@ func Load(root, id, shimName string, timeout time.Duration) (Container, error) { - continue - } - pid := d.Name() -- s, err := readProcessState(filepath.Join(root, id, pid)) -+ processStateDir := filepath.Join(root, id, pid) -+ s, err := readProcessState(processStateDir) - if err != nil { -- return nil, err -+ logrus.WithFields(logrus.Fields{"error": err, "pid": pid}).Warnf("containerd: failed to load exec process,removing state directory.") -+ os.RemoveAll(processStateDir) -+ continue - } -- p, err := loadProcess(filepath.Join(root, id, pid), pid, c, s) -+ p, err := loadProcess(processStateDir, pid, c, s) - if err != nil { - logrus.WithField("id", id).WithField("pid", pid).Debugf("containerd: error loading process %s", err) - continue diff --git a/SOURCES/97eff6cf6c9b58f8239b28be2f080e23c9da62c0.patch b/SOURCES/97eff6cf6c9b58f8239b28be2f080e23c9da62c0.patch deleted file mode 100644 index 2134937..0000000 --- a/SOURCES/97eff6cf6c9b58f8239b28be2f080e23c9da62c0.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 97eff6cf6c9b58f8239b28be2f080e23c9da62c0 Mon Sep 17 00:00:00 2001 -From: Ulrich Obergfell -Date: Thu, 11 Jul 2019 14:33:55 +0200 -Subject: [PATCH] fix deadlock in restore() function - -When containerd starts up, the restore() function walks through the directory -hierarchy under /run/docker/libcontainerd/containerd and imports the state of -processes from files in /run/docker/libcontainerd/containerd/CONTAINERID and -in /run/docker/libcontainerd/containerd/CONTAINERID/PROCESSID. The restore() -function adds an ExitTask entry to the s.tasks queue for each process that is -no longer in state 'running'. The size of the s.tasks queue is hard-coded and -limited to 2048 (defaultBufferSize). If more than 2048 ExitTask entries need -to be added to the queue, the restore() function gets blocked (queue is full). -If this happens, containerd is in a kind of deadlock situation because the -handleTask() function (which would drain the ExitTask entries from the queue) -has not been started in a separate goroutine yet, and the main goroutine is -blocked in the restore() function (unable to start the handleTask() function). - -This patch introduces the dynamically allocated restoreExitTasks slice which -the restore() function uses to store the ExitTask entries separately instead -of adding them to the s.tasks queue. The task handler goroutine subsequently -drains all entries from restoreExitTasks frist before it enters the loop that -handles entries from the s.tasks queue. - -Signed-off-by: Ulrich Obergfell ---- - supervisor/supervisor.go | 35 +++++++++++++++++++++++++++++++++-- - 1 file changed, 33 insertions(+), 2 deletions(-) - -diff --git a/supervisor/supervisor.go b/supervisor/supervisor.go -index 8a26af0..d92de8a 100644 ---- a/supervisor/supervisor.go -+++ b/supervisor/supervisor.go -@@ -18,6 +18,16 @@ const ( - defaultBufferSize = 2048 // size of queue in eventloop - ) - -+// Pointers to all ExitTask that are created by the restore() function are stored in this slice. -+var restoreExitTasks []*ExitTask -+ -+func max(x, y int) int { -+ if x < y { -+ return y -+ } -+ return x -+} -+ - // New returns an initialized Process supervisor. - func New(stateDir string, runtimeName, shimName string, runtimeArgs []string, timeout time.Duration, retainCount int) (*Supervisor, error) { - startTasks := make(chan *startTask, 10) -@@ -207,7 +217,9 @@ type eventV1 struct { - // Events returns an event channel that external consumers can use to receive updates - // on container events - func (s *Supervisor) Events(from time.Time, storedOnly bool, id string) chan Event { -- c := make(chan Event, defaultBufferSize) -+ var c chan Event -+ -+ c = make(chan Event, defaultBufferSize) - if storedOnly { - defer s.Unsubscribe(c) - } -@@ -216,6 +228,9 @@ func (s *Supervisor) Events(from time.Time, storedOnly bool, id string) chan Eve - if !from.IsZero() { - // replay old event - s.eventLock.Lock() -+ close(c) -+ // Allocate a channel that has enough space for the entire event log. -+ c = make(chan Event, max(defaultBufferSize, len(s.eventLog))) - past := s.eventLog[:] - s.eventLock.Unlock() - for _, e := range past { -@@ -276,6 +291,21 @@ func (s *Supervisor) Start() error { - "cpus": s.machine.Cpus, - }).Debug("containerd: supervisor running") - go func() { -+ if (len(restoreExitTasks) > 0) { -+ logrus.Infof("containerd: found %d exited processes after restart", len(restoreExitTasks)) -+ // -+ // If the restore() function stored any ExitTask in the dedicated slice, -+ // then handle those tasks first. The purpose of the one second delay is -+ // to give dockerd a chance to establish its event stream connection to -+ // containerd. If the connection is established before the ExitTask are -+ // being handled, then dockerd can receive exit notifications directly -+ // (rather than having to replay the notifications from the event log). -+ // -+ time.Sleep(time.Second) -+ for _, e := range restoreExitTasks { -+ s.handleTask(e) -+ } -+ } - for i := range s.tasks { - s.handleTask(i) - } -@@ -385,7 +415,8 @@ func (s *Supervisor) restore() error { - Process: p, - } - e.WithContext(context.Background()) -- s.SendTask(e) -+ // Store pointer to ExitTask in dedicated slice. -+ restoreExitTasks = append(restoreExitTasks, e) - } - } - } diff --git a/SOURCES/docker-1787148.patch b/SOURCES/docker-1787148.patch index 7a86c3a..376889d 100644 --- a/SOURCES/docker-1787148.patch +++ b/SOURCES/docker-1787148.patch @@ -1,6 +1,6 @@ diff -up docker-0be3e217c42ecf554bf5117bec9c832bd3f3b6fd/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go.orig docker-0be3e217c42ecf554bf5117bec9c832bd3f3b6fd/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go ---- docker-0be3e217c42ecf554bf5117bec9c832bd3f3b6fd/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go.orig 2021-02-12 11:34:42.913036670 +0100 -+++ docker-0be3e217c42ecf554bf5117bec9c832bd3f3b6fd/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go 2021-02-12 11:37:14.165696606 +0100 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/cgroups/systemd/apply_systemd.go.orig 2021-02-12 11:34:42.913036670 +0100 ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/cgroups/systemd/apply_systemd.go 2021-02-12 11:37:14.165696606 +0100 @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" diff --git a/SOURCES/docker-1879425.patch b/SOURCES/docker-1879425.patch deleted file mode 100644 index 149cc33..0000000 --- a/SOURCES/docker-1879425.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0f90cc1ecb2db92e5388e07b8662b6c4a3a64f6c Mon Sep 17 00:00:00 2001 -From: Kir Kolyshkin -Date: Tue, 15 Sep 2020 21:46:32 -0700 -Subject: [PATCH] runc run: fix panic on error - -In case (*initProcess).start did not set sentRun, and ierr is nil, -runc run panics: - -``` -panic: runtime error: invalid memory address or nil pointer dereference [recovered] - panic: runtime error: invalid memory address or nil pointer dereference -[signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x68a117] - -goroutine 1 [running]: -github.com/urfave/cli.HandleAction.func1(0xc0002277d8) - /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:478 +0x22d -panic(0x730b60, 0xa06fc0) - /usr/lib/golang/src/runtime/panic.go:969 +0x166 -github.com/opencontainers/runc/libcontainer.(*genericError).Error(0x0, 0xc0002ca0e0, 0xe) - /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/generic_error.go:93 +0x37 -github.com/opencontainers/runc/libcontainer.createSystemError(0x7fcd20, 0x0, 0x78c23e, 0xe, 0xc000098050, 0x0) - /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/generic_error.go:78 +0x14c -github.com/opencontainers/runc/libcontainer.newSystemErrorWithCause(...) - /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/generic_error.go:63 -github.com/opencontainers/runc/libcontainer.(*initProcess).start(0xc000298000, 0x0, 0x0) - /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/process_linux.go:361 +0x94b -.... -``` - -This is caused by the fact that `ierr` is a typed variable (rather than a -generic `error`), and when `newSystemErrorWithCause(ierr, ...)` is called -with a typed variable, the check `if err != nil` in `createSystemError` -does not work, since err has a type. This Golang peculiarity is described -in https://golang.org/doc/faq#nil_error. - -After this patch (tested by temporarily modifying the source to set -`sentRun` to `false`) it no longer panics, instead we get: - -``` -container_linux.go:247: starting container process caused "container init failed" -``` - -Signed-off-by: Kir Kolyshkin ---- - libcontainer/process_linux.go | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go -index 7c92c93a..53df9fa5 100644 ---- docker-0be3e217c42ecf554bf5117bec9c832bd3f3b6fd/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/process_linux.go -+++ docker-0be3e217c42ecf554bf5117bec9c832bd3f3b6fd/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/process_linux.go -@@ -364,7 +364,10 @@ loop: - return newSystemError(fmt.Errorf("container init exited prematurely")) - } - if !sentRun { -- return newSystemErrorWithCause(ierr, "container init") -+ if ierr != nil { -+ return newSystemErrorWithCause(ierr, "container init") -+ } -+ return newSystemError(errors.New("container init failed")) - } - if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume { - return newSystemError(fmt.Errorf("could not synchronise after executing prestart hooks with container process")) diff --git a/SOURCES/docker-2000782.patch b/SOURCES/docker-2000782.patch new file mode 100644 index 0000000..57ac124 --- /dev/null +++ b/SOURCES/docker-2000782.patch @@ -0,0 +1,865 @@ +From 78b46ab8595c094da910c338839455d8386d57b8 Mon Sep 17 00:00:00 2001 +From: "W. Trevor King" +Date: Wed, 14 Jun 2017 15:27:42 -0700 +Subject: [PATCH 1/6] libcontainer/system/proc: Add Stat and Stat_t + +So we can extract more than the start time with a single read. + +Signed-off-by: W. Trevor King +(cherry picked from commit 439eaa3584402d239297f278cc1f22c08dbdcc17) +Signed-off-by: Kir Kolyshkin +--- + libcontainer/system/proc.go | 35 ++++++++++++++++++++++++++------ + libcontainer/system/proc_test.go | 8 ++++---- + 2 files changed, 33 insertions(+), 10 deletions(-) + +diff --git a/libcontainer/system/proc.go b/libcontainer/system/proc.go +index a0e96371..4ffb8331 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/system/proc.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/system/proc.go +@@ -1,23 +1,43 @@ + package system + + import ( ++ "fmt" + "io/ioutil" + "path/filepath" + "strconv" + "strings" + ) + +-// look in /proc to find the process start time so that we can verify +-// that this pid has started after ourself ++// Stat_t represents the information from /proc/[pid]/stat, as ++// described in proc(5). ++type Stat_t struct { ++ // StartTime is the number of clock ticks after system boot (since ++ // Linux 2.6). ++ StartTime uint64 ++} ++ ++// Stat returns a Stat_t instance for the specified process. ++func Stat(pid int) (stat Stat_t, err error) { ++ bytes, err := ioutil.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat")) ++ if err != nil { ++ return stat, err ++ } ++ data := string(bytes) ++ stat.StartTime, err = parseStartTime(data) ++ return stat, err ++} ++ ++// GetProcessStartTime is deprecated. Use Stat(pid) and ++// Stat_t.StartTime instead. + func GetProcessStartTime(pid int) (string, error) { +- data, err := ioutil.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat")) ++ stat, err := Stat(pid) + if err != nil { + return "", err + } +- return parseStartTime(string(data)) ++ return fmt.Sprintf("%d", stat.StartTime), nil + } + +-func parseStartTime(stat string) (string, error) { ++func parseStartTime(stat string) (uint64, error) { + // the starttime is located at pos 22 + // from the man page + // +@@ -39,5 +59,8 @@ func parseStartTime(stat string) (string, error) { + // get parts after last `)`: + s := strings.Split(stat, ")") + parts := strings.Split(strings.TrimSpace(s[len(s)-1]), " ") +- return parts[22-3], nil // starts at 3 (after the filename pos `2`) ++ startTimeString := parts[22-3] // starts at 3 (after the filename pos `2`) ++ var startTime uint64 ++ fmt.Sscanf(startTimeString, "%d", &startTime) ++ return startTime, nil + } +diff --git a/libcontainer/system/proc_test.go b/libcontainer/system/proc_test.go +index ba910291..c7615ef9 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/system/proc_test.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/system/proc_test.go +@@ -3,10 +3,10 @@ package system + import "testing" + + func TestParseStartTime(t *testing.T) { +- data := map[string]string{ +- "4902 (gunicorn: maste) S 4885 4902 4902 0 -1 4194560 29683 29929 61 83 78 16 96 17 20 0 1 0 9126532 52965376 1903 18446744073709551615 4194304 7461796 140733928751520 140733928698072 139816984959091 0 0 16781312 137447943 1 0 0 17 3 0 0 9 0 0 9559488 10071156 33050624 140733928758775 140733928758945 140733928758945 140733928759264 0": "9126532", +- "9534 (cat) R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": "9214966", +- "24767 (irq/44-mei_me) S 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 -51 0 1 0 8722075 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 50 1 0 0 0 0 0 0 0 0 0 0 0": "8722075", ++ data := map[string]uint64{ ++ "4902 (gunicorn: maste) S 4885 4902 4902 0 -1 4194560 29683 29929 61 83 78 16 96 17 20 0 1 0 9126532 52965376 1903 18446744073709551615 4194304 7461796 140733928751520 140733928698072 139816984959091 0 0 16781312 137447943 1 0 0 17 3 0 0 9 0 0 9559488 10071156 33050624 140733928758775 140733928758945 140733928758945 140733928759264 0": 9126532, ++ "9534 (cat) R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": 9214966, ++ "24767 (irq/44-mei_me) S 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 -51 0 1 0 8722075 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 50 1 0 0 0 0 0 0 0 0 0 0 0": 8722075, + } + for line, startTime := range data { + st, err := parseStartTime(line) + +From c96dfcb196a08557e0ff434c2c190c288fb1b787 Mon Sep 17 00:00:00 2001 +From: "W. Trevor King" +Date: Wed, 14 Jun 2017 15:38:45 -0700 +Subject: [PATCH 2/6] libcontainer: Replace GetProcessStartTime with + Stat_t.StartTime + +And convert the various start-time properties from strings to uint64s. +This removes all internal consumers of the deprecated +GetProcessStartTime function. + +Signed-off-by: W. Trevor King +(cherry picked from commit 75d98b26b7acb0023b990a7305a2553c6dbc12d4) +Signed-off-by: Kir Kolyshkin +--- + libcontainer/container.go | 2 +- + libcontainer/container_linux.go | 10 +++++----- + libcontainer/container_linux_test.go | 10 +++++----- + libcontainer/process_linux.go | 12 +++++++----- + libcontainer/restored_process.go | 12 ++++++------ + 5 files changed, 24 insertions(+), 22 deletions(-) + +diff --git a/libcontainer/container.go b/libcontainer/container.go +index d51b159b..899925dd 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container.go +@@ -54,7 +54,7 @@ type BaseState struct { + InitProcessPid int `json:"init_process_pid"` + + // InitProcessStartTime is the init process start time in clock cycles since boot time. +- InitProcessStartTime string `json:"init_process_start"` ++ InitProcessStartTime uint64 `json:"init_process_start"` + + // Created is the unix timestamp for the creation time of the container in UTC + Created time.Time `json:"created"` +diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go +index 45688d60..98efcfcc 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go +@@ -37,7 +37,7 @@ type linuxContainer struct { + cgroupManager cgroups.Manager + initArgs []string + initProcess parentProcess +- initProcessStartTime string ++ initProcessStartTime uint64 + criuPath string + m sync.Mutex + criuVersion int +@@ -1117,11 +1117,11 @@ func (c *linuxContainer) refreshState() error { + // and a new process has been created with the same pid, in this case, the + // container would already be stopped. + func (c *linuxContainer) doesInitProcessExist(initPid int) (bool, error) { +- startTime, err := system.GetProcessStartTime(initPid) ++ stat, err := system.Stat(initPid) + if err != nil { +- return false, newSystemErrorWithCausef(err, "getting init process %d start time", initPid) ++ return false, newSystemErrorWithCausef(err, "getting init process %d status", initPid) + } +- if c.initProcessStartTime != startTime { ++ if c.initProcessStartTime != stat.StartTime { + return false, nil + } + return true, nil +@@ -1174,7 +1174,7 @@ func (c *linuxContainer) isPaused() (bool, error) { + + func (c *linuxContainer) currentState() (*State, error) { + var ( +- startTime string ++ startTime uint64 + externalDescriptors []string + pid = -1 + ) +diff --git a/libcontainer/container_linux_test.go b/libcontainer/container_linux_test.go +index b69e3449..3fdd4a80 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux_test.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux_test.go +@@ -52,7 +52,7 @@ func (m *mockCgroupManager) Freeze(state configs.FreezerState) error { + + type mockProcess struct { + _pid int +- started string ++ started uint64 + } + + func (m *mockProcess) terminate() error { +@@ -63,7 +63,7 @@ func (m *mockProcess) pid() int { + return m._pid + } + +-func (m *mockProcess) startTime() (string, error) { ++func (m *mockProcess) startTime() (uint64, error) { + return m.started, nil + } + +@@ -150,7 +150,7 @@ func TestGetContainerState(t *testing.T) { + }, + initProcess: &mockProcess{ + _pid: pid, +- started: "010", ++ started: 10, + }, + cgroupManager: &mockCgroupManager{ + pids: []int{1, 2, 3}, +@@ -174,8 +174,8 @@ func TestGetContainerState(t *testing.T) { + if state.InitProcessPid != pid { + t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid) + } +- if state.InitProcessStartTime != "010" { +- t.Fatalf("expected process start time 010 but received %s", state.InitProcessStartTime) ++ if state.InitProcessStartTime != 10 { ++ t.Fatalf("expected process start time 10 but received %d", state.InitProcessStartTime) + } + paths := state.CgroupPaths + if paths == nil { +diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go +index 53df9fa5..1232a7b2 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/process_linux.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/process_linux.go +@@ -33,7 +33,7 @@ type parentProcess interface { + wait() (*os.ProcessState, error) + + // startTime returns the process start time. +- startTime() (string, error) ++ startTime() (uint64, error) + + signal(os.Signal) error + +@@ -54,8 +54,9 @@ type setnsProcess struct { + rootDir *os.File + } + +-func (p *setnsProcess) startTime() (string, error) { +- return system.GetProcessStartTime(p.pid()) ++func (p *setnsProcess) startTime() (uint64, error) { ++ stat, err := system.Stat(p.pid()) ++ return stat.StartTime, err + } + + func (p *setnsProcess) signal(sig os.Signal) error { +@@ -406,8 +407,9 @@ func (p *initProcess) terminate() error { + return err + } + +-func (p *initProcess) startTime() (string, error) { +- return system.GetProcessStartTime(p.pid()) ++func (p *initProcess) startTime() (uint64, error) { ++ stat, err := system.Stat(p.pid()) ++ return stat.StartTime, err + } + + func (p *initProcess) sendConfig() error { +diff --git a/libcontainer/restored_process.go b/libcontainer/restored_process.go +index a96f4ca5..408916ad 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/restored_process.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/restored_process.go +@@ -17,20 +17,20 @@ func newRestoredProcess(pid int, fds []string) (*restoredProcess, error) { + if err != nil { + return nil, err + } +- started, err := system.GetProcessStartTime(pid) ++ stat, err := system.Stat(pid) + if err != nil { + return nil, err + } + return &restoredProcess{ + proc: proc, +- processStartTime: started, ++ processStartTime: stat.StartTime, + fds: fds, + }, nil + } + + type restoredProcess struct { + proc *os.Process +- processStartTime string ++ processStartTime uint64 + fds []string + } + +@@ -60,7 +60,7 @@ func (p *restoredProcess) wait() (*os.ProcessState, error) { + return st, nil + } + +-func (p *restoredProcess) startTime() (string, error) { ++func (p *restoredProcess) startTime() (uint64, error) { + return p.processStartTime, nil + } + +@@ -81,7 +81,7 @@ func (p *restoredProcess) setExternalDescriptors(newFds []string) { + // a persisted state. + type nonChildProcess struct { + processPid int +- processStartTime string ++ processStartTime uint64 + fds []string + } + +@@ -101,7 +101,7 @@ func (p *nonChildProcess) wait() (*os.ProcessState, error) { + return nil, newGenericError(fmt.Errorf("restored process cannot be waited on"), SystemError) + } + +-func (p *nonChildProcess) startTime() (string, error) { ++func (p *nonChildProcess) startTime() (uint64, error) { + return p.processStartTime, nil + } + + +From 0d15fca2013888bb496b6239274e8a4c69386642 Mon Sep 17 00:00:00 2001 +From: "W. Trevor King" +Date: Wed, 14 Jun 2017 16:41:16 -0700 +Subject: [PATCH 3/6] libcontainer/system/proc: Add Stat_t.State + +And Stat_t.PID and Stat_t.Name while we're at it. Then use the new +.State property in runType to distinguish between running and +zombie/dead processes, since kill(2) does not [1]. With this change +we no longer claim Running status for zombie/dead processes. + +I've also removed the kill(2) call from runType. It was originally +added in 13841ef3 (new-api: return the Running state only if the init +process is alive, 2014-12-23), but we've been accessing +/proc/[pid]/stat since 14e95b2a (Make state detection precise, +2016-07-05, #930), and with the /stat access the kill(2) check is +redundant. + +I also don't see much point to the previously-separate +doesInitProcessExist, so I've inlined that logic in runType. + +It would be nice to distinguish between "/proc/[pid]/stat doesn't +exist" and errors parsing its contents, but I've skipped that for the +moment. + +The Running -> Stopped change in checkpoint_test.go is because the +post-checkpoint process is a zombie, and with this commit zombie +processes are Stopped (and no longer Running). + +[1]: https://github.com/opencontainers/runc/pull/1483#issuecomment-307527789 + +Signed-off-by: W. Trevor King +(cherry picked from commit 2bea4c897e68475c0e698f7ebec4ba989ea0cda0) +Signed-off-by: Kir Kolyshkin +--- + libcontainer/container_linux.go | 33 +------ + libcontainer/integration/checkpoint_test.go | 2 +- + libcontainer/system/proc.go | 103 ++++++++++++++------ + libcontainer/system/proc_test.go | 41 ++++++-- + 4 files changed, 114 insertions(+), 65 deletions(-) + +diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go +index 98efcfcc..0d478702 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go +@@ -1112,40 +1112,17 @@ func (c *linuxContainer) refreshState() error { + return c.state.transition(&stoppedState{c: c}) + } + +-// doesInitProcessExist checks if the init process is still the same process +-// as the initial one, it could happen that the original process has exited +-// and a new process has been created with the same pid, in this case, the +-// container would already be stopped. +-func (c *linuxContainer) doesInitProcessExist(initPid int) (bool, error) { +- stat, err := system.Stat(initPid) +- if err != nil { +- return false, newSystemErrorWithCausef(err, "getting init process %d status", initPid) +- } +- if c.initProcessStartTime != stat.StartTime { +- return false, nil +- } +- return true, nil +-} +- + func (c *linuxContainer) runType() (Status, error) { + if c.initProcess == nil { + return Stopped, nil + } + pid := c.initProcess.pid() +- // return Running if the init process is alive +- if err := syscall.Kill(pid, 0); err != nil { +- if err == syscall.ESRCH { +- // It means the process does not exist anymore, could happen when the +- // process exited just when we call the function, we should not return +- // error in this case. +- return Stopped, nil +- } +- return Stopped, newSystemErrorWithCausef(err, "sending signal 0 to pid %d", pid) ++ stat, err := system.Stat(pid) ++ if err != nil { ++ return Stopped, nil + } +- // check if the process is still the original init process. +- exist, err := c.doesInitProcessExist(pid) +- if !exist || err != nil { +- return Stopped, err ++ if stat.StartTime != c.initProcessStartTime || stat.State == system.Zombie || stat.State == system.Dead { ++ return Stopped, nil + } + // check if the process that is running is the init process or the user's process. + // this is the difference between the container Running and Created. +diff --git a/libcontainer/integration/checkpoint_test.go b/libcontainer/integration/checkpoint_test.go +index 5fe09d5e..ea1853f4 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/integration/checkpoint_test.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/integration/checkpoint_test.go +@@ -130,7 +130,7 @@ func TestCheckpoint(t *testing.T) { + t.Fatal(err) + } + +- if state != libcontainer.Running { ++ if state != libcontainer.Stopped { + t.Fatal("Unexpected state checkpoint: ", state) + } + +diff --git a/libcontainer/system/proc.go b/libcontainer/system/proc.go +index 4ffb8331..79232a43 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/system/proc.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/system/proc.go +@@ -8,9 +8,55 @@ import ( + "strings" + ) + ++// State is the status of a process. ++type State rune ++ ++const ( // Only values for Linux 3.14 and later are listed here ++ Dead State = 'X' ++ DiskSleep State = 'D' ++ Running State = 'R' ++ Sleeping State = 'S' ++ Stopped State = 'T' ++ TracingStop State = 't' ++ Zombie State = 'Z' ++) ++ ++// String forms of the state from proc(5)'s documentation for ++// /proc/[pid]/status' "State" field. ++func (s State) String() string { ++ switch s { ++ case Dead: ++ return "dead" ++ case DiskSleep: ++ return "disk sleep" ++ case Running: ++ return "running" ++ case Sleeping: ++ return "sleeping" ++ case Stopped: ++ return "stopped" ++ case TracingStop: ++ return "tracing stop" ++ case Zombie: ++ return "zombie" ++ default: ++ return fmt.Sprintf("unknown (%c)", s) ++ } ++} ++ + // Stat_t represents the information from /proc/[pid]/stat, as +-// described in proc(5). ++// described in proc(5) with names based on the /proc/[pid]/status ++// fields. + type Stat_t struct { ++ // PID is the process ID. ++ PID uint ++ ++ // Name is the command run by the process. ++ Name string ++ ++ // State is the state of the process. ++ State State ++ + // StartTime is the number of clock ticks after system boot (since + // Linux 2.6). + StartTime uint64 +@@ -22,9 +68,7 @@ func Stat(pid int) (stat Stat_t, err error) { + if err != nil { + return stat, err + } +- data := string(bytes) +- stat.StartTime, err = parseStartTime(data) +- return stat, err ++ return parseStat(string(bytes)) + } + + // GetProcessStartTime is deprecated. Use Stat(pid) and +@@ -37,30 +81,33 @@ func GetProcessStartTime(pid int) (string, error) { + return fmt.Sprintf("%d", stat.StartTime), nil + } + +-func parseStartTime(stat string) (uint64, error) { +- // the starttime is located at pos 22 +- // from the man page +- // +- // starttime %llu (was %lu before Linux 2.6) +- // (22) The time the process started after system boot. In kernels before Linux 2.6, this +- // value was expressed in jiffies. Since Linux 2.6, the value is expressed in clock ticks +- // (divide by sysconf(_SC_CLK_TCK)). +- // +- // NOTE: +- // pos 2 could contain space and is inside `(` and `)`: +- // (2) comm %s +- // The filename of the executable, in parentheses. +- // This is visible whether or not the executable is +- // swapped out. +- // +- // the following is an example: ++func parseStat(data string) (stat Stat_t, err error) { ++ // From proc(5), field 2 could contain space and is inside `(` and `)`. ++ // The following is an example: + // 89653 (gunicorn: maste) S 89630 89653 89653 0 -1 4194560 29689 28896 0 3 146 32 76 19 20 0 1 0 2971844 52965376 3920 18446744073709551615 1 1 0 0 0 0 0 16781312 137447943 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ i := strings.LastIndex(data, ")") ++ if i <= 2 || i >= len(data)-1 { ++ return stat, fmt.Errorf("invalid stat data: %q", data) ++ } ++ ++ parts := strings.SplitN(data[:i], "(", 2) ++ if len(parts) != 2 { ++ return stat, fmt.Errorf("invalid stat data: %q", data) ++ } ++ ++ stat.Name = parts[1] ++ _, err = fmt.Sscanf(parts[0], "%d", &stat.PID) ++ if err != nil { ++ return stat, err ++ } + +- // get parts after last `)`: +- s := strings.Split(stat, ")") +- parts := strings.Split(strings.TrimSpace(s[len(s)-1]), " ") +- startTimeString := parts[22-3] // starts at 3 (after the filename pos `2`) +- var startTime uint64 +- fmt.Sscanf(startTimeString, "%d", &startTime) +- return startTime, nil ++ // parts indexes should be offset by 3 from the field number given ++ // proc(5), because parts is zero-indexed and we've removed fields ++ // one (PID) and two (Name) in the paren-split. ++ parts = strings.Split(data[i+2:], " ") ++ var state int ++ fmt.Sscanf(parts[3-3], "%c", &state) ++ stat.State = State(state) ++ fmt.Sscanf(parts[22-3], "%d", &stat.StartTime) ++ return stat, nil + } +diff --git a/libcontainer/system/proc_test.go b/libcontainer/system/proc_test.go +index c7615ef9..7e1acc5b 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/system/proc_test.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/system/proc_test.go +@@ -3,18 +3,43 @@ package system + import "testing" + + func TestParseStartTime(t *testing.T) { +- data := map[string]uint64{ +- "4902 (gunicorn: maste) S 4885 4902 4902 0 -1 4194560 29683 29929 61 83 78 16 96 17 20 0 1 0 9126532 52965376 1903 18446744073709551615 4194304 7461796 140733928751520 140733928698072 139816984959091 0 0 16781312 137447943 1 0 0 17 3 0 0 9 0 0 9559488 10071156 33050624 140733928758775 140733928758945 140733928758945 140733928759264 0": 9126532, +- "9534 (cat) R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": 9214966, +- "24767 (irq/44-mei_me) S 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 -51 0 1 0 8722075 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 50 1 0 0 0 0 0 0 0 0 0 0 0": 8722075, ++ data := map[string]Stat_t{ ++ "4902 (gunicorn: maste) S 4885 4902 4902 0 -1 4194560 29683 29929 61 83 78 16 96 17 20 0 1 0 9126532 52965376 1903 18446744073709551615 4194304 7461796 140733928751520 140733928698072 139816984959091 0 0 16781312 137447943 1 0 0 17 3 0 0 9 0 0 9559488 10071156 33050624 140733928758775 140733928758945 140733928758945 140733928759264 0": { ++ PID: 4902, ++ Name: "gunicorn: maste", ++ State: 'S', ++ StartTime: 9126532, ++ }, ++ "9534 (cat) R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": { ++ PID: 9534, ++ Name: "cat", ++ State: 'R', ++ StartTime: 9214966, ++ }, ++ ++ "24767 (irq/44-mei_me) S 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 -51 0 1 0 8722075 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 50 1 0 0 0 0 0 0 0 0 0 0 0": { ++ PID: 24767, ++ Name: "irq/44-mei_me", ++ State: 'S', ++ StartTime: 8722075, ++ }, + } +- for line, startTime := range data { +- st, err := parseStartTime(line) ++ for line, expected := range data { ++ st, err := parseStat(line) + if err != nil { + t.Fatal(err) + } +- if startTime != st { +- t.Fatalf("expected start time %q but received %q", startTime, st) ++ if st.PID != expected.PID { ++ t.Fatalf("expected PID %q but received %q", expected.PID, st.PID) ++ } ++ if st.State != expected.State { ++ t.Fatalf("expected state %q but received %q", expected.State, st.State) ++ } ++ if st.Name != expected.Name { ++ t.Fatalf("expected name %q but received %q", expected.Name, st.Name) ++ } ++ if st.StartTime != expected.StartTime { ++ t.Fatalf("expected start time %q but received %q", expected.StartTime, st.StartTime) + } + } + } + +From 9c340aade60d5b8ca0916b78340a199265129b8d Mon Sep 17 00:00:00 2001 +From: Will Martin +Date: Mon, 22 Jan 2018 17:03:02 +0000 +Subject: [PATCH 4/6] Avoid race when opening exec fifo + +When starting a container with `runc start` or `runc run`, the stub +process (runc[2:INIT]) opens a fifo for writing. Its parent runc process +will open the same fifo for reading. In this way, they synchronize. + +If the stub process exits at the wrong time, the parent runc process +will block forever. + +This can happen when racing 2 runc operations against each other: `runc +run/start`, and `runc delete`. It could also happen for other reasons, +e.g. the kernel's OOM killer may select the stub process. + +This commit resolves this race by racing the opening of the exec fifo +from the runc parent process against the stub process exiting. If the +stub process exits before we open the fifo, we return an error. + +Another solution is to wait on the stub process. However, it seems it +would require more refactoring to avoid calling wait multiple times on +the same process, which is an error. + +Signed-off-by: Craig Furman +(cherry picked from commit 8d3e6c9826815cf6f75dbd56c7b5a23fb5666108) +Signed-off-by: Kir Kolyshkin +--- + libcontainer/container_linux.go | 69 ++++++++++++++++++++++++++++----- + 1 file changed, 60 insertions(+), 9 deletions(-) + +diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go +index 0d478702..9e128fec 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go +@@ -5,6 +5,7 @@ package libcontainer + import ( + "bytes" + "encoding/json" ++ "errors" + "fmt" + "io" + "io/ioutil" +@@ -206,20 +207,70 @@ func (c *linuxContainer) Exec() error { + + func (c *linuxContainer) exec() error { + path := filepath.Join(c.root, execFifoFilename) +- f, err := os.OpenFile(path, os.O_RDONLY, 0) +- if err != nil { +- return newSystemErrorWithCause(err, "open exec fifo for reading") ++ ++ fifoOpen := make(chan struct{}) ++ select { ++ case <-awaitProcessExit(c.initProcess.pid(), fifoOpen): ++ return errors.New("container process is already dead") ++ case result := <-awaitFifoOpen(path): ++ close(fifoOpen) ++ if result.err != nil { ++ return result.err ++ } ++ f := result.file ++ defer f.Close() ++ if err := readFromExecFifo(f); err != nil { ++ return err ++ } ++ return os.Remove(path) + } +- defer f.Close() +- data, err := ioutil.ReadAll(f) ++} ++ ++func readFromExecFifo(execFifo io.Reader) error { ++ data, err := ioutil.ReadAll(execFifo) + if err != nil { + return err + } +- if len(data) > 0 { +- os.Remove(path) +- return nil ++ if len(data) <= 0 { ++ return fmt.Errorf("cannot start an already running container") + } +- return fmt.Errorf("cannot start an already running container") ++ return nil ++} ++ ++func awaitProcessExit(pid int, exit <-chan struct{}) <-chan struct{} { ++ isDead := make(chan struct{}) ++ go func() { ++ for { ++ select { ++ case <-exit: ++ return ++ case <-time.After(time.Millisecond * 100): ++ stat, err := system.Stat(pid) ++ if err != nil || stat.State == system.Zombie { ++ close(isDead) ++ return ++ } ++ } ++ } ++ }() ++ return isDead ++} ++ ++func awaitFifoOpen(path string) <-chan openResult { ++ fifoOpened := make(chan openResult) ++ go func() { ++ f, err := os.OpenFile(path, os.O_RDONLY, 0) ++ if err != nil { ++ fifoOpened <- openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")} ++ } ++ fifoOpened <- openResult{file: f} ++ }() ++ return fifoOpened ++} ++ ++type openResult struct { ++ file *os.File ++ err error + } + + func (c *linuxContainer) start(process *Process) error { + +From aba6dc87301b63d06691d7f867bdebf2b291fac1 Mon Sep 17 00:00:00 2001 +From: Ed King +Date: Tue, 23 Jan 2018 10:46:31 +0000 +Subject: [PATCH 5/6] Return from goroutine when it should terminate + +Signed-off-by: Craig Furman +(cherry picked from commit 5c0af14bf8925b845d91cb94fc1d5ab18140a81a) +Signed-off-by: Kir Kolyshkin +--- + libcontainer/container_linux.go | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go +index 9e128fec..d5a30496 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go +@@ -262,6 +262,7 @@ func awaitFifoOpen(path string) <-chan openResult { + f, err := os.OpenFile(path, os.O_RDONLY, 0) + if err != nil { + fifoOpened <- openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")} ++ return + } + fifoOpened <- openResult{file: f} + }() + +From 9471a96c113b05f0a0a84c9afd8e3979e7409508 Mon Sep 17 00:00:00 2001 +From: Jordan Liggitt +Date: Wed, 18 Dec 2019 15:20:53 +0000 +Subject: [PATCH 6/6] Fix race checking for process exit and waiting for exec + fifo + +Signed-off-by: Jordan Liggitt +(cherry picked from commit 8541d9cf3d8b6d46614cc41aaf38eaa2419549df) +Signed-off-by: Kir Kolyshkin +--- + libcontainer/container_linux.go | 83 +++++++++++++++++---------------- + 1 file changed, 43 insertions(+), 40 deletions(-) + +diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go +index d5a30496..fda163da 100644 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/container_linux.go +@@ -207,22 +207,24 @@ func (c *linuxContainer) Exec() error { + + func (c *linuxContainer) exec() error { + path := filepath.Join(c.root, execFifoFilename) +- +- fifoOpen := make(chan struct{}) +- select { +- case <-awaitProcessExit(c.initProcess.pid(), fifoOpen): +- return errors.New("container process is already dead") +- case result := <-awaitFifoOpen(path): +- close(fifoOpen) +- if result.err != nil { +- return result.err +- } +- f := result.file +- defer f.Close() +- if err := readFromExecFifo(f); err != nil { +- return err ++ pid := c.initProcess.pid() ++ blockingFifoOpenCh := awaitFifoOpen(path) ++ for { ++ select { ++ case result := <-blockingFifoOpenCh: ++ return handleFifoResult(result) ++ ++ case <-time.After(time.Millisecond * 100): ++ stat, err := system.Stat(pid) ++ if err != nil || stat.State == system.Zombie { ++ // could be because process started, ran, and completed between our 100ms timeout and our system.Stat() check. ++ // see if the fifo exists and has data (with a non-blocking open, which will succeed if the writing process is complete). ++ if err := handleFifoResult(fifoOpen(path, false)); err != nil { ++ return errors.New("container process is already dead") ++ } ++ return nil ++ } + } +- return os.Remove(path) + } + } + +@@ -237,38 +239,39 @@ func readFromExecFifo(execFifo io.Reader) error { + return nil + } + +-func awaitProcessExit(pid int, exit <-chan struct{}) <-chan struct{} { +- isDead := make(chan struct{}) +- go func() { +- for { +- select { +- case <-exit: +- return +- case <-time.After(time.Millisecond * 100): +- stat, err := system.Stat(pid) +- if err != nil || stat.State == system.Zombie { +- close(isDead) +- return +- } +- } +- } +- }() +- return isDead +-} +- + func awaitFifoOpen(path string) <-chan openResult { + fifoOpened := make(chan openResult) + go func() { +- f, err := os.OpenFile(path, os.O_RDONLY, 0) +- if err != nil { +- fifoOpened <- openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")} +- return +- } +- fifoOpened <- openResult{file: f} ++ result := fifoOpen(path, true) ++ fifoOpened <- result + }() + return fifoOpened + } + ++func fifoOpen(path string, block bool) openResult { ++ flags := os.O_RDONLY ++ if !block { ++ flags |= syscall.O_NONBLOCK ++ } ++ f, err := os.OpenFile(path, flags, 0) ++ if err != nil { ++ return openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")} ++ } ++ return openResult{file: f} ++} ++ ++func handleFifoResult(result openResult) error { ++ if result.err != nil { ++ return result.err ++ } ++ f := result.file ++ defer f.Close() ++ if err := readFromExecFifo(f); err != nil { ++ return err ++ } ++ return os.Remove(f.Name()) ++} ++ + type openResult struct { + file *os.File + err error diff --git a/SOURCES/docker-collectmode.patch b/SOURCES/docker-collectmode.patch index b938b08..2d444a8 100644 --- a/SOURCES/docker-collectmode.patch +++ b/SOURCES/docker-collectmode.patch @@ -1,6 +1,6 @@ diff -up docker-cccb291d3613ade11e2c0b82541452e9db87b835/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go.collectmode docker-cccb291d3613ade11e2c0b82541452e9db87b835/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go ---- docker-cccb291d3613ade11e2c0b82541452e9db87b835/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go.collectmode 2020-01-23 17:04:43.761004295 +0100 -+++ docker-cccb291d3613ade11e2c0b82541452e9db87b835/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go 2020-01-23 17:04:55.584168909 +0100 +--- docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/cgroups/systemd/apply_systemd.go.collectmode 2020-01-23 17:04:43.761004295 +0100 ++++ docker-7d71120b1f31f8bb4da733b5f1e5960b434696de/runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343/libcontainer/cgroups/systemd/apply_systemd.go 2020-01-23 17:04:55.584168909 +0100 @@ -130,8 +130,6 @@ func (m *Manager) Apply(pid int) error { properties = append(properties, newProp("PIDs", []uint32{uint32(pid)})) } diff --git a/SOURCES/docker.service b/SOURCES/docker.service index e67f0d2..d6c28fb 100644 --- a/SOURCES/docker.service +++ b/SOURCES/docker.service @@ -1,8 +1,9 @@ [Unit] Description=Docker Application Container Engine Documentation=http://docs.docker.com -After=network.target +After=network.target rhel-push-plugin.service registries.service Wants=docker-storage-setup.service +Requires=rhel-push-plugin.service registries.service Requires=docker-cleanup.timer [Service] @@ -18,6 +19,7 @@ Environment=PATH=/usr/libexec/docker:/usr/bin:/usr/sbin ExecStart=/usr/bin/dockerd-current \ --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current \ --default-runtime=docker-runc \ + --authorization-plugin=rhel-push-plugin \ --exec-opt native.cgroupdriver=systemd \ --userland-proxy-path=/usr/libexec/docker/docker-proxy-current \ --init-path=/usr/libexec/docker/docker-init-current \ diff --git a/SOURCES/f9a2eeb64054e740fb1ae3048dde153c257113c8.patch b/SOURCES/f9a2eeb64054e740fb1ae3048dde153c257113c8.patch deleted file mode 100644 index 1bd4019..0000000 --- a/SOURCES/f9a2eeb64054e740fb1ae3048dde153c257113c8.patch +++ /dev/null @@ -1,86 +0,0 @@ -From f9a2eeb64054e740fb1ae3048dde153c257113c8 Mon Sep 17 00:00:00 2001 -From: Ulrich Obergfell -Date: Thu, 10 Oct 2019 11:16:50 +0200 -Subject: [PATCH] revert changes introduced by "fix error handling in restore() - function", commit e96a10aef66e - (https://github.com/projectatomic/containerd/pull/10) - -Signed-off-by: Ulrich Obergfell ---- - runtime/container.go | 12 ++++++------ - supervisor/supervisor.go | 11 +++-------- - 2 files changed, 9 insertions(+), 14 deletions(-) - -diff --git a/runtime/container.go b/runtime/container.go -index 14002fc..2e9e663 100644 ---- a/runtime/container.go -+++ b/runtime/container.go -@@ -146,15 +146,15 @@ func New(opts ContainerOpts) (Container, error) { - } - - // Load return a new container from the matchin state file on disk. --func Load(root, id, shimName string, timeout time.Duration) (Container, error, string) { -+func Load(root, id, shimName string, timeout time.Duration) (Container, error) { - var s state - f, err := os.Open(filepath.Join(root, id, StateFile)) - if err != nil { -- return nil, err, "init" -+ return nil, err - } - defer f.Close() - if err := json.NewDecoder(f).Decode(&s); err != nil { -- return nil, err, "init" -+ return nil, err - } - c := &container{ - root: root, -@@ -175,7 +175,7 @@ func Load(root, id, shimName string, timeout time.Duration) (Container, error, s - - dirs, err := ioutil.ReadDir(filepath.Join(root, id)) - if err != nil { -- return nil, err, "init" -+ return nil, err - } - for _, d := range dirs { - if !d.IsDir() { -@@ -184,7 +184,7 @@ func Load(root, id, shimName string, timeout time.Duration) (Container, error, s - pid := d.Name() - s, err := readProcessState(filepath.Join(root, id, pid)) - if err != nil { -- return nil, err, pid -+ return nil, err - } - p, err := loadProcess(filepath.Join(root, id, pid), pid, c, s) - if err != nil { -@@ -193,7 +193,7 @@ func Load(root, id, shimName string, timeout time.Duration) (Container, error, s - } - c.processes[pid] = p - } -- return c, nil, "" -+ return c, nil - } - - func readProcessState(dir string) (*ProcessState, error) { -diff --git a/supervisor/supervisor.go b/supervisor/supervisor.go -index d92de8a..e21ae7b 100644 ---- a/supervisor/supervisor.go -+++ b/supervisor/supervisor.go -@@ -364,15 +364,10 @@ func (s *Supervisor) restore() error { - continue - } - id := d.Name() -- container, err, pid := runtime.Load(s.stateDir, id, s.shim, s.timeout) -+ container, err := runtime.Load(s.stateDir, id, s.shim, s.timeout) - if err != nil { -- if (pid == "init") { -- logrus.WithFields(logrus.Fields{"error": err, "id": id}).Warnf("containerd: failed to load container,removing state directory.") -- os.RemoveAll(filepath.Join(s.stateDir, id)) -- } else { -- logrus.WithFields(logrus.Fields{"error": err, "pid": pid}).Warnf("containerd: failed to load exec process,removing state directory.") -- os.RemoveAll(filepath.Join(s.stateDir, id, pid)) -- } -+ logrus.WithFields(logrus.Fields{"error": err, "id": id}).Warnf("containerd: failed to load container,removing state directory.") -+ os.RemoveAll(filepath.Join(s.stateDir, id)) - continue - } - processes, err := container.Processes() diff --git a/SPECS/docker.spec b/SPECS/docker.spec index 0ddb311..2a937c2 100644 --- a/SPECS/docker.spec +++ b/SPECS/docker.spec @@ -19,7 +19,7 @@ %global import_path %{provider}.%{provider_tld}/%{project}/%{repo} -%define gobuild(o:) go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${GO_LDFLAGS:-} ${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld'" -a -v -x %{?**}; +%define gobuild(o:) go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${GO_LDFLAGS:-} ${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld'" -a -v %{?**}; # docker %global git_docker https://github.com/projectatomic/docker @@ -45,9 +45,9 @@ %global shortcommit_novolume %(c=%{commit_novolume}; echo ${c:0:7}) # rhel-push-plugin -#%global git_rhel_push https://github.com/projectatomic/rhel-push-plugin -#%global commit_rhel_push af9107b2aedb235338e32a3c19507cad3f218b0d -#%global shortcommit_rhel_push %(c=%{commit_rhel_push}; echo ${c:0:7}) +%global git_rhel_push https://github.com/projectatomic/rhel-push-plugin +%global commit_rhel_push af9107b2aedb235338e32a3c19507cad3f218b0d +%global shortcommit_rhel_push %(c=%{commit_rhel_push}; echo ${c:0:7}) # docker-lvm-plugin %global git_lvm https://github.com/projectatomic/%{repo}-lvm-plugin @@ -56,12 +56,12 @@ # docker-runc %global git_runc https://github.com/projectatomic/runc -%global commit_runc 66aedde759f33c190954815fb765eedc1d782dd9 +%global commit_runc 8891bca22c049cd2dcf13ba2438c0bac8d7f3343 %global shortcommit_runc %(c=%{commit_runc}; echo ${c:0:7}) # docker-containerd %global git_containerd https://github.com/projectatomic/containerd -%global commit_containerd 9c53e35c39f214b128beed3dfb670ccf751c4173 +%global commit_containerd 46b69ea4c3d2d965e2116ef47e20e5584a3c2741 %global shortcommit_containerd %(c=%{commit_containerd}; echo ${c:0:7}) # docker-init @@ -77,15 +77,15 @@ Name: %{repo} Epoch: 2 Version: 1.13.1 -Release: 208.git%{shortcommit_docker}%{?dist} +Release: 209.git%{shortcommit_docker}%{?dist} Summary: Automates deployment of containerized applications License: ASL 2.0 URL: https://%{import_path} -ExclusiveArch: aarch64 %{arm} ppc64le s390x x86_64 %{ix86} +ExclusiveArch: aarch64 %{arm} ppc64le s390x x86_64 Source0: %{git_docker}/archive/%{commit_docker}.tar.gz Source2: %{git_dss}/archive/%{commit_dss}/container-storage-setup-%{shortcommit_dss}.tar.gz Source4: %{git_novolume}/archive/%{commit_novolume}/%{repo}-novolume-plugin-%{shortcommit_novolume}.tar.gz -#Source5: %{git_rhel_push}/archive/%{commit_rhel_push}/rhel-push-plugin-%{shortcommit_rhel_push}.tar.gz +Source5: %{git_rhel_push}/archive/%{commit_rhel_push}/rhel-push-plugin-%{shortcommit_rhel_push}.tar.gz Source6: %{git_lvm}/archive/%{commit_lvm}/%{repo}-lvm-plugin-%{shortcommit_lvm}.tar.gz Source8: %{name}.service Source9: %{name}.sysconfig @@ -109,31 +109,21 @@ Source29: 99-docker.conf Source30: %{git_tini}/archive/%{commit_tini}/tini-%{shortcommit_tini}.tar.gz Source31: %{git_libnetwork}/archive/%{commit_libnetwork}/libnetwork-%{shortcommit_libnetwork}.tar.gz Source32: seccomp.json -# https://bugzilla.redhat.com/show_bug.cgi?id=1636244 -Patch0: https://github.com/projectatomic/containerd/pull/11/commits/97eff6cf6c9b58f8239b28be2f080e23c9da62c0.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=1653292 -Patch1: https://github.com/projectatomic/containerd/pull/12/commits/f9a2eeb64054e740fb1ae3048dde153c257113c8.patch -Patch2: https://github.com/projectatomic/containerd/pull/12/commits/69518f0bbdb1f11113f46a4d794e09e2f21f5e91.patch # related: https://bugzilla.redhat.com/show_bug.cgi?id=1766665 there is no CollectMode property in RHEL7 systemd Patch3: docker-collectmode.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1784228 Patch4: bz1784228.patch Patch5: docker-1792243.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=1718441 -Patch6: https://patch-diff.githubusercontent.com/raw/projectatomic/runc/pull/30.patch # https://patch-diff.githubusercontent.com/raw/projectatomic/docker/pull/369.patch Patch7: docker-CVE-2020-8945.patch -# related bug: https://bugzilla.redhat.com/show_bug.cgi?id=1879425 -# patch: https://github.com/projectatomic/runc/pull/33.patch -Patch8: docker-1879425.patch Patch9: docker-1787148.patch -Patch10: https://patch-diff.githubusercontent.com/raw/projectatomic/runc/pull/54.patch -Patch11: https://patch-diff.githubusercontent.com/raw/kolyshkin/containerd-1/pull/1.patch +# https://patch-diff.githubusercontent.com/raw/projectatomic/runc/pull/56.patch +Patch10: docker-2000782.patch BuildRequires: cmake BuildRequires: sed BuildRequires: git BuildRequires: glibc-static -%if 0%{?fedora} +%if 0%{?fedora} || 0%{?centos} BuildRequires: %{?go_compiler:compiler(go-compiler)}%{!?go_compiler:golang} %else BuildRequires: go-toolset-1.10 @@ -207,7 +197,7 @@ Requires: device-mapper-libs >= 7:1.02.97 Requires: oci-umount >= 2:2.3.3-3 Requires: oci-register-machine >= 1:0-5.13 Requires: oci-systemd-hook >= 1:0.1.4-9 -#Requires: %{name}-rhel-push-plugin = %{epoch}:%{version}-%{release} +Requires: %{name}-rhel-push-plugin = %{epoch}:%{version}-%{release} Requires: xz Requires: atomic-registries Requires: container-selinux >= 2:2.51-1 @@ -259,16 +249,16 @@ local volumes defined. In particular, the plugin will block `docker run` with: The only thing allowed will be just bind mounts. -#%package rhel-push-plugin -#License: GPLv2 -#Summary: Avoids pushing a RHEL-based image to docker.io registry +%package rhel-push-plugin +License: GPLv2 +Summary: Avoids pushing a RHEL-based image to docker.io registry -#%description rhel-push-plugin -#In order to use this plugin you must be running at least Docker 1.10 which -#has support for authorization plugins. +%description rhel-push-plugin +In order to use this plugin you must be running at least Docker 1.10 which +has support for authorization plugins. -#This plugin avoids any RHEL based image to be pushed to the default docker.io -#registry preventing users to violate the RH subscription agreement. +This plugin avoids any RHEL based image to be pushed to the default docker.io +registry preventing users to violate the RH subscription agreement. %package lvm-plugin License: LGPLv3 @@ -293,7 +283,7 @@ tar zxf %{SOURCE2} tar zxf %{SOURCE4} # untar rhel-push-plugin -#tar zxf %{SOURCE5} +tar zxf %{SOURCE5} # untar lvm-plugin tar zxf %{SOURCE6} @@ -332,22 +322,12 @@ tar zxf %{SOURCE30} # untar libnetwork tar zxf %{SOURCE31} -cd containerd* -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -cd - %patch3 -p1 %patch4 -p1 %patch5 -p1 -%patch6 -p1 %patch7 -p1 - -# https://bugzilla.redhat.com/show_bug.cgi?id=1879425 -%patch8 -p1 %patch9 -p1 %patch10 -p1 -%patch11 -p1 %build # compile docker-proxy first - otherwise deps in gopath conflict with the others below and this fails. Remove libnetwork libs then. @@ -369,7 +349,7 @@ pushd _build mkdir -p src/%{provider}.%{provider_tld}/{%{name},projectatomic} ln -s $(dirs +1 -l) src/%{import_path} ln -s $(dirs +1 -l)/%{repo}-novolume-plugin-%{commit_novolume} src/%{provider}.%{provider_tld}/projectatomic/%{repo}-novolume-plugin -# ln -s $(dirs +1 -l)/rhel-push-plugin-%{commit_rhel_push} src/%{provider}.%{provider_tld}/projectatomic/rhel-push-plugin + ln -s $(dirs +1 -l)/rhel-push-plugin-%{commit_rhel_push} src/%{provider}.%{provider_tld}/projectatomic/rhel-push-plugin ln -s $(dirs +1 -l)/%{repo}-lvm-plugin-%{commit_lvm} src/%{provider}.%{provider_tld}/projectatomic/%{repo}-lvm-plugin popd @@ -378,10 +358,10 @@ pushd $(pwd)/_build/src %gobuild %{provider}.%{provider_tld}/projectatomic/%{repo}-novolume-plugin popd -#export GOPATH=$(pwd)/rhel-push-plugin-%{commit_rhel_push}/Godeps/_workspace:$(pwd)/_build -#pushd $(pwd)/_build/src -#%gobuild %{provider}.%{provider_tld}/projectatomic/rhel-push-plugin -#popd +export GOPATH=$(pwd)/rhel-push-plugin-%{commit_rhel_push}/Godeps/_workspace:$(pwd)/_build +pushd $(pwd)/_build/src +%gobuild %{provider}.%{provider_tld}/projectatomic/rhel-push-plugin +popd export GOPATH=$(pwd)/%{repo}-lvm-plugin-%{commit_lvm}/Godeps/_workspace:$(pwd)/_build pushd $(pwd)/_build/src @@ -404,7 +384,7 @@ export GOPATH=$(pwd)/_build:$(pwd)/vendor # build %%{name} manpages man/md2man-all.sh go-md2man -in %{repo}-novolume-plugin-%{commit_novolume}/man/%{repo}-novolume-plugin.8.md -out %{repo}-novolume-plugin.8 -#go-md2man -in rhel-push-plugin-%{commit_rhel_push}/man/rhel-push-plugin.8.md -out rhel-push-plugin.8 +go-md2man -in rhel-push-plugin-%{commit_rhel_push}/man/rhel-push-plugin.8.md -out rhel-push-plugin.8 go-md2man -in %{repo}-lvm-plugin-%{commit_lvm}/man/%{repo}-lvm-plugin.8.md -out %{repo}-lvm-plugin.8 # build %%{name} binary @@ -569,12 +549,12 @@ install -d %{buildroot}%{_mandir}/man8 install -p -m 644 %{repo}-novolume-plugin.8 %{buildroot}%{_mandir}/man8 # install rhel-push-plugin executable, unitfile, socket and man -#install -d %{buildroot}%{_libexecdir}/%{repo} -#install -p -m 755 _build/src/rhel-push-plugin %{buildroot}%{_libexecdir}/%{repo}/rhel-push-plugin -#install -p -m 644 rhel-push-plugin-%{commit_rhel_push}/systemd/rhel-push-plugin.service %{buildroot}%{_unitdir}/rhel-push-plugin.service -#install -p -m 644 rhel-push-plugin-%{commit_rhel_push}/systemd/rhel-push-plugin.socket %{buildroot}%{_unitdir}/rhel-push-plugin.socket -#install -d %{buildroot}%{_mandir}/man8 -#install -p -m 644 rhel-push-plugin.8 %{buildroot}%{_mandir}/man8 +install -d %{buildroot}%{_libexecdir}/%{repo} +install -p -m 755 _build/src/rhel-push-plugin %{buildroot}%{_libexecdir}/%{repo}/rhel-push-plugin +install -p -m 644 rhel-push-plugin-%{commit_rhel_push}/systemd/rhel-push-plugin.service %{buildroot}%{_unitdir}/rhel-push-plugin.service +install -p -m 644 rhel-push-plugin-%{commit_rhel_push}/systemd/rhel-push-plugin.socket %{buildroot}%{_unitdir}/rhel-push-plugin.socket +install -d %{buildroot}%{_mandir}/man8 +install -p -m 644 rhel-push-plugin.8 %{buildroot}%{_mandir}/man8 # install %%{repo}-lvm-plugin executable, unitfile, socket and man install -d %{buildroot}/%{_libexecdir}/%{repo} @@ -654,14 +634,14 @@ exit 0 %postun novolume-plugin %systemd_postun_with_restart %{name}-novolume-plugin.service -#%post rhel-push-plugin -#%systemd_post rhel-push-plugin.service +%post rhel-push-plugin +%systemd_post rhel-push-plugin.service -#%preun rhel-push-plugin -#%systemd_preun rhel-push-plugin.service +%preun rhel-push-plugin +%systemd_preun rhel-push-plugin.service -#%postun rhel-push-plugin -#%systemd_postun_with_restart rhel-push-plugin.service +%postun rhel-push-plugin +%systemd_postun_with_restart rhel-push-plugin.service %posttrans # Install a default docker-storage-setup based on kernel version. @@ -757,12 +737,12 @@ fi %{_libexecdir}/%{repo}/%{repo}-novolume-plugin %{_unitdir}/%{repo}-novolume-plugin.* -#%files rhel-push-plugin -#%license rhel-push-plugin-%{commit_rhel_push}/LICENSE -#%doc rhel-push-plugin-%{commit_rhel_push}/README.md -#%{_mandir}/man8/rhel-push-plugin.8.gz -#%{_libexecdir}/%{repo}/rhel-push-plugin -#%{_unitdir}/rhel-push-plugin.* +%files rhel-push-plugin +%license rhel-push-plugin-%{commit_rhel_push}/LICENSE +%doc rhel-push-plugin-%{commit_rhel_push}/README.md +%{_mandir}/man8/rhel-push-plugin.8.gz +%{_libexecdir}/%{repo}/rhel-push-plugin +%{_unitdir}/rhel-push-plugin.* %files lvm-plugin %license %{repo}-lvm-plugin-%{commit_lvm}/LICENSE @@ -778,6 +758,13 @@ fi %{_bindir}/%{name}-v1.10-migrator-* %changelog +* Fri Oct 01 2021 Jindrich Novy - 2:1.13.1-209.git7d71120 +- update to runc-8891bca22c049cd2dcf13ba2438c0bac8d7f3343 +- update to containerd-46b69ea4c3d2d965e2116ef47e20e5584a3c2741 +- apply https://github.com/projectatomic/runc/pull/56 +- drop applied patches +- Related: #2000782 + * Fri Jun 04 2021 Jindrich Novy - 2:1.13.1-208.git7d71120 - propagate mounts to the host - fix regression introduced by fix of CVE-2021-30465 - Resolves: #1966968