diff --git a/internal/linux/linux.go b/internal/linux/linux.go index 9c81a7434..b281a3347 100644 --- a/internal/linux/linux.go +++ b/internal/linux/linux.go @@ -6,6 +6,14 @@ import ( "golang.org/x/sys/unix" ) +// Dup3 wraps [unix.Dup3]. +func Dup3(oldfd, newfd, flags int) error { + err := retryOnEINTR(func() error { + return unix.Dup3(oldfd, newfd, flags) + }) + return os.NewSyscallError("dup3", err) +} + // Exec wraps [unix.Exec]. func Exec(cmd string, args []string, env []string) error { err := retryOnEINTR(func() error { @@ -23,6 +31,28 @@ func Getwd() (wd string, err error) { return wd, os.NewSyscallError("getwd", err) } +// Open wraps [unix.Open]. +func Open(path string, mode int, perm uint32) (fd int, err error) { + fd, err = retryOnEINTR2(func() (int, error) { + return unix.Open(path, mode, perm) + }) + if err != nil { + return -1, &os.PathError{Op: "open", Path: path, Err: err} + } + return fd, nil +} + +// Openat wraps [unix.Openat]. +func Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) { + fd, err = retryOnEINTR2(func() (int, error) { + return unix.Openat(dirfd, path, mode, perm) + }) + if err != nil { + return -1, &os.PathError{Op: "openat", Path: path, Err: err} + } + return fd, nil +} + // Sendmsg wraps [unix.Sendmsg]. func Sendmsg(fd int, p, oob []byte, to unix.Sockaddr, flags int) error { err := retryOnEINTR(func() error { diff --git a/libcontainer/console_linux.go b/libcontainer/console_linux.go index e506853e4..c42e60e3c 100644 --- a/libcontainer/console_linux.go +++ b/libcontainer/console_linux.go @@ -3,6 +3,7 @@ package libcontainer import ( "os" + "github.com/opencontainers/runc/internal/linux" "golang.org/x/sys/unix" ) @@ -26,16 +27,12 @@ func mountConsole(slavePath string) error { // dupStdio opens the slavePath for the console and dups the fds to the current // processes stdio, fd 0,1,2. func dupStdio(slavePath string) error { - fd, err := unix.Open(slavePath, unix.O_RDWR, 0) + fd, err := linux.Open(slavePath, unix.O_RDWR, 0) if err != nil { - return &os.PathError{ - Op: "open", - Path: slavePath, - Err: err, - } + return err } for _, i := range []int{0, 1, 2} { - if err := unix.Dup3(fd, i, 0); err != nil { + if err := linux.Dup3(fd, i, 0); err != nil { return err } } diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 3df948eeb..ec2bef074 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -24,6 +24,7 @@ import ( "github.com/opencontainers/cgroups" devices "github.com/opencontainers/cgroups/devices/config" "github.com/opencontainers/cgroups/fs2" + "github.com/opencontainers/runc/internal/linux" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/utils" ) @@ -883,12 +884,8 @@ func reOpenDevNull() error { } if stat.Rdev == devNullStat.Rdev { // Close and re-open the fd. - if err := unix.Dup3(int(file.Fd()), fd, 0); err != nil { - return &os.PathError{ - Op: "dup3", - Path: "fd " + strconv.Itoa(int(file.Fd())), - Err: err, - } + if err := linux.Dup3(int(file.Fd()), fd, 0); err != nil { + return err } } } @@ -1063,15 +1060,15 @@ func pivotRoot(rootfs string) error { // with pivot_root this allows us to pivot without creating directories in // the rootfs. Shout-outs to the LXC developers for giving us this idea. - oldroot, err := unix.Open("/", unix.O_DIRECTORY|unix.O_RDONLY, 0) + oldroot, err := linux.Open("/", unix.O_DIRECTORY|unix.O_RDONLY, 0) if err != nil { - return &os.PathError{Op: "open", Path: "/", Err: err} + return err } defer unix.Close(oldroot) - newroot, err := unix.Open(rootfs, unix.O_DIRECTORY|unix.O_RDONLY, 0) + newroot, err := linux.Open(rootfs, unix.O_DIRECTORY|unix.O_RDONLY, 0) if err != nil { - return &os.PathError{Op: "open", Path: rootfs, Err: err} + return err } defer unix.Close(newroot) diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go index cccb1d89a..6bf5ba39c 100644 --- a/libcontainer/standard_init_linux.go +++ b/libcontainer/standard_init_linux.go @@ -262,9 +262,9 @@ func (l *linuxStandardInit) Init() error { // user process. We open it through /proc/self/fd/$fd, because the fd that // was given to us was an O_PATH fd to the fifo itself. Linux allows us to // re-open an O_PATH fd through /proc. - fd, err := unix.Open(fifoPath, unix.O_WRONLY|unix.O_CLOEXEC, 0) + fd, err := linux.Open(fifoPath, unix.O_WRONLY|unix.O_CLOEXEC, 0) if err != nil { - return &os.PathError{Op: "open exec fifo", Path: fifoPath, Err: err} + return err } if _, err := unix.Write(fd, []byte("0")); err != nil { return &os.PathError{Op: "write exec fifo", Path: fifoPath, Err: err} diff --git a/libcontainer/utils/utils_unix.go b/libcontainer/utils/utils_unix.go index 98caa3151..3c32769dd 100644 --- a/libcontainer/utils/utils_unix.go +++ b/libcontainer/utils/utils_unix.go @@ -14,6 +14,7 @@ import ( _ "unsafe" // for go:linkname securejoin "github.com/cyphar/filepath-securejoin" + "github.com/opencontainers/runc/internal/linux" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -358,9 +359,9 @@ func Openat(dir *os.File, path string, flags int, mode uint32) (*os.File, error) } flags |= unix.O_CLOEXEC - fd, err := unix.Openat(dirFd, path, flags, mode) + fd, err := linux.Openat(dirFd, path, flags, mode) if err != nil { - return nil, &os.PathError{Op: "openat", Path: path, Err: err} + return nil, err } return os.NewFile(uintptr(fd), dir.Name()+"/"+path), nil } diff --git a/tests/cmd/seccompagent/seccompagent.go b/tests/cmd/seccompagent/seccompagent.go index be1e6c255..e9cc72303 100644 --- a/tests/cmd/seccompagent/seccompagent.go +++ b/tests/cmd/seccompagent/seccompagent.go @@ -14,6 +14,7 @@ import ( "strings" securejoin "github.com/cyphar/filepath-securejoin" + "github.com/opencontainers/runc/internal/linux" "github.com/opencontainers/runtime-spec/specs-go" libseccomp "github.com/seccomp/libseccomp-golang" "github.com/sirupsen/logrus" @@ -124,7 +125,7 @@ func handleNewMessage(sockfd int) (uintptr, string, error) { func readArgString(pid uint32, offset int64) (string, error) { buffer := make([]byte, 4096) // PATH_MAX - memfd, err := unix.Open(fmt.Sprintf("/proc/%d/mem", pid), unix.O_RDONLY, 0o777) + memfd, err := linux.Open(fmt.Sprintf("/proc/%d/mem", pid), unix.O_RDONLY, 0o777) if err != nil { return "", err }