ronantakizawa/codereview-bench huggingface dataset:
Repository: opencontainers/runc
File: libcontainer/configs/validate/rootless_test.go (Go)

Code before:
	}

	if err := Validate(config); err != nil {
		t.Errorf("Expected error to not occur when gid= not set in mount options: %+v", err)
	}

	config.Mounts[0].Data = "gid=5"
	if err := Validate(config); err == nil {
		t.Errorf("Expected error to occur when setting gid=5 in mount options")
	}

	config.Mounts[0].Data = "gid=0"
	if err := Validate(config); err != nil {
		t.Errorf("Expected error to not occur when setting gid=0 in mount options: %+v", err)
	}

	config.Mounts[0].Data = "gid=5"
	config.GIDMappings[0].Size = 10
	if err := Validate(config); err != nil {
		t.Errorf("Expected error to not occur when setting gid=5 in mount options and GidMapping[0].size is 10")
	}

	config.Mounts[0].Data = "gid=11"
	config.GIDMappings[0].Size = 10
	if err := Validate(config); err == nil {
		t.Errorf("Expected error to occur when setting gid=11 in mount options and GidMapping[0].size is 10")
	}
}

func BenchmarkRootlessEUIDMount(b *testing.B) {
	config := rootlessEUIDConfig()
	config.GIDMappings[0].Size = 10
	config.Mounts = []*configs.Mount{
		{
			Source:      "devpts",
			Destination: "/dev/pts",
			Device:      "devpts",
			Data:        "newinstance,ptmxmode=0666,mode=0620,uid=0,gid=5",
		},
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err := rootlessEUIDMount(config)
		if err != nil {
			b.Fatal(err)
		}
	}
}


Review comment (suggestion):
In this error msg, we should change `GidMapping` to `GIDMapping`.

Code after:
	}

	if err := Validate(config); err != nil {
		t.Errorf("Expected error to not occur when gid= not set in mount options: %+v", err)
	}

	config.Mounts[0].Data = "gid=5"
	if err := Validate(config); err == nil {
		t.Errorf("Expected error to occur when setting gid=5 in mount options")
	}

	config.Mounts[0].Data = "gid=0"
	if err := Validate(config); err != nil {
		t.Errorf("Expected error to not occur when setting gid=0 in mount options: %+v", err)
	}

	config.Mounts[0].Data = "gid=5"
	config.GIDMappings[0].Size = 10
	if err := Validate(config); err != nil {
		t.Errorf("Expected error to not occur when setting gid=5 in mount options and GIDMappings[0].size is 10")
	}

	config.Mounts[0].Data = "gid=11"
	config.GIDMappings[0].Size = 10
	if err := Validate(config); err == nil {
		t.Errorf("Expected error to occur when setting gid=11 in mount options and GIDMappings[0].size is 10")
	}
}

func BenchmarkRootlessEUIDMount(b *testing.B) {
	config := rootlessEUIDConfig()
	config.GIDMappings[0].Size = 10
	config.Mounts = []*configs.Mount{
		{
			Source:      "devpts",
			Destination: "/dev/pts",
			Device:      "devpts",
			Data:        "newinstance,ptmxmode=0666,mode=0620,uid=0,gid=5",
		},
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err := rootlessEUIDMount(config)
		if err != nil {
			b.Fatal(err)
		}
	}
}
Repository: opencontainers/runc
File: contrib/cmd/fs-idmap/fs-idmap.go (Go)

Code before:
	"os"
	"os/exec"
	"syscall"

	"golang.org/x/sys/unix"
)

