diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go index 58c742ac3e4..c849ec6b797 100644 --- a/libcontainer/init_linux.go +++ b/libcontainer/init_linux.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" "strings" + "syscall" "unsafe" "github.com/containerd/console" @@ -87,9 +88,7 @@ func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd, // Clean the RLIMIT_NOFILE cache in go runtime. // Issue: https://github.com/opencontainers/runc/issues/4195 - if containsRlimit(config.Rlimits, unix.RLIMIT_NOFILE) { - system.ClearRlimitNofileCache() - } + maybeClearRlimitNofileCache(config.Rlimits) switch t { case initSetns: @@ -268,7 +267,6 @@ func setupConsole(socket *os.File, config *initConfig, mount bool) error { Height: config.ConsoleHeight, Width: config.ConsoleWidth, }) - if err != nil { return err } @@ -525,13 +523,16 @@ func setupRoute(config *configs.Config) error { return nil } -func containsRlimit(limits []configs.Rlimit, resource int) bool { +func maybeClearRlimitNofileCache(limits []configs.Rlimit) { for _, rlimit := range limits { - if rlimit.Type == resource { - return true + if rlimit.Type == syscall.RLIMIT_NOFILE { + system.ClearRlimitNofileCache(&syscall.Rlimit{ + Cur: rlimit.Soft, + Max: rlimit.Hard, + }) + return } } - return false } func setupRlimits(limits []configs.Rlimit, pid int) error { diff --git a/libcontainer/system/rlimit_linux.go b/libcontainer/system/rlimit_linux.go new file mode 100644 index 00000000000..4595fa82aa1 --- /dev/null +++ b/libcontainer/system/rlimit_linux.go @@ -0,0 +1,15 @@ +//go:build go1.23 + +package system + +import ( + "syscall" +) + +// ClearRlimitNofileCache clears go runtime's nofile rlimit cache. The argument +// is process RLIMIT_NOFILE values. Relies on go.dev/cl/588076. +func ClearRlimitNofileCache(lim *syscall.Rlimit) { + // Ignore the return values since we only need to clean the cache, + // the limit is going to be set via unix.Prlimit elsewhere. + _ = syscall.Setrlimit(syscall.RLIMIT_NOFILE, lim) +} diff --git a/libcontainer/system/rlimit_go119.go b/libcontainer/system/rlimit_linux_go122.go similarity index 70% rename from libcontainer/system/rlimit_go119.go rename to libcontainer/system/rlimit_linux_go122.go index a68c8ca6038..674e44bd8f7 100644 --- a/libcontainer/system/rlimit_go119.go +++ b/libcontainer/system/rlimit_linux_go122.go @@ -1,19 +1,21 @@ -//go:build go1.19 +//go:build go1.19 && !go1.23 + +// TODO: remove this file once go 1.22 is no longer supported. package system import ( "sync/atomic" "syscall" - - _ "unsafe" // for go:linkname + _ "unsafe" // Needed for go:linkname to work. ) //go:linkname syscallOrigRlimitNofile syscall.origRlimitNofile var syscallOrigRlimitNofile atomic.Pointer[syscall.Rlimit] -// ClearRlimitNofileCache is to clear go runtime's nofile rlimit cache. -func ClearRlimitNofileCache() { +// ClearRlimitNofileCache clears go runtime's nofile rlimit cache. +// The argument is process RLIMIT_NOFILE values. +func ClearRlimitNofileCache(_ *syscall.Rlimit) { // As reported in issue #4195, the new version of go runtime(since 1.19) // will cache rlimit-nofile. Before executing execve, the rlimit-nofile // of the process will be restored with the cache. In runc, this will diff --git a/libcontainer/system/rlimit_stub.go b/libcontainer/system/rlimit_stub.go index 1b37dc5720c..96200df596c 100644 --- a/libcontainer/system/rlimit_stub.go +++ b/libcontainer/system/rlimit_stub.go @@ -2,5 +2,6 @@ package system -func ClearRlimitNofileCache() { -} +import "syscall" + +func ClearRlimitNofileCache(_ *syscall.Rlimit) {}