From bbb035cb090df06a4bbe95a1b2e29fa206ed0ec7 Mon Sep 17 00:00:00 2001 From: ls-ggg <335814617@qq.com> Date: Fri, 29 Mar 2024 18:12:08 +0800 Subject: [PATCH] libcontainer:clean cached rlimit nofile in go runtime As reported in issue #4195, the new version of go runtime will cache rlimit-nofile. before executing exec, the rlimit-nofile of the process will be updated with the cache. in runc, this will cause the rlimit-nofile set by the parent process for the container to become invalid. this can be solved by clearing the cache. Signed-off-by: ls-ggg <335814617@qq.com> --- libcontainer/setns_init_linux.go | 12 ++++++++++++ libcontainer/standard_init_linux.go | 10 ++++++++++ tests/integration/resources.bats | 22 ++++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/integration/resources.bats diff --git a/libcontainer/setns_init_linux.go b/libcontainer/setns_init_linux.go index ba48604d988..71471b6f603 100644 --- a/libcontainer/setns_init_linux.go +++ b/libcontainer/setns_init_linux.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "os/exec" + "syscall" "github.com/opencontainers/selinux/go-selinux" "github.com/sirupsen/logrus" @@ -49,6 +50,17 @@ func (l *linuxSetnsInit) Init() error { } } } + + // Clean the cache of RLIMIT_NOFILE in go runtime + // The problem originates from https://github.com/golang/go/commit/f5eef58e4381259cbd84b3f2074c79607fb5c821 + rlimit := syscall.Rlimit{} + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { + return err + } + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { + return err + } + if l.config.CreateConsole { if err := setupConsole(l.consoleSocket, l.config, false); err != nil { return err diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go index 4447032cf59..299a420d833 100644 --- a/libcontainer/standard_init_linux.go +++ b/libcontainer/standard_init_linux.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "os/exec" + "syscall" "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux" @@ -76,6 +77,15 @@ func (l *linuxStandardInit) Init() error { } } } + // Clean the cache of RLIMIT_NOFILE in go runtime + // The problem originates from https://github.com/golang/go/commit/f5eef58e4381259cbd84b3f2074c79607fb5c821 + rlimit := syscall.Rlimit{} + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { + return err + } + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { + return err + } if err := setupNetwork(l.config); err != nil { return err diff --git a/tests/integration/resources.bats b/tests/integration/resources.bats new file mode 100644 index 00000000000..8d035c3a0ef --- /dev/null +++ b/tests/integration/resources.bats @@ -0,0 +1,22 @@ +#!/usr/bin/env bats + +load helpers + +function setup() { + setup_busybox +} + +function teardown() { + teardown_bundle +} + +@test "runc run with RLIMIT_NOFILE" { + update_config '.process.args = ["/bin/sh", "-c", "ulimit -n"]' + update_config '.process.capabilities.bounding = ["CAP_SYS_RESOURCE"]' + update_config '.process.rlimits = [{"type": "RLIMIT_NOFILE", "hard": 10000, "soft": 10000}]' + + runc run test_hello + [ "$status" -eq 0 ] + + [[ "${output}" == "10000" ]] +}