func main() {
	if len(os.Args) != 2 {
		log.Fatalf("usage: %s path_to_mount_set_attr", os.Args[0])
	}

	src := os.Args[1]
	treeFD, err := unix.OpenTree(-1, src, uint(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH))
	if err != nil {
		log.Fatalf("error calling open_tree %q: %v", src, err)
	}
	defer unix.Close(treeFD)

	cmd := exec.Command("sleep", "5")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags:  syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
		GidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
	}
	if err := cmd.Start(); err != nil {
		log.Fatalf("failed to run the helper binary: %v", err)
	}
	defer func() { _ = cmd.Wait() }()

	path := fmt.Sprintf("/proc/%d/ns/user", cmd.Process.Pid)
	var userNsFile *os.File
	if userNsFile, err = os.Open(path); err != nil {
		log.Fatalf("unable to get user ns file descriptor: %v", err)
	}
	defer userNsFile.Close()

	attr := unix.MountAttr{
		Attr_set:  unix.MOUNT_ATTR_IDMAP,
		Userns_fd: uint64(userNsFile.Fd()),
	}
	if err := unix.MountSetattr(treeFD, "", unix.AT_EMPTY_PATH, &attr); err != nil {
		log.Fatalf("error calling mount_setattr: %v", err)
	}

	_ = cmd.Process.Kill()
}


Review comment (suggestion):
I think a better way of doing this is to use `Ptrace: true` to avoid doing an exec at all (that's what I'm doing in #3953). But I guess since this is a contrib program it doesn't really matter.

Code after:
	"os/exec"
	"syscall"

	"golang.org/x/sys/unix"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "path_to_mount_set_attr")
		os.Exit(1)
	}
	src := os.Args[1]
	if err := supportsIDMap(src); err != nil {
		fmt.Fprintln(os.Stderr, "fatal error:", err)
		os.Exit(1)
	}
}

func supportsIDMap(src string) error {
	treeFD, err := unix.OpenTree(unix.AT_FDCWD, src, uint(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH))
	if err != nil {
		return fmt.Errorf("error calling open_tree %q: %w", src, err)
	}
	defer unix.Close(treeFD)

	cmd := exec.Command("sleep", "5")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags:  syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
		GidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
	}
	if err := cmd.Start(); err != nil {
		return fmt.Errorf("failed to run the helper binary: %w", err)
	}
	defer func() {
		_ = cmd.Process.Kill()
		_ = cmd.Wait()
	}()

	path := fmt.Sprintf("/proc/%d/ns/user", cmd.Process.Pid)
	var userNsFile *os.File
	if userNsFile, err = os.Open(path); err != nil {
		return fmt.Errorf("unable to get user ns file descriptor: %w", err)
	}
	defer userNsFile.Close()

	attr := unix.MountAttr{
		Attr_set:  unix.MOUNT_ATTR_IDMAP,
		Userns_fd: uint64(userNsFile.Fd()),
	}
	if err := unix.MountSetattr(treeFD, "", unix.AT_EMPTY_PATH, &attr); err != nil {
Repository: opencontainers/runc
File: contrib/cmd/fs-idmap/fs-idmap.go (Go)

Code before:
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"syscall"

	"golang.org/x/sys/unix"
)

func main() {
	if len(os.Args) != 2 {
		log.Fatalf("usage: %s path_to_mount_set_attr", os.Args[0])
	}

	src := os.Args[1]
	treeFD, err := unix.OpenTree(-1, src, uint(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH))
	if err != nil {
		log.Fatalf("error calling open_tree %q: %v", src, err)
	}
	defer unix.Close(treeFD)

	cmd := exec.Command("sleep", "5")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags:  syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
		GidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
	}
	if err := cmd.Start(); err != nil {
		log.Fatalf("failed to run the helper binary: %v", err)
	}
	defer func() { _ = cmd.Wait() }()

	path := fmt.Sprintf("/proc/%d/ns/user", cmd.Process.Pid)
	var userNsFile *os.File
	if userNsFile, err = os.Open(path); err != nil {
		log.Fatalf("unable to get user ns file descriptor: %v", err)
	}
	defer userNsFile.Close()

	attr := unix.MountAttr{
		Attr_set:  unix.MOUNT_ATTR_IDMAP,

Review comment (suggestion):
```suggestion
	treeFD, err := unix.OpenTree(unix.AT_FDCWD, src, uint(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH))
```

I might've been persuaded with the argument behind using `-EBADF` in runc, but here there's no reason to not allow relative paths.

Code after:
package main

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"

	"golang.org/x/sys/unix"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "path_to_mount_set_attr")
		os.Exit(1)
	}
	src := os.Args[1]
	if err := supportsIDMap(src); err != nil {
		fmt.Fprintln(os.Stderr, "fatal error:", err)
		os.Exit(1)
	}
}

