fix container cgroup lookup

When running on cgroups v1, `/proc/{PID}/cgroup` has multiple entries,
each pointing potentially to a different cgroup.  Some may be empty,
some may point to parents.

The one we really need is the libpod-specific one, which always is the
longest path.  So instead of looking at the first entry, look at all and
select the longest one.

Fixes: #8397
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2020-11-20 11:31:12 +01:00
parent a18365c908
commit 1efb9b5e17

View File

@ -17,6 +17,7 @@ import (
"github.com/cri-o/ocicni/pkg/ocicni" "github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go" spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
// CgroupfsDefaultCgroupParent is the cgroup parent for CGroupFS in libpod // CgroupfsDefaultCgroupParent is the cgroup parent for CGroupFS in libpod
@ -920,19 +921,39 @@ func (c *Container) CGroupPath() (string, error) {
return "", errors.Wrapf(define.ErrNoCgroups, "this container is not creating cgroups") return "", errors.Wrapf(define.ErrNoCgroups, "this container is not creating cgroups")
} }
// Read /proc/[PID]/cgroup and look at the first line. cgroups(7) // Read /proc/[PID]/cgroup and find the *longest* cgroup entry. That's
// nails it down to three fields with the 3rd pointing to the cgroup's // needed to account for hacks in cgroups v1, where each line in the
// path which works both on v1 and v2. // file could potentially point to a cgroup. The longest one, however,
// is the libpod-specific one we're looking for.
//
// See #8397 on the need for the longest-path look up.
procPath := fmt.Sprintf("/proc/%d/cgroup", c.state.PID) procPath := fmt.Sprintf("/proc/%d/cgroup", c.state.PID)
lines, err := ioutil.ReadFile(procPath) lines, err := ioutil.ReadFile(procPath)
if err != nil { if err != nil {
return "", err return "", err
} }
fields := bytes.Split(bytes.Split(lines, []byte("\n"))[0], []byte(":"))
if len(fields) != 3 { var cgroupPath string
return "", errors.Errorf("expected 3 fields but got %d: %s", len(fields), procPath) for _, line := range bytes.Split(lines, []byte("\n")) {
// cgroups(7) nails it down to three fields with the 3rd
// pointing to the cgroup's path which works both on v1 and v2.
fields := bytes.Split(line, []byte(":"))
if len(fields) != 3 {
logrus.Debugf("Error parsing cgroup: expected 3 fields but got %d: %s", len(fields), procPath)
continue
}
path := string(fields[2])
if len(path) > len(cgroupPath) {
cgroupPath = path
}
} }
return string(fields[2]), nil
if len(cgroupPath) == 0 {
return "", errors.Errorf("could not find any cgroup in %q", procPath)
}
return cgroupPath, nil
} }
// RootFsSize returns the root FS size of the container // RootFsSize returns the root FS size of the container