app: integrate container autoroot
All checks were successful
Test / Create distribution (push) Successful in 36s
Test / Sandbox (push) Successful in 2m25s
Test / Sandbox (race detector) (push) Successful in 4m13s
Test / Hpkg (push) Successful in 4m36s
Test / Hakurei (race detector) (push) Successful in 5m2s
Test / Hakurei (push) Successful in 2m40s
Test / Flake checks (push) Successful in 1m36s
All checks were successful
Test / Create distribution (push) Successful in 36s
Test / Sandbox (push) Successful in 2m25s
Test / Sandbox (race detector) (push) Successful in 4m13s
Test / Hpkg (push) Successful in 4m36s
Test / Hakurei (race detector) (push) Successful in 5m2s
Test / Hakurei (push) Successful in 2m40s
Test / Flake checks (push) Successful in 1m36s
Doing this instead of mounting directly on / because it's impossible to ensure a parent is available for every path hakurei wants to mount to. This situation is similar to autoetc hence the similar name, however a symlink mirror will not work in this case. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -42,21 +42,10 @@ var testCasesPd = []sealTestCase{
|
||||
"XDG_SESSION_TYPE=tty",
|
||||
},
|
||||
Ops: new(container.Ops).
|
||||
Root("/", "4a450b6596d7bc15bd01780eb9a607ac", container.BindWritable).
|
||||
Proc("/proc").
|
||||
Tmpfs(hst.Tmp, 4096, 0755).
|
||||
Dev("/dev").Mqueue("/dev/mqueue").
|
||||
Bind("/bin", "/bin", container.BindWritable).
|
||||
Bind("/boot", "/boot", container.BindWritable).
|
||||
Bind("/home", "/home", container.BindWritable).
|
||||
Bind("/lib", "/lib", container.BindWritable).
|
||||
Bind("/lib64", "/lib64", container.BindWritable).
|
||||
Bind("/nix", "/nix", container.BindWritable).
|
||||
Bind("/root", "/root", container.BindWritable).
|
||||
Bind("/run", "/run", container.BindWritable).
|
||||
Bind("/srv", "/srv", container.BindWritable).
|
||||
Bind("/sys", "/sys", container.BindWritable).
|
||||
Bind("/usr", "/usr", container.BindWritable).
|
||||
Bind("/var", "/var", container.BindWritable).
|
||||
Bind("/dev/kvm", "/dev/kvm", container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Tmpfs("/run/user/1971", 8192, 0755).
|
||||
Tmpfs("/run/dbus", 8192, 0755).
|
||||
@@ -186,21 +175,10 @@ var testCasesPd = []sealTestCase{
|
||||
"XDG_SESSION_TYPE=tty",
|
||||
},
|
||||
Ops: new(container.Ops).
|
||||
Root("/", "ebf083d1b175911782d413369b64ce7c", container.BindWritable).
|
||||
Proc("/proc").
|
||||
Tmpfs(hst.Tmp, 4096, 0755).
|
||||
Dev("/dev").Mqueue("/dev/mqueue").
|
||||
Bind("/bin", "/bin", container.BindWritable).
|
||||
Bind("/boot", "/boot", container.BindWritable).
|
||||
Bind("/home", "/home", container.BindWritable).
|
||||
Bind("/lib", "/lib", container.BindWritable).
|
||||
Bind("/lib64", "/lib64", container.BindWritable).
|
||||
Bind("/nix", "/nix", container.BindWritable).
|
||||
Bind("/root", "/root", container.BindWritable).
|
||||
Bind("/run", "/run", container.BindWritable).
|
||||
Bind("/srv", "/srv", container.BindWritable).
|
||||
Bind("/sys", "/sys", container.BindWritable).
|
||||
Bind("/usr", "/usr", container.BindWritable).
|
||||
Bind("/var", "/var", container.BindWritable).
|
||||
Bind("/dev/dri", "/dev/dri", container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Bind("/dev/kvm", "/dev/kvm", container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Tmpfs("/run/user/1971", 8192, 0755).
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"io/fs"
|
||||
"maps"
|
||||
"path"
|
||||
"slices"
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/container"
|
||||
@@ -21,7 +22,7 @@ const preallocateOpsCount = 1 << 5
|
||||
|
||||
// newContainer initialises [container.Params] via [hst.ContainerConfig].
|
||||
// Note that remaining container setup must be queued by the caller.
|
||||
func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*container.Params, map[string]string, error) {
|
||||
func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid *int) (*container.Params, map[string]string, error) {
|
||||
if s == nil {
|
||||
return nil, nil, syscall.EBADE
|
||||
}
|
||||
@@ -72,6 +73,13 @@ func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*contain
|
||||
*gid = container.OverflowGid()
|
||||
}
|
||||
|
||||
if s.AutoRoot != "" {
|
||||
if !path.IsAbs(s.AutoRoot) {
|
||||
return nil, nil, fmt.Errorf("auto root target %q not absolute", s.AutoRoot)
|
||||
}
|
||||
params.Root(s.AutoRoot, prefix, s.RootFlags)
|
||||
}
|
||||
|
||||
params.
|
||||
Proc("/proc").
|
||||
Tmpfs(hst.Tmp, 1<<12, 0755)
|
||||
@@ -120,6 +128,28 @@ func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*contain
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
// evaluated path, input path
|
||||
hidePathSource := make([][2]string, 0, len(s.Filesystem))
|
||||
|
||||
// AutoRoot is a collection of many BindMountOp internally
|
||||
if s.AutoRoot != "" {
|
||||
if d, err := os.ReadDir(s.AutoRoot); err != nil {
|
||||
return nil, nil, err
|
||||
} else {
|
||||
hidePathSource = slices.Grow(hidePathSource, len(d))
|
||||
for _, ent := range d {
|
||||
name := ent.Name()
|
||||
if container.IsAutoRootBindable(name) {
|
||||
name = path.Join(s.AutoRoot, name)
|
||||
srcP := [2]string{name, name}
|
||||
if err = evalSymlinks(os, &srcP[0]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
hidePathSource = append(hidePathSource, srcP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range s.Filesystem {
|
||||
if c == nil {
|
||||
@@ -137,24 +167,11 @@ func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*contain
|
||||
return nil, nil, fmt.Errorf("dst path %q is not absolute", dest)
|
||||
}
|
||||
|
||||
srcH := c.Src
|
||||
if err := evalSymlinks(os, &srcH); err != nil {
|
||||
p := [2]string{c.Src, c.Src}
|
||||
if err := evalSymlinks(os, &p[0]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for i := range hidePaths {
|
||||
// skip matched entries
|
||||
if hidePathMatch[i] {
|
||||
continue
|
||||
}
|
||||
|
||||
if ok, err := deepContainsH(srcH, hidePaths[i]); err != nil {
|
||||
return nil, nil, err
|
||||
} else if ok {
|
||||
hidePathMatch[i] = true
|
||||
os.Printf("hiding paths from %q", c.Src)
|
||||
}
|
||||
}
|
||||
hidePathSource = append(hidePathSource, p)
|
||||
|
||||
var flags int
|
||||
if c.Write {
|
||||
@@ -169,6 +186,22 @@ func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*contain
|
||||
params.Bind(c.Src, dest, flags)
|
||||
}
|
||||
|
||||
for _, p := range hidePathSource {
|
||||
for i := range hidePaths {
|
||||
// skip matched entries
|
||||
if hidePathMatch[i] {
|
||||
continue
|
||||
}
|
||||
|
||||
if ok, err := deepContainsH(p[0], hidePaths[i]); err != nil {
|
||||
return nil, nil, err
|
||||
} else if ok {
|
||||
hidePathMatch[i] = true
|
||||
os.Printf("hiding path %q from %q", hidePaths[i], p[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cover matched paths
|
||||
for i, ok := range hidePathMatch {
|
||||
if ok {
|
||||
@@ -180,6 +213,18 @@ func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*contain
|
||||
params.Link(l[0], l[1])
|
||||
}
|
||||
|
||||
if !s.AutoEtc {
|
||||
if s.Etc != "" {
|
||||
params.Bind(s.Etc, "/etc", 0)
|
||||
}
|
||||
} else {
|
||||
etcPath := s.Etc
|
||||
if etcPath == "" {
|
||||
etcPath = "/etc"
|
||||
}
|
||||
params.Etc(etcPath, prefix)
|
||||
}
|
||||
|
||||
return params, maps.Clone(s.Env), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -241,26 +241,9 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
Net: true,
|
||||
Tty: true,
|
||||
AutoEtc: true,
|
||||
}
|
||||
// bind entries in /
|
||||
if d, err := sys.ReadDir("/"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
b := make([]*hst.FilesystemConfig, 0, len(d))
|
||||
for _, ent := range d {
|
||||
p := "/" + ent.Name()
|
||||
switch p {
|
||||
case "/proc":
|
||||
case "/dev":
|
||||
case "/tmp":
|
||||
case "/mnt":
|
||||
case "/etc":
|
||||
|
||||
default:
|
||||
b = append(b, &hst.FilesystemConfig{Src: p, Write: true, Must: true})
|
||||
}
|
||||
}
|
||||
conf.Filesystem = append(conf.Filesystem, b...)
|
||||
AutoRoot: "/",
|
||||
RootFlags: container.BindWritable,
|
||||
}
|
||||
|
||||
// hide nscd from sandbox if present
|
||||
@@ -282,7 +265,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
{
|
||||
var uid, gid int
|
||||
var err error
|
||||
seal.container, seal.env, err = newContainer(config.Container, sys, &uid, &gid)
|
||||
seal.container, seal.env, err = newContainer(config.Container, sys, seal.id.String(), &uid, &gid)
|
||||
seal.waitDelay = config.Container.WaitDelay
|
||||
if err != nil {
|
||||
return hlog.WrapErrSuffix(err,
|
||||
@@ -305,18 +288,6 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
}
|
||||
}
|
||||
|
||||
if !config.Container.AutoEtc {
|
||||
if config.Container.Etc != "" {
|
||||
seal.container.Bind(config.Container.Etc, "/etc", 0)
|
||||
}
|
||||
} else {
|
||||
etcPath := config.Container.Etc
|
||||
if etcPath == "" {
|
||||
etcPath = "/etc"
|
||||
}
|
||||
seal.container.Etc(etcPath, seal.id.String())
|
||||
}
|
||||
|
||||
// inner XDG_RUNTIME_DIR default formatting of `/run/user/%d` as mapped uid
|
||||
innerRuntimeDir := path.Join("/run/user", mapuid.String())
|
||||
seal.env[xdgRuntimeDir] = innerRuntimeDir
|
||||
|
||||
Reference in New Issue
Block a user