diff --git a/container/container.go b/container/container.go index 7d8837a..86bb3b3 100644 --- a/container/container.go +++ b/container/container.go @@ -186,31 +186,24 @@ var ( closeOnExecErr error ) -// ensureCloseOnExec ensures all currently open file descriptors have the syscall.FD_CLOEXEC flag set. -// This is only ran once as it is intended to handle files left open by the parent, and any file opened -// on this side should already have syscall.FD_CLOEXEC set. +// ensureCloseOnExec ensures all currently open file descriptors have the +// syscall.FD_CLOEXEC flag set. +// +// This is only ran once as it is intended to handle files left open by the +// parent, and any file opened on this side should already have +// syscall.FD_CLOEXEC set. func ensureCloseOnExec() error { - closeOnExecOnce.Do(func() { - const fdPrefixPath = "/proc/self/fd/" - - var entries []os.DirEntry - if entries, closeOnExecErr = os.ReadDir(fdPrefixPath); closeOnExecErr != nil { - return - } - - var fd int - for _, ent := range entries { - if fd, closeOnExecErr = strconv.Atoi(ent.Name()); closeOnExecErr != nil { - break // not reached - } - CloseOnExec(fd) - } - }) + closeOnExecOnce.Do(func() { closeOnExecErr = doCloseOnExec() }) if closeOnExecErr == nil { return nil } - return &StartError{Fatal: true, Step: "set FD_CLOEXEC on all open files", Err: closeOnExecErr, Passthrough: true} + return &StartError{ + Fatal: true, + Step: "set FD_CLOEXEC on all open files", + Err: closeOnExecErr, + Passthrough: true, + } } // Start starts the container init. The init process blocks until Serve is called. diff --git a/container/syscall_close_range.go b/container/syscall_close_range.go new file mode 100644 index 0000000..c4d6a05 --- /dev/null +++ b/container/syscall_close_range.go @@ -0,0 +1,11 @@ +//go:build close_range + +package container + +import "hakurei.app/ext" + +// doCloseOnExec implements ensureCloseOnExec by calling CloseRange with +// CLOSE_RANGE_CLOEXEC. +func doCloseOnExec() error { + return ext.CloseRange(0, ext.MaxUint, ext.CLOSE_RANGE_CLOEXEC) +} diff --git a/container/syscall_range_proc.go b/container/syscall_range_proc.go new file mode 100644 index 0000000..62b369f --- /dev/null +++ b/container/syscall_range_proc.go @@ -0,0 +1,28 @@ +//go:build !close_range + +package container + +import ( + "os" + "strconv" + "syscall" + + "hakurei.app/container/fhs" +) + +// doCloseOnExec implements ensureCloseOnExec by ranging over proc_pid_fd(5). +func doCloseOnExec() error { + entries, err := os.ReadDir(fhs.ProcSelf + "fd/") + if err != nil { + return err + } + + var fd int + for _, ent := range entries { + if fd, err = strconv.Atoi(ent.Name()); err != nil { + return err // not reached + } + syscall.CloseOnExec(fd) + } + return nil +}