aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-03-17 14:19:00 +0900
committerOphestra <cat@gensokyo.uk>2026-03-17 14:19:00 +0900
commit0a12d456ce5869042dc06c43c360c43cab942d6b (patch)
treee94bcc00c5f96eb3683155ffec0fc6362b9aeb2e
parentd1fc1a3db73e61ef85667f835005659dc7c1cb1f (diff)
container: set CLOEXEC via close_range
This is guarded behind the close_range build tag for now. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--container/container.go33
-rw-r--r--container/syscall_close_range.go11
-rw-r--r--container/syscall_range_proc.go28
3 files changed, 52 insertions, 20 deletions
diff --git a/container/container.go b/container/container.go
index 7d8837a3..86bb3b36 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 00000000..c4d6a051
--- /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 00000000..62b369f0
--- /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
+}