func supportsIDMap(src string) error {
	treeFD, err := unix.OpenTree(unix.AT_FDCWD, src, uint(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH))
	if err != nil {
		return fmt.Errorf("error calling open_tree %q: %w", src, err)
	}
	defer unix.Close(treeFD)

	cmd := exec.Command("sleep", "5")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags:  syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
		GidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
	}
	if err := cmd.Start(); err != nil {
		return fmt.Errorf("failed to run the helper binary: %w", err)
	}
	defer func() {
		_ = cmd.Process.Kill()
		_ = cmd.Wait()
	}()
Repository: opencontainers/runc
File: contrib/cmd/fs-idmap/fs-idmap.go (Go)

Code before:
	if len(os.Args) != 2 {
		log.Fatalf("usage: %s path_to_mount_set_attr", os.Args[0])
	}

	src := os.Args[1]
	treeFD, err := unix.OpenTree(-1, src, uint(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH))
	if err != nil {
		log.Fatalf("error calling open_tree %q: %v", src, err)
	}
	defer unix.Close(treeFD)

	cmd := exec.Command("sleep", "5")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags:  syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
		GidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
	}
	if err := cmd.Start(); err != nil {
		log.Fatalf("failed to run the helper binary: %v", err)
	}
	defer func() { _ = cmd.Wait() }()

	path := fmt.Sprintf("/proc/%d/ns/user", cmd.Process.Pid)
	var userNsFile *os.File
	if userNsFile, err = os.Open(path); err != nil {
		log.Fatalf("unable to get user ns file descriptor: %v", err)
	}
	defer userNsFile.Close()

	attr := unix.MountAttr{
		Attr_set:  unix.MOUNT_ATTR_IDMAP,
		Userns_fd: uint64(userNsFile.Fd()),
	}
	if err := unix.MountSetattr(treeFD, "", unix.AT_EMPTY_PATH, &attr); err != nil {
		log.Fatalf("error calling mount_setattr: %v", err)
	}

	_ = cmd.Process.Kill()
}


Review comment (suggestion):
`defer` statements don't execute on `Fatalf` because it doesn't panic nor return. This should be changed to `log.Errorf` and then `return`.

Code after:
		fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "path_to_mount_set_attr")
		os.Exit(1)
	}
	src := os.Args[1]
	if err := supportsIDMap(src); err != nil {
		fmt.Fprintln(os.Stderr, "fatal error:", err)
		os.Exit(1)
	}
}

func supportsIDMap(src string) error {
	treeFD, err := unix.OpenTree(unix.AT_FDCWD, src, uint(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH))
	if err != nil {
		return fmt.Errorf("error calling open_tree %q: %w", src, err)
	}
	defer unix.Close(treeFD)

	cmd := exec.Command("sleep", "5")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags:  syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
		GidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
	}
	if err := cmd.Start(); err != nil {
		return fmt.Errorf("failed to run the helper binary: %w", err)
	}
	defer func() {
		_ = cmd.Process.Kill()
		_ = cmd.Wait()
	}()

	path := fmt.Sprintf("/proc/%d/ns/user", cmd.Process.Pid)
	var userNsFile *os.File
	if userNsFile, err = os.Open(path); err != nil {
		return fmt.Errorf("unable to get user ns file descriptor: %w", err)
	}
	defer userNsFile.Close()

	attr := unix.MountAttr{
		Attr_set:  unix.MOUNT_ATTR_IDMAP,
		Userns_fd: uint64(userNsFile.Fd()),
	}
	if err := unix.MountSetattr(treeFD, "", unix.AT_EMPTY_PATH, &attr); err != nil {
		return fmt.Errorf("error calling mount_setattr: %w", err)
	}

	return nil
}
Repository: opencontainers/runc
File: script/prepare-cgroup-v2.sh (Shell)

