aboutsummaryrefslogtreecommitdiffhomepage
path: root/container
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-10-19 15:09:33 +0900
committerOphestra <cat@gensokyo.uk>2026-10-19 15:09:33 +0900
commit58913f00845903aa2068f6cb0778baa563d58d14 (patch)
tree37c6d6e6f5245c6b9c636bef1bcd21373cd48cfa /container
parent4de395f11996d3c269e4dae1dc5f7de83c2b83e9 (diff)
container/sysctl: remove calls to logger
This behaviour is counterintuitive, the responses are cached, and only the msg object of the first call is used. This change also improves error message formatting of these functions. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container')
-rw-r--r--container/container.go4
-rw-r--r--container/dispatcher.go16
-rw-r--r--container/dispatcher_test.go3
-rw-r--r--container/init.go4
-rw-r--r--container/sysctl.go69
-rw-r--r--container/sysctl_deprecated.go19
6 files changed, 74 insertions, 41 deletions
diff --git a/container/container.go b/container/container.go
index 3571d04a..6929c652 100644
--- a/container/container.go
+++ b/container/container.go
@@ -231,10 +231,10 @@ func (p *Container) Start() error {
// map to overflow id to work around ownership checks
if p.Uid < 1 {
- p.Uid = OverflowUid(p.msg)
+ p.Uid = OverflowUID()
}
if p.Gid < 1 {
- p.Gid = OverflowGid(p.msg)
+ p.Gid = OverflowGID()
}
if !p.RetainSession {
diff --git a/container/dispatcher.go b/container/dispatcher.go
index 4636a469..ba5e9c10 100644
--- a/container/dispatcher.go
+++ b/container/dispatcher.go
@@ -37,15 +37,15 @@ type syscallDispatcher interface {
// lockOSThread provides [runtime.LockOSThread].
lockOSThread()
- // setPtracer provides [SetPtracer].
+ // setPtracer provides [ext.SetPtracer].
setPtracer(pid uintptr) error
- // setDumpable provides [SetDumpable].
+ // setDumpable provides [ext.SetDumpable].
setDumpable(dumpable uintptr) error
- // setNoNewPrivs provides [SetNoNewPrivs].
+ // setNoNewPrivs provides setNoNewPrivs.
setNoNewPrivs() error
- // lastcap provides [LastCap].
- lastcap(msg message.Msg) uintptr
+ // lastcap provides lastcap.
+ lastcap() uintptr
// capset provides capset.
capset(hdrp *capHeader, datap *[2]capData) error
// capBoundingSetDrop provides capBoundingSetDrop.
@@ -54,9 +54,9 @@ type syscallDispatcher interface {
capAmbientClearAll() error
// capAmbientRaise provides capAmbientRaise.
capAmbientRaise(cap uintptr) error
- // isatty provides [Isatty].
+ // isatty provides [ext.Isatty].
isatty(fd int) bool
- // receive provides [Receive].
+ // receive provides [params.Receive].
receive(key string, e any, fdp *int) (closeFunc func() error, err error)
// bindMount provides procPaths.bindMount.
@@ -152,7 +152,7 @@ func (direct) setPtracer(pid uintptr) error { return ext.SetPtracer(pid) }
func (direct) setDumpable(dumpable uintptr) error { return ext.SetDumpable(dumpable) }
func (direct) setNoNewPrivs() error { return setNoNewPrivs() }
-func (direct) lastcap(msg message.Msg) uintptr { return LastCap(msg) }
+func (direct) lastcap() uintptr { return lastcap() }
func (direct) capset(hdrp *capHeader, datap *[2]capData) error { return capset(hdrp, datap) }
func (direct) capBoundingSetDrop(cap uintptr) error { return capBoundingSetDrop(cap) }
func (direct) capAmbientClearAll() error { return capAmbientClearAll() }
diff --git a/container/dispatcher_test.go b/container/dispatcher_test.go
index 242af1bf..9276a2c5 100644
--- a/container/dispatcher_test.go
+++ b/container/dispatcher_test.go
@@ -352,9 +352,8 @@ func (k *kstub) setDumpable(dumpable uintptr) error {
}
func (k *kstub) setNoNewPrivs() error { k.Helper(); return k.Expects("setNoNewPrivs").Err }
-func (k *kstub) lastcap(msg message.Msg) uintptr {
+func (k *kstub) lastcap() uintptr {
k.Helper()
- k.checkMsg(msg)
return k.Expects("lastcap").Ret.(uintptr)
}
diff --git a/container/init.go b/container/init.go
index 07fff357..03501646 100644
--- a/container/init.go
+++ b/container/init.go
@@ -226,7 +226,7 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
}
// cache sysctl before pivot_root
- lastcap := k.lastcap(msg)
+ lc := k.lastcap()
if err := k.mount(zeroString, fhs.Root, zeroString, MS_SILENT|MS_SLAVE|MS_REC, zeroString); err != nil {
k.fatalf(msg, "cannot make / rslave: %v", optionalErrorUnwrap(err))
@@ -399,7 +399,7 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
if err := k.capAmbientClearAll(); err != nil {
k.fatalf(msg, "cannot clear the ambient capability set: %v", err)
}
- for i := range lastcap + 1 {
+ for i := range lc + 1 {
if slices.Contains(keepCaps, i) {
continue
}
diff --git a/container/sysctl.go b/container/sysctl.go
index e4b7af23..2cf47258 100644
--- a/container/sysctl.go
+++ b/container/sysctl.go
@@ -2,14 +2,32 @@ package container
import (
"bytes"
+ "fmt"
"os"
"strconv"
"sync"
"hakurei.app/fhs"
- "hakurei.app/message"
)
+// mustSysctlInt reads a sysctl path via proc, interprets it as a decimal
+// representation of an integer, and terminates the program if the read was
+// unsuccessful or the response is invalid.
+func mustSysctlInt(path string) (v int) {
+ p, err := os.ReadFile(fhs.ProcSys + path)
+ if err != nil {
+ fmt.Println(err.Error())
+ os.Exit(1)
+ }
+
+ if v, err = strconv.Atoi(string(bytes.TrimSpace(p))); err != nil {
+ fmt.Printf("invalid sysctl response %q\n", string(p))
+ os.Exit(1)
+ }
+ return
+}
+
+// cached sysctl responses for populateSysctl
var (
kernelOverflowuid int
kernelOverflowgid int
@@ -18,34 +36,31 @@ var (
sysctlOnce sync.Once
)
-const (
- kernelOverflowuidPath = fhs.ProcSys + "kernel/overflowuid"
- kernelOverflowgidPath = fhs.ProcSys + "kernel/overflowgid"
- kernelCapLastCapPath = fhs.ProcSys + "kernel/cap_last_cap"
-)
-
-func mustReadSysctl(msg message.Msg) {
+// populateSysctl populates cached sysctl responses guarded by sysctlOnce.
+func populateSysctl() {
sysctlOnce.Do(func() {
- if v, err := os.ReadFile(kernelOverflowuidPath); err != nil {
- msg.GetLogger().Fatalf("cannot read %q: %v", kernelOverflowuidPath, err)
- } else if kernelOverflowuid, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
- msg.GetLogger().Fatalf("cannot interpret %q: %v", kernelOverflowuidPath, err)
- }
+ kernelOverflowuid = mustSysctlInt("kernel/overflowuid")
+ kernelOverflowgid = mustSysctlInt("kernel/overflowgid")
+ kernelCapLastCap = mustSysctlInt("kernel/cap_last_cap")
+ })
+}
- if v, err := os.ReadFile(kernelOverflowgidPath); err != nil {
- msg.GetLogger().Fatalf("cannot read %q: %v", kernelOverflowgidPath, err)
- } else if kernelOverflowgid, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
- msg.GetLogger().Fatalf("cannot interpret %q: %v", kernelOverflowgidPath, err)
- }
+// OverflowUID returns the fixed uid returned by legacy 16-bit UID system calls.
+// This value is also returned for unmapped UIDs in a user namespace.
+func OverflowUID() int {
+ populateSysctl()
+ return kernelOverflowuid
+}
- if v, err := os.ReadFile(kernelCapLastCapPath); err != nil {
- msg.GetLogger().Fatalf("cannot read %q: %v", kernelCapLastCapPath, err)
- } else if kernelCapLastCap, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
- msg.GetLogger().Fatalf("cannot interpret %q: %v", kernelCapLastCapPath, err)
- }
- })
+// OverflowGID is like [OverflowUID], but for GID instead.
+func OverflowGID() int {
+ populateSysctl()
+ return kernelOverflowgid
}
-func OverflowUid(msg message.Msg) int { mustReadSysctl(msg); return kernelOverflowuid }
-func OverflowGid(msg message.Msg) int { mustReadSysctl(msg); return kernelOverflowgid }
-func LastCap(msg message.Msg) uintptr { mustReadSysctl(msg); return uintptr(kernelCapLastCap) }
+// lastcap returns the highest valid capability of the running kernel. Exports
+// CAP_LAST_CAP from the kernel.
+func lastcap() uintptr {
+ populateSysctl()
+ return uintptr(kernelCapLastCap)
+}
diff --git a/container/sysctl_deprecated.go b/container/sysctl_deprecated.go
new file mode 100644
index 00000000..3c76be2c
--- /dev/null
+++ b/container/sysctl_deprecated.go
@@ -0,0 +1,19 @@
+package container
+
+import "hakurei.app/message"
+
+// OverflowUid is the old function signature of [OverflowUID].
+//
+// Deprecated: This function will be removed in 0.5.
+func OverflowUid(_ message.Msg) int { return OverflowUID() }
+
+// OverflowGid is the old function signature of [OverflowGID].
+//
+// Deprecated: This function will be removed in 0.5.
+func OverflowGid(_ message.Msg) int { return OverflowGID() }
+
+// LastCap returns the highest valid capability of the running kernel. Exports
+// CAP_LAST_CAP from the kernel.
+//
+// Deprecated: This function will be unexported in 0.5.
+func LastCap(_ message.Msg) uintptr { return lastcap() }