aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-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() }