Code before:
#!/bin/bash
#
# This script is used from ../Dockerfile as the ENTRYPOINT. It sets up cgroup
# delegation for cgroup v2 to make sure runc tests can be properly run inside
# a container.

# Only do this for cgroup v2.
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
	set -x
	# Move the current process to a sub-cgroup.
	mkdir /sys/fs/cgroup/init
	echo 0 >/sys/fs/cgroup/init/cgroup.procs
	# Enable all controllers.
	sed -e 's/ / +/g' -e 's/^/+/' <"/sys/fs/cgroup/cgroup.controllers" >"/sys/fs/cgroup/cgroup.subtree_control"
fi

exec "$@"


Review comment (suggestion):
Nit:

```suggestion
	sed 's/\b\w/+\0/g' <"/sys/fs/cgroup/cgroup.controllers" >"/sys/fs/cgroup/cgroup.subtree_control"
```

Code after:
#!/bin/bash
#
# This script is used from ../Dockerfile as the ENTRYPOINT. It sets up cgroup
# delegation for cgroup v2 to make sure runc tests can be properly run inside
# a container.

# Only do this for cgroup v2.
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
	set -x
	# Move the current process to a sub-cgroup.
	mkdir /sys/fs/cgroup/init
	echo 0 >/sys/fs/cgroup/init/cgroup.procs
	# Enable all controllers.
	sed 's/\b\w/+\0/g' <"/sys/fs/cgroup/cgroup.controllers" >"/sys/fs/cgroup/cgroup.subtree_control"
fi

exec "$@"
Repository: opencontainers/runc
File: libcontainer/utils/cmsg.go (Go)

Code before:
	}
	if n >= MaxNameLen || oobn != oobSpace {
		return nil, fmt.Errorf("recvfile: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
	}
	// Truncate.
	name = name[:n]
	oob = oob[:oobn]

	scms, err := unix.ParseSocketControlMessage(oob)
	if err != nil {
		return nil, err
	}

	// We cannot control how many SCM_RIGHTS we receive, and upon receiving
	// them all of the descriptors are installed in our fd table, so we need to
	// parse all of the SCM_RIGHTS we received in order to close all of the
	// descriptors on error.
	var fds []int
	defer func() {
		for i, fd := range fds {
			if i == 0 && err == nil {
				// Only close the first one on error.
				continue
			}
			// Always close extra ones.
			_ = unix.Close(fd)
		}
	}()
	var lastErr error
	for _, scm := range scms {
		if scm.Header.Type == unix.SCM_RIGHTS {
			scmFds, err := unix.ParseUnixRights(&scm)
			if err != nil {
				lastErr = err
			} else {
				fds = append(fds, scmFds...)
			}
		}
	}
	if lastErr != nil {
		return nil, lastErr
	}

	// We do this after collecting the fds to make sure we close them all when
	// returning an error here.
	if len(scms) != 1 {
		return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
	}
	if len(fds) != 1 {
		return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
	}

Review comment (suggestion):
@cyphar I slightly changed the code here; the original was this:
```go
			// Only close 0 if err != nil, and close everything else.
			if i != 0 || err != nil {
				_ = unix.Close(fd)
			}
```

I feel that my version is less compact but more readable. Feel free to 👎🏻 and I will revert :)

