Skip to content

Commit da68c8e

Browse files
ls-ggglifubang
authored andcommitted
libct: clean cached rlimit nofile in go runtime
As reported in issue opencontainers#4195, the new version(since 1.19) of go runtime will cache rlimit-nofile. Before executing execve, the rlimit-nofile of the process will be restored with the cache. In runc, this will cause the rlimit-nofile set by the parent process for the container to become invalid. It can be solved by clearing the cache. Signed-off-by: ls-ggg <[email protected]> (cherry picked from commit f9f8abf) Signed-off-by: lifubang <[email protected]>
1 parent a853a82 commit da68c8e

File tree

3 files changed

+31
-0
lines changed

3 files changed

+31
-0
lines changed

libcontainer/init_linux.go

+15
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ func containerInit(t initType, config *initConfig, pipe *syncSocket, consoleSock
223223
return err
224224
}
225225

226+
// Clean the RLIMIT_NOFILE cache in go runtime.
227+
// Issue: https://github.com/opencontainers/runc/issues/4195
228+
if containsRlimit(config.Rlimits, unix.RLIMIT_NOFILE) {
229+
system.ClearRlimitNofileCache()
230+
}
231+
226232
switch t {
227233
case initSetns:
228234
i := &linuxSetnsInit{
@@ -649,6 +655,15 @@ func setupRoute(config *configs.Config) error {
649655
return nil
650656
}
651657

658+
func containsRlimit(limits []configs.Rlimit, resource int) bool {
659+
for _, rlimit := range limits {
660+
if rlimit.Type == resource {
661+
return true
662+
}
663+
}
664+
return false
665+
}
666+
652667
func setupRlimits(limits []configs.Rlimit, pid int) error {
653668
for _, rlimit := range limits {
654669
if err := unix.Prlimit(pid, rlimit.Type, &unix.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}, nil); err != nil {

libcontainer/setns_init_linux.go

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func (l *linuxSetnsInit) Init() error {
4949
}
5050
}
5151
}
52+
5253
if l.config.CreateConsole {
5354
if err := setupConsole(l.consoleSocket, l.config, false); err != nil {
5455
return err

libcontainer/system/linux.go

+15
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,28 @@ import (
88
"io"
99
"os"
1010
"strconv"
11+
"sync/atomic"
1112
"syscall"
1213
"unsafe"
1314

1415
"github.com/sirupsen/logrus"
1516
"golang.org/x/sys/unix"
1617
)
1718

19+
//go:linkname syscallOrigRlimitNofile syscall.origRlimitNofile
20+
var syscallOrigRlimitNofile atomic.Pointer[syscall.Rlimit]
21+
22+
// As reported in issue #4195, the new version of go runtime(since 1.19)
23+
// will cache rlimit-nofile. Before executing execve, the rlimit-nofile
24+
// of the process will be restored with the cache. In runc, this will
25+
// cause the rlimit-nofile setting by the parent process for the container
26+
// to become invalid. It can be solved by clearing this cache. But
27+
// unfortunately, go stdlib doesn't provide such function, so we need to
28+
// link to the private var `origRlimitNofile` in package syscall to hack.
29+
func ClearRlimitNofileCache() {
30+
syscallOrigRlimitNofile.Store(nil)
31+
}
32+
1833
type ParentDeathSignal int
1934

2035
func (p ParentDeathSignal) Restore() error {

0 commit comments

Comments
 (0)