Compare commits
18 Commits
699c19e972
...
c5aefe5e9d
| Author | SHA1 | Date | |
|---|---|---|---|
|
c5aefe5e9d
|
|||
|
0f8ffee44d
|
|||
|
1685a4d000
|
|||
|
6c338b433a
|
|||
|
8accd3b219
|
|||
|
c5f59c5488
|
|||
|
fcd9becf9a
|
|||
|
622f945c22
|
|||
|
e94acc424c
|
|||
|
b1a4d801be
|
|||
|
56beae17fe
|
|||
|
ea978101b1
|
|||
|
fbd1638e7f
|
|||
|
d42067df7c
|
|||
|
b9459a80c7
|
|||
|
f8189d1488
|
|||
|
5063b774c1
|
|||
|
766dd89ffa
|
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -51,7 +50,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
||||
Flag(&flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity").
|
||||
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable")
|
||||
|
||||
c.Command("shim", command.UsageInternal, func([]string) error { app.ShimMain(); return errSuccess })
|
||||
c.Command("shim", command.UsageInternal, func([]string) error { app.Shim(msg); return errSuccess })
|
||||
|
||||
c.Command("app", "Load and start container from configuration file", func(args []string) error {
|
||||
if len(args) < 1 {
|
||||
@@ -227,8 +226,11 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
||||
} else {
|
||||
if f, err := os.Open(flagDBusConfigSession); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
} else if err = json.NewDecoder(f).Decode(&config.SessionBus); err != nil {
|
||||
log.Fatalf("cannot load session bus proxy config from %q: %s", flagDBusConfigSession, err)
|
||||
} else {
|
||||
decodeJSON(log.Fatal, "load session bus proxy config", f, &config.SessionBus)
|
||||
if err = f.Close(); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,8 +238,11 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
||||
if flagDBusConfigSystem != "nil" {
|
||||
if f, err := os.Open(flagDBusConfigSystem); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
} else if err = json.NewDecoder(f).Decode(&config.SystemBus); err != nil {
|
||||
log.Fatalf("cannot load system bus proxy config from %q: %s", flagDBusConfigSystem, err)
|
||||
} else {
|
||||
decodeJSON(log.Fatal, "load system bus proxy config", f, &config.SystemBus)
|
||||
if err = f.Close(); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +328,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
||||
|
||||
c.Command("version", "Display version information", func(args []string) error { fmt.Println(internal.Version()); return errSuccess })
|
||||
c.Command("license", "Show full license text", func(args []string) error { fmt.Println(license); return errSuccess })
|
||||
c.Command("template", "Produce a config template", func(args []string) error { printJSON(os.Stdout, false, hst.Template()); return errSuccess })
|
||||
c.Command("template", "Produce a config template", func(args []string) error { encodeJSON(log.Fatal, os.Stdout, false, hst.Template()); return errSuccess })
|
||||
c.Command("help", "Show this help message", func([]string) error { c.PrintHelp(); return errSuccess })
|
||||
|
||||
return c
|
||||
|
||||
60
cmd/hakurei/json.go
Normal file
60
cmd/hakurei/json.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// decodeJSON decodes json from r and stores it in v. A non-nil error results in a call to fatal.
|
||||
func decodeJSON(fatal func(v ...any), op string, r io.Reader, v any) {
|
||||
err := json.NewDecoder(r).Decode(v)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
syntaxError *json.SyntaxError
|
||||
unmarshalTypeError *json.UnmarshalTypeError
|
||||
|
||||
msg string
|
||||
)
|
||||
|
||||
switch {
|
||||
case errors.As(err, &syntaxError) && syntaxError != nil:
|
||||
msg = syntaxError.Error() +
|
||||
" at byte " + strconv.FormatInt(syntaxError.Offset, 10)
|
||||
|
||||
case errors.As(err, &unmarshalTypeError) && unmarshalTypeError != nil:
|
||||
msg = "inappropriate " + unmarshalTypeError.Value +
|
||||
" at byte " + strconv.FormatInt(unmarshalTypeError.Offset, 10)
|
||||
|
||||
default:
|
||||
// InvalidUnmarshalError: incorrect usage, does not need to be handled
|
||||
// io.ErrUnexpectedEOF: no additional error information available
|
||||
msg = err.Error()
|
||||
}
|
||||
|
||||
fatal("cannot " + op + ": " + msg)
|
||||
}
|
||||
|
||||
// encodeJSON encodes v to output. A non-nil error results in a call to fatal.
|
||||
func encodeJSON(fatal func(v ...any), output io.Writer, short bool, v any) {
|
||||
encoder := json.NewEncoder(output)
|
||||
if !short {
|
||||
encoder.SetIndent("", " ")
|
||||
}
|
||||
|
||||
if err := encoder.Encode(v); err != nil {
|
||||
var marshalerError *json.MarshalerError
|
||||
if errors.As(err, &marshalerError) && marshalerError != nil {
|
||||
// this likely indicates an implementation error in hst
|
||||
fatal("cannot encode json for " + marshalerError.Type.String() + ": " + marshalerError.Err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// UnsupportedTypeError, UnsupportedValueError: incorrect usage, does not need to be handled
|
||||
fatal("cannot write json: " + err.Error())
|
||||
}
|
||||
}
|
||||
107
cmd/hakurei/json_test.go
Normal file
107
cmd/hakurei/json_test.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
_ "unsafe"
|
||||
|
||||
"hakurei.app/container/stub"
|
||||
)
|
||||
|
||||
//go:linkname decodeJSON hakurei.app/cmd/hakurei.decodeJSON
|
||||
func decodeJSON(fatal func(v ...any), op string, r io.Reader, v any)
|
||||
|
||||
func TestDecodeJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
t reflect.Type
|
||||
data string
|
||||
want any
|
||||
msg string
|
||||
}{
|
||||
{"success", reflect.TypeFor[uintptr](), "3735928559\n", uintptr(0xdeadbeef), ""},
|
||||
|
||||
{"syntax", reflect.TypeFor[*int](), "\x00", nil,
|
||||
`cannot load sample: invalid character '\x00' looking for beginning of value at byte 1`},
|
||||
{"type", reflect.TypeFor[uintptr](), "-1", nil,
|
||||
`cannot load sample: inappropriate number -1 at byte 2`},
|
||||
{"default", reflect.TypeFor[*int](), "{", nil,
|
||||
"cannot load sample: unexpected EOF"},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
gotP = reflect.New(tc.t)
|
||||
gotMsg *string
|
||||
)
|
||||
decodeJSON(func(v ...any) {
|
||||
if gotMsg != nil {
|
||||
t.Fatal("fatal called twice")
|
||||
}
|
||||
msg := v[0].(string)
|
||||
gotMsg = &msg
|
||||
}, "load sample", strings.NewReader(tc.data), gotP.Interface())
|
||||
if tc.msg != "" {
|
||||
if gotMsg == nil {
|
||||
t.Errorf("decodeJSON: success, want fatal %q", tc.msg)
|
||||
} else if *gotMsg != tc.msg {
|
||||
t.Errorf("decodeJSON: fatal = %q, want %q", *gotMsg, tc.msg)
|
||||
}
|
||||
} else if gotMsg != nil {
|
||||
t.Errorf("decodeJSON: fatal = %q", *gotMsg)
|
||||
} else if !reflect.DeepEqual(gotP.Elem().Interface(), tc.want) {
|
||||
t.Errorf("decodeJSON: %#v, want %#v", gotP.Elem().Interface(), tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//go:linkname encodeJSON hakurei.app/cmd/hakurei.encodeJSON
|
||||
func encodeJSON(fatal func(v ...any), output io.Writer, short bool, v any)
|
||||
|
||||
func TestEncodeJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
v any
|
||||
want string
|
||||
}{
|
||||
{"marshaler", errorJSONMarshaler{},
|
||||
`cannot encode json for main_test.errorJSONMarshaler: unique error 3735928559 injected by the test suite`},
|
||||
{"default", func() {},
|
||||
`cannot write json: json: unsupported type: func()`},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var called bool
|
||||
encodeJSON(func(v ...any) {
|
||||
if called {
|
||||
t.Fatal("fatal called twice")
|
||||
}
|
||||
called = true
|
||||
|
||||
if v[0].(string) != tc.want {
|
||||
t.Errorf("encodeJSON: fatal = %q, want %q", v[0].(string), tc.want)
|
||||
}
|
||||
}, nil, false, tc.v)
|
||||
|
||||
if !called {
|
||||
t.Errorf("encodeJSON: success, want fatal %q", tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// errorJSONMarshaler implements json.Marshaler.
|
||||
type errorJSONMarshaler struct{}
|
||||
|
||||
func (errorJSONMarshaler) MarshalJSON() ([]byte, error) { return nil, stub.UniqueError(0xdeadbeef) }
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
@@ -17,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func tryPath(msg message.Msg, name string) (config *hst.Config) {
|
||||
var r io.Reader
|
||||
var r io.ReadCloser
|
||||
config = new(hst.Config)
|
||||
|
||||
if name != "-" {
|
||||
@@ -26,26 +25,20 @@ func tryPath(msg message.Msg, name string) (config *hst.Config) {
|
||||
msg.Verbose("load configuration from file")
|
||||
|
||||
if f, err := os.Open(name); err != nil {
|
||||
log.Fatalf("cannot access configuration file %q: %s", name, err)
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
} else {
|
||||
// finalizer closes f
|
||||
r = f
|
||||
}
|
||||
} else {
|
||||
defer func() {
|
||||
if err := r.(io.ReadCloser).Close(); err != nil {
|
||||
log.Printf("cannot close config fd: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
} else {
|
||||
r = os.Stdin
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r).Decode(&config); err != nil {
|
||||
log.Fatalf("cannot load configuration: %v", err)
|
||||
decodeJSON(log.Fatal, "load configuration", r, &config)
|
||||
if err := r.Close(); err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -12,23 +11,26 @@ import (
|
||||
"time"
|
||||
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal"
|
||||
"hakurei.app/internal/app"
|
||||
"hakurei.app/internal/app/state"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
// printShowSystem populates and writes a representation of [hst.Info] to output.
|
||||
func printShowSystem(output io.Writer, short, flagJSON bool) {
|
||||
t := newPrinter(output)
|
||||
defer t.MustFlush()
|
||||
|
||||
info := &hst.Info{User: new(app.Hsu).MustID(nil)}
|
||||
info := &hst.Info{Version: internal.Version(), User: new(app.Hsu).MustID(nil)}
|
||||
app.CopyPaths().Copy(&info.Paths, info.User)
|
||||
|
||||
if flagJSON {
|
||||
printJSON(output, short, info)
|
||||
encodeJSON(log.Fatal, output, short, info)
|
||||
return
|
||||
}
|
||||
|
||||
t.Printf("Version:\t%s\n", info.Version)
|
||||
t.Printf("User:\t%d\n", info.User)
|
||||
t.Printf("TempDir:\t%s\n", info.TempDir)
|
||||
t.Printf("SharePath:\t%s\n", info.SharePath)
|
||||
@@ -36,6 +38,7 @@ func printShowSystem(output io.Writer, short, flagJSON bool) {
|
||||
t.Printf("RunDirPath:\t%s\n", info.RunDirPath)
|
||||
}
|
||||
|
||||
// printShowInstance writes a representation of [state.State] or [hst.Config] to output.
|
||||
func printShowInstance(
|
||||
output io.Writer, now time.Time,
|
||||
instance *state.State, config *hst.Config,
|
||||
@@ -44,9 +47,9 @@ func printShowInstance(
|
||||
|
||||
if flagJSON {
|
||||
if instance != nil {
|
||||
printJSON(output, short, instance)
|
||||
encodeJSON(log.Fatal, output, short, instance)
|
||||
} else {
|
||||
printJSON(output, short, config)
|
||||
encodeJSON(log.Fatal, output, short, config)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -86,24 +89,19 @@ func printShowInstance(
|
||||
if params.Hostname != "" {
|
||||
t.Printf(" Hostname:\t%s\n", params.Hostname)
|
||||
}
|
||||
flags := make([]string, 0, 7)
|
||||
writeFlag := func(name string, flag uintptr, force bool) {
|
||||
if params.Flags&flag != 0 || force {
|
||||
flags = append(flags, name)
|
||||
flags := params.Flags.String()
|
||||
|
||||
// this is included in the upper hst.Config struct but is relevant here
|
||||
const flagDirectWayland = "directwl"
|
||||
if config.DirectWayland {
|
||||
// hardcoded value when every flag is unset
|
||||
if flags == "none" {
|
||||
flags = flagDirectWayland
|
||||
} else {
|
||||
flags += ", " + flagDirectWayland
|
||||
}
|
||||
}
|
||||
writeFlag("userns", hst.FUserns, false)
|
||||
writeFlag("devel", hst.FDevel, false)
|
||||
writeFlag("net", hst.FHostNet, false)
|
||||
writeFlag("abstract", hst.FHostAbstract, false)
|
||||
writeFlag("device", hst.FDevice, false)
|
||||
writeFlag("tty", hst.FTty, false)
|
||||
writeFlag("mapuid", hst.FMapRealUID, false)
|
||||
writeFlag("directwl", 0, config.DirectWayland)
|
||||
if len(flags) == 0 {
|
||||
flags = append(flags, "none")
|
||||
}
|
||||
t.Printf(" Flags:\t%s\n", strings.Join(flags, " "))
|
||||
t.Printf(" Flags:\t%s\n", flags)
|
||||
|
||||
if params.Path != nil {
|
||||
t.Printf(" Path:\t%s\n", params.Path)
|
||||
@@ -168,6 +166,7 @@ func printShowInstance(
|
||||
return
|
||||
}
|
||||
|
||||
// printPs writes a representation of active instances to output.
|
||||
func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON bool) {
|
||||
var entries state.Entries
|
||||
if e, err := state.Join(s); err != nil {
|
||||
@@ -184,7 +183,7 @@ func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON boo
|
||||
for id, instance := range entries {
|
||||
es[id.String()] = instance
|
||||
}
|
||||
printJSON(output, short, es)
|
||||
encodeJSON(log.Fatal, output, short, es)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -213,7 +212,7 @@ func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON boo
|
||||
for i, e := range exp {
|
||||
v[i] = e.s
|
||||
}
|
||||
printJSON(output, short, v)
|
||||
encodeJSON(log.Fatal, output, short, v)
|
||||
} else {
|
||||
for _, e := range exp {
|
||||
mustPrintln(output, e.s[:8])
|
||||
@@ -247,40 +246,39 @@ func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON boo
|
||||
}
|
||||
}
|
||||
|
||||
// expandedStateEntry stores [state.State] alongside a string representation of its [state.ID].
|
||||
type expandedStateEntry struct {
|
||||
s string
|
||||
*state.State
|
||||
}
|
||||
|
||||
func printJSON(output io.Writer, short bool, v any) {
|
||||
encoder := json.NewEncoder(output)
|
||||
if !short {
|
||||
encoder.SetIndent("", " ")
|
||||
}
|
||||
if err := encoder.Encode(v); err != nil {
|
||||
log.Fatalf("cannot serialise: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// newPrinter returns a configured, wrapped [tabwriter.Writer].
|
||||
func newPrinter(output io.Writer) *tp { return &tp{tabwriter.NewWriter(output, 0, 1, 4, ' ', 0)} }
|
||||
|
||||
// tp wraps [tabwriter.Writer] to provide additional formatting methods.
|
||||
type tp struct{ *tabwriter.Writer }
|
||||
|
||||
// Printf calls [fmt.Fprintf] on the underlying [tabwriter.Writer].
|
||||
func (p *tp) Printf(format string, a ...any) {
|
||||
if _, err := fmt.Fprintf(p, format, a...); err != nil {
|
||||
log.Fatalf("cannot write to tabwriter: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Println calls [fmt.Fprintln] on the underlying [tabwriter.Writer].
|
||||
func (p *tp) Println(a ...any) {
|
||||
if _, err := fmt.Fprintln(p, a...); err != nil {
|
||||
log.Fatalf("cannot write to tabwriter: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustFlush calls the Flush method of [tabwriter.Writer] and calls [log.Fatalf] on a non-nil error.
|
||||
func (p *tp) MustFlush() {
|
||||
if err := p.Writer.Flush(); err != nil {
|
||||
log.Fatalf("cannot flush tabwriter: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func mustPrint(output io.Writer, a ...any) {
|
||||
if _, err := fmt.Fprint(output, a...); err != nil {
|
||||
log.Fatalf("cannot print: %v", err)
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestPrintShowInstance(t *testing.T) {
|
||||
Groups: video, dialout, plugdev
|
||||
Home: /data/data/org.chromium.Chromium
|
||||
Hostname: localhost
|
||||
Flags: userns devel net abstract device tty mapuid
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir
|
||||
Path: /run/current-system/sw/bin/chromium
|
||||
Arguments: chromium --ignore-gpu-blocklist --disable-smooth-scrolling --enable-features=UseOzonePlatform --ozone-platform=wayland
|
||||
|
||||
@@ -87,6 +87,22 @@ App
|
||||
Enablements: (no enablements)
|
||||
Flags: none
|
||||
|
||||
`, false},
|
||||
{"config flag none directwl", nil, &hst.Config{DirectWayland: true, Container: new(hst.ContainerConfig)}, false, false, `Error: container configuration missing path to home directory!
|
||||
|
||||
App
|
||||
Identity: 0
|
||||
Enablements: (no enablements)
|
||||
Flags: directwl
|
||||
|
||||
`, false},
|
||||
{"config flag directwl", nil, &hst.Config{DirectWayland: true, Container: &hst.ContainerConfig{Flags: hst.FMultiarch}}, false, false, `Error: container configuration missing path to home directory!
|
||||
|
||||
App
|
||||
Identity: 0
|
||||
Enablements: (no enablements)
|
||||
Flags: multiarch, directwl
|
||||
|
||||
`, false},
|
||||
{"config nil entries", nil, &hst.Config{Container: &hst.ContainerConfig{Filesystem: make([]hst.FilesystemConfigJSON, 1)}, ExtraPerms: make([]hst.ExtraPermConfig, 1)}, false, false, `Error: container configuration missing path to home directory!
|
||||
|
||||
@@ -124,7 +140,7 @@ App
|
||||
Groups: video, dialout, plugdev
|
||||
Home: /data/data/org.chromium.Chromium
|
||||
Hostname: localhost
|
||||
Flags: userns devel net abstract device tty mapuid
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir
|
||||
Path: /run/current-system/sw/bin/chromium
|
||||
Arguments: chromium --ignore-gpu-blocklist --disable-smooth-scrolling --enable-features=UseOzonePlatform --ozone-platform=wayland
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
var hakureiPath = internal.MustHakureiPath()
|
||||
var hakureiPathVal = internal.MustHakureiPath().String()
|
||||
|
||||
func mustRunApp(ctx context.Context, msg message.Msg, config *hst.Config, beforeFail func()) {
|
||||
var (
|
||||
@@ -27,9 +27,9 @@ func mustRunApp(ctx context.Context, msg message.Msg, config *hst.Config, before
|
||||
log.Fatalf("cannot pipe: %v", err)
|
||||
} else {
|
||||
if msg.IsVerbose() {
|
||||
cmd = exec.CommandContext(ctx, hakureiPath.String(), "-v", "app", "3")
|
||||
cmd = exec.CommandContext(ctx, hakureiPathVal, "-v", "app", "3")
|
||||
} else {
|
||||
cmd = exec.CommandContext(ctx, hakureiPath.String(), "app", "3")
|
||||
cmd = exec.CommandContext(ctx, hakureiPathVal, "app", "3")
|
||||
}
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
cmd.ExtraFiles = []*os.File{r}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -26,7 +27,14 @@ const (
|
||||
identityMax = 9999
|
||||
)
|
||||
|
||||
// hakureiPath is the absolute path to Hakurei.
|
||||
//
|
||||
// This is set by the linker.
|
||||
var hakureiPath string
|
||||
|
||||
func main() {
|
||||
runtime.LockOSThread()
|
||||
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("hsu: ")
|
||||
log.SetOutput(os.Stderr)
|
||||
@@ -43,13 +51,18 @@ func main() {
|
||||
log.Fatal("this program must not be started by root")
|
||||
}
|
||||
|
||||
if !path.IsAbs(hakureiPath) {
|
||||
log.Fatal("this program is compiled incorrectly")
|
||||
return
|
||||
}
|
||||
|
||||
var toolPath string
|
||||
pexe := path.Join("/proc", strconv.Itoa(os.Getppid()), "exe")
|
||||
if p, err := os.Readlink(pexe); err != nil {
|
||||
log.Fatalf("cannot read parent executable path: %v", err)
|
||||
} else if strings.HasSuffix(p, " (deleted)") {
|
||||
log.Fatal("hakurei executable has been deleted")
|
||||
} else if p != mustCheckPath(hmain) {
|
||||
} else if p != hakureiPath {
|
||||
log.Fatal("this program must be started by hakurei")
|
||||
} else {
|
||||
toolPath = p
|
||||
|
||||
@@ -19,5 +19,5 @@ buildGoModule {
|
||||
ldflags = lib.attrsets.foldlAttrs (
|
||||
ldflags: name: value:
|
||||
ldflags ++ [ "-X main.${name}=${value}" ]
|
||||
) [ "-s -w" ] { hmain = "${hakurei}/libexec/hakurei"; };
|
||||
) [ "-s -w" ] { hakureiPath = "${hakurei}/libexec/hakurei"; };
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestParseUint32Fast(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("full range", func(t *testing.T) {
|
||||
t.Run("range", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testRange := func(i, end int) {
|
||||
@@ -61,11 +61,9 @@ func TestParseUint32Fast(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
testRange(0, 5000)
|
||||
testRange(105000, 110000)
|
||||
testRange(23005000, 23010000)
|
||||
testRange(456005000, 456010000)
|
||||
testRange(7890005000, 7890010000)
|
||||
testRange(0, 2500)
|
||||
testRange(23002500, 23005000)
|
||||
testRange(7890002500, 7890005000)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
)
|
||||
|
||||
const compPoison = "INVALIDINVALIDINVALIDINVALIDINVALID"
|
||||
|
||||
var (
|
||||
hmain = compPoison
|
||||
)
|
||||
|
||||
func mustCheckPath(p string) string {
|
||||
if p != compPoison && p != "" && path.IsAbs(p) {
|
||||
return p
|
||||
}
|
||||
log.Fatal("this program is compiled incorrectly")
|
||||
return compPoison
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
@@ -23,14 +23,14 @@ func TestAutoRootOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"readdir", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, []stub.Call{
|
||||
call("readdir", stub.ExpectArgs{"/"}, stubDir(), stub.UniqueError(2)),
|
||||
}, stub.UniqueError(2), nil, nil},
|
||||
|
||||
{"early", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, []stub.Call{
|
||||
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
||||
@@ -39,7 +39,7 @@ func TestAutoRootOp(t *testing.T) {
|
||||
|
||||
{"apply", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, []stub.Call{
|
||||
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
||||
@@ -60,7 +60,7 @@ func TestAutoRootOp(t *testing.T) {
|
||||
|
||||
{"success pd", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, []stub.Call{
|
||||
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
||||
@@ -127,10 +127,10 @@ func TestAutoRootOp(t *testing.T) {
|
||||
})
|
||||
|
||||
checkOpsBuilder(t, []opsBuilderTestCase{
|
||||
{"pd", new(Ops).Root(check.MustAbs("/"), bits.BindWritable), Ops{
|
||||
{"pd", new(Ops).Root(check.MustAbs("/"), comp.BindWritable), Ops{
|
||||
&AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
},
|
||||
}},
|
||||
})
|
||||
@@ -140,42 +140,42 @@ func TestAutoRootOp(t *testing.T) {
|
||||
|
||||
{"internal ne", &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
resolved: []*BindMountOp{new(BindMountOp)},
|
||||
}, true},
|
||||
|
||||
{"flags differs", &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable | bits.BindDevice,
|
||||
Flags: comp.BindWritable | comp.BindDevice,
|
||||
}, &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, false},
|
||||
|
||||
{"host differs", &AutoRootOp{
|
||||
Host: check.MustAbs("/tmp/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, false},
|
||||
|
||||
{"equals", &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, true},
|
||||
})
|
||||
|
||||
checkOpMeta(t, []opMetaTestCase{
|
||||
{"root", &AutoRootOp{
|
||||
Host: check.MustAbs("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}, "setting up", `auto root "/" flags 0x2`},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Package bits contains constants for configuring the container.
|
||||
package bits
|
||||
|
||||
const (
|
||||
// BindOptional skips nonexistent host paths.
|
||||
BindOptional = 1 << iota
|
||||
// BindWritable mounts filesystem read-write.
|
||||
BindWritable
|
||||
// BindDevice allows access to devices (special files) on this filesystem.
|
||||
BindDevice
|
||||
// BindEnsure attempts to create the host path if it does not exist.
|
||||
BindEnsure
|
||||
)
|
||||
@@ -49,41 +49,10 @@ func capset(hdrp *capHeader, datap *[2]capData) error {
|
||||
}
|
||||
|
||||
// capBoundingSetDrop drops a capability from the calling thread's capability bounding set.
|
||||
func capBoundingSetDrop(cap uintptr) error {
|
||||
r, _, errno := syscall.Syscall(
|
||||
syscall.SYS_PRCTL,
|
||||
syscall.PR_CAPBSET_DROP,
|
||||
cap, 0,
|
||||
)
|
||||
if r != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func capBoundingSetDrop(cap uintptr) error { return Prctl(syscall.PR_CAPBSET_DROP, cap, 0) }
|
||||
|
||||
// capAmbientClearAll clears the ambient capability set of the calling thread.
|
||||
func capAmbientClearAll() error {
|
||||
r, _, errno := syscall.Syscall(
|
||||
syscall.SYS_PRCTL,
|
||||
PR_CAP_AMBIENT,
|
||||
PR_CAP_AMBIENT_CLEAR_ALL, 0,
|
||||
)
|
||||
if r != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func capAmbientClearAll() error { return Prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0) }
|
||||
|
||||
// capAmbientRaise adds to the ambient capability set of the calling thread.
|
||||
func capAmbientRaise(cap uintptr) error {
|
||||
r, _, errno := syscall.Syscall(
|
||||
syscall.SYS_PRCTL,
|
||||
PR_CAP_AMBIENT,
|
||||
PR_CAP_AMBIENT_RAISE,
|
||||
cap,
|
||||
)
|
||||
if r != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func capAmbientRaise(cap uintptr) error { return Prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap) }
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
package bits
|
||||
// Package comp contains constants from container packages without depending on cgo.
|
||||
package comp
|
||||
|
||||
const (
|
||||
// BindOptional skips nonexistent host paths.
|
||||
BindOptional = 1 << iota
|
||||
// BindWritable mounts filesystem read-write.
|
||||
BindWritable
|
||||
// BindDevice allows access to devices (special files) on this filesystem.
|
||||
BindDevice
|
||||
// BindEnsure attempts to create the host path if it does not exist.
|
||||
BindEnsure
|
||||
)
|
||||
|
||||
// FilterPreset specifies parts of the syscall filter preset to enable.
|
||||
type FilterPreset int
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
. "syscall"
|
||||
"time"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/message"
|
||||
@@ -86,7 +86,7 @@ type (
|
||||
// Extra seccomp flags.
|
||||
SeccompFlags seccomp.ExportFlag
|
||||
// Seccomp presets. Has no effect unless SeccompRules is zero-length.
|
||||
SeccompPresets bits.FilterPreset
|
||||
SeccompPresets comp.FilterPreset
|
||||
// Do not load seccomp program.
|
||||
SeccompDisable bool
|
||||
|
||||
@@ -174,7 +174,7 @@ func (p *Container) Start() error {
|
||||
}
|
||||
|
||||
if !p.RetainSession {
|
||||
p.SeccompPresets |= bits.PresetDenyTTY
|
||||
p.SeccompPresets |= comp.PresetDenyTTY
|
||||
}
|
||||
|
||||
if p.AdoptWaitDelay == 0 {
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
|
||||
"hakurei.app/command"
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/vfs"
|
||||
"hakurei.app/hst"
|
||||
@@ -206,20 +206,20 @@ var containerTestCases = []struct {
|
||||
|
||||
rules []seccomp.NativeRule
|
||||
flags seccomp.ExportFlag
|
||||
presets bits.FilterPreset
|
||||
presets comp.FilterPreset
|
||||
}{
|
||||
{"minimal", true, false, false, true,
|
||||
emptyOps, emptyMnt,
|
||||
1000, 100, nil, 0, bits.PresetStrict},
|
||||
1000, 100, nil, 0, comp.PresetStrict},
|
||||
{"allow", true, true, true, false,
|
||||
emptyOps, emptyMnt,
|
||||
1000, 100, nil, 0, bits.PresetExt | bits.PresetDenyDevel},
|
||||
1000, 100, nil, 0, comp.PresetExt | comp.PresetDenyDevel},
|
||||
{"no filter", false, true, true, true,
|
||||
emptyOps, emptyMnt,
|
||||
1000, 100, nil, 0, bits.PresetExt},
|
||||
1000, 100, nil, 0, comp.PresetExt},
|
||||
{"custom rules", true, true, true, false,
|
||||
emptyOps, emptyMnt,
|
||||
1, 31, []seccomp.NativeRule{{Syscall: seccomp.ScmpSyscall(syscall.SYS_SETUID), Errno: seccomp.ScmpErrno(syscall.EPERM)}}, 0, bits.PresetExt},
|
||||
1, 31, []seccomp.NativeRule{{Syscall: seccomp.ScmpSyscall(syscall.SYS_SETUID), Errno: seccomp.ScmpErrno(syscall.EPERM)}}, 0, comp.PresetExt},
|
||||
|
||||
{"tmpfs", true, false, false, true,
|
||||
earlyOps(new(container.Ops).
|
||||
@@ -228,7 +228,7 @@ var containerTestCases = []struct {
|
||||
earlyMnt(
|
||||
ent("/", hst.PrivateTmp, "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", ignore),
|
||||
),
|
||||
9, 9, nil, 0, bits.PresetStrict},
|
||||
9, 9, nil, 0, comp.PresetStrict},
|
||||
|
||||
{"dev", true, true /* go test output is not a tty */, false, false,
|
||||
earlyOps(new(container.Ops).
|
||||
@@ -246,7 +246,7 @@ var containerTestCases = []struct {
|
||||
ent("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
|
||||
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
||||
),
|
||||
1971, 100, nil, 0, bits.PresetStrict},
|
||||
1971, 100, nil, 0, comp.PresetStrict},
|
||||
|
||||
{"dev no mqueue", true, true /* go test output is not a tty */, false, false,
|
||||
earlyOps(new(container.Ops).
|
||||
@@ -263,7 +263,7 @@ var containerTestCases = []struct {
|
||||
ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
|
||||
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
||||
),
|
||||
1971, 100, nil, 0, bits.PresetStrict},
|
||||
1971, 100, nil, 0, comp.PresetStrict},
|
||||
|
||||
{"overlay", true, false, false, true,
|
||||
func(t *testing.T) (*container.Ops, context.Context) {
|
||||
@@ -300,7 +300,7 @@ var containerTestCases = []struct {
|
||||
",redirect_dir=nofollow,uuid=on,userxattr"),
|
||||
}
|
||||
},
|
||||
1 << 3, 1 << 14, nil, 0, bits.PresetStrict},
|
||||
1 << 3, 1 << 14, nil, 0, comp.PresetStrict},
|
||||
|
||||
{"overlay ephemeral", true, false, false, true,
|
||||
func(t *testing.T) (*container.Ops, context.Context) {
|
||||
@@ -324,7 +324,7 @@ var containerTestCases = []struct {
|
||||
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay", ignore),
|
||||
}
|
||||
},
|
||||
1 << 3, 1 << 14, nil, 0, bits.PresetStrict},
|
||||
1 << 3, 1 << 14, nil, 0, comp.PresetStrict},
|
||||
|
||||
{"overlay readonly", true, false, false, true,
|
||||
func(t *testing.T) (*container.Ops, context.Context) {
|
||||
@@ -352,7 +352,7 @@ var containerTestCases = []struct {
|
||||
",redirect_dir=nofollow,userxattr"),
|
||||
}
|
||||
},
|
||||
1 << 3, 1 << 14, nil, 0, bits.PresetStrict},
|
||||
1 << 3, 1 << 14, nil, 0, comp.PresetStrict},
|
||||
}
|
||||
|
||||
func TestContainer(t *testing.T) {
|
||||
@@ -560,9 +560,9 @@ func TestContainerString(t *testing.T) {
|
||||
c := container.NewCommand(t.Context(), msg, check.MustAbs("/run/current-system/sw/bin/ldd"), "ldd", "/usr/bin/env")
|
||||
c.SeccompFlags |= seccomp.AllowMultiarch
|
||||
c.SeccompRules = seccomp.Preset(
|
||||
bits.PresetExt|bits.PresetDenyNS|bits.PresetDenyTTY,
|
||||
comp.PresetExt|comp.PresetDenyNS|comp.PresetDenyTTY,
|
||||
c.SeccompFlags)
|
||||
c.SeccompPresets = bits.PresetStrict
|
||||
c.SeccompPresets = comp.PresetStrict
|
||||
want := `argv: ["ldd" "/usr/bin/env"], filter: true, rules: 65, flags: 0x1, presets: 0xf`
|
||||
if got := c.String(); got != want {
|
||||
t.Errorf("String: %s, want %s", got, want)
|
||||
|
||||
@@ -96,16 +96,15 @@ type initParams struct {
|
||||
}
|
||||
|
||||
// Init is called by [TryArgv0] if the current process is the container init.
|
||||
func Init(msg message.Msg) {
|
||||
if msg == nil {
|
||||
panic("attempting to call initEntrypoint with nil msg")
|
||||
}
|
||||
initEntrypoint(direct{}, msg)
|
||||
}
|
||||
func Init(msg message.Msg) { initEntrypoint(direct{}, msg) }
|
||||
|
||||
func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
||||
k.lockOSThread()
|
||||
|
||||
if msg == nil {
|
||||
panic("attempting to call initEntrypoint with nil msg")
|
||||
}
|
||||
|
||||
if k.getpid() != 1 {
|
||||
k.fatal(msg, "this process must run as pid 1")
|
||||
}
|
||||
@@ -451,6 +450,7 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
||||
}
|
||||
}
|
||||
|
||||
// initName is the prefix used by log.std in the init process.
|
||||
const initName = "init"
|
||||
|
||||
// TryArgv0 calls [Init] if the last element of argv0 is "init".
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/stub"
|
||||
)
|
||||
@@ -70,7 +70,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(79), nil),
|
||||
@@ -95,7 +95,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Hostname: "hakurei-check",
|
||||
Ops: (*Ops)(sliceAddr(make(Ops, 1))),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(78), nil),
|
||||
@@ -123,7 +123,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Hostname: "hakurei-check",
|
||||
Ops: (*Ops)(sliceAddr(make(Ops, 1))),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(76), nil),
|
||||
@@ -152,7 +152,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Hostname: "hakurei-check",
|
||||
Ops: (*Ops)(sliceAddr(make(Ops, 1))),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(74), nil),
|
||||
@@ -182,7 +182,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Hostname: "hakurei-check",
|
||||
Ops: (*Ops)(sliceAddr(make(Ops, 1))),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(72), nil),
|
||||
@@ -213,7 +213,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Hostname: "hakurei-check",
|
||||
Ops: (*Ops)(sliceAddr(make(Ops, 1))),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(70), nil),
|
||||
@@ -245,7 +245,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Hostname: "hakurei-check",
|
||||
Ops: (*Ops)(sliceAddr(make(Ops, 1))),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(68), nil),
|
||||
@@ -279,7 +279,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Hostname: "hakurei-check",
|
||||
Ops: (*Ops)(sliceAddr(make(Ops, 1))),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(66), nil),
|
||||
@@ -315,7 +315,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Hostname: "hakurei-check",
|
||||
Ops: (*Ops)(sliceAddr(make(Ops, 1))),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(64), nil),
|
||||
@@ -351,9 +351,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(nil, nil, bits.BindDevice),
|
||||
Ops: new(Ops).Bind(nil, nil, comp.BindDevice),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(63), nil),
|
||||
@@ -389,9 +389,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(62), nil),
|
||||
@@ -428,9 +428,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(60), nil),
|
||||
@@ -467,9 +467,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(59), nil),
|
||||
@@ -507,9 +507,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(57), nil),
|
||||
@@ -548,9 +548,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(55), nil),
|
||||
@@ -590,9 +590,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(53), nil),
|
||||
@@ -633,9 +633,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(51), nil),
|
||||
@@ -677,9 +677,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(49), nil),
|
||||
@@ -722,9 +722,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(47), nil),
|
||||
@@ -768,9 +768,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(45), nil),
|
||||
@@ -823,9 +823,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(43), nil),
|
||||
@@ -878,9 +878,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(42), nil),
|
||||
@@ -934,9 +934,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(40), nil),
|
||||
@@ -991,9 +991,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(38), nil),
|
||||
@@ -1029,8 +1029,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, stub.UniqueError(37)),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, stub.UniqueError(37)),
|
||||
call("fatalf", stub.ExpectArgs{"cannot open intermediate root: %v", []any{stub.UniqueError(37)}}, nil, nil),
|
||||
},
|
||||
}, nil},
|
||||
@@ -1050,9 +1050,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(36), nil),
|
||||
@@ -1088,8 +1088,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, stub.UniqueError(35)),
|
||||
call("fatalf", stub.ExpectArgs{"cannot enter sysroot: %v", []any{stub.UniqueError(35)}}, nil, nil),
|
||||
},
|
||||
@@ -1110,9 +1110,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(34), nil),
|
||||
@@ -1148,8 +1148,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, stub.UniqueError(33)),
|
||||
call("fatalf", stub.ExpectArgs{"cannot pivot into sysroot: %v", []any{stub.UniqueError(33)}}, nil, nil),
|
||||
@@ -1171,9 +1171,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(32), nil),
|
||||
@@ -1209,8 +1209,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, stub.UniqueError(31)),
|
||||
@@ -1233,9 +1233,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(30), nil),
|
||||
@@ -1271,8 +1271,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -1296,9 +1296,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(28), nil),
|
||||
@@ -1334,8 +1334,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -1360,9 +1360,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(26), nil),
|
||||
@@ -1398,8 +1398,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -1425,9 +1425,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(24), nil),
|
||||
@@ -1463,8 +1463,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -1491,9 +1491,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(22), nil),
|
||||
@@ -1529,8 +1529,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -1565,9 +1565,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(20), nil),
|
||||
@@ -1603,8 +1603,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -1672,9 +1672,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(18), nil),
|
||||
@@ -1710,8 +1710,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -1780,9 +1780,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(16), nil),
|
||||
@@ -1818,8 +1818,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -1869,7 +1869,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
||||
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, nil),
|
||||
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0, 0x200000, 0x200000}, {0, 0, 0}}}, nil, nil),
|
||||
call("verbosef", stub.ExpectArgs{"resolving presets %#x", []any{bits.FilterPreset(0xf)}}, nil, nil),
|
||||
call("verbosef", stub.ExpectArgs{"resolving presets %#x", []any{comp.FilterPreset(0xf)}}, nil, nil),
|
||||
call("seccompLoad", stub.ExpectArgs{seccomp.Preset(0xf, 0), seccomp.ExportFlag(0)}, nil, stub.UniqueError(15)),
|
||||
call("fatalf", stub.ExpectArgs{"cannot load syscall filter: %v", []any{stub.UniqueError(15)}}, nil, nil),
|
||||
},
|
||||
@@ -1890,7 +1890,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 24,
|
||||
Gid: 1 << 47,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
@@ -1927,8 +1927,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -2004,7 +2004,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 24,
|
||||
Gid: 1 << 47,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
@@ -2041,8 +2041,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -2106,7 +2106,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 24,
|
||||
Gid: 1 << 47,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
@@ -2143,8 +2143,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -2199,7 +2199,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 24,
|
||||
Gid: 1 << 47,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
@@ -2236,8 +2236,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -2294,7 +2294,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 24,
|
||||
Gid: 1 << 47,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
@@ -2331,8 +2331,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -2396,7 +2396,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 24,
|
||||
Gid: 1 << 47,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
@@ -2433,8 +2433,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -2534,9 +2534,9 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
Uid: 1 << 32,
|
||||
Gid: 1 << 31,
|
||||
Hostname: "hakurei-check",
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), bits.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), comp.BindDevice).Proc(check.MustAbs("/proc/")),
|
||||
SeccompRules: make([]seccomp.NativeRule, 0),
|
||||
SeccompPresets: bits.PresetStrict,
|
||||
SeccompPresets: comp.PresetStrict,
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(0), nil),
|
||||
@@ -2572,8 +2572,8 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
/* end apply */
|
||||
call("mount", stub.ExpectArgs{"host", "host", "", uintptr(0x4c000), ""}, nil, nil),
|
||||
call("unmount", stub.ExpectArgs{"host", 2}, nil, nil),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", 0x10000, uint32(0)}, 1<<35, nil),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, syscall.EINTR),
|
||||
call("open", stub.ExpectArgs{"/", syscall.O_DIRECTORY | syscall.O_RDONLY, uint32(0)}, 1<<35, nil),
|
||||
call("chdir", stub.ExpectArgs{"/sysroot"}, nil, nil),
|
||||
call("pivotRoot", stub.ExpectArgs{".", "."}, nil, nil),
|
||||
call("fchdir", stub.ExpectArgs{1 << 35}, nil, nil),
|
||||
@@ -2623,7 +2623,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
||||
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, nil),
|
||||
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0, 0x200000, 0x200000}, {0, 0, 0}}}, nil, nil),
|
||||
call("verbosef", stub.ExpectArgs{"resolving presets %#x", []any{bits.FilterPreset(0xf)}}, nil, nil),
|
||||
call("verbosef", stub.ExpectArgs{"resolving presets %#x", []any{comp.FilterPreset(0xf)}}, nil, nil),
|
||||
call("seccompLoad", stub.ExpectArgs{seccomp.Preset(0xf, 0), seccomp.ExportFlag(0)}, nil, nil),
|
||||
call("verbosef", stub.ExpectArgs{"%d filter rules loaded", []any{73}}, nil, nil),
|
||||
call("newFile", stub.ExpectArgs{uintptr(10), "extra file 0"}, (*os.File)(nil), nil),
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
)
|
||||
|
||||
func init() { gob.Register(new(BindMountOp)) }
|
||||
@@ -29,18 +29,18 @@ type BindMountOp struct {
|
||||
func (b *BindMountOp) Valid() bool {
|
||||
return b != nil &&
|
||||
b.Source != nil && b.Target != nil &&
|
||||
b.Flags&(bits.BindOptional|bits.BindEnsure) != (bits.BindOptional|bits.BindEnsure)
|
||||
b.Flags&(comp.BindOptional|comp.BindEnsure) != (comp.BindOptional|comp.BindEnsure)
|
||||
}
|
||||
|
||||
func (b *BindMountOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
if b.Flags&bits.BindEnsure != 0 {
|
||||
if b.Flags&comp.BindEnsure != 0 {
|
||||
if err := k.mkdirAll(b.Source.String(), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if pathname, err := k.evalSymlinks(b.Source.String()); err != nil {
|
||||
if os.IsNotExist(err) && b.Flags&bits.BindOptional != 0 {
|
||||
if os.IsNotExist(err) && b.Flags&comp.BindOptional != 0 {
|
||||
// leave sourceFinal as nil
|
||||
return nil
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func (b *BindMountOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
|
||||
func (b *BindMountOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
if b.sourceFinal == nil {
|
||||
if b.Flags&bits.BindOptional == 0 {
|
||||
if b.Flags&comp.BindOptional == 0 {
|
||||
// unreachable
|
||||
return OpStateError("bind")
|
||||
}
|
||||
@@ -76,10 +76,10 @@ func (b *BindMountOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
}
|
||||
|
||||
var flags uintptr = syscall.MS_REC
|
||||
if b.Flags&bits.BindWritable == 0 {
|
||||
if b.Flags&comp.BindWritable == 0 {
|
||||
flags |= syscall.MS_RDONLY
|
||||
}
|
||||
if b.Flags&bits.BindDevice == 0 {
|
||||
if b.Flags&comp.BindDevice == 0 {
|
||||
flags |= syscall.MS_NODEV
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/stub"
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"skip optional", new(Params), &BindMountOp{
|
||||
Source: check.MustAbs("/bin/"),
|
||||
Target: check.MustAbs("/bin/"),
|
||||
Flags: bits.BindOptional,
|
||||
Flags: comp.BindOptional,
|
||||
}, []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "", syscall.ENOENT),
|
||||
}, nil, nil, nil},
|
||||
@@ -33,7 +33,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"success optional", new(Params), &BindMountOp{
|
||||
Source: check.MustAbs("/bin/"),
|
||||
Target: check.MustAbs("/bin/"),
|
||||
Flags: bits.BindOptional,
|
||||
Flags: comp.BindOptional,
|
||||
}, []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil),
|
||||
}, nil, []stub.Call{
|
||||
@@ -46,7 +46,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"ensureFile device", new(Params), &BindMountOp{
|
||||
Source: check.MustAbs("/dev/null"),
|
||||
Target: check.MustAbs("/dev/null"),
|
||||
Flags: bits.BindWritable | bits.BindDevice,
|
||||
Flags: comp.BindWritable | comp.BindDevice,
|
||||
}, []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
||||
}, nil, []stub.Call{
|
||||
@@ -57,7 +57,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"mkdirAll ensure", new(Params), &BindMountOp{
|
||||
Source: check.MustAbs("/bin/"),
|
||||
Target: check.MustAbs("/bin/"),
|
||||
Flags: bits.BindEnsure,
|
||||
Flags: comp.BindEnsure,
|
||||
}, []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/bin/", os.FileMode(0700)}, nil, stub.UniqueError(4)),
|
||||
}, stub.UniqueError(4), nil, nil},
|
||||
@@ -65,7 +65,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"success ensure", new(Params), &BindMountOp{
|
||||
Source: check.MustAbs("/bin/"),
|
||||
Target: check.MustAbs("/usr/bin/"),
|
||||
Flags: bits.BindEnsure,
|
||||
Flags: comp.BindEnsure,
|
||||
}, []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/bin/", os.FileMode(0700)}, nil, nil),
|
||||
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil),
|
||||
@@ -79,7 +79,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"success device ro", new(Params), &BindMountOp{
|
||||
Source: check.MustAbs("/dev/null"),
|
||||
Target: check.MustAbs("/dev/null"),
|
||||
Flags: bits.BindDevice,
|
||||
Flags: comp.BindDevice,
|
||||
}, []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
||||
}, nil, []stub.Call{
|
||||
@@ -92,7 +92,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"success device", new(Params), &BindMountOp{
|
||||
Source: check.MustAbs("/dev/null"),
|
||||
Target: check.MustAbs("/dev/null"),
|
||||
Flags: bits.BindWritable | bits.BindDevice,
|
||||
Flags: comp.BindWritable | comp.BindDevice,
|
||||
}, []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
||||
}, nil, []stub.Call{
|
||||
@@ -182,7 +182,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"zero", new(BindMountOp), false},
|
||||
{"nil source", &BindMountOp{Target: check.MustAbs("/")}, false},
|
||||
{"nil target", &BindMountOp{Source: check.MustAbs("/")}, false},
|
||||
{"flag optional ensure", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/"), Flags: bits.BindOptional | bits.BindEnsure}, false},
|
||||
{"flag optional ensure", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/"), Flags: comp.BindOptional | comp.BindEnsure}, false},
|
||||
{"valid", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/")}, true},
|
||||
})
|
||||
|
||||
@@ -217,7 +217,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
}, &BindMountOp{
|
||||
Source: check.MustAbs("/etc/"),
|
||||
Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"),
|
||||
Flags: bits.BindOptional,
|
||||
Flags: comp.BindOptional,
|
||||
}, false},
|
||||
|
||||
{"source differs", &BindMountOp{
|
||||
@@ -256,7 +256,7 @@ func TestBindMountOp(t *testing.T) {
|
||||
{"hostdev", &BindMountOp{
|
||||
Source: check.MustAbs("/dev/"),
|
||||
Target: check.MustAbs("/dev/"),
|
||||
Flags: bits.BindWritable | bits.BindDevice,
|
||||
Flags: comp.BindWritable | comp.BindDevice,
|
||||
}, "mounting", `"/dev/" flags 0x6`},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package seccomp_test
|
||||
|
||||
import (
|
||||
. "hakurei.app/container/bits"
|
||||
. "hakurei.app/container/comp"
|
||||
. "hakurei.app/container/seccomp"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package seccomp_test
|
||||
|
||||
import (
|
||||
. "hakurei.app/container/bits"
|
||||
. "hakurei.app/container/comp"
|
||||
. "hakurei.app/container/seccomp"
|
||||
)
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ import (
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/seccomp"
|
||||
)
|
||||
|
||||
type (
|
||||
bpfPreset = struct {
|
||||
seccomp.ExportFlag
|
||||
bits.FilterPreset
|
||||
comp.FilterPreset
|
||||
}
|
||||
bpfLookup map[bpfPreset][sha512.Size]byte
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
. "hakurei.app/container/bits"
|
||||
. "hakurei.app/container/comp"
|
||||
. "hakurei.app/container/seccomp"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,32 +5,32 @@ package seccomp
|
||||
import (
|
||||
. "syscall"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/comp"
|
||||
)
|
||||
|
||||
func Preset(presets bits.FilterPreset, flags ExportFlag) (rules []NativeRule) {
|
||||
func Preset(presets comp.FilterPreset, flags ExportFlag) (rules []NativeRule) {
|
||||
allowedPersonality := PersonaLinux
|
||||
if presets&bits.PresetLinux32 != 0 {
|
||||
if presets&comp.PresetLinux32 != 0 {
|
||||
allowedPersonality = PersonaLinux32
|
||||
}
|
||||
presetDevelFinal := presetDevel(ScmpDatum(allowedPersonality))
|
||||
|
||||
l := len(presetCommon)
|
||||
if presets&bits.PresetDenyNS != 0 {
|
||||
if presets&comp.PresetDenyNS != 0 {
|
||||
l += len(presetNamespace)
|
||||
}
|
||||
if presets&bits.PresetDenyTTY != 0 {
|
||||
if presets&comp.PresetDenyTTY != 0 {
|
||||
l += len(presetTTY)
|
||||
}
|
||||
if presets&bits.PresetDenyDevel != 0 {
|
||||
if presets&comp.PresetDenyDevel != 0 {
|
||||
l += len(presetDevelFinal)
|
||||
}
|
||||
if flags&AllowMultiarch == 0 {
|
||||
l += len(presetEmu)
|
||||
}
|
||||
if presets&bits.PresetExt != 0 {
|
||||
if presets&comp.PresetExt != 0 {
|
||||
l += len(presetCommonExt)
|
||||
if presets&bits.PresetDenyNS != 0 {
|
||||
if presets&comp.PresetDenyNS != 0 {
|
||||
l += len(presetNamespaceExt)
|
||||
}
|
||||
if flags&AllowMultiarch == 0 {
|
||||
@@ -40,21 +40,21 @@ func Preset(presets bits.FilterPreset, flags ExportFlag) (rules []NativeRule) {
|
||||
|
||||
rules = make([]NativeRule, 0, l)
|
||||
rules = append(rules, presetCommon...)
|
||||
if presets&bits.PresetDenyNS != 0 {
|
||||
if presets&comp.PresetDenyNS != 0 {
|
||||
rules = append(rules, presetNamespace...)
|
||||
}
|
||||
if presets&bits.PresetDenyTTY != 0 {
|
||||
if presets&comp.PresetDenyTTY != 0 {
|
||||
rules = append(rules, presetTTY...)
|
||||
}
|
||||
if presets&bits.PresetDenyDevel != 0 {
|
||||
if presets&comp.PresetDenyDevel != 0 {
|
||||
rules = append(rules, presetDevelFinal...)
|
||||
}
|
||||
if flags&AllowMultiarch == 0 {
|
||||
rules = append(rules, presetEmu...)
|
||||
}
|
||||
if presets&bits.PresetExt != 0 {
|
||||
if presets&comp.PresetExt != 0 {
|
||||
rules = append(rules, presetCommonExt...)
|
||||
if presets&bits.PresetDenyNS != 0 {
|
||||
if presets&comp.PresetDenyNS != 0 {
|
||||
rules = append(rules, presetNamespaceExt...)
|
||||
}
|
||||
if flags&AllowMultiarch == 0 {
|
||||
|
||||
@@ -1,50 +1,41 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
. "syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// SetPtracer allows processes to ptrace(2) the calling process.
|
||||
func SetPtracer(pid uintptr) error {
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_SET_PTRACER, pid, 0)
|
||||
if errno == 0 {
|
||||
return nil
|
||||
}
|
||||
// Prctl manipulates various aspects of the behavior of the calling thread or process.
|
||||
func Prctl(op, arg2, arg3 uintptr) error {
|
||||
r, _, errno := Syscall(SYS_PRCTL, op, arg2, arg3)
|
||||
if r < 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPtracer allows processes to ptrace(2) the calling process.
|
||||
func SetPtracer(pid uintptr) error { return Prctl(PR_SET_PTRACER, pid, 0) }
|
||||
|
||||
// linux/sched/coredump.h
|
||||
const (
|
||||
SUID_DUMP_DISABLE = iota
|
||||
SUID_DUMP_USER
|
||||
)
|
||||
|
||||
// SetDumpable sets the "dumpable" attribute of the calling process.
|
||||
func SetDumpable(dumpable uintptr) error {
|
||||
// linux/sched/coredump.h
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_SET_DUMPABLE, dumpable, 0); errno != 0 {
|
||||
return errno
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func SetDumpable(dumpable uintptr) error { return Prctl(PR_SET_DUMPABLE, dumpable, 0) }
|
||||
|
||||
// SetNoNewPrivs sets the calling thread's no_new_privs attribute.
|
||||
func SetNoNewPrivs() error {
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_PRCTL, PR_SET_NO_NEW_PRIVS, 1, 0)
|
||||
if errno == 0 {
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
func SetNoNewPrivs() error { return Prctl(PR_SET_NO_NEW_PRIVS, 1, 0) }
|
||||
|
||||
// Isatty tests whether a file descriptor refers to a terminal.
|
||||
func Isatty(fd int) bool {
|
||||
var buf [8]byte
|
||||
r, _, _ := syscall.Syscall(
|
||||
syscall.SYS_IOCTL,
|
||||
r, _, _ := Syscall(
|
||||
SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
syscall.TIOCGWINSZ,
|
||||
TIOCGWINSZ,
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
)
|
||||
return r == 0
|
||||
@@ -60,7 +51,7 @@ func Isatty(fd int) bool {
|
||||
func IgnoringEINTR(fn func() error) error {
|
||||
for {
|
||||
err := fn()
|
||||
if err != syscall.EINTR {
|
||||
if err != EINTR {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
8
dist/release.sh
vendored
8
dist/release.sh
vendored
@@ -10,10 +10,10 @@ cp -rv "dist/comp" "${out}"
|
||||
|
||||
go generate ./...
|
||||
go build -trimpath -v -o "${out}/bin/" -ldflags "-s -w -buildid= -extldflags '-static'
|
||||
-X hakurei.app/internal.version=${VERSION}
|
||||
-X hakurei.app/internal.hmain=/usr/bin/hakurei
|
||||
-X hakurei.app/internal.hsu=/usr/bin/hsu
|
||||
-X main.hmain=/usr/bin/hakurei" ./...
|
||||
-X hakurei.app/internal.buildVersion=${VERSION}
|
||||
-X hakurei.app/internal.hakureiPath=/usr/bin/hakurei
|
||||
-X hakurei.app/internal.hsuPath=/usr/bin/hsu
|
||||
-X main.hakureiPath=/usr/bin/hakurei" ./...
|
||||
|
||||
rm -f "./${out}.tar.gz" && tar -C dist -czf "${out}.tar.gz" "${pname}"
|
||||
rm -rf "./${out}"
|
||||
|
||||
@@ -2,6 +2,7 @@ package hst
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -38,9 +39,12 @@ const (
|
||||
ExitRequest = 254
|
||||
)
|
||||
|
||||
// Flags are options held by [ContainerConfig].
|
||||
type Flags uintptr
|
||||
|
||||
const (
|
||||
// FMultiarch unblocks syscalls required for multiarch to work on applicable targets.
|
||||
FMultiarch uintptr = 1 << iota
|
||||
FMultiarch Flags = 1 << iota
|
||||
|
||||
// FSeccompCompat changes emitted seccomp filter programs to be identical to that of Flatpak.
|
||||
FSeccompCompat
|
||||
@@ -74,6 +78,45 @@ const (
|
||||
FAll = fMax - 1
|
||||
)
|
||||
|
||||
func (flags Flags) String() string {
|
||||
switch flags {
|
||||
case FMultiarch:
|
||||
return "multiarch"
|
||||
case FSeccompCompat:
|
||||
return "compat"
|
||||
case FDevel:
|
||||
return "devel"
|
||||
case FUserns:
|
||||
return "userns"
|
||||
case FHostNet:
|
||||
return "net"
|
||||
case FHostAbstract:
|
||||
return "abstract"
|
||||
case FTty:
|
||||
return "tty"
|
||||
case FMapRealUID:
|
||||
return "mapuid"
|
||||
case FDevice:
|
||||
return "device"
|
||||
case FShareRuntime:
|
||||
return "runtime"
|
||||
case FShareTmpdir:
|
||||
return "tmpdir"
|
||||
|
||||
default:
|
||||
s := make([]string, 0, 1<<4)
|
||||
for f := Flags(1); f < fMax; f <<= 1 {
|
||||
if flags&f != 0 {
|
||||
s = append(s, f.String())
|
||||
}
|
||||
}
|
||||
if len(s) == 0 {
|
||||
return "none"
|
||||
}
|
||||
return strings.Join(s, ", ")
|
||||
}
|
||||
}
|
||||
|
||||
// ContainerConfig describes the container configuration to be applied to an underlying [container].
|
||||
type ContainerConfig struct {
|
||||
// Container UTS namespace hostname.
|
||||
@@ -106,7 +149,7 @@ type ContainerConfig struct {
|
||||
Args []string `json:"args"`
|
||||
|
||||
// Flags holds boolean options of [ContainerConfig].
|
||||
Flags uintptr `json:"-"`
|
||||
Flags Flags `json:"-"`
|
||||
}
|
||||
|
||||
// ContainerConfigF is [ContainerConfig] stripped of its methods.
|
||||
|
||||
@@ -3,6 +3,7 @@ package hst_test
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"testing"
|
||||
@@ -10,6 +11,30 @@ import (
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
|
||||
func TestFlagsString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
flags hst.Flags
|
||||
want string
|
||||
}{
|
||||
{"none", 0, "none"},
|
||||
{"none high", hst.FAll + 1, "none"},
|
||||
{"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir"},
|
||||
{"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir"},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if got := tc.flags.String(); got != tc.want {
|
||||
t.Errorf("String(%#b): %q, want %q", tc.flags, got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainerConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"encoding/gob"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
)
|
||||
|
||||
@@ -97,16 +97,16 @@ func (b *FSBind) Apply(z *ApplyState) {
|
||||
}
|
||||
var flags int
|
||||
if b.Write {
|
||||
flags |= bits.BindWritable
|
||||
flags |= comp.BindWritable
|
||||
}
|
||||
if b.Device {
|
||||
flags |= bits.BindDevice | bits.BindWritable
|
||||
flags |= comp.BindDevice | comp.BindWritable
|
||||
}
|
||||
if b.Ensure {
|
||||
flags |= bits.BindEnsure
|
||||
flags |= comp.BindEnsure
|
||||
}
|
||||
if b.Optional {
|
||||
flags |= bits.BindOptional
|
||||
flags |= comp.BindOptional
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestFSBind(t *testing.T) {
|
||||
}, true, container.Ops{&container.BindMountOp{
|
||||
Source: m("/mnt/dev"),
|
||||
Target: m("/dev"),
|
||||
Flags: bits.BindWritable | bits.BindDevice | bits.BindOptional,
|
||||
Flags: comp.BindWritable | comp.BindDevice | comp.BindOptional,
|
||||
}}, m("/dev"), ms("/mnt/dev"),
|
||||
"d+/mnt/dev:/dev"},
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestFSBind(t *testing.T) {
|
||||
}, true, container.Ops{&container.BindMountOp{
|
||||
Source: m("/mnt/dev"),
|
||||
Target: m("/dev"),
|
||||
Flags: bits.BindWritable | bits.BindDevice | bits.BindEnsure,
|
||||
Flags: comp.BindWritable | comp.BindDevice | comp.BindEnsure,
|
||||
}}, m("/dev"), ms("/mnt/dev"),
|
||||
"d-/mnt/dev:/dev"},
|
||||
|
||||
@@ -48,7 +48,7 @@ func TestFSBind(t *testing.T) {
|
||||
}, true, container.Ops{&container.BindMountOp{
|
||||
Source: m("/mnt/dev"),
|
||||
Target: m("/dev"),
|
||||
Flags: bits.BindWritable | bits.BindDevice,
|
||||
Flags: comp.BindWritable | comp.BindDevice,
|
||||
}}, m("/dev"), ms("/mnt/dev"),
|
||||
"d*/mnt/dev:/dev"},
|
||||
|
||||
@@ -59,7 +59,7 @@ func TestFSBind(t *testing.T) {
|
||||
}, true, container.Ops{&container.BindMountOp{
|
||||
Source: m("/mnt/tmp"),
|
||||
Target: m("/tmp"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}}, m("/tmp"), ms("/mnt/tmp"),
|
||||
"w*/mnt/tmp:/tmp"},
|
||||
|
||||
@@ -98,7 +98,7 @@ func TestFSBind(t *testing.T) {
|
||||
Special: true,
|
||||
}, true, container.Ops{&container.AutoRootOp{
|
||||
Host: m("/"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}}, m("/"), ms("/"), "autoroot:w"},
|
||||
|
||||
{"autoroot silly", &hst.FSBind{
|
||||
@@ -108,7 +108,7 @@ func TestFSBind(t *testing.T) {
|
||||
Special: true,
|
||||
}, true, container.Ops{&container.AutoRootOp{
|
||||
Host: m("/etc"),
|
||||
Flags: bits.BindWritable,
|
||||
Flags: comp.BindWritable,
|
||||
}}, m("/"), ms("/etc"), "autoroot:w:/etc"},
|
||||
|
||||
{"autoetc", &hst.FSBind{
|
||||
|
||||
@@ -52,7 +52,10 @@ type Paths struct {
|
||||
RunDirPath *check.Absolute `json:"run_dir_path"`
|
||||
}
|
||||
|
||||
// Info holds basic system information collected from the implementation.
|
||||
type Info struct {
|
||||
// Version is a hardcoded version string.
|
||||
Version string `json:"version"`
|
||||
// User is the userid according to hsu.
|
||||
User int `json:"user"`
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ func Main(ctx context.Context, msg message.Msg, config *hst.Config) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
seal := outcome{syscallDispatcher: direct{}}
|
||||
seal := outcome{syscallDispatcher: direct{msg}}
|
||||
if err := seal.finalise(ctx, msg, &id, config); err != nil {
|
||||
printMessageError("cannot seal app:", err)
|
||||
os.Exit(1)
|
||||
|
||||
@@ -17,9 +17,10 @@ import (
|
||||
"time"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/app/state"
|
||||
"hakurei.app/message"
|
||||
@@ -41,9 +42,149 @@ func TestApp(t *testing.T) {
|
||||
wantSys *system.I
|
||||
wantParams *container.Params
|
||||
}{
|
||||
{
|
||||
"nixos permissive defaults no enablements", new(stubNixOS),
|
||||
&hst.Config{Container: &hst.ContainerConfig{
|
||||
{"template", new(stubNixOS), hst.Template(), checkExpectInstanceId, system.New(panicMsgContext{}, message.NewMsg(nil), 1000009).
|
||||
// spParamsOp
|
||||
Ensure(m("/tmp/hakurei.0"), 0711).
|
||||
|
||||
// spRuntimeOp
|
||||
Ensure(m("/tmp/hakurei.0/runtime"), 0700).
|
||||
UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/runtime/9"), 0700).
|
||||
UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/9"), acl.Read, acl.Write, acl.Execute).
|
||||
|
||||
// spTmpdirOp
|
||||
Ensure(m("/tmp/hakurei.0/tmpdir"), 0700).
|
||||
UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir"), acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/tmpdir/9"), 01700).
|
||||
UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/9"), acl.Read, acl.Write, acl.Execute).
|
||||
|
||||
// instance
|
||||
Ephemeral(system.Process, m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), 0711).
|
||||
|
||||
// spWaylandOp
|
||||
Wayland(
|
||||
m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"),
|
||||
m("/run/user/1971/wayland-0"),
|
||||
"org.chromium.Chromium",
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
).
|
||||
|
||||
// ensureRuntimeDir
|
||||
Ensure(m("/run/user/1971/hakurei"), 0700).
|
||||
UpdatePermType(system.User, m("/run/user/1971/hakurei"), acl.Execute).
|
||||
Ensure(m("/run/user/1971"), 0700).
|
||||
UpdatePermType(system.User, m("/run/user/1971"), acl.Execute).
|
||||
|
||||
// runtime
|
||||
Ephemeral(system.Process, m("/run/user/1971/hakurei/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), 0700).
|
||||
UpdatePerm(m("/run/user/1971/hakurei/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), acl.Execute).
|
||||
|
||||
// spPulseOp
|
||||
Link(m("/run/user/1971/pulse/native"), m("/run/user/1971/hakurei/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pulse")).
|
||||
|
||||
// spDBusOp
|
||||
MustProxyDBus(
|
||||
hst.Template().SessionBus,
|
||||
hst.Template().SystemBus, dbus.ProxyPair{
|
||||
"unix:path=/run/user/1971/bus",
|
||||
"/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bus",
|
||||
}, dbus.ProxyPair{
|
||||
"unix:path=/var/run/dbus/system_bus_socket",
|
||||
"/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket",
|
||||
},
|
||||
).UpdatePerm(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bus"), acl.Read, acl.Write).
|
||||
UpdatePerm(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket"), acl.Read, acl.Write).
|
||||
|
||||
// spFilesystemOp
|
||||
Ensure(m("/var/lib/hakurei/u0"), 0700).
|
||||
UpdatePermType(system.User, m("/var/lib/hakurei/u0"), acl.Execute).
|
||||
UpdatePermType(system.User, m("/var/lib/hakurei/u0/org.chromium.Chromium"), acl.Read, acl.Write, acl.Execute), &container.Params{
|
||||
|
||||
Dir: m("/data/data/org.chromium.Chromium"),
|
||||
Env: []string{
|
||||
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1971/bus",
|
||||
"DBUS_SYSTEM_BUS_ADDRESS=unix:path=/var/run/dbus/system_bus_socket",
|
||||
"GOOGLE_API_KEY=AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
||||
"GOOGLE_DEFAULT_CLIENT_ID=77185425430.apps.googleusercontent.com",
|
||||
"GOOGLE_DEFAULT_CLIENT_SECRET=OTJgUOQcT7lO7GsGZq2G4IlT",
|
||||
"HOME=/data/data/org.chromium.Chromium",
|
||||
"PULSE_COOKIE=/.hakurei/pulse-cookie",
|
||||
"PULSE_SERVER=unix:/run/user/1971/pulse/native",
|
||||
"SHELL=/run/current-system/sw/bin/zsh",
|
||||
"TERM=xterm-256color",
|
||||
"USER=chronos",
|
||||
"WAYLAND_DISPLAY=wayland-0",
|
||||
"XDG_RUNTIME_DIR=/run/user/1971",
|
||||
"XDG_SESSION_CLASS=user",
|
||||
"XDG_SESSION_TYPE=wayland",
|
||||
},
|
||||
|
||||
// spParamsOp
|
||||
Hostname: "localhost",
|
||||
RetainSession: true,
|
||||
HostNet: true,
|
||||
HostAbstract: true,
|
||||
Path: m("/run/current-system/sw/bin/chromium"),
|
||||
Args: []string{
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland",
|
||||
},
|
||||
SeccompFlags: seccomp.AllowMultiarch,
|
||||
Uid: 1971,
|
||||
Gid: 100,
|
||||
|
||||
Ops: new(container.Ops).
|
||||
// resolveRoot
|
||||
Root(m("/var/lib/hakurei/base/org.debian"), comp.BindWritable).
|
||||
// spParamsOp
|
||||
Proc(fhs.AbsProc).
|
||||
Tmpfs(hst.AbsPrivateTmp, 1<<12, 0755).
|
||||
Bind(fhs.AbsDev, fhs.AbsDev, comp.BindWritable|comp.BindDevice).
|
||||
Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777).
|
||||
|
||||
// spRuntimeOp
|
||||
Tmpfs(fhs.AbsRunUser, 1<<12, 0755).
|
||||
Bind(m("/tmp/hakurei.0/runtime/9"), m("/run/user/1971"), comp.BindWritable).
|
||||
|
||||
// spTmpdirOp
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/9"), fhs.AbsTmp, comp.BindWritable).
|
||||
|
||||
// spAccountOp
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1971:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
|
||||
// spWaylandOp
|
||||
Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1971/wayland-0"), 0).
|
||||
|
||||
// spPulseOp
|
||||
Bind(m("/run/user/1971/hakurei/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pulse"), m("/run/user/1971/pulse/native"), 0).
|
||||
Place(m("/.hakurei/pulse-cookie"), bytes.Repeat([]byte{0}, pulseCookieSizeMax)).
|
||||
|
||||
// spDBusOp
|
||||
Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bus"), m("/run/user/1971/bus"), 0).
|
||||
Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket"), m("/var/run/dbus/system_bus_socket"), 0).
|
||||
|
||||
// spFilesystemOp
|
||||
Etc(fhs.AbsEtc, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").
|
||||
Tmpfs(fhs.AbsTmp, 0, 0755).
|
||||
Overlay(m("/nix/store"),
|
||||
fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/upper"),
|
||||
fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/work"),
|
||||
fhs.AbsVarLib.Append("hakurei/base/org.nixos/ro-store")).
|
||||
Link(m("/run/current-system"), "/run/current-system", true).
|
||||
Link(m("/run/opengl-driver"), "/run/opengl-driver", true).
|
||||
Bind(fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"),
|
||||
m("/data/data/org.chromium.Chromium"),
|
||||
comp.BindWritable|comp.BindEnsure).
|
||||
Bind(fhs.AbsDev.Append("dri"), fhs.AbsDev.Append("dri"),
|
||||
comp.BindOptional|comp.BindWritable|comp.BindDevice).
|
||||
Remount(fhs.AbsRoot, syscall.MS_RDONLY),
|
||||
}},
|
||||
|
||||
{"nixos permissive defaults no enablements", new(stubNixOS), &hst.Config{Container: &hst.ContainerConfig{
|
||||
Filesystem: []hst.FilesystemConfigJSON{
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
Target: fhs.AbsRoot,
|
||||
@@ -71,20 +212,22 @@ func TestApp(t *testing.T) {
|
||||
Args: []string{"/run/current-system/sw/bin/zsh"},
|
||||
|
||||
Flags: hst.FUserns | hst.FHostNet | hst.FHostAbstract | hst.FTty | hst.FShareRuntime | hst.FShareTmpdir,
|
||||
}},
|
||||
state.ID{
|
||||
}}, state.ID{
|
||||
0x4a, 0x45, 0x0b, 0x65,
|
||||
0x96, 0xd7, 0xbc, 0x15,
|
||||
0xbd, 0x01, 0x78, 0x0e,
|
||||
0xb9, 0xa6, 0x07, 0xac,
|
||||
},
|
||||
system.New(t.Context(), msg, 1000000).
|
||||
}, system.New(t.Context(), msg, 1000000).
|
||||
Ensure(m("/tmp/hakurei.0"), 0711).
|
||||
Ensure(m("/tmp/hakurei.0/runtime"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/runtime/0"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/0"), acl.Read, acl.Write, acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/tmpdir"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir"), acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/tmpdir/0"), 01700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/0"), acl.Read, acl.Write, acl.Execute),
|
||||
&container.Params{
|
||||
Ensure(m("/tmp/hakurei.0/runtime"), 0700).
|
||||
UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/runtime/0"), 0700).
|
||||
UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/0"), acl.Read, acl.Write, acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/tmpdir"), 0700).
|
||||
UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir"), acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/tmpdir/0"), 01700).
|
||||
UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/0"), acl.Read, acl.Write, acl.Execute), &container.Params{
|
||||
|
||||
Dir: m("/home/chronos"),
|
||||
Path: m("/run/current-system/sw/bin/zsh"),
|
||||
Args: []string{"/run/current-system/sw/bin/zsh"},
|
||||
@@ -98,33 +241,31 @@ func TestApp(t *testing.T) {
|
||||
"XDG_SESSION_TYPE=tty",
|
||||
},
|
||||
Ops: new(container.Ops).
|
||||
Root(m("/"), bits.BindWritable).
|
||||
Root(m("/"), comp.BindWritable).
|
||||
Proc(m("/proc/")).
|
||||
Tmpfs(hst.AbsPrivateTmp, 4096, 0755).
|
||||
DevWritable(m("/dev/"), true).
|
||||
Tmpfs(m("/dev/shm"), 0, 01777).
|
||||
Tmpfs(m("/run/user/"), 4096, 0755).
|
||||
Bind(m("/tmp/hakurei.0/runtime/0"), m("/run/user/65534"), bits.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/0"), m("/tmp/"), bits.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/runtime/0"), m("/run/user/65534"), comp.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/0"), m("/tmp/"), comp.BindWritable).
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:65534:\n")).
|
||||
Bind(m("/dev/kvm"), m("/dev/kvm"), bits.BindWritable|bits.BindDevice|bits.BindOptional).
|
||||
Bind(m("/dev/kvm"), m("/dev/kvm"), comp.BindWritable|comp.BindDevice|comp.BindOptional).
|
||||
Etc(m("/etc/"), "4a450b6596d7bc15bd01780eb9a607ac").
|
||||
Tmpfs(m("/run/user/1971"), 8192, 0755).
|
||||
Tmpfs(m("/run/nscd"), 8192, 0755).
|
||||
Tmpfs(m("/run/dbus"), 8192, 0755).
|
||||
Remount(m("/dev/"), syscall.MS_RDONLY).
|
||||
Remount(m("/"), syscall.MS_RDONLY),
|
||||
SeccompPresets: bits.PresetExt | bits.PresetDenyDevel,
|
||||
SeccompPresets: comp.PresetExt | comp.PresetDenyDevel,
|
||||
HostNet: true,
|
||||
HostAbstract: true,
|
||||
RetainSession: true,
|
||||
ForwardCancel: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
"nixos permissive defaults chromium", new(stubNixOS),
|
||||
&hst.Config{
|
||||
}},
|
||||
|
||||
{"nixos permissive defaults chromium", new(stubNixOS), &hst.Config{
|
||||
ID: "org.chromium.Chromium",
|
||||
Identity: 9,
|
||||
Groups: []string{"video"},
|
||||
@@ -195,14 +336,12 @@ func TestApp(t *testing.T) {
|
||||
|
||||
Flags: hst.FUserns | hst.FHostNet | hst.FHostAbstract | hst.FTty | hst.FShareRuntime | hst.FShareTmpdir,
|
||||
},
|
||||
},
|
||||
state.ID{
|
||||
}, state.ID{
|
||||
0xeb, 0xf0, 0x83, 0xd1,
|
||||
0xb1, 0x75, 0x91, 0x17,
|
||||
0x82, 0xd4, 0x13, 0x36,
|
||||
0x9b, 0x64, 0xce, 0x7c,
|
||||
},
|
||||
system.New(t.Context(), msg, 1000009).
|
||||
}, system.New(t.Context(), msg, 1000009).
|
||||
Ensure(m("/tmp/hakurei.0"), 0711).
|
||||
Ensure(m("/tmp/hakurei.0/runtime"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/runtime/9"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/9"), acl.Read, acl.Write, acl.Execute).
|
||||
@@ -251,8 +390,8 @@ func TestApp(t *testing.T) {
|
||||
"/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/system_bus_socket",
|
||||
}).
|
||||
UpdatePerm(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/bus"), acl.Read, acl.Write).
|
||||
UpdatePerm(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/system_bus_socket"), acl.Read, acl.Write),
|
||||
&container.Params{
|
||||
UpdatePerm(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/system_bus_socket"), acl.Read, acl.Write), &container.Params{
|
||||
|
||||
Dir: m("/home/chronos"),
|
||||
Path: m("/run/current-system/sw/bin/zsh"),
|
||||
Args: []string{"zsh", "-c", "exec chromium "},
|
||||
@@ -271,14 +410,14 @@ func TestApp(t *testing.T) {
|
||||
"XDG_SESSION_TYPE=wayland",
|
||||
},
|
||||
Ops: new(container.Ops).
|
||||
Root(m("/"), bits.BindWritable).
|
||||
Root(m("/"), comp.BindWritable).
|
||||
Proc(m("/proc/")).
|
||||
Tmpfs(hst.AbsPrivateTmp, 4096, 0755).
|
||||
DevWritable(m("/dev/"), true).
|
||||
Tmpfs(m("/dev/shm"), 0, 01777).
|
||||
Tmpfs(m("/run/user/"), 4096, 0755).
|
||||
Bind(m("/tmp/hakurei.0/runtime/9"), m("/run/user/65534"), bits.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/9"), m("/tmp/"), bits.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/runtime/9"), m("/run/user/65534"), comp.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/9"), m("/tmp/"), comp.BindWritable).
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:65534:\n")).
|
||||
Bind(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/wayland"), m("/run/user/65534/wayland-0"), 0).
|
||||
@@ -286,25 +425,22 @@ func TestApp(t *testing.T) {
|
||||
Place(m(hst.PrivateTmp+"/pulse-cookie"), bytes.Repeat([]byte{0}, pulseCookieSizeMax)).
|
||||
Bind(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/bus"), m("/run/user/65534/bus"), 0).
|
||||
Bind(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/system_bus_socket"), m("/var/run/dbus/system_bus_socket"), 0).
|
||||
Bind(m("/dev/dri"), m("/dev/dri"), bits.BindWritable|bits.BindDevice|bits.BindOptional).
|
||||
Bind(m("/dev/kvm"), m("/dev/kvm"), bits.BindWritable|bits.BindDevice|bits.BindOptional).
|
||||
Bind(m("/dev/dri"), m("/dev/dri"), comp.BindWritable|comp.BindDevice|comp.BindOptional).
|
||||
Bind(m("/dev/kvm"), m("/dev/kvm"), comp.BindWritable|comp.BindDevice|comp.BindOptional).
|
||||
Etc(m("/etc/"), "ebf083d1b175911782d413369b64ce7c").
|
||||
Tmpfs(m("/run/user/1971"), 8192, 0755).
|
||||
Tmpfs(m("/run/nscd"), 8192, 0755).
|
||||
Tmpfs(m("/run/dbus"), 8192, 0755).
|
||||
Remount(m("/dev/"), syscall.MS_RDONLY).
|
||||
Remount(m("/"), syscall.MS_RDONLY),
|
||||
SeccompPresets: bits.PresetExt | bits.PresetDenyDevel,
|
||||
SeccompPresets: comp.PresetExt | comp.PresetDenyDevel,
|
||||
HostNet: true,
|
||||
HostAbstract: true,
|
||||
RetainSession: true,
|
||||
ForwardCancel: true,
|
||||
},
|
||||
},
|
||||
}},
|
||||
|
||||
{
|
||||
"nixos chromium direct wayland", new(stubNixOS),
|
||||
&hst.Config{
|
||||
{"nixos chromium direct wayland", new(stubNixOS), &hst.Config{
|
||||
ID: "org.chromium.Chromium",
|
||||
Enablements: hst.NewEnablements(hst.EWayland | hst.EDBus | hst.EPulse),
|
||||
Container: &hst.ContainerConfig{
|
||||
@@ -354,14 +490,12 @@ func TestApp(t *testing.T) {
|
||||
DirectWayland: true,
|
||||
|
||||
Identity: 1, Groups: []string{},
|
||||
},
|
||||
state.ID{
|
||||
}, state.ID{
|
||||
0x8e, 0x2c, 0x76, 0xb0,
|
||||
0x66, 0xda, 0xbe, 0x57,
|
||||
0x4c, 0xf0, 0x73, 0xbd,
|
||||
0xb4, 0x6e, 0xb5, 0xc1,
|
||||
},
|
||||
system.New(t.Context(), msg, 1000001).
|
||||
}, system.New(t.Context(), msg, 1000001).
|
||||
Ensure(m("/tmp/hakurei.0"), 0711).
|
||||
Ensure(m("/tmp/hakurei.0/runtime"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute).
|
||||
Ensure(m("/tmp/hakurei.0/runtime/1"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/1"), acl.Read, acl.Write, acl.Execute).
|
||||
@@ -401,8 +535,8 @@ func TestApp(t *testing.T) {
|
||||
"/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket",
|
||||
}).
|
||||
UpdatePerm(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/bus"), acl.Read, acl.Write).
|
||||
UpdatePerm(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket"), acl.Read, acl.Write),
|
||||
&container.Params{
|
||||
UpdatePerm(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket"), acl.Read, acl.Write), &container.Params{
|
||||
|
||||
Uid: 1971,
|
||||
Gid: 100,
|
||||
Dir: m("/var/lib/persist/module/hakurei/0/1"),
|
||||
@@ -428,8 +562,8 @@ func TestApp(t *testing.T) {
|
||||
DevWritable(m("/dev/"), true).
|
||||
Tmpfs(m("/dev/shm"), 0, 01777).
|
||||
Tmpfs(m("/run/user/"), 4096, 0755).
|
||||
Bind(m("/tmp/hakurei.0/runtime/1"), m("/run/user/1971"), bits.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/1"), m("/tmp/"), bits.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/runtime/1"), m("/run/user/1971"), comp.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/1"), m("/tmp/"), comp.BindWritable).
|
||||
Place(m("/etc/passwd"), []byte("u0_a1:x:1971:100:Hakurei:/var/lib/persist/module/hakurei/0/1:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
Bind(m("/run/user/1971/wayland-0"), m("/run/user/1971/wayland-0"), 0).
|
||||
@@ -441,22 +575,21 @@ func TestApp(t *testing.T) {
|
||||
Bind(m("/usr/bin/"), m("/usr/bin/"), 0).
|
||||
Bind(m("/nix/store"), m("/nix/store"), 0).
|
||||
Bind(m("/run/current-system"), m("/run/current-system"), 0).
|
||||
Bind(m("/sys/block"), m("/sys/block"), bits.BindOptional).
|
||||
Bind(m("/sys/bus"), m("/sys/bus"), bits.BindOptional).
|
||||
Bind(m("/sys/class"), m("/sys/class"), bits.BindOptional).
|
||||
Bind(m("/sys/dev"), m("/sys/dev"), bits.BindOptional).
|
||||
Bind(m("/sys/devices"), m("/sys/devices"), bits.BindOptional).
|
||||
Bind(m("/sys/block"), m("/sys/block"), comp.BindOptional).
|
||||
Bind(m("/sys/bus"), m("/sys/bus"), comp.BindOptional).
|
||||
Bind(m("/sys/class"), m("/sys/class"), comp.BindOptional).
|
||||
Bind(m("/sys/dev"), m("/sys/dev"), comp.BindOptional).
|
||||
Bind(m("/sys/devices"), m("/sys/devices"), comp.BindOptional).
|
||||
Bind(m("/run/opengl-driver"), m("/run/opengl-driver"), 0).
|
||||
Bind(m("/dev/dri"), m("/dev/dri"), bits.BindDevice|bits.BindWritable|bits.BindOptional).
|
||||
Bind(m("/dev/dri"), m("/dev/dri"), comp.BindDevice|comp.BindWritable|comp.BindOptional).
|
||||
Etc(m("/etc/"), "8e2c76b066dabe574cf073bdb46eb5c1").
|
||||
Bind(m("/var/lib/persist/module/hakurei/0/1"), m("/var/lib/persist/module/hakurei/0/1"), bits.BindWritable|bits.BindEnsure).
|
||||
Bind(m("/var/lib/persist/module/hakurei/0/1"), m("/var/lib/persist/module/hakurei/0/1"), comp.BindWritable|comp.BindEnsure).
|
||||
Remount(m("/dev/"), syscall.MS_RDONLY).
|
||||
Remount(m("/"), syscall.MS_RDONLY),
|
||||
SeccompPresets: bits.PresetExt | bits.PresetDenyTTY | bits.PresetDenyDevel,
|
||||
SeccompPresets: comp.PresetExt | comp.PresetDenyTTY | comp.PresetDenyDevel,
|
||||
HostNet: true,
|
||||
ForwardCancel: true,
|
||||
},
|
||||
},
|
||||
}},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -574,10 +707,9 @@ func (s stubOsFileReadCloser) Stat() (fs.FileInfo, error) { panic("attempting to
|
||||
|
||||
type stubNixOS struct {
|
||||
usernameErr map[string]error
|
||||
panicDispatcher
|
||||
}
|
||||
|
||||
func (k *stubNixOS) new(func(k syscallDispatcher)) { panic("not implemented") }
|
||||
|
||||
func (k *stubNixOS) getpid() int { return 0xdeadbeef }
|
||||
func (k *stubNixOS) getuid() int { return 1971 }
|
||||
func (k *stubNixOS) getgid() int { return 100 }
|
||||
@@ -659,6 +791,10 @@ func (k *stubNixOS) readdir(name string) ([]fs.DirEntry, error) {
|
||||
"tmpfiles.d", "udev", "udisks2", "UPower", "vconsole.conf", "X11", "zfs", "zinputrc",
|
||||
"zoneinfo", "zprofile", "zshenv", "zshrc")
|
||||
|
||||
case "/var/lib/hakurei/base/org.debian":
|
||||
return stubDirEntries("bin", "dev", "etc", "home", "lib64", "lost+found",
|
||||
"mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var")
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("attempted to read unexpected directory %q", name))
|
||||
}
|
||||
@@ -726,6 +862,38 @@ func (k *stubNixOS) evalSymlinks(path string) (string, error) {
|
||||
return "/nix/store/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-graphics-drivers", nil
|
||||
case "/var/lib/persist/module/hakurei/0/1":
|
||||
return "/var/lib/persist/module/hakurei/0/1", nil
|
||||
|
||||
case "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper":
|
||||
return "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper", nil
|
||||
case "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work":
|
||||
return "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work", nil
|
||||
case "/var/lib/hakurei/base/org.nixos/ro-store":
|
||||
return "/var/lib/hakurei/base/org.nixos/ro-store", nil
|
||||
case "/var/lib/hakurei/u0/org.chromium.Chromium":
|
||||
return "/var/lib/hakurei/u0/org.chromium.Chromium", nil
|
||||
case "/var/lib/hakurei/base/org.debian/bin":
|
||||
return "/var/lib/hakurei/base/org.debian/bin", nil
|
||||
case "/var/lib/hakurei/base/org.debian/home":
|
||||
return "/var/lib/hakurei/base/org.debian/home", nil
|
||||
case "/var/lib/hakurei/base/org.debian/lib64":
|
||||
return "/var/lib/hakurei/base/org.debian/lib64", nil
|
||||
case "/var/lib/hakurei/base/org.debian/lost+found":
|
||||
return "/var/lib/hakurei/base/org.debian/lost+found", nil
|
||||
case "/var/lib/hakurei/base/org.debian/nix":
|
||||
return "/var/lib/hakurei/base/org.debian/nix", nil
|
||||
case "/var/lib/hakurei/base/org.debian/root":
|
||||
return "/var/lib/hakurei/base/org.debian/root", nil
|
||||
case "/var/lib/hakurei/base/org.debian/run":
|
||||
return "/var/lib/hakurei/base/org.debian/run", nil
|
||||
case "/var/lib/hakurei/base/org.debian/srv":
|
||||
return "/var/lib/hakurei/base/org.debian/srv", nil
|
||||
case "/var/lib/hakurei/base/org.debian/sys":
|
||||
return "/var/lib/hakurei/base/org.debian/sys", nil
|
||||
case "/var/lib/hakurei/base/org.debian/usr":
|
||||
return "/var/lib/hakurei/base/org.debian/usr", nil
|
||||
case "/var/lib/hakurei/base/org.debian/var":
|
||||
return "/var/lib/hakurei/base/org.debian/var", nil
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("attempted to evaluate unexpected path %q", path))
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/internal"
|
||||
"hakurei.app/message"
|
||||
"hakurei.app/system/dbus"
|
||||
@@ -28,7 +30,7 @@ type syscallDispatcher interface {
|
||||
// new starts a goroutine with a new instance of syscallDispatcher.
|
||||
// A syscallDispatcher must never be used in any goroutine other than the one owning it,
|
||||
// just synchronising access is not enough, as this is for test instrumentation.
|
||||
new(f func(k syscallDispatcher))
|
||||
new(f func(k syscallDispatcher, msg message.Msg))
|
||||
|
||||
// getpid provides [os.Getpid].
|
||||
getpid() int
|
||||
@@ -38,6 +40,8 @@ type syscallDispatcher interface {
|
||||
getgid() int
|
||||
// lookupEnv provides [os.LookupEnv].
|
||||
lookupEnv(key string) (string, bool)
|
||||
// pipe provides os.Pipe.
|
||||
pipe() (r, w *os.File, err error)
|
||||
// stat provides [os.Stat].
|
||||
stat(name string) (os.FileInfo, error)
|
||||
// open provides [os.Open].
|
||||
@@ -46,6 +50,8 @@ type syscallDispatcher interface {
|
||||
readdir(name string) ([]os.DirEntry, error)
|
||||
// tempdir provides [os.TempDir].
|
||||
tempdir() string
|
||||
// exit provides [os.Exit].
|
||||
exit(code int)
|
||||
|
||||
// evalSymlinks provides [filepath.EvalSymlinks].
|
||||
evalSymlinks(path string) (string, error)
|
||||
@@ -56,10 +62,29 @@ type syscallDispatcher interface {
|
||||
// cmdOutput provides the Output method of [exec.Cmd].
|
||||
cmdOutput(cmd *exec.Cmd) ([]byte, error)
|
||||
|
||||
// notifyContext provides [signal.NotifyContext].
|
||||
notifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)
|
||||
|
||||
// prctl provides [container.Prctl].
|
||||
prctl(op, arg2, arg3 uintptr) error
|
||||
// overflowUid provides [container.OverflowUid].
|
||||
overflowUid(msg message.Msg) int
|
||||
// overflowGid provides [container.OverflowGid].
|
||||
overflowGid(msg message.Msg) int
|
||||
// setDumpable provides [container.SetDumpable].
|
||||
setDumpable(dumpable uintptr) error
|
||||
// receive provides [container.Receive].
|
||||
receive(key string, e any, fdp *uintptr) (closeFunc func() error, err error)
|
||||
|
||||
// containerStart provides the Start method of [container.Container].
|
||||
containerStart(z *container.Container) error
|
||||
// containerStart provides the Serve method of [container.Container].
|
||||
containerServe(z *container.Container) error
|
||||
// containerStart provides the Wait method of [container.Container].
|
||||
containerWait(z *container.Container) error
|
||||
|
||||
// seccompLoad provides [seccomp.Load].
|
||||
seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error
|
||||
|
||||
// mustHsuPath provides [internal.MustHsuPath].
|
||||
mustHsuPath() *check.Absolute
|
||||
@@ -67,23 +92,32 @@ type syscallDispatcher interface {
|
||||
// dbusAddress provides [dbus.Address].
|
||||
dbusAddress() (session, system string)
|
||||
|
||||
// setupContSignal provides setupContSignal.
|
||||
setupContSignal(pid int) (io.ReadCloser, func(), error)
|
||||
|
||||
// getMsg returns the [message.Msg] held by syscallDispatcher.
|
||||
getMsg() message.Msg
|
||||
// fatal provides [log.Fatal].
|
||||
fatal(v ...any)
|
||||
// fatalf provides [log.Fatalf].
|
||||
fatalf(format string, v ...any)
|
||||
}
|
||||
|
||||
// direct implements syscallDispatcher on the current kernel.
|
||||
type direct struct{}
|
||||
type direct struct{ msg message.Msg }
|
||||
|
||||
func (k direct) new(f func(k syscallDispatcher)) { go f(k) }
|
||||
func (k direct) new(f func(k syscallDispatcher, msg message.Msg)) { go f(k, k.msg) }
|
||||
|
||||
func (direct) getpid() int { return os.Getpid() }
|
||||
func (direct) getuid() int { return os.Getuid() }
|
||||
func (direct) getgid() int { return os.Getgid() }
|
||||
func (direct) lookupEnv(key string) (string, bool) { return os.LookupEnv(key) }
|
||||
func (direct) pipe() (r, w *os.File, err error) { return os.Pipe() }
|
||||
func (direct) stat(name string) (os.FileInfo, error) { return os.Stat(name) }
|
||||
func (direct) open(name string) (osFile, error) { return os.Open(name) }
|
||||
func (direct) readdir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) }
|
||||
func (direct) tempdir() string { return os.TempDir() }
|
||||
func (direct) exit(code int) { os.Exit(code) }
|
||||
|
||||
func (direct) evalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) }
|
||||
|
||||
@@ -98,11 +132,32 @@ func (direct) lookupGroupId(name string) (gid string, err error) {
|
||||
|
||||
func (direct) cmdOutput(cmd *exec.Cmd) ([]byte, error) { return cmd.Output() }
|
||||
|
||||
func (direct) notifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) {
|
||||
return signal.NotifyContext(parent, signals...)
|
||||
}
|
||||
|
||||
func (direct) prctl(op, arg2, arg3 uintptr) error { return container.Prctl(op, arg2, arg3) }
|
||||
func (direct) overflowUid(msg message.Msg) int { return container.OverflowUid(msg) }
|
||||
func (direct) overflowGid(msg message.Msg) int { return container.OverflowGid(msg) }
|
||||
func (direct) setDumpable(dumpable uintptr) error { return container.SetDumpable(dumpable) }
|
||||
func (direct) receive(key string, e any, fdp *uintptr) (func() error, error) {
|
||||
return container.Receive(key, e, fdp)
|
||||
}
|
||||
|
||||
func (direct) containerStart(z *container.Container) error { return z.Start() }
|
||||
func (direct) containerServe(z *container.Container) error { return z.Serve() }
|
||||
func (direct) containerWait(z *container.Container) error { return z.Wait() }
|
||||
|
||||
func (direct) seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error {
|
||||
return seccomp.Load(rules, flags)
|
||||
}
|
||||
|
||||
func (direct) mustHsuPath() *check.Absolute { return internal.MustHsuPath() }
|
||||
|
||||
func (k direct) dbusAddress() (session, system string) { return dbus.Address() }
|
||||
func (direct) dbusAddress() (session, system string) { return dbus.Address() }
|
||||
|
||||
func (direct) fatalf(format string, v ...any) { log.Fatalf(format, v...) }
|
||||
func (direct) setupContSignal(pid int) (io.ReadCloser, func(), error) { return setupContSignal(pid) }
|
||||
|
||||
func (k direct) getMsg() message.Msg { return k.msg }
|
||||
func (k direct) fatal(v ...any) { k.msg.GetLogger().Fatal(v...) }
|
||||
func (k direct) fatalf(format string, v ...any) { k.msg.GetLogger().Fatalf(format, v...) }
|
||||
|
||||
@@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
@@ -10,11 +11,14 @@ import (
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/app/state"
|
||||
@@ -312,6 +316,10 @@ type kstub struct {
|
||||
*stub.Stub[syscallDispatcher]
|
||||
}
|
||||
|
||||
func (k *kstub) new(f func(k syscallDispatcher, msg message.Msg)) {
|
||||
k.New(func(k syscallDispatcher) { f(k, k.(*kstub)) })
|
||||
}
|
||||
|
||||
func (k *kstub) getpid() int { k.Helper(); return k.Expects("getpid").Ret.(int) }
|
||||
func (k *kstub) getuid() int { k.Helper(); return k.Expects("getuid").Ret.(int) }
|
||||
func (k *kstub) getgid() int { k.Helper(); return k.Expects("getgid").Ret.(int) }
|
||||
@@ -353,6 +361,61 @@ func (k *kstub) evalSymlinks(path string) (string, error) {
|
||||
stub.CheckArg(k.Stub, "path", path, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) prctl(op, arg2, arg3 uintptr) error {
|
||||
k.Helper()
|
||||
return k.Expects("prctl").Error(
|
||||
stub.CheckArg(k.Stub, "op", op, 0),
|
||||
stub.CheckArg(k.Stub, "arg2", arg2, 1),
|
||||
stub.CheckArg(k.Stub, "arg3", arg3, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) setDumpable(dumpable uintptr) error {
|
||||
k.Helper()
|
||||
return k.Expects("setDumpable").Error(
|
||||
stub.CheckArg(k.Stub, "dumpable", dumpable, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) receive(key string, e any, fdp *uintptr) (closeFunc func() error, err error) {
|
||||
k.Helper()
|
||||
expect := k.Expects("receive")
|
||||
reflect.ValueOf(e).Elem().Set(reflect.ValueOf(expect.Args[1]))
|
||||
if expect.Args[2] != nil {
|
||||
*fdp = expect.Args[2].(uintptr)
|
||||
}
|
||||
return func() error { return k.Expects("closeReceive").Err }, expect.Error(
|
||||
stub.CheckArg(k.Stub, "key", key, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) expectCheckContainer(expect *stub.Call, z *container.Container) error {
|
||||
k.Helper()
|
||||
err := expect.Error(
|
||||
stub.CheckArgReflect(k.Stub, "params", &z.Params, 0))
|
||||
if err != nil {
|
||||
k.Errorf("params:\n%s\n%s", mustMarshal(&z.Params), mustMarshal(expect.Args[0]))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (k *kstub) containerStart(z *container.Container) error {
|
||||
k.Helper()
|
||||
return k.expectCheckContainer(k.Expects("containerStart"), z)
|
||||
}
|
||||
func (k *kstub) containerServe(z *container.Container) error {
|
||||
k.Helper()
|
||||
return k.expectCheckContainer(k.Expects("containerServe"), z)
|
||||
}
|
||||
func (k *kstub) containerWait(z *container.Container) error {
|
||||
k.Helper()
|
||||
return k.expectCheckContainer(k.Expects("containerWait"), z)
|
||||
}
|
||||
|
||||
func (k *kstub) seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error {
|
||||
k.Helper()
|
||||
return k.Expects("seccompLoad").Error(
|
||||
stub.CheckArgReflect(k.Stub, "rules", rules, 0),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) cmdOutput(cmd *exec.Cmd) ([]byte, error) {
|
||||
k.Helper()
|
||||
expect := k.Expects("cmdOutput")
|
||||
@@ -363,6 +426,16 @@ func (k *kstub) cmdOutput(cmd *exec.Cmd) ([]byte, error) {
|
||||
stub.CheckArg(k.Stub, "cmd.Dir", cmd.Dir, 3))
|
||||
}
|
||||
|
||||
func (k *kstub) notifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) {
|
||||
k.Helper()
|
||||
if k.Expects("notifyContext").Error(
|
||||
stub.CheckArgReflect(k.Stub, "parent", parent, 0),
|
||||
stub.CheckArgReflect(k.Stub, "signals", signals, 1)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
return k.Context(), func() { k.Helper(); k.Expects("notifyContextStop") }
|
||||
}
|
||||
|
||||
func (k *kstub) mustHsuPath() *check.Absolute {
|
||||
k.Helper()
|
||||
return k.Expects("mustHsuPath").Ret.(*check.Absolute)
|
||||
@@ -374,8 +447,51 @@ func (k *kstub) dbusAddress() (session, system string) {
|
||||
return ret[0], ret[1]
|
||||
}
|
||||
|
||||
func (k *kstub) GetLogger() *log.Logger { panic("unreachable") }
|
||||
// stubTrackReader embeds kstub but switches the underlying [stub.Stub] index to sub on its first Read.
|
||||
// The resulting kstub does not share any state with the instance passed to the instrumented goroutine.
|
||||
// Therefore, any method making use of such must not be called.
|
||||
type stubTrackReader struct {
|
||||
sub int
|
||||
subOnce sync.Once
|
||||
|
||||
*kstub
|
||||
}
|
||||
|
||||
func (r *stubTrackReader) Read(p []byte) (n int, err error) {
|
||||
r.subOnce.Do(func() {
|
||||
subVal := reflect.ValueOf(r.kstub.Stub).Elem().FieldByName("sub")
|
||||
r.kstub = &kstub{panicDispatcher{}, reflect.
|
||||
NewAt(subVal.Type(), unsafe.Pointer(subVal.UnsafeAddr())).Elem().
|
||||
Interface().([]*stub.Stub[syscallDispatcher])[r.sub]}
|
||||
})
|
||||
|
||||
return r.kstub.Read(p)
|
||||
}
|
||||
|
||||
func (k *kstub) setupContSignal(pid int) (io.ReadCloser, func(), error) {
|
||||
k.Helper()
|
||||
expect := k.Expects("setupContSignal")
|
||||
return &stubTrackReader{sub: expect.Ret.(int), kstub: k}, func() { k.Expects("wKeepAlive") }, expect.Error(
|
||||
stub.CheckArg(k.Stub, "pid", pid, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) getMsg() message.Msg { k.Helper(); k.Expects("getMsg"); return k }
|
||||
|
||||
func (k *kstub) Close() error { k.Helper(); return k.Expects("rcClose").Err }
|
||||
func (k *kstub) Read(p []byte) (n int, err error) {
|
||||
k.Helper()
|
||||
expect := k.Expects("rcRead")
|
||||
|
||||
// special case to terminate exit outcomes goroutine
|
||||
// to proceed with further testing of the entrypoint
|
||||
if expect.Ret == nil {
|
||||
panic(stub.PanicExit)
|
||||
}
|
||||
|
||||
return copy(p, expect.Ret.([]byte)), expect.Err
|
||||
}
|
||||
|
||||
func (k *kstub) GetLogger() *log.Logger { k.Helper(); return k.Expects("getLogger").Ret.(*log.Logger) }
|
||||
func (k *kstub) IsVerbose() bool { k.Helper(); return k.Expects("isVerbose").Ret.(bool) }
|
||||
func (k *kstub) SwapVerbose(verbose bool) bool {
|
||||
k.Helper()
|
||||
@@ -492,20 +608,38 @@ func (panicMsgContext) Value(any) any { panic("unreachable") }
|
||||
// This type is meant to be embedded in partial syscallDispatcher implementations.
|
||||
type panicDispatcher struct{}
|
||||
|
||||
func (panicDispatcher) new(func(k syscallDispatcher)) { panic("unreachable") }
|
||||
func (panicDispatcher) new(func(k syscallDispatcher, msg message.Msg)) { panic("unreachable") }
|
||||
func (panicDispatcher) getpid() int { panic("unreachable") }
|
||||
func (panicDispatcher) getuid() int { panic("unreachable") }
|
||||
func (panicDispatcher) getgid() int { panic("unreachable") }
|
||||
func (panicDispatcher) lookupEnv(string) (string, bool) { panic("unreachable") }
|
||||
func (panicDispatcher) pipe() (*os.File, *os.File, error) { panic("unreachable") }
|
||||
func (panicDispatcher) stat(string) (os.FileInfo, error) { panic("unreachable") }
|
||||
func (panicDispatcher) open(string) (osFile, error) { panic("unreachable") }
|
||||
func (panicDispatcher) readdir(string) ([]os.DirEntry, error) { panic("unreachable") }
|
||||
func (panicDispatcher) tempdir() string { panic("unreachable") }
|
||||
func (panicDispatcher) exit(int) { panic("unreachable") }
|
||||
func (panicDispatcher) evalSymlinks(string) (string, error) { panic("unreachable") }
|
||||
func (panicDispatcher) prctl(uintptr, uintptr, uintptr) error { panic("unreachable") }
|
||||
func (panicDispatcher) lookupGroupId(string) (string, error) { panic("unreachable") }
|
||||
func (panicDispatcher) cmdOutput(*exec.Cmd) ([]byte, error) { panic("unreachable") }
|
||||
func (panicDispatcher) overflowUid(message.Msg) int { panic("unreachable") }
|
||||
func (panicDispatcher) overflowGid(message.Msg) int { panic("unreachable") }
|
||||
func (panicDispatcher) setDumpable(uintptr) error { panic("unreachable") }
|
||||
func (panicDispatcher) receive(string, any, *uintptr) (func() error, error) { panic("unreachable") }
|
||||
func (panicDispatcher) containerStart(*container.Container) error { panic("unreachable") }
|
||||
func (panicDispatcher) containerServe(*container.Container) error { panic("unreachable") }
|
||||
func (panicDispatcher) containerWait(*container.Container) error { panic("unreachable") }
|
||||
func (panicDispatcher) mustHsuPath() *check.Absolute { panic("unreachable") }
|
||||
func (panicDispatcher) dbusAddress() (string, string) { panic("unreachable") }
|
||||
func (panicDispatcher) setupContSignal(int) (io.ReadCloser, func(), error) { panic("unreachable") }
|
||||
func (panicDispatcher) getMsg() message.Msg { panic("unreachable") }
|
||||
func (panicDispatcher) fatal(...any) { panic("unreachable") }
|
||||
func (panicDispatcher) fatalf(string, ...any) { panic("unreachable") }
|
||||
|
||||
func (panicDispatcher) notifyContext(context.Context, ...os.Signal) (context.Context, context.CancelFunc) {
|
||||
panic("unreachable")
|
||||
}
|
||||
func (panicDispatcher) seccompLoad([]seccomp.NativeRule, seccomp.ExportFlag) error {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ type Hsu struct {
|
||||
id int
|
||||
|
||||
kOnce sync.Once
|
||||
|
||||
// msg is not populated
|
||||
k syscallDispatcher
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,13 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/message"
|
||||
@@ -23,6 +22,20 @@ import (
|
||||
//#include "shim-signal.h"
|
||||
import "C"
|
||||
|
||||
// setupContSignal sets up the SIGCONT signal handler for the cross-uid shim exit hack.
|
||||
// The signal handler is implemented in C, signals can be processed by reading from the returned reader.
|
||||
// The returned function must be called after all signal processing concludes.
|
||||
func setupContSignal(pid int) (io.ReadCloser, func(), error) {
|
||||
if r, w, err := os.Pipe(); err != nil {
|
||||
return nil, nil, err
|
||||
} else if _, err = C.hakurei_shim_setup_cont_signal(C.pid_t(pid), C.int(w.Fd())); err != nil {
|
||||
_, _ = r.Close(), w.Close()
|
||||
return nil, nil, err
|
||||
} else {
|
||||
return r, func() { runtime.KeepAlive(w) }, nil
|
||||
}
|
||||
}
|
||||
|
||||
// shimEnv is the name of the environment variable storing decimal representation of
|
||||
// setup pipe fd for [container.Receive].
|
||||
const shimEnv = "HAKUREI_SHIM"
|
||||
@@ -46,76 +59,102 @@ type shimParams struct {
|
||||
// valid checks shimParams to be safe for use.
|
||||
func (p *shimParams) valid() bool { return p != nil && p.PrivPID > 0 }
|
||||
|
||||
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
|
||||
func ShimMain() {
|
||||
log.SetPrefix("shim: ")
|
||||
log.SetFlags(0)
|
||||
msg := message.NewMsg(log.Default())
|
||||
// shimName is the prefix used by log.std in the shim process.
|
||||
const shimName = "shim"
|
||||
|
||||
if err := container.SetDumpable(container.SUID_DUMP_DISABLE); err != nil {
|
||||
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
|
||||
// Shim is called by the main function of the shim process and runs as the unconstrained target user.
|
||||
// Shim does not return.
|
||||
func Shim(msg message.Msg) {
|
||||
if msg == nil {
|
||||
msg = message.NewMsg(log.Default())
|
||||
}
|
||||
shimEntrypoint(direct{msg})
|
||||
}
|
||||
|
||||
func shimEntrypoint(k syscallDispatcher) {
|
||||
msg := k.getMsg()
|
||||
if msg == nil {
|
||||
panic("attempting to call shimEntrypoint with nil msg")
|
||||
} else if logger := msg.GetLogger(); logger != nil {
|
||||
logger.SetPrefix(shimName + ": ")
|
||||
logger.SetFlags(0)
|
||||
}
|
||||
|
||||
if err := k.setDumpable(container.SUID_DUMP_DISABLE); err != nil {
|
||||
k.fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
|
||||
}
|
||||
|
||||
var (
|
||||
state outcomeState
|
||||
closeSetup func() error
|
||||
)
|
||||
if f, err := container.Receive(shimEnv, &state, nil); err != nil {
|
||||
if f, err := k.receive(shimEnv, &state, nil); err != nil {
|
||||
if errors.Is(err, syscall.EBADF) {
|
||||
log.Fatal("invalid config descriptor")
|
||||
k.fatal("invalid config descriptor")
|
||||
}
|
||||
if errors.Is(err, container.ErrReceiveEnv) {
|
||||
log.Fatal(shimEnv + " not set")
|
||||
k.fatal(shimEnv + " not set")
|
||||
}
|
||||
|
||||
log.Fatalf("cannot receive shim setup params: %v", err)
|
||||
k.fatalf("cannot receive shim setup params: %v", err)
|
||||
} else {
|
||||
msg.SwapVerbose(state.Shim.Verbose)
|
||||
closeSetup = f
|
||||
|
||||
if err = state.populateLocal(direct{}, msg); err != nil {
|
||||
if err = state.populateLocal(k, msg); err != nil {
|
||||
if m, ok := message.GetMessage(err); ok {
|
||||
log.Fatal(m)
|
||||
k.fatal(m)
|
||||
} else {
|
||||
log.Fatalf("cannot populate local state: %v", err)
|
||||
k.fatalf("cannot populate local state: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the Go runtime does not expose siginfo_t so SIGCONT is handled in C to check si_pid
|
||||
var signalPipe io.ReadCloser
|
||||
if r, w, err := os.Pipe(); err != nil {
|
||||
log.Fatalf("cannot pipe: %v", err)
|
||||
} else if _, err = C.hakurei_shim_setup_cont_signal(C.pid_t(state.Shim.PrivPID), C.int(w.Fd())); err != nil {
|
||||
log.Fatalf("cannot install SIGCONT handler: %v", err)
|
||||
if r, wKeepAlive, err := k.setupContSignal(state.Shim.PrivPID); err != nil {
|
||||
switch {
|
||||
case errors.As(err, new(*os.SyscallError)): // returned by os.Pipe
|
||||
k.fatal(err.Error())
|
||||
return
|
||||
|
||||
case errors.As(err, new(syscall.Errno)): // returned by hakurei_shim_setup_cont_signal
|
||||
k.fatalf("cannot install SIGCONT handler: %v", err)
|
||||
return
|
||||
|
||||
default: // unreachable
|
||||
k.fatalf("cannot set up exit request: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
defer runtime.KeepAlive(w)
|
||||
defer wKeepAlive()
|
||||
signalPipe = r
|
||||
}
|
||||
|
||||
// pdeath_signal delivery is checked as if the dying process called kill(2), see kernel/exit.c
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, uintptr(syscall.SIGCONT), 0); errno != 0 {
|
||||
log.Fatalf("cannot set parent-death signal: %v", errno)
|
||||
if err := k.prctl(syscall.PR_SET_PDEATHSIG, uintptr(syscall.SIGCONT), 0); err != nil {
|
||||
k.fatalf("cannot set parent-death signal: %v", err)
|
||||
}
|
||||
|
||||
stateParams := state.newParams()
|
||||
for _, op := range state.Shim.Ops {
|
||||
if err := op.toContainer(stateParams); err != nil {
|
||||
if m, ok := message.GetMessage(err); ok {
|
||||
log.Fatal(m)
|
||||
k.fatal(m)
|
||||
} else {
|
||||
log.Fatalf("cannot create container state: %v", err)
|
||||
k.fatalf("cannot create container state: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// shim exit outcomes
|
||||
var cancelContainer atomic.Pointer[context.CancelFunc]
|
||||
go func() {
|
||||
k.new(func(k syscallDispatcher, msg message.Msg) {
|
||||
buf := make([]byte, 1)
|
||||
for {
|
||||
if _, err := signalPipe.Read(buf); err != nil {
|
||||
log.Fatalf("cannot read from signal pipe: %v", err)
|
||||
k.fatalf("cannot read from signal pipe: %v", err)
|
||||
}
|
||||
|
||||
switch buf[0] {
|
||||
@@ -128,37 +167,37 @@ func ShimMain() {
|
||||
|
||||
// setup has not completed, terminate immediately
|
||||
msg.Resume()
|
||||
os.Exit(hst.ExitRequest)
|
||||
k.exit(hst.ExitRequest)
|
||||
return
|
||||
|
||||
case 1: // got SIGCONT after adoption: monitor died before delivering signal
|
||||
msg.BeforeExit()
|
||||
os.Exit(hst.ExitOrphan)
|
||||
k.exit(hst.ExitOrphan)
|
||||
return
|
||||
|
||||
case 2: // unreachable
|
||||
log.Println("sa_sigaction got invalid siginfo")
|
||||
msg.Verbose("sa_sigaction got invalid siginfo")
|
||||
|
||||
case 3: // got SIGCONT from unexpected process: hopefully the terminal driver
|
||||
log.Println("got SIGCONT from unexpected process")
|
||||
msg.Verbose("got SIGCONT from unexpected process")
|
||||
|
||||
default: // unreachable
|
||||
log.Fatalf("got invalid message %d from signal handler", buf[0])
|
||||
k.fatalf("got invalid message %d from signal handler", buf[0])
|
||||
}
|
||||
}
|
||||
}()
|
||||
})
|
||||
|
||||
if stateParams.params.Ops == nil {
|
||||
log.Fatal("invalid container params")
|
||||
k.fatal("invalid container params")
|
||||
}
|
||||
|
||||
// close setup socket
|
||||
if err := closeSetup(); err != nil {
|
||||
log.Printf("cannot close setup pipe: %v", err)
|
||||
msg.Verbosef("cannot close setup pipe: %v", err)
|
||||
// not fatal
|
||||
}
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
ctx, stop := k.notifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
cancelContainer.Store(&stop)
|
||||
z := container.New(ctx, msg)
|
||||
z.Params = *stateParams.params
|
||||
@@ -167,30 +206,30 @@ func ShimMain() {
|
||||
// bounds and default enforced in finalise.go
|
||||
z.WaitDelay = state.Shim.WaitDelay
|
||||
|
||||
if err := z.Start(); err != nil {
|
||||
if err := k.containerStart(z); err != nil {
|
||||
printMessageError("cannot start container:", err)
|
||||
os.Exit(hst.ExitFailure)
|
||||
k.exit(hst.ExitFailure)
|
||||
}
|
||||
if err := z.Serve(); err != nil {
|
||||
if err := k.containerServe(z); err != nil {
|
||||
printMessageError("cannot configure container:", err)
|
||||
}
|
||||
|
||||
if err := seccomp.Load(
|
||||
seccomp.Preset(bits.PresetStrict, seccomp.AllowMultiarch),
|
||||
if err := k.seccompLoad(
|
||||
seccomp.Preset(comp.PresetStrict, seccomp.AllowMultiarch),
|
||||
seccomp.AllowMultiarch,
|
||||
); err != nil {
|
||||
log.Fatalf("cannot load syscall filter: %v", err)
|
||||
k.fatalf("cannot load syscall filter: %v", err)
|
||||
}
|
||||
|
||||
if err := z.Wait(); err != nil {
|
||||
if err := k.containerWait(z); err != nil {
|
||||
var exitError *exec.ExitError
|
||||
if !errors.As(err, &exitError) {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
os.Exit(hst.ExitCancel)
|
||||
k.exit(hst.ExitCancel)
|
||||
}
|
||||
log.Printf("wait: %v", err)
|
||||
os.Exit(127)
|
||||
msg.Verbosef("cannot wait: %v", err)
|
||||
k.exit(127)
|
||||
}
|
||||
os.Exit(exitError.ExitCode())
|
||||
k.exit(exitError.ExitCode())
|
||||
}
|
||||
}
|
||||
|
||||
155
internal/app/shim_test.go
Normal file
155
internal/app/shim_test.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
|
||||
func TestShimEntrypoint(t *testing.T) {
|
||||
t.Parallel()
|
||||
shimPreset := seccomp.Preset(comp.PresetStrict, seccomp.AllowMultiarch)
|
||||
templateParams := &container.Params{
|
||||
Dir: m("/data/data/org.chromium.Chromium"),
|
||||
Env: []string{
|
||||
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus",
|
||||
"DBUS_SYSTEM_BUS_ADDRESS=unix:path=/var/run/dbus/system_bus_socket",
|
||||
"GOOGLE_API_KEY=AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
||||
"GOOGLE_DEFAULT_CLIENT_ID=77185425430.apps.googleusercontent.com",
|
||||
"GOOGLE_DEFAULT_CLIENT_SECRET=OTJgUOQcT7lO7GsGZq2G4IlT",
|
||||
"HOME=/data/data/org.chromium.Chromium",
|
||||
"PULSE_COOKIE=/.hakurei/pulse-cookie",
|
||||
"PULSE_SERVER=unix:/run/user/1000/pulse/native",
|
||||
"SHELL=/run/current-system/sw/bin/zsh",
|
||||
"TERM=xterm-256color",
|
||||
"USER=chronos",
|
||||
"WAYLAND_DISPLAY=wayland-0",
|
||||
"XDG_RUNTIME_DIR=/run/user/1000",
|
||||
"XDG_SESSION_CLASS=user",
|
||||
"XDG_SESSION_TYPE=wayland",
|
||||
},
|
||||
|
||||
// spParamsOp
|
||||
Hostname: "localhost",
|
||||
RetainSession: true,
|
||||
HostNet: true,
|
||||
HostAbstract: true,
|
||||
ForwardCancel: true,
|
||||
Path: m("/run/current-system/sw/bin/chromium"),
|
||||
Args: []string{
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland",
|
||||
},
|
||||
SeccompFlags: seccomp.AllowMultiarch,
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
|
||||
Ops: new(container.Ops).
|
||||
// resolveRoot
|
||||
Root(m("/var/lib/hakurei/base/org.debian"), comp.BindWritable).
|
||||
// spParamsOp
|
||||
Proc(fhs.AbsProc).
|
||||
Tmpfs(hst.AbsPrivateTmp, 1<<12, 0755).
|
||||
Bind(fhs.AbsDev, fhs.AbsDev, comp.BindWritable|comp.BindDevice).
|
||||
Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777).
|
||||
|
||||
// spRuntimeOp
|
||||
Tmpfs(fhs.AbsRunUser, 1<<12, 0755).
|
||||
Bind(m("/tmp/hakurei.10/runtime/9999"), m("/run/user/1000"), comp.BindWritable).
|
||||
|
||||
// spTmpdirOp
|
||||
Bind(m("/tmp/hakurei.10/tmpdir/9999"), fhs.AbsTmp, comp.BindWritable).
|
||||
|
||||
// spAccountOp
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
|
||||
// spWaylandOp
|
||||
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1000/wayland-0"), 0).
|
||||
|
||||
// spPulseOp
|
||||
Bind(m("/run/user/1000/hakurei/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pulse"), m("/run/user/1000/pulse/native"), 0).
|
||||
Place(m("/.hakurei/pulse-cookie"), bytes.Repeat([]byte{0}, pulseCookieSizeMax)).
|
||||
|
||||
// spDBusOp
|
||||
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bus"), m("/run/user/1000/bus"), 0).
|
||||
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket"), m("/var/run/dbus/system_bus_socket"), 0).
|
||||
|
||||
// spFilesystemOp
|
||||
Etc(fhs.AbsEtc, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").
|
||||
Tmpfs(fhs.AbsTmp, 0, 0755).
|
||||
Overlay(m("/nix/store"),
|
||||
fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/upper"),
|
||||
fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/work"),
|
||||
fhs.AbsVarLib.Append("hakurei/base/org.nixos/ro-store")).
|
||||
Link(m("/run/current-system"), "/run/current-system", true).
|
||||
Link(m("/run/opengl-driver"), "/run/opengl-driver", true).
|
||||
Bind(fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"),
|
||||
m("/data/data/org.chromium.Chromium"),
|
||||
comp.BindWritable|comp.BindEnsure).
|
||||
Bind(fhs.AbsDev.Append("dri"), fhs.AbsDev.Append("dri"),
|
||||
comp.BindOptional|comp.BindWritable|comp.BindDevice).
|
||||
Remount(fhs.AbsRoot, syscall.MS_RDONLY),
|
||||
}
|
||||
|
||||
checkSimple(t, "shimEntrypoint", []simpleTestCase{
|
||||
{"success", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{
|
||||
call("getMsg", stub.ExpectArgs{}, nil, nil),
|
||||
call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil),
|
||||
call("receive", stub.ExpectArgs{"HAKUREI_SHIM", outcomeState{
|
||||
Shim: &shimParams{PrivPID: 0xbad, WaitDelay: 0xf, Verbose: true, Ops: []outcomeOp{
|
||||
&spParamsOp{"xterm-256color", true},
|
||||
&spRuntimeOp{sessionTypeWayland},
|
||||
spTmpdirOp{},
|
||||
spAccountOp{},
|
||||
&spWaylandOp{},
|
||||
&spPulseOp{(*[256]byte)(bytes.Repeat([]byte{0}, pulseCookieSizeMax)), pulseCookieSizeMax},
|
||||
&spDBusOp{true},
|
||||
&spFilesystemOp{},
|
||||
}},
|
||||
|
||||
ID: &checkExpectInstanceId,
|
||||
Identity: hst.IdentityMax,
|
||||
UserID: 10,
|
||||
Container: hst.Template().Container,
|
||||
Mapuid: 1000,
|
||||
Mapgid: 100,
|
||||
EnvPaths: &EnvPaths{TempDir: fhs.AbsTmp, RuntimePath: fhs.AbsRunUser.Append("1000")},
|
||||
}, nil}, nil, nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil),
|
||||
call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil),
|
||||
call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil),
|
||||
call("New", stub.ExpectArgs{}, nil, nil),
|
||||
call("closeReceive", stub.ExpectArgs{}, nil, nil),
|
||||
call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, nil, nil),
|
||||
call("containerStart", stub.ExpectArgs{templateParams}, nil, nil),
|
||||
call("containerServe", stub.ExpectArgs{templateParams}, nil, nil),
|
||||
call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, nil),
|
||||
call("containerWait", stub.ExpectArgs{templateParams}, nil, nil),
|
||||
|
||||
// deferred
|
||||
call("wKeepAlive", stub.ExpectArgs{}, nil, nil),
|
||||
}, Tracks: []stub.Expect{{Calls: []stub.Call{
|
||||
call("rcRead", stub.ExpectArgs{}, []byte{2}, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"sa_sigaction got invalid siginfo"}}, nil, nil),
|
||||
call("rcRead", stub.ExpectArgs{}, []byte{3}, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"got SIGCONT from unexpected process"}}, nil, nil),
|
||||
call("rcRead", stub.ExpectArgs{}, nil, nil), // stub terminates this goroutine
|
||||
}}}}, nil},
|
||||
})
|
||||
}
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/hst"
|
||||
@@ -75,16 +75,16 @@ func (s *spParamsOp) toContainer(state *outcomeStateParams) error {
|
||||
}
|
||||
|
||||
if state.Container.Flags&hst.FSeccompCompat == 0 {
|
||||
state.params.SeccompPresets |= bits.PresetExt
|
||||
state.params.SeccompPresets |= comp.PresetExt
|
||||
}
|
||||
if state.Container.Flags&hst.FDevel == 0 {
|
||||
state.params.SeccompPresets |= bits.PresetDenyDevel
|
||||
state.params.SeccompPresets |= comp.PresetDenyDevel
|
||||
}
|
||||
if state.Container.Flags&hst.FUserns == 0 {
|
||||
state.params.SeccompPresets |= bits.PresetDenyNS
|
||||
state.params.SeccompPresets |= comp.PresetDenyNS
|
||||
}
|
||||
if state.Container.Flags&hst.FTty == 0 {
|
||||
state.params.SeccompPresets |= bits.PresetDenyTTY
|
||||
state.params.SeccompPresets |= comp.PresetDenyTTY
|
||||
}
|
||||
|
||||
if state.Container.Flags&hst.FMapRealUID != 0 {
|
||||
@@ -112,7 +112,7 @@ func (s *spParamsOp) toContainer(state *outcomeStateParams) error {
|
||||
if state.Container.Flags&hst.FDevice == 0 {
|
||||
state.params.DevWritable(fhs.AbsDev, true)
|
||||
} else {
|
||||
state.params.Bind(fhs.AbsDev, fhs.AbsDev, bits.BindWritable|bits.BindDevice)
|
||||
state.params.Bind(fhs.AbsDev, fhs.AbsDev, comp.BindWritable|comp.BindDevice)
|
||||
}
|
||||
// /dev is mounted readonly later on, this prevents /dev/shm from going readonly with it
|
||||
state.params.Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777)
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/stub"
|
||||
@@ -65,11 +65,11 @@ func TestSpParamsOp(t *testing.T) {
|
||||
HostAbstract: true,
|
||||
Path: config.Container.Path,
|
||||
Args: []string{config.Container.Path.String()},
|
||||
SeccompPresets: bits.PresetExt | bits.PresetDenyDevel | bits.PresetDenyNS | bits.PresetDenyTTY,
|
||||
SeccompPresets: comp.PresetExt | comp.PresetDenyDevel | comp.PresetDenyNS | comp.PresetDenyTTY,
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
Ops: new(container.Ops).
|
||||
Root(m("/var/lib/hakurei/base/org.debian"), bits.BindWritable).
|
||||
Root(m("/var/lib/hakurei/base/org.debian"), comp.BindWritable).
|
||||
Proc(fhs.AbsProc).Tmpfs(hst.AbsPrivateTmp, 1<<12, 0755).
|
||||
DevWritable(fhs.AbsDev, true).
|
||||
Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777),
|
||||
@@ -107,9 +107,9 @@ func TestSpParamsOp(t *testing.T) {
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
Ops: new(container.Ops).
|
||||
Root(m("/var/lib/hakurei/base/org.debian"), bits.BindWritable).
|
||||
Root(m("/var/lib/hakurei/base/org.debian"), comp.BindWritable).
|
||||
Proc(fhs.AbsProc).Tmpfs(hst.AbsPrivateTmp, 1<<12, 0755).
|
||||
Bind(fhs.AbsDev, fhs.AbsDev, bits.BindWritable|bits.BindDevice).
|
||||
Bind(fhs.AbsDev, fhs.AbsDev, comp.BindWritable|comp.BindDevice).
|
||||
Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777),
|
||||
}, paramsWantEnv(config, map[string]string{
|
||||
"TERM": "xterm",
|
||||
@@ -425,8 +425,8 @@ func TestSpFilesystemOp(t *testing.T) {
|
||||
Bind(
|
||||
fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"),
|
||||
check.MustAbs("/data/data/org.chromium.Chromium"),
|
||||
bits.BindWritable|bits.BindEnsure).
|
||||
Bind(fhs.AbsDev.Append("dri"), fhs.AbsDev.Append("dri"), bits.BindDevice|bits.BindWritable|bits.BindOptional).
|
||||
comp.BindWritable|comp.BindEnsure).
|
||||
Bind(fhs.AbsDev.Append("dri"), fhs.AbsDev.Append("dri"), comp.BindDevice|comp.BindWritable|comp.BindOptional).
|
||||
Remount(fhs.AbsRoot, syscall.MS_RDONLY),
|
||||
}, nil, nil},
|
||||
})
|
||||
|
||||
@@ -3,8 +3,8 @@ package app
|
||||
import (
|
||||
"encoding/gob"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/system"
|
||||
@@ -111,7 +111,7 @@ func (s *spRuntimeOp) toContainer(state *outcomeStateParams) error {
|
||||
state.params.Tmpfs(fhs.AbsRunUser, 1<<12, 0755)
|
||||
if state.Container.Flags&hst.FShareRuntime != 0 {
|
||||
_, runtimeDirInst := s.commonPaths(state.outcomeState)
|
||||
state.params.Bind(runtimeDirInst, state.runtimeDir, bits.BindWritable)
|
||||
state.params.Bind(runtimeDirInst, state.runtimeDir, comp.BindWritable)
|
||||
} else {
|
||||
state.params.Mkdir(state.runtimeDir, 0700)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/hst"
|
||||
@@ -41,7 +41,7 @@ func TestSpRuntimeOp(t *testing.T) {
|
||||
}, &container.Params{
|
||||
Ops: new(container.Ops).
|
||||
Tmpfs(fhs.AbsRunUser, 1<<12, 0755).
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), m("/run/user/1000"), bits.BindWritable),
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), m("/run/user/1000"), comp.BindWritable),
|
||||
}, paramsWantEnv(config, map[string]string{
|
||||
"XDG_RUNTIME_DIR": "/run/user/1000",
|
||||
"XDG_SESSION_CLASS": "user",
|
||||
@@ -68,7 +68,7 @@ func TestSpRuntimeOp(t *testing.T) {
|
||||
}, &container.Params{
|
||||
Ops: new(container.Ops).
|
||||
Tmpfs(fhs.AbsRunUser, 1<<12, 0755).
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), m("/run/user/1000"), bits.BindWritable),
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), m("/run/user/1000"), comp.BindWritable),
|
||||
}, paramsWantEnv(config, map[string]string{
|
||||
"XDG_RUNTIME_DIR": "/run/user/1000",
|
||||
"XDG_SESSION_CLASS": "user",
|
||||
@@ -95,7 +95,7 @@ func TestSpRuntimeOp(t *testing.T) {
|
||||
}, &container.Params{
|
||||
Ops: new(container.Ops).
|
||||
Tmpfs(fhs.AbsRunUser, 1<<12, 0755).
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), m("/run/user/1000"), bits.BindWritable),
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), m("/run/user/1000"), comp.BindWritable),
|
||||
}, paramsWantEnv(config, map[string]string{
|
||||
"XDG_RUNTIME_DIR": "/run/user/1000",
|
||||
"XDG_SESSION_CLASS": "user",
|
||||
@@ -118,7 +118,7 @@ func TestSpRuntimeOp(t *testing.T) {
|
||||
}, &container.Params{
|
||||
Ops: new(container.Ops).
|
||||
Tmpfs(fhs.AbsRunUser, 1<<12, 0755).
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), m("/run/user/1000"), bits.BindWritable),
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), m("/run/user/1000"), comp.BindWritable),
|
||||
}, paramsWantEnv(config, map[string]string{
|
||||
"XDG_RUNTIME_DIR": "/run/user/1000",
|
||||
"XDG_SESSION_CLASS": "user",
|
||||
|
||||
@@ -3,8 +3,8 @@ package app
|
||||
import (
|
||||
"encoding/gob"
|
||||
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/system"
|
||||
@@ -30,7 +30,7 @@ func (s spTmpdirOp) toSystem(state *outcomeStateSys) error {
|
||||
func (s spTmpdirOp) toContainer(state *outcomeStateParams) error {
|
||||
if state.Container.Flags&hst.FShareTmpdir != 0 {
|
||||
_, tmpdirInst := s.commonPaths(state.outcomeState)
|
||||
state.params.Bind(tmpdirInst, fhs.AbsTmp, bits.BindWritable)
|
||||
state.params.Bind(tmpdirInst, fhs.AbsTmp, comp.BindWritable)
|
||||
} else {
|
||||
state.params.Tmpfs(fhs.AbsTmp, 0, 01777)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/hst"
|
||||
@@ -28,7 +28,7 @@ func TestSpTmpdirOp(t *testing.T) {
|
||||
// this op configures the container state and does not make calls during toContainer
|
||||
}, &container.Params{
|
||||
Ops: new(container.Ops).
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/tmpdir/9"), fhs.AbsTmp, bits.BindWritable),
|
||||
Bind(m("/proc/nonexistent/tmp/hakurei.0/tmpdir/9"), fhs.AbsTmp, comp.BindWritable),
|
||||
}, nil, nil},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package internal
|
||||
|
||||
const compPoison = "INVALIDINVALIDINVALIDINVALIDINVALID"
|
||||
|
||||
var (
|
||||
version = compPoison
|
||||
)
|
||||
|
||||
// checkComp validates string value set at compile time.
|
||||
func checkComp(s string) (string, bool) { return s, s != compPoison && s != "" }
|
||||
|
||||
func Version() string {
|
||||
if v, ok := checkComp(version); ok {
|
||||
return v
|
||||
}
|
||||
return "impure"
|
||||
}
|
||||
@@ -6,20 +6,20 @@ import (
|
||||
"hakurei.app/container/check"
|
||||
)
|
||||
|
||||
var (
|
||||
hmain = compPoison
|
||||
hsu = compPoison
|
||||
)
|
||||
// Absolute paths to the Hakurei installation.
|
||||
//
|
||||
// These are set by the linker.
|
||||
var hakureiPath, hsuPath string
|
||||
|
||||
// MustHakureiPath returns the absolute path to hakurei, configured at compile time.
|
||||
func MustHakureiPath() *check.Absolute { return mustCheckPath(log.Fatal, "hakurei", hmain) }
|
||||
// MustHakureiPath returns the [check.Absolute] path to hakurei.
|
||||
func MustHakureiPath() *check.Absolute { return mustCheckPath(log.Fatal, "hakurei", hakureiPath) }
|
||||
|
||||
// MustHsuPath returns the absolute path to hakurei, configured at compile time.
|
||||
func MustHsuPath() *check.Absolute { return mustCheckPath(log.Fatal, "hsu", hsu) }
|
||||
// MustHsuPath returns the [check.Absolute] to hsu.
|
||||
func MustHsuPath() *check.Absolute { return mustCheckPath(log.Fatal, "hsu", hsuPath) }
|
||||
|
||||
// mustCheckPath checks a pathname against compPoison, then [container.NewAbs], calling fatal if either step fails.
|
||||
// mustCheckPath checks a pathname to not be zero, then [check.NewAbs], calling fatal if either step fails.
|
||||
func mustCheckPath(fatal func(v ...any), name, pathname string) *check.Absolute {
|
||||
if pathname != compPoison && pathname != "" {
|
||||
if pathname != "" {
|
||||
if a, err := check.NewAbs(pathname); err != nil {
|
||||
fatal(err.Error())
|
||||
return nil // unreachable
|
||||
|
||||
@@ -15,7 +15,6 @@ func TestMustCheckPath(t *testing.T) {
|
||||
pathname string
|
||||
wantFatal string
|
||||
}{
|
||||
{"poison", compPoison, "invalid test path, this program is compiled incorrectly"},
|
||||
{"zero", "", "invalid test path, this program is compiled incorrectly"},
|
||||
{"not absolute", "\x00", `path "\x00" is not absolute`},
|
||||
{"success", "/proc/nonexistent", ""},
|
||||
|
||||
19
internal/version.go
Normal file
19
internal/version.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package internal
|
||||
|
||||
// FallbackVersion is returned when a version string was not set by the linker.
|
||||
const FallbackVersion = "dirty"
|
||||
|
||||
// buildVersion is the Hakurei tree's version string at build time.
|
||||
//
|
||||
// This is set by the linker.
|
||||
var buildVersion string
|
||||
|
||||
// Version returns the Hakurei tree's version string.
|
||||
// It is either the value of the constant [FallbackVersion] or,
|
||||
// when possible, a release tag like "v1.0.0".
|
||||
func Version() string {
|
||||
if buildVersion != "" {
|
||||
return buildVersion
|
||||
}
|
||||
return FallbackVersion
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"time"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/message"
|
||||
@@ -40,7 +40,7 @@ func Exec(ctx context.Context, msg message.Msg, p string) ([]*Entry, error) {
|
||||
z := container.NewCommand(c, msg, toolPath, lddName, p)
|
||||
z.Hostname = "hakurei-" + lddName
|
||||
z.SeccompFlags |= seccomp.AllowMultiarch
|
||||
z.SeccompPresets |= bits.PresetStrict
|
||||
z.SeccompPresets |= comp.PresetStrict
|
||||
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
|
||||
z.Stdout = stdout
|
||||
z.Stderr = stderr
|
||||
|
||||
@@ -75,9 +75,9 @@ buildGoModule rec {
|
||||
]
|
||||
)
|
||||
{
|
||||
version = "v${version}";
|
||||
hmain = "${placeholder "out"}/libexec/hakurei";
|
||||
hsu = "/run/wrappers/bin/hsu";
|
||||
buildVersion = "v${version}";
|
||||
hakureiPath = "${placeholder "out"}/libexec/hakurei";
|
||||
hsuPath = "/run/wrappers/bin/hsu";
|
||||
};
|
||||
|
||||
# nix build environment does not allow acls
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/comp"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/helper"
|
||||
"hakurei.app/ldd"
|
||||
@@ -65,7 +65,7 @@ func (p *Proxy) Start() error {
|
||||
p.final, true,
|
||||
argF, func(z *container.Container) {
|
||||
z.SeccompFlags |= seccomp.AllowMultiarch
|
||||
z.SeccompPresets |= bits.PresetStrict
|
||||
z.SeccompPresets |= comp.PresetStrict
|
||||
z.Hostname = "hakurei-dbus"
|
||||
if p.output != nil {
|
||||
z.Stdout, z.Stderr = p.output, p.output
|
||||
@@ -114,7 +114,7 @@ func (p *Proxy) Start() error {
|
||||
check.SortAbs(sockDirPaths)
|
||||
sockDirPaths = check.CompactAbs(sockDirPaths)
|
||||
for _, name := range sockDirPaths {
|
||||
z.Bind(name, name, bits.BindWritable)
|
||||
z.Bind(name, name, comp.BindWritable)
|
||||
}
|
||||
|
||||
// xdg-dbus-proxy bin path
|
||||
|
||||
@@ -32,6 +32,16 @@ nixosTest {
|
||||
environment.systemPackages = [
|
||||
# For go tests:
|
||||
(writeShellScriptBin "hakurei-test" ''
|
||||
# Assert hst CGO_ENABLED=0: ${
|
||||
with pkgs;
|
||||
runCommand "hakurei-hst-cgo" { nativeBuildInputs = [ go ]; } ''
|
||||
cp -r ${options.environment.hakurei.package.default.src} "$out"
|
||||
chmod -R +w "$out"
|
||||
cp ${writeText "hst_cgo_test.go" ''package hakurei_test;import("testing";"hakurei.app/hst");func TestTemplate(t *testing.T){hst.Template()}''} "$out/hst_cgo_test.go"
|
||||
(cd "$out" && HOME="$(mktemp -d)" CGO_ENABLED=0 go test .)
|
||||
''
|
||||
}
|
||||
|
||||
cd ${self.packages.${system}.hakurei.src}
|
||||
${fhs}/bin/hakurei-fhs -c \
|
||||
'go test ${if withRace then "-race" else "-count 16"} ./...' \
|
||||
|
||||
@@ -22,7 +22,7 @@ in
|
||||
{
|
||||
name = "funcgraph-retval";
|
||||
patch = null;
|
||||
extraStructuredConfig.FUNCTION_GRAPH_RETVAL = lib.kernel.yes;
|
||||
structuredExtraConfig.FUNCTION_GRAPH_RETVAL = lib.kernel.yes;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user