Code after:
	}
	if n >= MaxNameLen || oobn != oobSpace {
		return nil, fmt.Errorf("recvfile: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
	}
	// Truncate.
	name = name[:n]
	oob = oob[:oobn]

	scms, err := unix.ParseSocketControlMessage(oob)
	if err != nil {
		return nil, err
	}

	// We cannot control how many SCM_RIGHTS we receive, and upon receiving
	// them all of the descriptors are installed in our fd table, so we need to
	// parse all of the SCM_RIGHTS we received in order to close all of the
	// descriptors on error.
	var fds []int
	defer func() {
		for i, fd := range fds {
			if i == 0 && Err == nil {
				// Only close the first one on error.
				continue
			}
			// Always close extra ones.
			_ = unix.Close(fd)
		}
	}()
	var lastErr error
	for _, scm := range scms {
		if scm.Header.Type == unix.SCM_RIGHTS {
			scmFds, err := unix.ParseUnixRights(&scm)
			if err != nil {
				lastErr = err
			} else {
				fds = append(fds, scmFds...)
			}
		}
	}
	if lastErr != nil {
		return nil, lastErr
	}

	// We do this after collecting the fds to make sure we close them all when
	// returning an error here.
	if len(scms) != 1 {
		return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
	}
	if len(fds) != 1 {
		return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
	}
Repository: opencontainers/runc
File: libcontainer/cgroups/fs2/memory.go (Go)

Code before:
			// if kernel CONFIG_MEMCG_SWAP is not set or
			// swapaccount=0 kernel boot parameter is given.
			return cgroups.MemoryData{}, nil
		}
		return cgroups.MemoryData{}, err
	}
	memoryData.Usage = value

	value, err = fscommon.GetCgroupParamUint(path, limit)
	if err != nil {
		return cgroups.MemoryData{}, err
	}
	memoryData.Limit = value

	// `memory.peak` since kernel 5.19
	// `memory.swap.peak` since kernel 6.5
	value, err = fscommon.GetCgroupParamUint(path, maxUsage)
	if err != nil && !os.IsNotExist(err) {
		return cgroups.MemoryData{}, err
	}
	memoryData.MaxUsage = value

	return memoryData, nil
}

