diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-05-07 15:40:47 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-05-07 15:55:19 +0900 |
| commit | 575ef307ad5cedb13a514cd038a4880ab8c91242 (patch) | |
| tree | 71c0bd20e32e08c56ce1be6824f8dbe0f1a091ed /container/init.go | |
| parent | d4144fcf7f9217d2a2dcec21202421d5fa9d4928 (diff) | |
container: binfmt registration
This arranges for binfmt entries to be registered for the container.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container/init.go')
| -rw-r--r-- | container/init.go | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/container/init.go b/container/init.go index 3b850073..41de58cd 100644 --- a/container/init.go +++ b/container/init.go @@ -11,11 +11,13 @@ import ( "path/filepath" "slices" "strconv" + "strings" "sync" "sync/atomic" . "syscall" "time" + "hakurei.app/check" "hakurei.app/container/seccomp" "hakurei.app/ext" "hakurei.app/fhs" @@ -240,6 +242,16 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) { k.fatalf(msg, "cannot enter intermediate host path: %v", err) } + if len(param.Binfmt) > 0 { + for i, e := range param.Binfmt { + if pathname, err := k.evalSymlinks(e.Interpreter.String()); err != nil { + k.fatal(msg, err) + } else if param.Binfmt[i].Interpreter, err = check.NewAbs(pathname); err != nil { + k.fatal(msg, err) + } + } + } + /* early is called right before pivot_root into intermediate root; this step is mostly for gathering information that would otherwise be difficult to obtain via library functions after pivot_root, and @@ -295,6 +307,48 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) { } } + if len(param.Binfmt) > 0 { + const interpreter = "/interpreter" + + if param.BinfmtPath == nil { + param.BinfmtPath = fhs.AbsProcSys.Append("fs/binfmt_misc") + } + binfmt := sysrootPath + param.BinfmtPath.String() + if err := k.mkdirAll(binfmt, 0); err != nil { + k.fatal(msg, err) + } + if err := k.mount( + SourceBinfmtMisc, + binfmt, + FstypeBinfmtMisc, + MS_NOSUID|MS_NOEXEC|MS_NODEV, + zeroString, + ); err != nil { + k.fatal(msg, err) + } + + var buf strings.Builder + buf.Grow(1920) + + register := binfmt + "/register" + for i, e := range param.Binfmt { + if err := k.symlink(hostPath+e.Interpreter.String(), interpreter); err != nil { + k.fatal(msg, err) + } else if err = k.writeFile(register, []byte(":"+ + strconv.Itoa(i)+":"+ + "M:"+ + strconv.Itoa(int(e.Offset))+":"+ + escapeBinfmt(&buf, e.Magic)+":"+ + escapeBinfmt(&buf, e.Mask)+":"+ + interpreter+":"+ + "F"), 0); err != nil { + k.fatal(msg, err) + } else if err = k.remove(interpreter); err != nil { + k.fatal(msg, err) + } + } + } + // setup requiring host root complete at this point if err := k.mount(hostDir, hostDir, zeroString, MS_SILENT|MS_REC|MS_PRIVATE, zeroString); err != nil { k.fatalf(msg, "cannot make host root rprivate: %v", optionalErrorUnwrap(err)) |
