summaryrefslogtreecommitdiff
path: root/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go')
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go60
1 files changed, 42 insertions, 18 deletions
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go
index 5f6ab9fd6..0cdaf7478 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go
@@ -2,20 +2,27 @@ package cgroups
import (
"bytes"
+ "errors"
+ "fmt"
"os"
+ "path"
+ "strconv"
"strings"
"sync"
- "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
// OpenFile opens a cgroup file in a given dir with given flags.
-// It is supposed to be used for cgroup files only.
+// It is supposed to be used for cgroup files only, and returns
+// an error if the file is not a cgroup file.
+//
+// Arguments dir and file are joined together to form an absolute path
+// to a file being opened.
func OpenFile(dir, file string, flags int) (*os.File, error) {
if dir == "" {
- return nil, errors.Errorf("no directory specified for %s", file)
+ return nil, fmt.Errorf("no directory specified for %s", file)
}
return openFile(dir, file, flags)
}
@@ -43,7 +50,8 @@ func WriteFile(dir, file, data string) error {
}
defer fd.Close()
if err := retryingWriteFile(fd, data); err != nil {
- return errors.Wrapf(err, "failed to write %q", data)
+ // Having data in the error message helps in debugging.
+ return fmt.Errorf("failed to write %q: %w", data, err)
}
return nil
}
@@ -81,7 +89,7 @@ func prepareOpenat2() error {
})
if err != nil {
prepErr = &os.PathError{Op: "openat2", Path: cgroupfsDir, Err: err}
- if err != unix.ENOSYS {
+ if err != unix.ENOSYS { //nolint:errorlint // unix errors are bare
logrus.Warnf("falling back to securejoin: %s", prepErr)
} else {
logrus.Debug("openat2 not available, falling back to securejoin")
@@ -107,8 +115,6 @@ func prepareOpenat2() error {
return prepErr
}
-// OpenFile opens a cgroup file in a given dir with given flags.
-// It is supposed to be used for cgroup files only.
func openFile(dir, file string, flags int) (*os.File, error) {
mode := os.FileMode(0)
if TestMode && flags&os.O_WRONLY != 0 {
@@ -116,34 +122,52 @@ func openFile(dir, file string, flags int) (*os.File, error) {
flags |= os.O_TRUNC | os.O_CREATE
mode = 0o600
}
+ path := path.Join(dir, file)
if prepareOpenat2() != nil {
- return openFallback(dir, file, flags, mode)
+ return openFallback(path, flags, mode)
}
- reldir := strings.TrimPrefix(dir, cgroupfsPrefix)
- if len(reldir) == len(dir) { // non-standard path, old system?
- return openFallback(dir, file, flags, mode)
+ relPath := strings.TrimPrefix(path, cgroupfsPrefix)
+ if len(relPath) == len(path) { // non-standard path, old system?
+ return openFallback(path, flags, mode)
}
- relname := reldir + "/" + file
- fd, err := unix.Openat2(cgroupFd, relname,
+ fd, err := unix.Openat2(cgroupFd, relPath,
&unix.OpenHow{
Resolve: resolveFlags,
Flags: uint64(flags) | unix.O_CLOEXEC,
Mode: uint64(mode),
})
if err != nil {
- return nil, &os.PathError{Op: "openat2", Path: dir + "/" + file, Err: err}
+ err = &os.PathError{Op: "openat2", Path: path, Err: err}
+ // Check if cgroupFd is still opened to cgroupfsDir
+ // (happens when this package is incorrectly used
+ // across the chroot/pivot_root/mntns boundary, or
+ // when /sys/fs/cgroup is remounted).
+ //
+ // TODO: if such usage will ever be common, amend this
+ // to reopen cgroupFd and retry openat2.
+ fdStr := strconv.Itoa(cgroupFd)
+ fdDest, _ := os.Readlink("/proc/self/fd/" + fdStr)
+ if fdDest != cgroupfsDir {
+ // Wrap the error so it is clear that cgroupFd
+ // is opened to an unexpected/wrong directory.
+ err = fmt.Errorf("cgroupFd %s unexpectedly opened to %s != %s: %w",
+ fdStr, fdDest, cgroupfsDir, err)
+ }
+ return nil, err
}
- return os.NewFile(uintptr(fd), cgroupfsPrefix+relname), nil
+ return os.NewFile(uintptr(fd), path), nil
}
var errNotCgroupfs = errors.New("not a cgroup file")
-// openFallback is used when openat2(2) is not available. It checks the opened
+// Can be changed by unit tests.
+var openFallback = openAndCheck
+
+// openAndCheck is used when openat2(2) is not available. It checks the opened
// file is on cgroupfs, returning an error otherwise.
-func openFallback(dir, file string, flags int, mode os.FileMode) (*os.File, error) {
- path := dir + "/" + file
+func openAndCheck(path string, flags int, mode os.FileMode) (*os.File, error) {
fd, err := os.OpenFile(path, flags, mode)
if err != nil {
return nil, err