func rootStatsFromMeminfo(stats *cgroups.Stats) error {
	const file = "/proc/meminfo"
	f, err := os.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()

	// Fields we are interested in.
	var (
		swap_free  uint64
		swap_total uint64
	)
	mem := map[string]*uint64{
		"SwapFree":  &swap_free,
		"SwapTotal": &swap_total,
	}

	found := 0
	sc := bufio.NewScanner(f)
	for sc.Scan() {
		parts := strings.SplitN(sc.Text(), ":", 3)
		if len(parts) != 2 {
			// Should not happen.
			continue
		}

Review comment (suggestion):
Please look into `fscommon.GetCgroupParamUnit`, If there is an error, the return value may be 0, so I think we should check err when setting `MaxUsage` value. Just like this:
```go
	value, err = fscommon.GetCgroupParamUint(path, maxUsage)
	if err != nil {
		if !os.IsNotExist(err) {
			return cgroups.MemoryData{}, err
		}
	} else {
		memoryData.MaxUsage = value
	}
```

Code after:

	value, err := fscommon.GetCgroupParamUint(path, usage)
	if err != nil {
		if name != "" && os.IsNotExist(err) {
			// Ignore EEXIST as there's no swap accounting
			// if kernel CONFIG_MEMCG_SWAP is not set or
			// swapaccount=0 kernel boot parameter is given.
			return cgroups.MemoryData{}, nil
		}
		return cgroups.MemoryData{}, err
	}
	memoryData.Usage = value

	value, err = fscommon.GetCgroupParamUint(path, limit)
	if err != nil {
		return cgroups.MemoryData{}, err
	}
	memoryData.Limit = value

	// `memory.peak` since kernel 5.19
	// `memory.swap.peak` since kernel 6.5
	value, err = fscommon.GetCgroupParamUint(path, maxUsage)
	if err != nil && !os.IsNotExist(err) {
		return cgroups.MemoryData{}, err
	}
	memoryData.MaxUsage = value

	return memoryData, nil
}

func rootStatsFromMeminfo(stats *cgroups.Stats) error {
	const file = "/proc/meminfo"
	f, err := os.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()

	// Fields we are interested in.
	var (
		swap_free  uint64
		swap_total uint64
	)
	mem := map[string]*uint64{
		"SwapFree":  &swap_free,
		"SwapTotal": &swap_total,
	}

	found := 0
	sc := bufio.NewScanner(f)
	for sc.Scan() {
Repository: opencontainers/runc
File: libcontainer/configs/validate/validator.go (Go)

Code before:
func isHostNetNS(path string) (bool, error) {
	const currentProcessNetns = "/proc/self/ns/net"

	var st1, st2 unix.Stat_t

	if err := unix.Stat(currentProcessNetns, &st1); err != nil {
		return false, &os.PathError{Op: "stat", Path: currentProcessNetns, Err: err}
	}
	if err := unix.Stat(path, &st2); err != nil {
		return false, &os.PathError{Op: "stat", Path: path, Err: err}
	}

	return (st1.Dev == st2.Dev) && (st1.Ino == st2.Ino), nil
}

// scheduler is to validate scheduler configs according to https://man7.org/linux/man-pages/man2/sched_setattr.2.html
func scheduler(config *configs.Config) error {
	if config.Scheduler == nil {
		return nil
	}
	niceValue := config.Scheduler.Nice
	if niceValue < -20 || niceValue > 19 {
		return fmt.Errorf("invalid scheduler.nice: %d", niceValue)
	}
	if config.Scheduler.Policy != specs.SchedFIFO && config.Scheduler.Policy != specs.SchedRR {
		if config.Scheduler.Priority != 0 {
			return fmt.Errorf("invalid scheduler.priority: %d", config.Scheduler.Priority)
		}
	}
	if config.Scheduler.Policy != specs.SchedDeadline {
		if config.Scheduler.Runtime != 0 {
			return fmt.Errorf("invalid scheduler.runtime: %d", config.Scheduler.Runtime)
		}
		if config.Scheduler.Deadline != 0 {
			return fmt.Errorf("invalid scheduler.deadline: %d", config.Scheduler.Deadline)
		}
		if config.Scheduler.Period != 0 {
			return fmt.Errorf("invalid scheduler.period: %d", config.Scheduler.Period)
		}
	}
	return nil
}


Review comment (suggestion):
I would revert the order of conditions, and also change the error message:

```go
if s.Priority != 0  && (s.Policy != specs.SchedFIFO && s.Policy != specs.SchedRR) {
	return errors.New("scheduler.priority can only be specified for SchedFIFO or SchedRR policy")
}
```

Code after:
func isHostNetNS(path string) (bool, error) {
	const currentProcessNetns = "/proc/self/ns/net"

	var st1, st2 unix.Stat_t

	if err := unix.Stat(currentProcessNetns, &st1); err != nil {
		return false, &os.PathError{Op: "stat", Path: currentProcessNetns, Err: err}
	}
	if err := unix.Stat(path, &st2); err != nil {
		return false, &os.PathError{Op: "stat", Path: path, Err: err}
	}

	return (st1.Dev == st2.Dev) && (st1.Ino == st2.Ino), nil
}

// scheduler is to validate scheduler configs according to https://man7.org/linux/man-pages/man2/sched_setattr.2.html
func scheduler(config *configs.Config) error {
	s := config.Scheduler
	if s == nil {
		return nil
	}
	if s.Policy == "" {
		return errors.New("scheduler policy is required")
	}
	if s.Nice < -20 || s.Nice > 19 {
		return fmt.Errorf("invalid scheduler.nice: %d", s.Nice)
	}
	if s.Priority != 0 && (s.Policy != specs.SchedFIFO && s.Policy != specs.SchedRR) {
		return errors.New("scheduler.priority can only be specified for SchedFIFO or SchedRR policy")
	}
	if s.Policy != specs.SchedDeadline && (s.Runtime != 0 || s.Deadline != 0 || s.Period != 0) {
		return errors.New("scheduler runtime/deadline/period can only be specified for SchedDeadline policy")
	}
	return nil
}