container/init: wrap syscall helper functions
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m7s
Test / Hakurei (push) Successful in 3m8s
Test / Hpkg (push) Successful in 3m59s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hakurei (race detector) (push) Successful in 5m6s
Test / Flake checks (push) Successful in 1m26s
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m7s
Test / Hakurei (push) Successful in 3m8s
Test / Hpkg (push) Successful in 3m59s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hakurei (race detector) (push) Successful in 5m6s
Test / Flake checks (push) Successful in 1m26s
This allows tests to stub all kernel behaviour, enabling measurement of all function call arguments and error injection. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
d500d6e559
commit
09d2844981
@ -3,8 +3,7 @@ package container
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
func init() { gob.Register(new(AutoEtcOp)) }
|
||||
@ -21,38 +20,35 @@ func (f *Ops) Etc(host *Absolute, prefix string) *Ops {
|
||||
|
||||
type AutoEtcOp struct{ Prefix string }
|
||||
|
||||
func (e *AutoEtcOp) Valid() bool { return e != nil }
|
||||
func (e *AutoEtcOp) early(*setupState) error { return nil }
|
||||
func (e *AutoEtcOp) apply(state *setupState) error {
|
||||
func (e *AutoEtcOp) Valid() bool { return e != nil }
|
||||
func (e *AutoEtcOp) early(*setupState, syscallDispatcher) error { return nil }
|
||||
func (e *AutoEtcOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
if state.nonrepeatable&nrAutoEtc != 0 {
|
||||
return msg.WrapErr(syscall.EINVAL, "autoetc is not repeatable")
|
||||
return msg.WrapErr(fs.ErrInvalid, "autoetc is not repeatable")
|
||||
}
|
||||
state.nonrepeatable |= nrAutoEtc
|
||||
|
||||
const target = sysrootPath + FHSEtc
|
||||
rel := e.hostRel() + "/"
|
||||
|
||||
if err := os.MkdirAll(target, 0755); err != nil {
|
||||
if err := k.mkdirAll(target, 0755); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
if d, err := os.ReadDir(toSysroot(e.hostPath().String())); err != nil {
|
||||
if d, err := k.readdir(toSysroot(e.hostPath().String())); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else {
|
||||
for _, ent := range d {
|
||||
n := ent.Name()
|
||||
switch n {
|
||||
case ".host":
|
||||
|
||||
case "passwd":
|
||||
case "group":
|
||||
case ".host", "passwd", "group":
|
||||
|
||||
case "mtab":
|
||||
if err = os.Symlink(FHSProc+"mounts", target+n); err != nil {
|
||||
if err = k.symlink(FHSProc+"mounts", target+n); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
|
||||
default:
|
||||
if err = os.Symlink(rel+n, target+n); err != nil {
|
||||
if err = k.symlink(rel+n, target+n); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,253 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAutoEtcOp(t *testing.T) {
|
||||
t.Run("nonrepeatable", func(t *testing.T) {
|
||||
wantErr := msg.WrapErr(fs.ErrInvalid, "autoetc is not repeatable")
|
||||
if err := (&AutoEtcOp{Prefix: "81ceabb30d37bbdb3868004629cb84e9"}).apply(&setupState{nonrepeatable: nrAutoEtc}, nil); !errors.Is(err, wantErr) {
|
||||
t.Errorf("apply: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"mkdirAll", new(Params), &AutoEtcOp{
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc/", os.FileMode(0755)}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"readdir", new(Params), &AutoEtcOp{
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc/", os.FileMode(0755)}, nil, nil},
|
||||
{"readdir", expectArgs{"/sysroot/etc/.host/81ceabb30d37bbdb3868004629cb84e9"}, stubDir(), errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"symlink", new(Params), &AutoEtcOp{
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc/", os.FileMode(0755)}, nil, nil},
|
||||
{"readdir", expectArgs{"/sysroot/etc/.host/81ceabb30d37bbdb3868004629cb84e9"}, stubDir(".host",
|
||||
"alsa", "bash_logout", "bashrc", "binfmt.d", "dbus-1", "default", "dhcpcd.exit-hook", "fonts",
|
||||
"fstab", "fuse.conf", "group", "host.conf", "hostname", "hosts", "hsurc", "inputrc", "issue", "kbd",
|
||||
"locale.conf", "login.defs", "lsb-release", "lvm", "machine-id", "man_db.conf", "mdadm.conf",
|
||||
"modprobe.d", "modules-load.d", "mtab", "nanorc", "netgroup", "nix", "nixos", "NIXOS", "nscd.conf",
|
||||
"nsswitch.conf", "os-release", "pam", "pam.d", "passwd", "pipewire", "pki", "polkit-1", "profile",
|
||||
"protocols", "resolv.conf", "resolvconf.conf", "rpc", "services", "set-environment", "shadow", "shells",
|
||||
"ssh", "ssl", "static", "subgid", "subuid", "sudoers", "sway", "sysctl.d", "systemd", "terminfo",
|
||||
"tmpfiles.d", "udev", "vconsole.conf", "X11", "xdg", "zoneinfo"), nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/alsa", "/sysroot/etc/alsa"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"symlink mtab", new(Params), &AutoEtcOp{
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc/", os.FileMode(0755)}, nil, nil},
|
||||
{"readdir", expectArgs{"/sysroot/etc/.host/81ceabb30d37bbdb3868004629cb84e9"}, stubDir(".host",
|
||||
"alsa", "bash_logout", "bashrc", "binfmt.d", "dbus-1", "default", "dhcpcd.exit-hook", "fonts",
|
||||
"fstab", "fuse.conf", "group", "host.conf", "hostname", "hosts", "hsurc", "inputrc", "issue", "kbd",
|
||||
"locale.conf", "login.defs", "lsb-release", "lvm", "machine-id", "man_db.conf", "mdadm.conf",
|
||||
"modprobe.d", "modules-load.d", "mtab", "nanorc", "netgroup", "nix", "nixos", "NIXOS", "nscd.conf",
|
||||
"nsswitch.conf", "os-release", "pam", "pam.d", "passwd", "pipewire", "pki", "polkit-1", "profile",
|
||||
"protocols", "resolv.conf", "resolvconf.conf", "rpc", "services", "set-environment", "shadow", "shells",
|
||||
"ssh", "ssl", "static", "subgid", "subuid", "sudoers", "sway", "sysctl.d", "systemd", "terminfo",
|
||||
"tmpfiles.d", "udev", "vconsole.conf", "X11", "xdg", "zoneinfo"), nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/alsa", "/sysroot/etc/alsa"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/bash_logout", "/sysroot/etc/bash_logout"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/bashrc", "/sysroot/etc/bashrc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/binfmt.d", "/sysroot/etc/binfmt.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/dbus-1", "/sysroot/etc/dbus-1"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/default", "/sysroot/etc/default"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/dhcpcd.exit-hook", "/sysroot/etc/dhcpcd.exit-hook"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fonts", "/sysroot/etc/fonts"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fstab", "/sysroot/etc/fstab"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fuse.conf", "/sysroot/etc/fuse.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/host.conf", "/sysroot/etc/host.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hostname", "/sysroot/etc/hostname"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hosts", "/sysroot/etc/hosts"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hsurc", "/sysroot/etc/hsurc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/inputrc", "/sysroot/etc/inputrc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/issue", "/sysroot/etc/issue"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/kbd", "/sysroot/etc/kbd"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/locale.conf", "/sysroot/etc/locale.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/login.defs", "/sysroot/etc/login.defs"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/lsb-release", "/sysroot/etc/lsb-release"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/lvm", "/sysroot/etc/lvm"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/machine-id", "/sysroot/etc/machine-id"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/man_db.conf", "/sysroot/etc/man_db.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/mdadm.conf", "/sysroot/etc/mdadm.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/modprobe.d", "/sysroot/etc/modprobe.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/modules-load.d", "/sysroot/etc/modules-load.d"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/mounts", "/sysroot/etc/mtab"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"success nested", new(Params), &AutoEtcOp{
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc/", os.FileMode(0755)}, nil, nil},
|
||||
{"readdir", expectArgs{"/sysroot/etc/.host/81ceabb30d37bbdb3868004629cb84e9"}, stubDir(".host",
|
||||
"alsa", "bash_logout", "bashrc", "binfmt.d", "dbus-1", "default", "dhcpcd.exit-hook", "fonts",
|
||||
"fstab", "fuse.conf", "group", "host.conf", "hostname", "hosts", "hsurc", "inputrc", "issue", "kbd",
|
||||
"locale.conf", "login.defs", "lsb-release", "lvm", "machine-id", "man_db.conf", "mdadm.conf",
|
||||
"modprobe.d", "modules-load.d", "mtab", "nanorc", "netgroup", "nix", "nixos", "NIXOS", "nscd.conf",
|
||||
"nsswitch.conf", "os-release", "pam", "pam.d", "passwd", "pipewire", "pki", "polkit-1", "profile",
|
||||
"protocols", "resolv.conf", "resolvconf.conf", "rpc", "services", "set-environment", "shadow", "shells",
|
||||
"ssh", "ssl", "static", "subgid", "subuid", "sudoers", "sway", "sysctl.d", "systemd", "terminfo",
|
||||
"tmpfiles.d", "udev", "vconsole.conf", "X11", "xdg", "zoneinfo"), nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/alsa", "/sysroot/etc/alsa"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/bash_logout", "/sysroot/etc/bash_logout"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/bashrc", "/sysroot/etc/bashrc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/binfmt.d", "/sysroot/etc/binfmt.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/dbus-1", "/sysroot/etc/dbus-1"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/default", "/sysroot/etc/default"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/dhcpcd.exit-hook", "/sysroot/etc/dhcpcd.exit-hook"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fonts", "/sysroot/etc/fonts"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fstab", "/sysroot/etc/fstab"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fuse.conf", "/sysroot/etc/fuse.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/host.conf", "/sysroot/etc/host.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hostname", "/sysroot/etc/hostname"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hosts", "/sysroot/etc/hosts"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hsurc", "/sysroot/etc/hsurc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/inputrc", "/sysroot/etc/inputrc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/issue", "/sysroot/etc/issue"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/kbd", "/sysroot/etc/kbd"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/locale.conf", "/sysroot/etc/locale.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/login.defs", "/sysroot/etc/login.defs"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/lsb-release", "/sysroot/etc/lsb-release"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/lvm", "/sysroot/etc/lvm"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/machine-id", "/sysroot/etc/machine-id"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/man_db.conf", "/sysroot/etc/man_db.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/mdadm.conf", "/sysroot/etc/mdadm.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/modprobe.d", "/sysroot/etc/modprobe.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/modules-load.d", "/sysroot/etc/modules-load.d"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/mounts", "/sysroot/etc/mtab"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nanorc", "/sysroot/etc/nanorc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/netgroup", "/sysroot/etc/netgroup"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nix", "/sysroot/etc/nix"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nixos", "/sysroot/etc/nixos"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/NIXOS", "/sysroot/etc/NIXOS"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nscd.conf", "/sysroot/etc/nscd.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nsswitch.conf", "/sysroot/etc/nsswitch.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/os-release", "/sysroot/etc/os-release"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/pam", "/sysroot/etc/pam"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/pam.d", "/sysroot/etc/pam.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/pipewire", "/sysroot/etc/pipewire"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/pki", "/sysroot/etc/pki"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/polkit-1", "/sysroot/etc/polkit-1"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/profile", "/sysroot/etc/profile"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/protocols", "/sysroot/etc/protocols"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/resolv.conf", "/sysroot/etc/resolv.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/resolvconf.conf", "/sysroot/etc/resolvconf.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/rpc", "/sysroot/etc/rpc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/services", "/sysroot/etc/services"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/set-environment", "/sysroot/etc/set-environment"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/shadow", "/sysroot/etc/shadow"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/shells", "/sysroot/etc/shells"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/ssh", "/sysroot/etc/ssh"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/ssl", "/sysroot/etc/ssl"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/static", "/sysroot/etc/static"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/subgid", "/sysroot/etc/subgid"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/subuid", "/sysroot/etc/subuid"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/sudoers", "/sysroot/etc/sudoers"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/sway", "/sysroot/etc/sway"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/sysctl.d", "/sysroot/etc/sysctl.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/systemd", "/sysroot/etc/systemd"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/terminfo", "/sysroot/etc/terminfo"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/tmpfiles.d", "/sysroot/etc/tmpfiles.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/udev", "/sysroot/etc/udev"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/vconsole.conf", "/sysroot/etc/vconsole.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/X11", "/sysroot/etc/X11"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/xdg", "/sysroot/etc/xdg"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/zoneinfo", "/sysroot/etc/zoneinfo"}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success", new(Params), &AutoEtcOp{
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc/", os.FileMode(0755)}, nil, nil},
|
||||
{"readdir", expectArgs{"/sysroot/etc/.host/81ceabb30d37bbdb3868004629cb84e9"}, stubDir(
|
||||
"alsa", "bash_logout", "bashrc", "binfmt.d", "dbus-1", "default", "dhcpcd.exit-hook", "fonts",
|
||||
"fstab", "fuse.conf", "group", "host.conf", "hostname", "hosts", "hsurc", "inputrc", "issue", "kbd",
|
||||
"locale.conf", "login.defs", "lsb-release", "lvm", "machine-id", "man_db.conf", "mdadm.conf",
|
||||
"modprobe.d", "modules-load.d", "mtab", "nanorc", "netgroup", "nix", "nixos", "NIXOS", "nscd.conf",
|
||||
"nsswitch.conf", "os-release", "pam", "pam.d", "passwd", "pipewire", "pki", "polkit-1", "profile",
|
||||
"protocols", "resolv.conf", "resolvconf.conf", "rpc", "services", "set-environment", "shadow", "shells",
|
||||
"ssh", "ssl", "static", "subgid", "subuid", "sudoers", "sway", "sysctl.d", "systemd", "terminfo",
|
||||
"tmpfiles.d", "udev", "vconsole.conf", "X11", "xdg", "zoneinfo"), nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/alsa", "/sysroot/etc/alsa"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/bash_logout", "/sysroot/etc/bash_logout"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/bashrc", "/sysroot/etc/bashrc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/binfmt.d", "/sysroot/etc/binfmt.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/dbus-1", "/sysroot/etc/dbus-1"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/default", "/sysroot/etc/default"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/dhcpcd.exit-hook", "/sysroot/etc/dhcpcd.exit-hook"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fonts", "/sysroot/etc/fonts"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fstab", "/sysroot/etc/fstab"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/fuse.conf", "/sysroot/etc/fuse.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/host.conf", "/sysroot/etc/host.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hostname", "/sysroot/etc/hostname"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hosts", "/sysroot/etc/hosts"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/hsurc", "/sysroot/etc/hsurc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/inputrc", "/sysroot/etc/inputrc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/issue", "/sysroot/etc/issue"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/kbd", "/sysroot/etc/kbd"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/locale.conf", "/sysroot/etc/locale.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/login.defs", "/sysroot/etc/login.defs"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/lsb-release", "/sysroot/etc/lsb-release"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/lvm", "/sysroot/etc/lvm"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/machine-id", "/sysroot/etc/machine-id"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/man_db.conf", "/sysroot/etc/man_db.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/mdadm.conf", "/sysroot/etc/mdadm.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/modprobe.d", "/sysroot/etc/modprobe.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/modules-load.d", "/sysroot/etc/modules-load.d"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/mounts", "/sysroot/etc/mtab"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nanorc", "/sysroot/etc/nanorc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/netgroup", "/sysroot/etc/netgroup"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nix", "/sysroot/etc/nix"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nixos", "/sysroot/etc/nixos"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/NIXOS", "/sysroot/etc/NIXOS"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nscd.conf", "/sysroot/etc/nscd.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/nsswitch.conf", "/sysroot/etc/nsswitch.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/os-release", "/sysroot/etc/os-release"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/pam", "/sysroot/etc/pam"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/pam.d", "/sysroot/etc/pam.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/pipewire", "/sysroot/etc/pipewire"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/pki", "/sysroot/etc/pki"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/polkit-1", "/sysroot/etc/polkit-1"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/profile", "/sysroot/etc/profile"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/protocols", "/sysroot/etc/protocols"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/resolv.conf", "/sysroot/etc/resolv.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/resolvconf.conf", "/sysroot/etc/resolvconf.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/rpc", "/sysroot/etc/rpc"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/services", "/sysroot/etc/services"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/set-environment", "/sysroot/etc/set-environment"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/shadow", "/sysroot/etc/shadow"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/shells", "/sysroot/etc/shells"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/ssh", "/sysroot/etc/ssh"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/ssl", "/sysroot/etc/ssl"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/static", "/sysroot/etc/static"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/subgid", "/sysroot/etc/subgid"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/subuid", "/sysroot/etc/subuid"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/sudoers", "/sysroot/etc/sudoers"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/sway", "/sysroot/etc/sway"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/sysctl.d", "/sysroot/etc/sysctl.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/systemd", "/sysroot/etc/systemd"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/terminfo", "/sysroot/etc/terminfo"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/tmpfiles.d", "/sysroot/etc/tmpfiles.d"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/udev", "/sysroot/etc/udev"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/vconsole.conf", "/sysroot/etc/vconsole.conf"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/X11", "/sysroot/etc/X11"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/xdg", "/sysroot/etc/xdg"}, nil, nil},
|
||||
{"symlink", expectArgs{".host/81ceabb30d37bbdb3868004629cb84e9/zoneinfo", "/sysroot/etc/zoneinfo"}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*AutoEtcOp)(nil), false},
|
||||
{"zero", new(AutoEtcOp), true},
|
||||
|
@ -3,8 +3,7 @@ package container
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
func init() { gob.Register(new(AutoRootOp)) }
|
||||
@ -30,8 +29,8 @@ type AutoRootOp struct {
|
||||
|
||||
func (r *AutoRootOp) Valid() bool { return r != nil && r.Host != nil }
|
||||
|
||||
func (r *AutoRootOp) early(state *setupState) error {
|
||||
if d, err := os.ReadDir(r.Host.String()); err != nil {
|
||||
func (r *AutoRootOp) early(state *setupState, k syscallDispatcher) error {
|
||||
if d, err := k.readdir(r.Host.String()); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else {
|
||||
r.resolved = make([]Op, 0, len(d))
|
||||
@ -43,7 +42,7 @@ func (r *AutoRootOp) early(state *setupState) error {
|
||||
Target: AbsFHSRoot.Append(name),
|
||||
Flags: r.Flags,
|
||||
}
|
||||
if err = op.early(state); err != nil {
|
||||
if err = op.early(state, k); err != nil {
|
||||
return err
|
||||
}
|
||||
r.resolved = append(r.resolved, op)
|
||||
@ -53,15 +52,15 @@ func (r *AutoRootOp) early(state *setupState) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *AutoRootOp) apply(state *setupState) error {
|
||||
func (r *AutoRootOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
if state.nonrepeatable&nrAutoRoot != 0 {
|
||||
return msg.WrapErr(syscall.EINVAL, "autoroot is not repeatable")
|
||||
return msg.WrapErr(fs.ErrInvalid, "autoroot is not repeatable")
|
||||
}
|
||||
state.nonrepeatable |= nrAutoRoot
|
||||
|
||||
for _, op := range r.resolved {
|
||||
msg.Verbosef("%s %s", op.prefix(), op)
|
||||
if err := op.apply(state); err != nil {
|
||||
k.verbosef("%s %s", op.prefix(), op)
|
||||
if err := op.apply(state, k); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -83,13 +82,11 @@ func (r *AutoRootOp) String() string {
|
||||
// IsAutoRootBindable returns whether a dir entry name is selected for AutoRoot.
|
||||
func IsAutoRootBindable(name string) bool {
|
||||
switch name {
|
||||
case "proc":
|
||||
case "dev":
|
||||
case "tmp":
|
||||
case "mnt":
|
||||
case "etc":
|
||||
case "proc", "dev", "tmp", "mnt", "etc":
|
||||
|
||||
case "": // guard against accidentally binding /
|
||||
// should be unreachable
|
||||
msg.Verbose("got unexpected root entry")
|
||||
|
||||
default:
|
||||
return true
|
||||
|
@ -1,8 +1,126 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAutoRootOp(t *testing.T) {
|
||||
t.Run("nonrepeatable", func(t *testing.T) {
|
||||
wantErr := msg.WrapErr(fs.ErrInvalid, "autoroot is not repeatable")
|
||||
if err := (&AutoRootOp{Prefix: "81ceabb30d37bbdb3868004629cb84e9"}).apply(&setupState{nonrepeatable: nrAutoRoot}, nil); !errors.Is(err, wantErr) {
|
||||
t.Errorf("apply: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"readdir", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: MustAbs("/"),
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
Flags: BindWritable,
|
||||
}, []kexpect{
|
||||
{"readdir", expectArgs{"/"}, stubDir(), errUnique},
|
||||
}, wrapErrSelf(errUnique), nil, nil},
|
||||
|
||||
{"early", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: MustAbs("/"),
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
Flags: BindWritable,
|
||||
}, []kexpect{
|
||||
{"readdir", expectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil},
|
||||
{"evalSymlinks", expectArgs{"/bin"}, "", errUnique},
|
||||
}, wrapErrSelf(errUnique), nil, nil},
|
||||
|
||||
{"apply", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: MustAbs("/"),
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
Flags: BindWritable,
|
||||
}, []kexpect{
|
||||
{"readdir", expectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil},
|
||||
{"evalSymlinks", expectArgs{"/bin"}, "/usr/bin", nil},
|
||||
{"evalSymlinks", expectArgs{"/home"}, "/home", nil},
|
||||
{"evalSymlinks", expectArgs{"/lib64"}, "/lib64", nil},
|
||||
{"evalSymlinks", expectArgs{"/lost+found"}, "/lost+found", nil},
|
||||
{"evalSymlinks", expectArgs{"/nix"}, "/nix", nil},
|
||||
{"evalSymlinks", expectArgs{"/root"}, "/root", nil},
|
||||
{"evalSymlinks", expectArgs{"/run"}, "/run", nil},
|
||||
{"evalSymlinks", expectArgs{"/srv"}, "/srv", nil},
|
||||
{"evalSymlinks", expectArgs{"/sys"}, "/sys", nil},
|
||||
{"evalSymlinks", expectArgs{"/usr"}, "/usr", nil},
|
||||
{"evalSymlinks", expectArgs{"/var"}, "/var", nil},
|
||||
}, nil, []kexpect{
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/usr/bin"), MustAbs("/bin"), MustAbs("/bin"), BindWritable}}}, nil, nil},
|
||||
{"stat", expectArgs{"/host/usr/bin"}, isDirFi(false), errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"success pd", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: MustAbs("/"),
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
Flags: BindWritable,
|
||||
}, []kexpect{
|
||||
{"readdir", expectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil},
|
||||
{"evalSymlinks", expectArgs{"/bin"}, "/usr/bin", nil},
|
||||
{"evalSymlinks", expectArgs{"/home"}, "/home", nil},
|
||||
{"evalSymlinks", expectArgs{"/lib64"}, "/lib64", nil},
|
||||
{"evalSymlinks", expectArgs{"/lost+found"}, "/lost+found", nil},
|
||||
{"evalSymlinks", expectArgs{"/nix"}, "/nix", nil},
|
||||
{"evalSymlinks", expectArgs{"/root"}, "/root", nil},
|
||||
{"evalSymlinks", expectArgs{"/run"}, "/run", nil},
|
||||
{"evalSymlinks", expectArgs{"/srv"}, "/srv", nil},
|
||||
{"evalSymlinks", expectArgs{"/sys"}, "/sys", nil},
|
||||
{"evalSymlinks", expectArgs{"/usr"}, "/usr", nil},
|
||||
{"evalSymlinks", expectArgs{"/var"}, "/var", nil},
|
||||
}, nil, []kexpect{
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/usr/bin"), MustAbs("/bin"), MustAbs("/bin"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/usr/bin"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/bin", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/usr/bin", "/sysroot/bin", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/home"), MustAbs("/home"), MustAbs("/home"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/home"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/home", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/home", "/sysroot/home", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/lib64"), MustAbs("/lib64"), MustAbs("/lib64"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/lib64"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/lib64", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/lib64", "/sysroot/lib64", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/lost+found"), MustAbs("/lost+found"), MustAbs("/lost+found"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/lost+found"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/lost+found", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/lost+found", "/sysroot/lost+found", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/nix"), MustAbs("/nix"), MustAbs("/nix"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/nix"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/nix", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/nix", "/sysroot/nix", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/root"), MustAbs("/root"), MustAbs("/root"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/root"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/root", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/root", "/sysroot/root", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/run"), MustAbs("/run"), MustAbs("/run"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/run"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/run", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/run", "/sysroot/run", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/srv"), MustAbs("/srv"), MustAbs("/srv"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/srv"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/srv", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/srv", "/sysroot/srv", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/sys"), MustAbs("/sys"), MustAbs("/sys"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/sys"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/sys", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/sys", "/sysroot/sys", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/usr"), MustAbs("/usr"), MustAbs("/usr"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/usr"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/usr", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/usr", "/sysroot/usr", uintptr(0x4004), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var"), MustAbs("/var"), MustAbs("/var"), BindWritable}}}, nil, nil}, {"stat", expectArgs{"/host/var"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/var", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var", "/sysroot/var", uintptr(0x4004), false}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||
Host: MustAbs("/var/lib/planterette/base/debian:f92c9052"),
|
||||
Prefix: "81ceabb30d37bbdb3868004629cb84e9",
|
||||
}, []kexpect{
|
||||
{"readdir", expectArgs{"/var/lib/planterette/base/debian:f92c9052"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/bin"}, "/var/lib/planterette/base/debian:f92c9052/usr/bin", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/home"}, "/var/lib/planterette/base/debian:f92c9052/home", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/lib64"}, "/var/lib/planterette/base/debian:f92c9052/lib64", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/lost+found"}, "/var/lib/planterette/base/debian:f92c9052/lost+found", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/nix"}, "/var/lib/planterette/base/debian:f92c9052/nix", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/root"}, "/var/lib/planterette/base/debian:f92c9052/root", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/run"}, "/var/lib/planterette/base/debian:f92c9052/run", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/srv"}, "/var/lib/planterette/base/debian:f92c9052/srv", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/sys"}, "/var/lib/planterette/base/debian:f92c9052/sys", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/usr"}, "/var/lib/planterette/base/debian:f92c9052/usr", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052/var"}, "/var/lib/planterette/base/debian:f92c9052/var", nil},
|
||||
}, nil, []kexpect{
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/usr/bin"), MustAbs("/var/lib/planterette/base/debian:f92c9052/bin"), MustAbs("/bin"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/usr/bin"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/bin", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/usr/bin", "/sysroot/bin", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/home"), MustAbs("/var/lib/planterette/base/debian:f92c9052/home"), MustAbs("/home"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/home"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/home", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/home", "/sysroot/home", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/lib64"), MustAbs("/var/lib/planterette/base/debian:f92c9052/lib64"), MustAbs("/lib64"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/lib64"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/lib64", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/lib64", "/sysroot/lib64", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/lost+found"), MustAbs("/var/lib/planterette/base/debian:f92c9052/lost+found"), MustAbs("/lost+found"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/lost+found"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/lost+found", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/lost+found", "/sysroot/lost+found", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/nix"), MustAbs("/var/lib/planterette/base/debian:f92c9052/nix"), MustAbs("/nix"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/nix"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/nix", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/nix", "/sysroot/nix", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/root"), MustAbs("/var/lib/planterette/base/debian:f92c9052/root"), MustAbs("/root"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/root"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/root", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/root", "/sysroot/root", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/run"), MustAbs("/var/lib/planterette/base/debian:f92c9052/run"), MustAbs("/run"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/run"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/run", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/run", "/sysroot/run", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/srv"), MustAbs("/var/lib/planterette/base/debian:f92c9052/srv"), MustAbs("/srv"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/srv"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/srv", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/srv", "/sysroot/srv", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/sys"), MustAbs("/var/lib/planterette/base/debian:f92c9052/sys"), MustAbs("/sys"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/sys"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/sys", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/sys", "/sysroot/sys", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/usr"), MustAbs("/var/lib/planterette/base/debian:f92c9052/usr"), MustAbs("/usr"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/usr"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/usr", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/usr", "/sysroot/usr", uintptr(0x4005), false}, nil, nil},
|
||||
{"verbosef", expectArgs{"%s %s", []any{"mounting", &BindMountOp{MustAbs("/var/lib/planterette/base/debian:f92c9052/var"), MustAbs("/var/lib/planterette/base/debian:f92c9052/var"), MustAbs("/var"), 0}}}, nil, nil}, {"stat", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/var"}, isDirFi(true), nil}, {"mkdirAll", expectArgs{"/sysroot/var", os.FileMode(0700)}, nil, nil}, {"bindMount", expectArgs{"/host/var/lib/planterette/base/debian:f92c9052/var", "/sysroot/var", uintptr(0x4005), false}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*AutoRootOp)(nil), false},
|
||||
{"zero", new(AutoRootOp), false},
|
||||
|
@ -37,9 +37,52 @@ func capToIndex(cap uintptr) uintptr { return cap >> 5 }
|
||||
func capToMask(cap uintptr) uint32 { return 1 << uint(cap&31) }
|
||||
|
||||
func capset(hdrp *capHeader, datap *[2]capData) error {
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_CAPSET,
|
||||
r, _, errno := syscall.Syscall(
|
||||
syscall.SYS_CAPSET,
|
||||
uintptr(unsafe.Pointer(hdrp)),
|
||||
uintptr(unsafe.Pointer(&datap[0])), 0); errno != 0 {
|
||||
uintptr(unsafe.Pointer(&datap[0])), 0,
|
||||
)
|
||||
if r != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
|
229
container/dispatcher.go
Normal file
229
container/dispatcher.go
Normal file
@ -0,0 +1,229 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/container/seccomp"
|
||||
)
|
||||
|
||||
type osFile interface {
|
||||
Name() string
|
||||
io.Writer
|
||||
fs.File
|
||||
}
|
||||
|
||||
// syscallDispatcher provides methods that make state-dependent system calls as part of their behaviour.
|
||||
type syscallDispatcher interface {
|
||||
// setPtracer provides [SetPtracer].
|
||||
setPtracer(pid uintptr) error
|
||||
// setDumpable provides [SetDumpable].
|
||||
setDumpable(dumpable uintptr) error
|
||||
// setNoNewPrivs provides [SetNoNewPrivs].
|
||||
setNoNewPrivs() error
|
||||
|
||||
// lastcap provides [LastCap].
|
||||
lastcap() uintptr
|
||||
// capset provides capset.
|
||||
capset(hdrp *capHeader, datap *[2]capData) error
|
||||
// capBoundingSetDrop provides capBoundingSetDrop.
|
||||
capBoundingSetDrop(cap uintptr) error
|
||||
// capAmbientClearAll provides capAmbientClearAll.
|
||||
capAmbientClearAll() error
|
||||
// capAmbientRaise provides capAmbientRaise.
|
||||
capAmbientRaise(cap uintptr) error
|
||||
// isatty provides [Isatty].
|
||||
isatty(fd int) bool
|
||||
// receive provides [Receive].
|
||||
receive(key string, e any, v **os.File) (closeFunc func() error, err error)
|
||||
|
||||
// bindMount provides procPaths.bindMount.
|
||||
bindMount(source, target string, flags uintptr, eq bool) error
|
||||
// remount provides procPaths.remount.
|
||||
remount(target string, flags uintptr) error
|
||||
// mountTmpfs provides mountTmpfs.
|
||||
mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error
|
||||
// ensureFile provides ensureFile.
|
||||
ensureFile(name string, perm, pperm os.FileMode) error
|
||||
|
||||
// seccompLoad provides [seccomp.Load].
|
||||
seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error
|
||||
// notify provides [signal.Notify].
|
||||
notify(c chan<- os.Signal, sig ...os.Signal)
|
||||
// start starts [os/exec.Cmd].
|
||||
start(c *exec.Cmd) error
|
||||
// signal signals the underlying process of [os/exec.Cmd].
|
||||
signal(c *exec.Cmd, sig os.Signal) error
|
||||
// evalSymlinks provides [filepath.EvalSymlinks].
|
||||
evalSymlinks(path string) (string, error)
|
||||
|
||||
// exit provides [os.Exit].
|
||||
exit(code int)
|
||||
// getpid provides [os.Getpid].
|
||||
getpid() int
|
||||
// stat provides [os.Stat].
|
||||
stat(name string) (os.FileInfo, error)
|
||||
// mkdir provides [os.Mkdir].
|
||||
mkdir(name string, perm os.FileMode) error
|
||||
// mkdirTemp provides [os.MkdirTemp].
|
||||
mkdirTemp(dir, pattern string) (string, error)
|
||||
// mkdirAll provides [os.MkdirAll].
|
||||
mkdirAll(path string, perm os.FileMode) error
|
||||
// readdir provides [os.ReadDir].
|
||||
readdir(name string) ([]os.DirEntry, error)
|
||||
// writeFile provides [os.WriteFile].
|
||||
writeFile(name string, data []byte, perm os.FileMode) error
|
||||
// createTemp provides [os.CreateTemp].
|
||||
createTemp(dir, pattern string) (osFile, error)
|
||||
// remove provides os.Remove.
|
||||
remove(name string) error
|
||||
// newFile provides os.NewFile.
|
||||
newFile(fd uintptr, name string) *os.File
|
||||
// symlink provides os.Symlink.
|
||||
symlink(oldname, newname string) error
|
||||
// readlink provides [os.Readlink].
|
||||
readlink(name string) (string, error)
|
||||
|
||||
// umask provides syscall.Umask.
|
||||
umask(mask int) (oldmask int)
|
||||
// sethostname provides syscall.Sethostname
|
||||
sethostname(p []byte) (err error)
|
||||
// chdir provides syscall.Chdir
|
||||
chdir(path string) (err error)
|
||||
// fchdir provides syscall.Fchdir
|
||||
fchdir(fd int) (err error)
|
||||
// open provides syscall.Open
|
||||
open(path string, mode int, perm uint32) (fd int, err error)
|
||||
// close provides syscall.Close
|
||||
close(fd int) (err error)
|
||||
// pivotRoot provides syscall.PivotRoot
|
||||
pivotRoot(newroot, putold string) (err error)
|
||||
// mount provides syscall.Mount
|
||||
mount(source, target, fstype string, flags uintptr, data string) (err error)
|
||||
// unmount provides syscall.Unmount
|
||||
unmount(target string, flags int) (err error)
|
||||
// wait4 provides syscall.Wait4
|
||||
wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *syscall.Rusage) (wpid int, err error)
|
||||
|
||||
// printf provides [log.Printf].
|
||||
printf(format string, v ...any)
|
||||
// fatal provides [log.Fatal]
|
||||
fatal(v ...any)
|
||||
// fatalf provides [log.Fatalf]
|
||||
fatalf(format string, v ...any)
|
||||
// verbose provides [Msg.Verbose].
|
||||
verbose(v ...any)
|
||||
// verbosef provides [Msg.Verbosef].
|
||||
verbosef(format string, v ...any)
|
||||
// suspend provides [Msg.Suspend].
|
||||
suspend()
|
||||
// resume provides [Msg.Resume].
|
||||
resume() bool
|
||||
// beforeExit provides [Msg.BeforeExit].
|
||||
beforeExit()
|
||||
// printBaseErr provides [Msg.PrintBaseErr].
|
||||
printBaseErr(err error, fallback string)
|
||||
}
|
||||
|
||||
// direct implements syscallDispatcher on the current kernel.
|
||||
type direct struct{}
|
||||
|
||||
func (direct) setPtracer(pid uintptr) error { return SetPtracer(pid) }
|
||||
func (direct) setDumpable(dumpable uintptr) error { return SetDumpable(dumpable) }
|
||||
func (direct) setNoNewPrivs() error { return SetNoNewPrivs() }
|
||||
|
||||
func (direct) lastcap() uintptr { return LastCap() }
|
||||
func (direct) capset(hdrp *capHeader, datap *[2]capData) error { return capset(hdrp, datap) }
|
||||
func (direct) capBoundingSetDrop(cap uintptr) error { return capBoundingSetDrop(cap) }
|
||||
func (direct) capAmbientClearAll() error { return capAmbientClearAll() }
|
||||
func (direct) capAmbientRaise(cap uintptr) error { return capAmbientRaise(cap) }
|
||||
func (direct) isatty(fd int) bool { return Isatty(fd) }
|
||||
func (direct) receive(key string, e any, v **os.File) (func() error, error) {
|
||||
return Receive(key, e, v)
|
||||
}
|
||||
|
||||
func (direct) bindMount(source, target string, flags uintptr, eq bool) error {
|
||||
return hostProc.bindMount(source, target, flags, eq)
|
||||
}
|
||||
func (direct) remount(target string, flags uintptr) error {
|
||||
return hostProc.remount(target, flags)
|
||||
}
|
||||
func (direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
||||
return mountTmpfs(fsname, target, flags, size, perm)
|
||||
}
|
||||
func (direct) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||
return ensureFile(name, perm, pperm)
|
||||
}
|
||||
|
||||
func (direct) seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error {
|
||||
return seccomp.Load(rules, flags)
|
||||
}
|
||||
func (direct) notify(c chan<- os.Signal, sig ...os.Signal) { signal.Notify(c, sig...) }
|
||||
func (direct) start(c *exec.Cmd) error { return c.Start() }
|
||||
func (direct) signal(c *exec.Cmd, sig os.Signal) error { return c.Process.Signal(sig) }
|
||||
func (direct) evalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) }
|
||||
|
||||
func (direct) exit(code int) { os.Exit(code) }
|
||||
func (direct) getpid() int { return os.Getpid() }
|
||||
func (direct) stat(name string) (os.FileInfo, error) { return os.Stat(name) }
|
||||
func (direct) mkdir(name string, perm os.FileMode) error { return os.Mkdir(name, perm) }
|
||||
func (direct) mkdirTemp(dir, pattern string) (string, error) { return os.MkdirTemp(dir, pattern) }
|
||||
func (direct) mkdirAll(path string, perm os.FileMode) error { return os.MkdirAll(path, perm) }
|
||||
func (direct) readdir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) }
|
||||
func (direct) writeFile(name string, data []byte, perm os.FileMode) error {
|
||||
return os.WriteFile(name, data, perm)
|
||||
}
|
||||
func (direct) createTemp(dir, pattern string) (osFile, error) {
|
||||
return os.CreateTemp(dir, pattern)
|
||||
}
|
||||
func (direct) remove(name string) error {
|
||||
return os.Remove(name)
|
||||
}
|
||||
func (direct) newFile(fd uintptr, name string) *os.File {
|
||||
return os.NewFile(fd, name)
|
||||
}
|
||||
func (direct) symlink(oldname, newname string) error {
|
||||
return os.Symlink(oldname, newname)
|
||||
}
|
||||
func (direct) readlink(name string) (string, error) {
|
||||
return os.Readlink(name)
|
||||
}
|
||||
|
||||
func (direct) umask(mask int) (oldmask int) { return syscall.Umask(mask) }
|
||||
func (direct) sethostname(p []byte) (err error) { return syscall.Sethostname(p) }
|
||||
func (direct) chdir(path string) (err error) { return syscall.Chdir(path) }
|
||||
func (direct) fchdir(fd int) (err error) { return syscall.Fchdir(fd) }
|
||||
func (direct) open(path string, mode int, perm uint32) (fd int, err error) {
|
||||
return syscall.Open(path, mode, perm)
|
||||
}
|
||||
func (direct) close(fd int) (err error) {
|
||||
return syscall.Close(fd)
|
||||
}
|
||||
func (direct) pivotRoot(newroot, putold string) (err error) {
|
||||
return syscall.PivotRoot(newroot, putold)
|
||||
}
|
||||
func (direct) mount(source, target, fstype string, flags uintptr, data string) (err error) {
|
||||
return syscall.Mount(source, target, fstype, flags, data)
|
||||
}
|
||||
func (direct) unmount(target string, flags int) (err error) {
|
||||
return syscall.Unmount(target, flags)
|
||||
}
|
||||
func (direct) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *syscall.Rusage) (wpid int, err error) {
|
||||
return syscall.Wait4(pid, wstatus, options, rusage)
|
||||
}
|
||||
|
||||
func (direct) printf(format string, v ...any) { log.Printf(format, v...) }
|
||||
func (direct) fatal(v ...any) { log.Fatal(v...) }
|
||||
func (direct) fatalf(format string, v ...any) { log.Fatalf(format, v...) }
|
||||
func (direct) verbose(v ...any) { msg.Verbose(v...) }
|
||||
func (direct) verbosef(format string, v ...any) { msg.Verbosef(format, v...) }
|
||||
func (direct) suspend() { msg.Suspend() }
|
||||
func (direct) resume() bool { return msg.Resume() }
|
||||
func (direct) beforeExit() { msg.BeforeExit() }
|
||||
func (direct) printBaseErr(err error, fallback string) { msg.PrintBaseErr(err, fallback) }
|
595
container/dispatcher_test.go
Normal file
595
container/dispatcher_test.go
Normal file
@ -0,0 +1,595 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"slices"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"hakurei.app/container/seccomp"
|
||||
)
|
||||
|
||||
var errUnique = errors.New("unique error injected by the test suite")
|
||||
|
||||
type opValidTestCase struct {
|
||||
name string
|
||||
op Op
|
||||
want bool
|
||||
}
|
||||
|
||||
func checkOpsValid(t *testing.T, testCases []opValidTestCase) {
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := tc.op.Valid(); got != tc.want {
|
||||
t.Errorf("Valid: %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type opsBuilderTestCase struct {
|
||||
name string
|
||||
ops *Ops
|
||||
want Ops
|
||||
}
|
||||
|
||||
func checkOpsBuilder(t *testing.T, testCases []opsBuilderTestCase) {
|
||||
t.Run("build", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if !slices.EqualFunc(*tc.ops, tc.want, func(op Op, v Op) bool { return op.Is(v) }) {
|
||||
t.Errorf("Ops: %#v, want %#v", tc.ops, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type opIsTestCase struct {
|
||||
name string
|
||||
op, v Op
|
||||
want bool
|
||||
}
|
||||
|
||||
func checkOpIs(t *testing.T, testCases []opIsTestCase) {
|
||||
t.Run("is", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := tc.op.Is(tc.v); got != tc.want {
|
||||
t.Errorf("Is: %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type opMetaTestCase struct {
|
||||
name string
|
||||
op Op
|
||||
|
||||
wantPrefix string
|
||||
wantString string
|
||||
}
|
||||
|
||||
func checkOpMeta(t *testing.T, testCases []opMetaTestCase) {
|
||||
t.Run("meta", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Run("prefix", func(t *testing.T) {
|
||||
if got := tc.op.prefix(); got != tc.wantPrefix {
|
||||
t.Errorf("prefix: %q, want %q", got, tc.wantPrefix)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("string", func(t *testing.T) {
|
||||
if got := tc.op.String(); got != tc.wantString {
|
||||
t.Errorf("String: %s, want %s", got, tc.wantString)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type opBehaviourTestCase struct {
|
||||
name string
|
||||
params *Params
|
||||
op Op
|
||||
|
||||
early []kexpect
|
||||
wantErrEarly error
|
||||
|
||||
apply []kexpect
|
||||
wantErrApply error
|
||||
}
|
||||
|
||||
func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
t.Run("behaviour", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
state := &setupState{Params: tc.params}
|
||||
k := &kstub{t: t, want: slices.Concat(tc.early, []kexpect{{name: "\x00"}}, tc.apply)}
|
||||
errEarly := tc.op.early(state, k)
|
||||
k.expect("\x00")
|
||||
if !errors.Is(errEarly, tc.wantErrEarly) {
|
||||
t.Errorf("early: error = %v, want %v", errEarly, tc.wantErrEarly)
|
||||
}
|
||||
if errEarly != nil {
|
||||
goto out
|
||||
}
|
||||
|
||||
if err := tc.op.apply(state, k); !errors.Is(err, tc.wantErrApply) {
|
||||
t.Errorf("apply: error = %v, want %v", err, tc.wantErrApply)
|
||||
}
|
||||
|
||||
out:
|
||||
if len(k.want) != k.pos {
|
||||
count := k.pos - 1 // separator
|
||||
if count < len(tc.early) {
|
||||
t.Errorf("early: %d calls, want %d", count, len(tc.early))
|
||||
} else {
|
||||
t.Errorf("apply: %d calls, want %d", count-len(tc.early), len(tc.apply))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func newCheckedFile(t *testing.T, name, wantData string, closeErr error) osFile {
|
||||
f := &checkedOsFile{t: t, name: name, want: wantData, closeErr: closeErr}
|
||||
// check happens in Close, and cleanup is not guaranteed to run, so relying on it for sloppy implementations will cause sporadic test results
|
||||
f.cleanup = runtime.AddCleanup(f, func(name string) { f.t.Fatalf("checkedOsFile %s became unreachable without a call to Close", name) }, f.name)
|
||||
return f
|
||||
}
|
||||
|
||||
type checkedOsFile struct {
|
||||
t *testing.T
|
||||
name string
|
||||
want string
|
||||
closeErr error
|
||||
cleanup runtime.Cleanup
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (f *checkedOsFile) Name() string { return f.name }
|
||||
func (f *checkedOsFile) Stat() (fs.FileInfo, error) { panic("unreachable") }
|
||||
func (f *checkedOsFile) Close() error {
|
||||
defer f.cleanup.Stop()
|
||||
if f.String() != f.want {
|
||||
f.t.Errorf("checkedOsFile:\n%s\nwant\n%s", f.String(), f.want)
|
||||
return syscall.ENOTRECOVERABLE
|
||||
}
|
||||
return f.closeErr
|
||||
}
|
||||
|
||||
type writeErrOsFile struct{ err error }
|
||||
|
||||
func (writeErrOsFile) Name() string { panic("unreachable") }
|
||||
func (f writeErrOsFile) Write([]byte) (int, error) { return 0, f.err }
|
||||
func (writeErrOsFile) Stat() (fs.FileInfo, error) { panic("unreachable") }
|
||||
func (writeErrOsFile) Read([]byte) (int, error) { panic("unreachable") }
|
||||
func (writeErrOsFile) Close() error { panic("unreachable") }
|
||||
|
||||
type expectArgs = [5]any
|
||||
|
||||
type isDirFi bool
|
||||
|
||||
func (isDirFi) Name() string { panic("unreachable") }
|
||||
func (isDirFi) Size() int64 { panic("unreachable") }
|
||||
func (isDirFi) Mode() fs.FileMode { panic("unreachable") }
|
||||
func (isDirFi) ModTime() time.Time { panic("unreachable") }
|
||||
func (fi isDirFi) IsDir() bool { return bool(fi) }
|
||||
func (isDirFi) Sys() any { panic("unreachable") }
|
||||
|
||||
func stubDir(names ...string) []os.DirEntry {
|
||||
d := make([]os.DirEntry, len(names))
|
||||
for i, name := range names {
|
||||
d[i] = nameDentry(name)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type nameDentry string
|
||||
|
||||
func (e nameDentry) Name() string { return string(e) }
|
||||
func (nameDentry) IsDir() bool { panic("unreachable") }
|
||||
func (nameDentry) Type() fs.FileMode { panic("unreachable") }
|
||||
func (nameDentry) Info() (fs.FileInfo, error) { panic("unreachable") }
|
||||
|
||||
type kexpect struct {
|
||||
name string
|
||||
args expectArgs
|
||||
ret any
|
||||
err error
|
||||
}
|
||||
|
||||
func (k *kexpect) error(ok ...bool) error {
|
||||
if !slices.Contains(ok, false) {
|
||||
return k.err
|
||||
}
|
||||
return syscall.ENOTRECOVERABLE
|
||||
}
|
||||
|
||||
type kstub struct {
|
||||
t *testing.T
|
||||
want []kexpect
|
||||
pos int
|
||||
}
|
||||
|
||||
// expect checks name and returns the current kexpect and advances pos.
|
||||
func (k *kstub) expect(name string) (expect *kexpect) {
|
||||
if len(k.want) == k.pos {
|
||||
k.t.Fatal("expect: want too short")
|
||||
}
|
||||
expect = &k.want[k.pos]
|
||||
if name != expect.name {
|
||||
if expect.name == "\x00" {
|
||||
k.t.Fatalf("expect: func = %s, separator overrun", name)
|
||||
}
|
||||
if name == "\x00" {
|
||||
k.t.Fatalf("expect: separator, want %s", expect.name)
|
||||
}
|
||||
k.t.Fatalf("expect: func = %s, want %s", name, expect.name)
|
||||
}
|
||||
k.pos++
|
||||
return
|
||||
}
|
||||
|
||||
// checkArg checks an argument comparable with the == operator. Avoid using this with pointers.
|
||||
func checkArg[T comparable](k *kstub, arg string, got T, n int) bool {
|
||||
if k.pos == 0 {
|
||||
panic("invalid call to checkArg")
|
||||
}
|
||||
expect := k.want[k.pos-1]
|
||||
want, ok := expect.args[n].(T)
|
||||
if !ok || got != want {
|
||||
k.t.Errorf("%s: %s = %#v, want %#v (%d)", expect.name, arg, got, want, k.pos-1)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// checkArgReflect checks an argument of any type.
|
||||
func checkArgReflect(k *kstub, arg string, got any, n int) bool {
|
||||
if k.pos == 0 {
|
||||
panic("invalid call to checkArgReflect")
|
||||
}
|
||||
expect := k.want[k.pos-1]
|
||||
want := expect.args[n]
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
k.t.Errorf("%s: %s = %#v, want %#v (%d)", expect.name, arg, got, want, k.pos-1)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (k *kstub) setPtracer(pid uintptr) error {
|
||||
return k.expect("setPtracer").error(
|
||||
checkArg(k, "pid", pid, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) setDumpable(dumpable uintptr) error {
|
||||
return k.expect("setDumpable").error(
|
||||
checkArg(k, "dumpable", dumpable, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) setNoNewPrivs() error { return k.expect("setNoNewPrivs").err }
|
||||
func (k *kstub) lastcap() uintptr { return k.expect("setNoNewPrivs").ret.(uintptr) }
|
||||
|
||||
func (k *kstub) capset(hdrp *capHeader, datap *[2]capData) error {
|
||||
return k.expect("capset").error(
|
||||
checkArgReflect(k, "hdrp", hdrp, 0),
|
||||
checkArgReflect(k, "datap", datap, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) capBoundingSetDrop(cap uintptr) error {
|
||||
return k.expect("capBoundingSetDrop").error(
|
||||
checkArg(k, "cap", cap, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) capAmbientClearAll() error { return k.expect("capAmbientClearAll").err }
|
||||
|
||||
func (k *kstub) capAmbientRaise(cap uintptr) error {
|
||||
return k.expect("capAmbientRaise").error(
|
||||
checkArg(k, "cap", cap, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) isatty(fd int) bool {
|
||||
expect := k.expect("isatty")
|
||||
if !checkArg(k, "fd", fd, 0) {
|
||||
k.t.FailNow()
|
||||
}
|
||||
return expect.ret.(bool)
|
||||
}
|
||||
|
||||
func (k *kstub) receive(key string, e any, v **os.File) (closeFunc func() error, err error) {
|
||||
expect := k.expect("receive")
|
||||
return expect.ret.(func() error), expect.error(
|
||||
checkArg(k, "key", key, 0),
|
||||
checkArgReflect(k, "e", e, 1),
|
||||
checkArg(k, "v", v, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) bindMount(source, target string, flags uintptr, eq bool) error {
|
||||
return k.expect("bindMount").error(
|
||||
checkArg(k, "source", source, 0),
|
||||
checkArg(k, "target", target, 1),
|
||||
checkArg(k, "flags", flags, 2),
|
||||
checkArg(k, "eq", eq, 3))
|
||||
}
|
||||
|
||||
func (k *kstub) remount(target string, flags uintptr) error {
|
||||
return k.expect("remount").error(
|
||||
checkArg(k, "target", target, 0),
|
||||
checkArg(k, "flags", flags, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
||||
return k.expect("mountTmpfs").error(
|
||||
checkArg(k, "fsname", fsname, 0),
|
||||
checkArg(k, "target", target, 1),
|
||||
checkArg(k, "flags", flags, 2),
|
||||
checkArg(k, "size", size, 3),
|
||||
checkArg(k, "perm", perm, 4))
|
||||
}
|
||||
|
||||
func (k *kstub) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||
|
||||
return k.expect("ensureFile").error(
|
||||
checkArg(k, "name", name, 0),
|
||||
checkArg(k, "perm", perm, 1),
|
||||
checkArg(k, "pperm", pperm, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error {
|
||||
return k.expect("seccompLoad").error(
|
||||
checkArgReflect(k, "rules", rules, 0),
|
||||
checkArg(k, "flags", flags, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) notify(c chan<- os.Signal, sig ...os.Signal) {
|
||||
expect := k.expect("notify")
|
||||
if c == nil || expect.error(
|
||||
checkArgReflect(k, "sig", sig, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
|
||||
// export channel for external instrumentation
|
||||
if chanp, ok := expect.args[0].(*chan<- os.Signal); ok && chanp != nil {
|
||||
if *chanp != nil {
|
||||
panic(fmt.Sprintf("attempting reuse of %p", chanp))
|
||||
}
|
||||
*chanp = c
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) start(c *exec.Cmd) error {
|
||||
return k.expect("start").error(
|
||||
checkArg(k, "c.Path", c.Path, 0),
|
||||
checkArgReflect(k, "c.Args", c.Args, 1),
|
||||
checkArgReflect(k, "c.Env", c.Env, 2),
|
||||
checkArg(k, "c.Dir", c.Dir, 3))
|
||||
}
|
||||
|
||||
func (k *kstub) signal(c *exec.Cmd, sig os.Signal) error {
|
||||
return k.expect("signal").error(
|
||||
checkArg(k, "c.Path", c.Path, 0),
|
||||
checkArgReflect(k, "c.Args", c.Args, 1),
|
||||
checkArgReflect(k, "c.Env", c.Env, 2),
|
||||
checkArg(k, "c.Dir", c.Dir, 3),
|
||||
checkArg(k, "sig", sig, 4))
|
||||
}
|
||||
|
||||
func (k *kstub) evalSymlinks(path string) (string, error) {
|
||||
expect := k.expect("evalSymlinks")
|
||||
return expect.ret.(string), expect.error(
|
||||
checkArg(k, "path", path, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) exit(code int) {
|
||||
k.expect("exit")
|
||||
if !checkArg(k, "code", code, 0) {
|
||||
k.t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) getpid() int { return k.expect("getpid").ret.(int) }
|
||||
|
||||
func (k *kstub) stat(name string) (os.FileInfo, error) {
|
||||
expect := k.expect("stat")
|
||||
return expect.ret.(os.FileInfo), expect.error(
|
||||
checkArg(k, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) mkdir(name string, perm os.FileMode) error {
|
||||
return k.expect("mkdir").error(
|
||||
checkArg(k, "name", name, 0),
|
||||
checkArg(k, "perm", perm, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) mkdirTemp(dir, pattern string) (string, error) {
|
||||
expect := k.expect("mkdirTemp")
|
||||
return expect.ret.(string), expect.error(
|
||||
checkArg(k, "dir", dir, 0),
|
||||
checkArg(k, "pattern", pattern, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) mkdirAll(path string, perm os.FileMode) error {
|
||||
return k.expect("mkdirAll").error(
|
||||
checkArg(k, "path", path, 0),
|
||||
checkArg(k, "perm", perm, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) readdir(name string) ([]os.DirEntry, error) {
|
||||
expect := k.expect("readdir")
|
||||
return expect.ret.([]os.DirEntry), expect.error(
|
||||
checkArg(k, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) writeFile(name string, data []byte, perm os.FileMode) error {
|
||||
return k.expect("writeFile").error(
|
||||
checkArg(k, "name", name, 0),
|
||||
checkArgReflect(k, "data", data, 1),
|
||||
checkArg(k, "perm", perm, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) createTemp(dir, pattern string) (osFile, error) {
|
||||
expect := k.expect("createTemp")
|
||||
return expect.ret.(osFile), expect.error(
|
||||
checkArg(k, "dir", dir, 0),
|
||||
checkArg(k, "pattern", pattern, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) remove(name string) error {
|
||||
return k.expect("remove").error(
|
||||
checkArg(k, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) newFile(fd uintptr, name string) *os.File {
|
||||
expect := k.expect("newFile")
|
||||
if expect.error(
|
||||
checkArg(k, "fd", fd, 0),
|
||||
checkArg(k, "name", name, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
return expect.ret.(*os.File)
|
||||
}
|
||||
|
||||
func (k *kstub) symlink(oldname, newname string) error {
|
||||
return k.expect("symlink").error(
|
||||
checkArg(k, "oldname", oldname, 0),
|
||||
checkArg(k, "newname", newname, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) readlink(name string) (string, error) {
|
||||
expect := k.expect("readlink")
|
||||
return expect.ret.(string), expect.error(
|
||||
checkArg(k, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) umask(mask int) (oldmask int) {
|
||||
expect := k.expect("umask")
|
||||
if !checkArg(k, "mask", mask, 0) {
|
||||
k.t.FailNow()
|
||||
}
|
||||
return expect.ret.(int)
|
||||
}
|
||||
|
||||
func (k *kstub) sethostname(p []byte) (err error) {
|
||||
return k.expect("sethostname").error(
|
||||
checkArgReflect(k, "p", p, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) chdir(path string) (err error) {
|
||||
return k.expect("chdir").error(
|
||||
checkArg(k, "path", path, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) fchdir(fd int) (err error) {
|
||||
return k.expect("fchdir").error(
|
||||
checkArg(k, "fd", fd, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) open(path string, mode int, perm uint32) (fd int, err error) {
|
||||
expect := k.expect("open")
|
||||
return expect.ret.(int), expect.error(
|
||||
checkArg(k, "path", path, 0),
|
||||
checkArg(k, "mode", mode, 1),
|
||||
checkArg(k, "perm", perm, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) close(fd int) (err error) {
|
||||
return k.expect("close").error(
|
||||
checkArg(k, "fd", fd, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) pivotRoot(newroot, putold string) (err error) {
|
||||
return k.expect("pivotRoot").error(
|
||||
checkArg(k, "newroot", newroot, 0),
|
||||
checkArg(k, "putold", putold, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) mount(source, target, fstype string, flags uintptr, data string) (err error) {
|
||||
return k.expect("mount").error(
|
||||
checkArg(k, "source", source, 0),
|
||||
checkArg(k, "target", target, 1),
|
||||
checkArg(k, "fstype", fstype, 2),
|
||||
checkArg(k, "flags", flags, 3),
|
||||
checkArg(k, "data", data, 4))
|
||||
}
|
||||
|
||||
func (k *kstub) unmount(target string, flags int) (err error) {
|
||||
return k.expect("unmount").error(
|
||||
checkArg(k, "target", target, 0),
|
||||
checkArg(k, "flags", flags, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *syscall.Rusage) (wpid int, err error) {
|
||||
expect := k.expect("wait4")
|
||||
return expect.ret.(int), expect.error(
|
||||
checkArg(k, "pid", pid, 0),
|
||||
checkArg(k, "wstatus", wstatus, 1),
|
||||
checkArg(k, "options", options, 2),
|
||||
checkArg(k, "rusage", rusage, 3))
|
||||
}
|
||||
|
||||
func (k *kstub) printf(format string, v ...any) {
|
||||
if k.expect("printf").error(
|
||||
checkArg(k, "format", format, 0),
|
||||
checkArgReflect(k, "v", v, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) fatal(v ...any) {
|
||||
if k.expect("fatal").error(
|
||||
checkArgReflect(k, "v", v, 0)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) fatalf(format string, v ...any) {
|
||||
if k.expect("fatalf").error(
|
||||
checkArg(k, "format", format, 0),
|
||||
checkArgReflect(k, "v", v, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) verbose(v ...any) {
|
||||
if k.expect("verbose").error(
|
||||
checkArgReflect(k, "v", v, 0)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) verbosef(format string, v ...any) {
|
||||
if k.expect("verbosef").error(
|
||||
checkArg(k, "format", format, 0),
|
||||
checkArgReflect(k, "v", v, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) suspend() { k.expect("suspend") }
|
||||
func (k *kstub) resume() bool { return k.expect("resume").ret.(bool) }
|
||||
func (k *kstub) beforeExit() { k.expect("beforeExit") }
|
||||
|
||||
func (k *kstub) printBaseErr(err error, fallback string) {
|
||||
if k.expect("printBaseErr").error(
|
||||
checkArgReflect(k, "err", err, 0),
|
||||
checkArg(k, "fallback", fallback, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
}
|
@ -3,10 +3,8 @@ package container
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path"
|
||||
"runtime"
|
||||
"slices"
|
||||
@ -46,9 +44,9 @@ type (
|
||||
// Implementations of this interface are sent as a stream of gobs.
|
||||
Op interface {
|
||||
// early is called in host root.
|
||||
early(state *setupState) error
|
||||
early(state *setupState, k syscallDispatcher) error
|
||||
// apply is called in intermediate root.
|
||||
apply(state *setupState) error
|
||||
apply(state *setupState, k syscallDispatcher) error
|
||||
|
||||
prefix() string
|
||||
Is(op Op) bool
|
||||
@ -82,16 +80,20 @@ type initParams struct {
|
||||
Verbose bool
|
||||
}
|
||||
|
||||
func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
runtime.LockOSThread()
|
||||
prepare("init")
|
||||
func Init(prepareLogger func(prefix string), setVerbose func(verbose bool)) {
|
||||
initEntrypoint(prepareLogger, setVerbose, direct{})
|
||||
}
|
||||
|
||||
if os.Getpid() != 1 {
|
||||
log.Fatal("this process must run as pid 1")
|
||||
func initEntrypoint(prepareLogger func(prefix string), setVerbose func(verbose bool), k syscallDispatcher) {
|
||||
runtime.LockOSThread()
|
||||
prepareLogger("init")
|
||||
|
||||
if k.getpid() != 1 {
|
||||
k.fatal("this process must run as pid 1")
|
||||
}
|
||||
|
||||
if err := SetPtracer(0); err != nil {
|
||||
msg.Verbosef("cannot enable ptrace protection via Yama LSM: %v", err)
|
||||
if err := k.setPtracer(0); err != nil {
|
||||
k.verbosef("cannot enable ptrace protection via Yama LSM: %v", err)
|
||||
// not fatal: this program has no additional privileges at initial program start
|
||||
}
|
||||
|
||||
@ -101,64 +103,64 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
setupFile *os.File
|
||||
offsetSetup int
|
||||
)
|
||||
if f, err := Receive(setupEnv, ¶ms, &setupFile); err != nil {
|
||||
if f, err := k.receive(setupEnv, ¶ms, &setupFile); err != nil {
|
||||
if errors.Is(err, EBADF) {
|
||||
log.Fatal("invalid setup descriptor")
|
||||
k.fatal("invalid setup descriptor")
|
||||
}
|
||||
if errors.Is(err, ErrNotSet) {
|
||||
log.Fatal("HAKUREI_SETUP not set")
|
||||
k.fatal("HAKUREI_SETUP not set")
|
||||
}
|
||||
|
||||
log.Fatalf("cannot decode init setup payload: %v", err)
|
||||
k.fatalf("cannot decode init setup payload: %v", err)
|
||||
} else {
|
||||
if params.Ops == nil {
|
||||
log.Fatal("invalid setup parameters")
|
||||
k.fatal("invalid setup parameters")
|
||||
}
|
||||
if params.ParentPerm == 0 {
|
||||
params.ParentPerm = 0755
|
||||
}
|
||||
|
||||
setVerbose(params.Verbose)
|
||||
msg.Verbose("received setup parameters")
|
||||
k.verbose("received setup parameters")
|
||||
closeSetup = f
|
||||
offsetSetup = int(setupFile.Fd() + 1)
|
||||
}
|
||||
|
||||
// write uid/gid map here so parent does not need to set dumpable
|
||||
if err := SetDumpable(SUID_DUMP_USER); err != nil {
|
||||
log.Fatalf("cannot set SUID_DUMP_USER: %s", err)
|
||||
if err := k.setDumpable(SUID_DUMP_USER); err != nil {
|
||||
k.fatalf("cannot set SUID_DUMP_USER: %s", err)
|
||||
}
|
||||
if err := os.WriteFile(FHSProc+"self/uid_map",
|
||||
if err := k.writeFile(FHSProc+"self/uid_map",
|
||||
append([]byte{}, strconv.Itoa(params.Uid)+" "+strconv.Itoa(params.HostUid)+" 1\n"...),
|
||||
0); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
k.fatalf("%v", err)
|
||||
}
|
||||
if err := os.WriteFile(FHSProc+"self/setgroups",
|
||||
if err := k.writeFile(FHSProc+"self/setgroups",
|
||||
[]byte("deny\n"),
|
||||
0); err != nil && !os.IsNotExist(err) {
|
||||
log.Fatalf("%v", err)
|
||||
k.fatalf("%v", err)
|
||||
}
|
||||
if err := os.WriteFile(FHSProc+"self/gid_map",
|
||||
if err := k.writeFile(FHSProc+"self/gid_map",
|
||||
append([]byte{}, strconv.Itoa(params.Gid)+" "+strconv.Itoa(params.HostGid)+" 1\n"...),
|
||||
0); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
k.fatalf("%v", err)
|
||||
}
|
||||
if err := SetDumpable(SUID_DUMP_DISABLE); err != nil {
|
||||
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
|
||||
if err := k.setDumpable(SUID_DUMP_DISABLE); err != nil {
|
||||
k.fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
|
||||
}
|
||||
|
||||
oldmask := Umask(0)
|
||||
oldmask := k.umask(0)
|
||||
if params.Hostname != "" {
|
||||
if err := Sethostname([]byte(params.Hostname)); err != nil {
|
||||
log.Fatalf("cannot set hostname: %v", err)
|
||||
if err := k.sethostname([]byte(params.Hostname)); err != nil {
|
||||
k.fatalf("cannot set hostname: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// cache sysctl before pivot_root
|
||||
LastCap()
|
||||
k.lastcap()
|
||||
|
||||
if err := Mount(zeroString, FHSRoot, zeroString, MS_SILENT|MS_SLAVE|MS_REC, zeroString); err != nil {
|
||||
log.Fatalf("cannot make / rslave: %v", err)
|
||||
if err := k.mount(zeroString, FHSRoot, zeroString, MS_SILENT|MS_SLAVE|MS_REC, zeroString); err != nil {
|
||||
k.fatalf("cannot make / rslave: %v", err)
|
||||
}
|
||||
|
||||
state := &setupState{Params: ¶ms.Params}
|
||||
@ -169,40 +171,40 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
the state of the mount namespace */
|
||||
for i, op := range *params.Ops {
|
||||
if op == nil || !op.Valid() {
|
||||
log.Fatalf("invalid op at index %d", i)
|
||||
k.fatalf("invalid op at index %d", i)
|
||||
}
|
||||
|
||||
if err := op.early(state); err != nil {
|
||||
msg.PrintBaseErr(err,
|
||||
fmt.Sprintf("cannot prepare op %d:", i))
|
||||
msg.BeforeExit()
|
||||
os.Exit(1)
|
||||
if err := op.early(state, k); err != nil {
|
||||
k.printBaseErr(err,
|
||||
fmt.Sprintf("cannot prepare op at index %d:", i))
|
||||
k.beforeExit()
|
||||
k.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if err := Mount(SourceTmpfsRootfs, intermediateHostPath, FstypeTmpfs, MS_NODEV|MS_NOSUID, zeroString); err != nil {
|
||||
log.Fatalf("cannot mount intermediate root: %v", err)
|
||||
if err := k.mount(SourceTmpfsRootfs, intermediateHostPath, FstypeTmpfs, MS_NODEV|MS_NOSUID, zeroString); err != nil {
|
||||
k.fatalf("cannot mount intermediate root: %v", err)
|
||||
}
|
||||
if err := os.Chdir(intermediateHostPath); err != nil {
|
||||
log.Fatalf("cannot enter base path: %v", err)
|
||||
if err := k.chdir(intermediateHostPath); err != nil {
|
||||
k.fatalf("cannot enter intermediate host path: %v", err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir(sysrootDir, 0755); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
if err := k.mkdir(sysrootDir, 0755); err != nil {
|
||||
k.fatalf("%v", err)
|
||||
}
|
||||
if err := Mount(sysrootDir, sysrootDir, zeroString, MS_SILENT|MS_BIND|MS_REC, zeroString); err != nil {
|
||||
log.Fatalf("cannot bind sysroot: %v", err)
|
||||
if err := k.mount(sysrootDir, sysrootDir, zeroString, MS_SILENT|MS_BIND|MS_REC, zeroString); err != nil {
|
||||
k.fatalf("cannot bind sysroot: %v", err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir(hostDir, 0755); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
if err := k.mkdir(hostDir, 0755); err != nil {
|
||||
k.fatalf("%v", err)
|
||||
}
|
||||
// pivot_root uncovers intermediateHostPath in hostDir
|
||||
if err := PivotRoot(intermediateHostPath, hostDir); err != nil {
|
||||
log.Fatalf("cannot pivot into intermediate root: %v", err)
|
||||
if err := k.pivotRoot(intermediateHostPath, hostDir); err != nil {
|
||||
k.fatalf("cannot pivot into intermediate root: %v", err)
|
||||
}
|
||||
if err := os.Chdir(FHSRoot); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
if err := k.chdir(FHSRoot); err != nil {
|
||||
k.fatalf("cannot enter intermediate root: %v", err)
|
||||
}
|
||||
|
||||
/* apply is called right after pivot_root and entering the new root;
|
||||
@ -211,62 +213,62 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
chdir is allowed but discouraged */
|
||||
for i, op := range *params.Ops {
|
||||
// ops already checked during early setup
|
||||
msg.Verbosef("%s %s", op.prefix(), op)
|
||||
if err := op.apply(state); err != nil {
|
||||
msg.PrintBaseErr(err,
|
||||
fmt.Sprintf("cannot apply op %d:", i))
|
||||
msg.BeforeExit()
|
||||
os.Exit(1)
|
||||
k.verbosef("%s %s", op.prefix(), op)
|
||||
if err := op.apply(state, k); err != nil {
|
||||
k.printBaseErr(err,
|
||||
fmt.Sprintf("cannot apply op at index %d:", i))
|
||||
k.beforeExit()
|
||||
k.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// setup requiring host root complete at this point
|
||||
if err := Mount(hostDir, hostDir, zeroString, MS_SILENT|MS_REC|MS_PRIVATE, zeroString); err != nil {
|
||||
log.Fatalf("cannot make host root rprivate: %v", err)
|
||||
if err := k.mount(hostDir, hostDir, zeroString, MS_SILENT|MS_REC|MS_PRIVATE, zeroString); err != nil {
|
||||
k.fatalf("cannot make host root rprivate: %v", err)
|
||||
}
|
||||
if err := Unmount(hostDir, MNT_DETACH); err != nil {
|
||||
log.Fatalf("cannot unmount host root: %v", err)
|
||||
if err := k.unmount(hostDir, MNT_DETACH); err != nil {
|
||||
k.fatalf("cannot unmount host root: %v", err)
|
||||
}
|
||||
|
||||
{
|
||||
var fd int
|
||||
if err := IgnoringEINTR(func() (err error) {
|
||||
fd, err = Open(FHSRoot, O_DIRECTORY|O_RDONLY, 0)
|
||||
fd, err = k.open(FHSRoot, O_DIRECTORY|O_RDONLY, 0)
|
||||
return
|
||||
}); err != nil {
|
||||
log.Fatalf("cannot open intermediate root: %v", err)
|
||||
k.fatalf("cannot open intermediate root: %v", err)
|
||||
}
|
||||
if err := os.Chdir(sysrootPath); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
if err := k.chdir(sysrootPath); err != nil {
|
||||
k.fatalf("cannot enter sysroot: %v", err)
|
||||
}
|
||||
|
||||
if err := PivotRoot(".", "."); err != nil {
|
||||
log.Fatalf("cannot pivot into sysroot: %v", err)
|
||||
if err := k.pivotRoot(".", "."); err != nil {
|
||||
k.fatalf("cannot pivot into sysroot: %v", err)
|
||||
}
|
||||
if err := Fchdir(fd); err != nil {
|
||||
log.Fatalf("cannot re-enter intermediate root: %v", err)
|
||||
if err := k.fchdir(fd); err != nil {
|
||||
k.fatalf("cannot re-enter intermediate root: %v", err)
|
||||
}
|
||||
if err := Unmount(".", MNT_DETACH); err != nil {
|
||||
log.Fatalf("cannot unmount intemediate root: %v", err)
|
||||
if err := k.unmount(".", MNT_DETACH); err != nil {
|
||||
k.fatalf("cannot unmount intemediate root: %v", err)
|
||||
}
|
||||
if err := os.Chdir(FHSRoot); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
if err := k.chdir(FHSRoot); err != nil {
|
||||
k.fatalf("cannot enter root: %v", err)
|
||||
}
|
||||
|
||||
if err := Close(fd); err != nil {
|
||||
log.Fatalf("cannot close intermediate root: %v", err)
|
||||
if err := k.close(fd); err != nil {
|
||||
k.fatalf("cannot close intermediate root: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, _, errno := Syscall(SYS_PRCTL, PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0); errno != 0 {
|
||||
log.Fatalf("cannot clear the ambient capability set: %v", errno)
|
||||
if err := k.capAmbientClearAll(); err != nil {
|
||||
k.fatalf("cannot clear the ambient capability set: %v", err)
|
||||
}
|
||||
for i := uintptr(0); i <= LastCap(); i++ {
|
||||
for i := uintptr(0); i <= k.lastcap(); i++ {
|
||||
if params.Privileged && i == CAP_SYS_ADMIN {
|
||||
continue
|
||||
}
|
||||
if _, _, errno := Syscall(SYS_PRCTL, PR_CAPBSET_DROP, i, 0); errno != 0 {
|
||||
log.Fatalf("cannot drop capability from bonding set: %v", errno)
|
||||
if err := k.capBoundingSetDrop(i); err != nil {
|
||||
k.fatalf("cannot drop capability from bounding set: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,38 +276,38 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
if params.Privileged {
|
||||
keep[capToIndex(CAP_SYS_ADMIN)] |= capToMask(CAP_SYS_ADMIN)
|
||||
|
||||
if _, _, errno := Syscall(SYS_PRCTL, PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_SYS_ADMIN); errno != 0 {
|
||||
log.Fatalf("cannot raise CAP_SYS_ADMIN: %v", errno)
|
||||
if err := k.capAmbientRaise(CAP_SYS_ADMIN); err != nil {
|
||||
k.fatalf("cannot raise CAP_SYS_ADMIN: %v", err)
|
||||
}
|
||||
}
|
||||
if err := capset(
|
||||
if err := k.capset(
|
||||
&capHeader{_LINUX_CAPABILITY_VERSION_3, 0},
|
||||
&[2]capData{{0, keep[0], keep[0]}, {0, keep[1], keep[1]}},
|
||||
); err != nil {
|
||||
log.Fatalf("cannot capset: %v", err)
|
||||
k.fatalf("cannot capset: %v", err)
|
||||
}
|
||||
|
||||
if !params.SeccompDisable {
|
||||
rules := params.SeccompRules
|
||||
if len(rules) == 0 { // non-empty rules slice always overrides presets
|
||||
msg.Verbosef("resolving presets %#x", params.SeccompPresets)
|
||||
k.verbosef("resolving presets %#x", params.SeccompPresets)
|
||||
rules = seccomp.Preset(params.SeccompPresets, params.SeccompFlags)
|
||||
}
|
||||
if err := seccomp.Load(rules, params.SeccompFlags); err != nil {
|
||||
if err := k.seccompLoad(rules, params.SeccompFlags); err != nil {
|
||||
// this also indirectly asserts PR_SET_NO_NEW_PRIVS
|
||||
log.Fatalf("cannot load syscall filter: %v", err)
|
||||
k.fatalf("cannot load syscall filter: %v", err)
|
||||
}
|
||||
msg.Verbosef("%d filter rules loaded", len(rules))
|
||||
k.verbosef("%d filter rules loaded", len(rules))
|
||||
} else {
|
||||
msg.Verbose("syscall filter not configured")
|
||||
k.verbose("syscall filter not configured")
|
||||
}
|
||||
|
||||
extraFiles := make([]*os.File, params.Count)
|
||||
for i := range extraFiles {
|
||||
// setup fd is placed before all extra files
|
||||
extraFiles[i] = os.NewFile(uintptr(offsetSetup+i), "extra file "+strconv.Itoa(i))
|
||||
extraFiles[i] = k.newFile(uintptr(offsetSetup+i), "extra file "+strconv.Itoa(i))
|
||||
}
|
||||
Umask(oldmask)
|
||||
k.umask(oldmask)
|
||||
|
||||
cmd := exec.Command(params.Path.String())
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
@ -314,14 +316,14 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
cmd.ExtraFiles = extraFiles
|
||||
cmd.Dir = params.Dir.String()
|
||||
|
||||
msg.Verbosef("starting initial program %s", params.Path)
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
k.verbosef("starting initial program %s", params.Path)
|
||||
if err := k.start(cmd); err != nil {
|
||||
k.fatalf("%v", err)
|
||||
}
|
||||
msg.Suspend()
|
||||
k.suspend()
|
||||
|
||||
if err := closeSetup(); err != nil {
|
||||
log.Printf("cannot close setup pipe: %v", err)
|
||||
k.printf("cannot close setup pipe: %v", err)
|
||||
// not fatal
|
||||
}
|
||||
|
||||
@ -351,11 +353,11 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
|
||||
err = EINTR
|
||||
for errors.Is(err, EINTR) {
|
||||
wpid, err = Wait4(-1, &wstatus, 0, nil)
|
||||
wpid, err = k.wait4(-1, &wstatus, 0, nil)
|
||||
}
|
||||
}
|
||||
if !errors.Is(err, ECHILD) {
|
||||
log.Printf("unexpected wait4 response: %v", err)
|
||||
k.printf("unexpected wait4 response: %v", err)
|
||||
}
|
||||
|
||||
close(done)
|
||||
@ -363,7 +365,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
|
||||
// handle signals to dump withheld messages
|
||||
sig := make(chan os.Signal, 2)
|
||||
signal.Notify(sig, os.Interrupt, CancelSignal)
|
||||
k.notify(sig, os.Interrupt, CancelSignal)
|
||||
|
||||
// closed after residualProcessTimeout has elapsed after initial process death
|
||||
timeout := make(chan struct{})
|
||||
@ -372,45 +374,48 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
for {
|
||||
select {
|
||||
case s := <-sig:
|
||||
if msg.Resume() {
|
||||
msg.Verbosef("%s after process start", s.String())
|
||||
if k.resume() {
|
||||
k.verbosef("%s after process start", s.String())
|
||||
} else {
|
||||
msg.Verbosef("got %s", s.String())
|
||||
k.verbosef("got %s", s.String())
|
||||
}
|
||||
if s == CancelSignal && params.ForwardCancel && cmd.Process != nil {
|
||||
msg.Verbose("forwarding context cancellation")
|
||||
if err := cmd.Process.Signal(os.Interrupt); err != nil {
|
||||
log.Printf("cannot forward cancellation: %v", err)
|
||||
k.verbose("forwarding context cancellation")
|
||||
if err := k.signal(cmd, os.Interrupt); err != nil {
|
||||
k.printf("cannot forward cancellation: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
os.Exit(0)
|
||||
k.exit(0)
|
||||
|
||||
case w := <-info:
|
||||
if w.wpid == cmd.Process.Pid {
|
||||
// initial process exited, output is most likely available again
|
||||
msg.Resume()
|
||||
k.resume()
|
||||
|
||||
switch {
|
||||
case w.wstatus.Exited():
|
||||
r = w.wstatus.ExitStatus()
|
||||
msg.Verbosef("initial process exited with code %d", w.wstatus.ExitStatus())
|
||||
k.verbosef("initial process exited with code %d", w.wstatus.ExitStatus())
|
||||
case w.wstatus.Signaled():
|
||||
r = 128 + int(w.wstatus.Signal())
|
||||
msg.Verbosef("initial process exited with signal %s", w.wstatus.Signal())
|
||||
k.verbosef("initial process exited with signal %s", w.wstatus.Signal())
|
||||
default:
|
||||
r = 255
|
||||
msg.Verbosef("initial process exited with status %#x", w.wstatus)
|
||||
k.verbosef("initial process exited with status %#x", w.wstatus)
|
||||
}
|
||||
|
||||
go func() { time.Sleep(params.AdoptWaitDelay); close(timeout) }()
|
||||
}
|
||||
|
||||
case <-done:
|
||||
msg.BeforeExit()
|
||||
os.Exit(r)
|
||||
k.beforeExit()
|
||||
k.exit(r)
|
||||
|
||||
case <-timeout:
|
||||
log.Println("timeout exceeded waiting for lingering processes")
|
||||
msg.BeforeExit()
|
||||
os.Exit(r)
|
||||
k.printf("timeout exceeded waiting for lingering processes")
|
||||
k.beforeExit()
|
||||
k.exit(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,7 @@ import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
. "syscall"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func init() { gob.Register(new(BindMountOp)) }
|
||||
@ -35,8 +34,8 @@ const (
|
||||
BindDevice
|
||||
)
|
||||
|
||||
func (b *BindMountOp) early(*setupState) error {
|
||||
if pathname, err := filepath.EvalSymlinks(b.Source.String()); err != nil {
|
||||
func (b *BindMountOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
if pathname, err := k.evalSymlinks(b.Source.String()); err != nil {
|
||||
if os.IsNotExist(err) && b.Flags&BindOptional != 0 {
|
||||
// leave sourceFinal as nil
|
||||
return nil
|
||||
@ -48,11 +47,11 @@ func (b *BindMountOp) early(*setupState) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BindMountOp) apply(*setupState) error {
|
||||
func (b *BindMountOp) apply(_ *setupState, k syscallDispatcher) error {
|
||||
if b.sourceFinal == nil {
|
||||
if b.Flags&BindOptional == 0 {
|
||||
// unreachable
|
||||
return EBADE
|
||||
return msg.WrapErr(os.ErrClosed, "impossible bind state reached")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -62,25 +61,25 @@ func (b *BindMountOp) apply(*setupState) error {
|
||||
|
||||
// this perm value emulates bwrap behaviour as it clears bits from 0755 based on
|
||||
// op->perms which is never set for any bind setup op so always results in 0700
|
||||
if fi, err := os.Stat(source); err != nil {
|
||||
if fi, err := k.stat(source); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else if fi.IsDir() {
|
||||
if err = os.MkdirAll(target, 0700); err != nil {
|
||||
if err = k.mkdirAll(target, 0700); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
} else if err = ensureFile(target, 0444, 0700); err != nil {
|
||||
} else if err = k.ensureFile(target, 0444, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var flags uintptr = MS_REC
|
||||
var flags uintptr = syscall.MS_REC
|
||||
if b.Flags&BindWritable == 0 {
|
||||
flags |= MS_RDONLY
|
||||
flags |= syscall.MS_RDONLY
|
||||
}
|
||||
if b.Flags&BindDevice == 0 {
|
||||
flags |= MS_NODEV
|
||||
flags |= syscall.MS_NODEV
|
||||
}
|
||||
|
||||
return hostProc.bindMount(source, target, flags, b.sourceFinal == b.Target)
|
||||
return k.bindMount(source, target, flags, b.sourceFinal == b.Target)
|
||||
}
|
||||
|
||||
func (b *BindMountOp) Is(op Op) bool {
|
||||
|
@ -1,8 +1,134 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBindMountOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"ENOENT not optional", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/bin/"),
|
||||
Target: MustAbs("/bin/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/bin/"}, "", syscall.ENOENT},
|
||||
}, wrapErrSelf(syscall.ENOENT), nil, nil},
|
||||
|
||||
{"skip optional", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/bin/"),
|
||||
Target: MustAbs("/bin/"),
|
||||
Flags: BindOptional,
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/bin/"}, "", syscall.ENOENT},
|
||||
}, nil, nil, nil},
|
||||
|
||||
{"success optional", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/bin/"),
|
||||
Target: MustAbs("/bin/"),
|
||||
Flags: BindOptional,
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/bin/"}, "/usr/bin", nil},
|
||||
}, nil, []kexpect{
|
||||
{"stat", expectArgs{"/host/usr/bin"}, isDirFi(true), nil},
|
||||
{"mkdirAll", expectArgs{"/sysroot/bin", os.FileMode(0700)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/usr/bin", "/sysroot/bin", uintptr(0x4005), false}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"ensureFile device", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/dev/null"),
|
||||
Target: MustAbs("/dev/null"),
|
||||
Flags: BindWritable | BindDevice,
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/dev/null"}, "/dev/null", nil},
|
||||
}, nil, []kexpect{
|
||||
{"stat", expectArgs{"/host/dev/null"}, isDirFi(false), nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0700)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"success device ro", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/dev/null"),
|
||||
Target: MustAbs("/dev/null"),
|
||||
Flags: BindDevice,
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/dev/null"}, "/dev/null", nil},
|
||||
}, nil, []kexpect{
|
||||
{"stat", expectArgs{"/host/dev/null"}, isDirFi(false), nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0700)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0x4001), false}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success device", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/dev/null"),
|
||||
Target: MustAbs("/dev/null"),
|
||||
Flags: BindWritable | BindDevice,
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/dev/null"}, "/dev/null", nil},
|
||||
}, nil, []kexpect{
|
||||
{"stat", expectArgs{"/host/dev/null"}, isDirFi(false), nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0700)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0x4000), false}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"evalSymlinks", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/bin/"),
|
||||
Target: MustAbs("/bin/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/bin/"}, "/usr/bin", errUnique},
|
||||
}, wrapErrSelf(errUnique), nil, nil},
|
||||
|
||||
{"stat", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/bin/"),
|
||||
Target: MustAbs("/bin/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/bin/"}, "/usr/bin", nil},
|
||||
}, nil, []kexpect{
|
||||
{"stat", expectArgs{"/host/usr/bin"}, isDirFi(true), errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"mkdirAll", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/bin/"),
|
||||
Target: MustAbs("/bin/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/bin/"}, "/usr/bin", nil},
|
||||
}, nil, []kexpect{
|
||||
{"stat", expectArgs{"/host/usr/bin"}, isDirFi(true), nil},
|
||||
{"mkdirAll", expectArgs{"/sysroot/bin", os.FileMode(0700)}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"bindMount", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/bin/"),
|
||||
Target: MustAbs("/bin/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/bin/"}, "/usr/bin", nil},
|
||||
}, nil, []kexpect{
|
||||
{"stat", expectArgs{"/host/usr/bin"}, isDirFi(true), nil},
|
||||
{"mkdirAll", expectArgs{"/sysroot/bin", os.FileMode(0700)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/usr/bin", "/sysroot/bin", uintptr(0x4005), false}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"success", new(Params), &BindMountOp{
|
||||
Source: MustAbs("/bin/"),
|
||||
Target: MustAbs("/bin/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/bin/"}, "/usr/bin", nil},
|
||||
}, nil, []kexpect{
|
||||
{"stat", expectArgs{"/host/usr/bin"}, isDirFi(true), nil},
|
||||
{"mkdirAll", expectArgs{"/sysroot/bin", os.FileMode(0700)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/usr/bin", "/sysroot/bin", uintptr(0x4005), false}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
t.Run("unreachable", func(t *testing.T) {
|
||||
t.Run("nil sourceFinal not optional", func(t *testing.T) {
|
||||
wantErr := msg.WrapErr(os.ErrClosed, "impossible bind state reached")
|
||||
if err := new(BindMountOp).apply(nil, nil); !errors.Is(err, wantErr) {
|
||||
t.Errorf("apply: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*BindMountOp)(nil), false},
|
||||
{"zero", new(BindMountOp), false},
|
||||
|
@ -3,10 +3,8 @@ package container
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
. "syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func init() { gob.Register(new(MountDevOp)) }
|
||||
@ -33,21 +31,21 @@ type MountDevOp struct {
|
||||
Write bool
|
||||
}
|
||||
|
||||
func (d *MountDevOp) Valid() bool { return d != nil && d.Target != nil }
|
||||
func (d *MountDevOp) early(*setupState) error { return nil }
|
||||
func (d *MountDevOp) apply(state *setupState) error {
|
||||
func (d *MountDevOp) Valid() bool { return d != nil && d.Target != nil }
|
||||
func (d *MountDevOp) early(*setupState, syscallDispatcher) error { return nil }
|
||||
func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
target := toSysroot(d.Target.String())
|
||||
|
||||
if err := mountTmpfs(SourceTmpfsDevtmpfs, target, MS_NOSUID|MS_NODEV, 0, state.ParentPerm); err != nil {
|
||||
if err := k.mountTmpfs(SourceTmpfsDevtmpfs, target, MS_NOSUID|MS_NODEV, 0, state.ParentPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range []string{"null", "zero", "full", "random", "urandom", "tty"} {
|
||||
targetPath := path.Join(target, name)
|
||||
if err := ensureFile(targetPath, 0444, state.ParentPerm); err != nil {
|
||||
if err := k.ensureFile(targetPath, 0444, state.ParentPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hostProc.bindMount(
|
||||
if err := k.bindMount(
|
||||
toHost(FHSDev+name),
|
||||
targetPath,
|
||||
0,
|
||||
@ -57,7 +55,7 @@ func (d *MountDevOp) apply(state *setupState) error {
|
||||
}
|
||||
}
|
||||
for i, name := range []string{"stdin", "stdout", "stderr"} {
|
||||
if err := os.Symlink(
|
||||
if err := k.symlink(
|
||||
FHSProc+"self/fd/"+string(rune(i+'0')),
|
||||
path.Join(target, name),
|
||||
); err != nil {
|
||||
@ -69,34 +67,33 @@ func (d *MountDevOp) apply(state *setupState) error {
|
||||
{FHSProc + "kcore", "core"},
|
||||
{"pts/ptmx", "ptmx"},
|
||||
} {
|
||||
if err := os.Symlink(pair[0], path.Join(target, pair[1])); err != nil {
|
||||
if err := k.symlink(pair[0], path.Join(target, pair[1])); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
}
|
||||
|
||||
devPtsPath := path.Join(target, "pts")
|
||||
for _, name := range []string{path.Join(target, "shm"), devPtsPath} {
|
||||
if err := os.Mkdir(name, state.ParentPerm); err != nil {
|
||||
if err := k.mkdir(name, state.ParentPerm); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := Mount(SourceDevpts, devPtsPath, FstypeDevpts, MS_NOSUID|MS_NOEXEC,
|
||||
if err := k.mount(SourceDevpts, devPtsPath, FstypeDevpts, MS_NOSUID|MS_NOEXEC,
|
||||
"newinstance,ptmxmode=0666,mode=620"); err != nil {
|
||||
return wrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot mount devpts on %q:", devPtsPath))
|
||||
}
|
||||
|
||||
if state.RetainSession {
|
||||
var buf [8]byte
|
||||
if _, _, errno := Syscall(SYS_IOCTL, 1, TIOCGWINSZ, uintptr(unsafe.Pointer(&buf[0]))); errno == 0 {
|
||||
if k.isatty(Stdout) {
|
||||
consolePath := path.Join(target, "console")
|
||||
if err := ensureFile(consolePath, 0444, state.ParentPerm); err != nil {
|
||||
if err := k.ensureFile(consolePath, 0444, state.ParentPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
if name, err := os.Readlink(hostProc.stdout()); err != nil {
|
||||
if name, err := k.readlink(hostProc.stdout()); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else if err = hostProc.bindMount(
|
||||
} else if err = k.bindMount(
|
||||
toHost(name),
|
||||
consolePath,
|
||||
0,
|
||||
@ -109,10 +106,10 @@ func (d *MountDevOp) apply(state *setupState) error {
|
||||
|
||||
if d.Mqueue {
|
||||
mqueueTarget := path.Join(target, "mqueue")
|
||||
if err := os.Mkdir(mqueueTarget, state.ParentPerm); err != nil {
|
||||
if err := k.mkdir(mqueueTarget, state.ParentPerm); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
if err := Mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil {
|
||||
if err := k.mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil {
|
||||
return wrapErrSuffix(err, "cannot mount mqueue:")
|
||||
}
|
||||
}
|
||||
@ -120,7 +117,7 @@ func (d *MountDevOp) apply(state *setupState) error {
|
||||
if d.Write {
|
||||
return nil
|
||||
}
|
||||
return wrapErrSuffix(hostProc.remount(target, MS_RDONLY),
|
||||
return wrapErrSuffix(k.remount(target, MS_RDONLY),
|
||||
fmt.Sprintf("cannot remount %q:", target))
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,723 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMountDevOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"mountTmpfs", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"ensureFile null", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"bindMount null", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"ensureFile zero", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"bindMount zero", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"ensureFile full", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"bindMount full", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"ensureFile random", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"bindMount random", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"ensureFile urandom", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"bindMount urandom", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"ensureFile tty", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"bindMount tty", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"symlink stdin", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"symlink stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"symlink stderr", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"symlink fd", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"symlink kcore", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"symlink ptmx", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"mkdir shm", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"mkdir devpts", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"mount devpts", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, errUnique},
|
||||
}, wrapErrSuffix(errUnique, `cannot mount devpts on "/sysroot/dev/pts":`)},
|
||||
|
||||
{"ensureFile stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, true, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/console", os.FileMode(0444), os.FileMode(0750)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"readlink stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, true, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/console", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"readlink", expectArgs{"/host/proc/self/fd/1"}, "", errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"bindMount stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, true, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/console", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"readlink", expectArgs{"/host/proc/self/fd/1"}, "/dev/pts/2", nil},
|
||||
{"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"mkdir mqueue", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, true, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/console", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"readlink", expectArgs{"/host/proc/self/fd/1"}, "/dev/pts/2", nil},
|
||||
{"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0750)}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"mount mqueue", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, true, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/console", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"readlink", expectArgs{"/host/proc/self/fd/1"}, "/dev/pts/2", nil},
|
||||
{"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"mqueue", "/sysroot/dev/mqueue", "mqueue", uintptr(0xe), ""}, nil, errUnique},
|
||||
}, wrapErrSuffix(errUnique, "cannot mount mqueue:")},
|
||||
|
||||
{"success no session", &Params{ParentPerm: 0755}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
Write: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0755)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0755)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0755)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0755)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0755)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0755)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0755)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0755)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0755)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0755)}, nil, nil},
|
||||
{"mount", expectArgs{"mqueue", "/sysroot/dev/mqueue", "mqueue", uintptr(0xe), ""}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success no tty", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
Write: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, false, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"mqueue", "/sysroot/dev/mqueue", "mqueue", uintptr(0xe), ""}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success no mqueue", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, true, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/console", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"readlink", expectArgs{"/host/proc/self/fd/1"}, "/dev/pts/2", nil},
|
||||
{"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, nil},
|
||||
{"remount", expectArgs{"/sysroot/dev", uintptr(1)}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success rw", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
Write: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, true, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/console", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"readlink", expectArgs{"/host/proc/self/fd/1"}, "/dev/pts/2", nil},
|
||||
{"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"mqueue", "/sysroot/dev/mqueue", "mqueue", uintptr(0xe), ""}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
|
||||
Target: MustAbs("/dev/"),
|
||||
Mqueue: true,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/null", "/sysroot/dev/null", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/zero", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/zero", "/sysroot/dev/zero", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/full", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/full", "/sysroot/dev/full", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/random", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/random", "/sysroot/dev/random", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/urandom", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/urandom", "/sysroot/dev/urandom", uintptr(0), true}, nil, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/tty", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"bindMount", expectArgs{"/host/dev/tty", "/sysroot/dev/tty", uintptr(0), true}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/0", "/sysroot/dev/stdin"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/1", "/sysroot/dev/stdout"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd/2", "/sysroot/dev/stderr"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/self/fd", "/sysroot/dev/fd"}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/kcore", "/sysroot/dev/core"}, nil, nil},
|
||||
{"symlink", expectArgs{"pts/ptmx", "/sysroot/dev/ptmx"}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, nil},
|
||||
{"isatty", expectArgs{1}, true, nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/dev/console", os.FileMode(0444), os.FileMode(0750)}, nil, nil},
|
||||
{"readlink", expectArgs{"/host/proc/self/fd/1"}, "/dev/pts/2", nil},
|
||||
{"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, nil},
|
||||
{"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0750)}, nil, nil},
|
||||
{"mount", expectArgs{"mqueue", "/sysroot/dev/mqueue", "mqueue", uintptr(0xe), ""}, nil, nil},
|
||||
{"remount", expectArgs{"/sysroot/dev", uintptr(1)}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*MountDevOp)(nil), false},
|
||||
{"zero", new(MountDevOp), false},
|
||||
|
@ -20,10 +20,10 @@ type MkdirOp struct {
|
||||
Perm os.FileMode
|
||||
}
|
||||
|
||||
func (m *MkdirOp) Valid() bool { return m != nil && m.Path != nil }
|
||||
func (m *MkdirOp) early(*setupState) error { return nil }
|
||||
func (m *MkdirOp) apply(*setupState) error {
|
||||
return wrapErrSelf(os.MkdirAll(toSysroot(m.Path.String()), m.Perm))
|
||||
func (m *MkdirOp) Valid() bool { return m != nil && m.Path != nil }
|
||||
func (m *MkdirOp) early(*setupState, syscallDispatcher) error { return nil }
|
||||
func (m *MkdirOp) apply(_ *setupState, k syscallDispatcher) error {
|
||||
return wrapErrSelf(k.mkdirAll(toSysroot(m.Path.String()), m.Perm))
|
||||
}
|
||||
|
||||
func (m *MkdirOp) Is(op Op) bool {
|
||||
|
@ -1,8 +1,20 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMkdirOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"success", new(Params), &MkdirOp{
|
||||
Path: MustAbs("/.hakurei"),
|
||||
Perm: 0500,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/.hakurei", os.FileMode(0500)}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*MkdirOp)(nil), false},
|
||||
{"zero", new(MkdirOp), false},
|
||||
|
@ -3,11 +3,9 @@ package container
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"io/fs"
|
||||
"slices"
|
||||
"strings"
|
||||
. "syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -81,14 +79,14 @@ func (o *MountOverlayOp) Valid() bool {
|
||||
return o.Target != nil
|
||||
}
|
||||
|
||||
func (o *MountOverlayOp) early(*setupState) error {
|
||||
func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
if o.Work == nil && o.Upper != nil {
|
||||
switch o.Upper.String() {
|
||||
case FHSRoot: // ephemeral
|
||||
o.ephemeral = true // intermediate root not yet available
|
||||
|
||||
default:
|
||||
return msg.WrapErr(EINVAL, fmt.Sprintf("upperdir has unexpected value %q", o.Upper))
|
||||
return msg.WrapErr(fs.ErrInvalid, fmt.Sprintf("upperdir has unexpected value %q", o.Upper))
|
||||
}
|
||||
}
|
||||
// readonly handled in apply
|
||||
@ -96,11 +94,11 @@ func (o *MountOverlayOp) early(*setupState) error {
|
||||
if !o.ephemeral {
|
||||
if o.Upper != o.Work && (o.Upper == nil || o.Work == nil) {
|
||||
// unreachable
|
||||
return msg.WrapErr(ENOTRECOVERABLE, "impossible overlay state reached")
|
||||
return msg.WrapErr(fs.ErrClosed, "impossible overlay state reached")
|
||||
}
|
||||
|
||||
if o.Upper != nil {
|
||||
if v, err := filepath.EvalSymlinks(o.Upper.String()); err != nil {
|
||||
if v, err := k.evalSymlinks(o.Upper.String()); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else {
|
||||
o.upper = EscapeOverlayDataSegment(toHost(v))
|
||||
@ -108,7 +106,7 @@ func (o *MountOverlayOp) early(*setupState) error {
|
||||
}
|
||||
|
||||
if o.Work != nil {
|
||||
if v, err := filepath.EvalSymlinks(o.Work.String()); err != nil {
|
||||
if v, err := k.evalSymlinks(o.Work.String()); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else {
|
||||
o.work = EscapeOverlayDataSegment(toHost(v))
|
||||
@ -118,7 +116,7 @@ func (o *MountOverlayOp) early(*setupState) error {
|
||||
|
||||
o.lower = make([]string, len(o.Lower))
|
||||
for i, a := range o.Lower { // nil checked in Valid
|
||||
if v, err := filepath.EvalSymlinks(a.String()); err != nil {
|
||||
if v, err := k.evalSymlinks(a.String()); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else {
|
||||
o.lower[i] = EscapeOverlayDataSegment(toHost(v))
|
||||
@ -127,19 +125,19 @@ func (o *MountOverlayOp) early(*setupState) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *MountOverlayOp) apply(state *setupState) error {
|
||||
func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
target := toSysroot(o.Target.String())
|
||||
if err := os.MkdirAll(target, state.ParentPerm); err != nil {
|
||||
if err := k.mkdirAll(target, state.ParentPerm); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
|
||||
if o.ephemeral {
|
||||
var err error
|
||||
// these directories are created internally, therefore early (absolute, symlink, prefix, escape) is bypassed
|
||||
if o.upper, err = os.MkdirTemp(FHSRoot, intermediatePatternOverlayUpper); err != nil {
|
||||
if o.upper, err = k.mkdirTemp(FHSRoot, intermediatePatternOverlayUpper); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
if o.work, err = os.MkdirTemp(FHSRoot, intermediatePatternOverlayWork); err != nil {
|
||||
if o.work, err = k.mkdirTemp(FHSRoot, intermediatePatternOverlayWork); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
}
|
||||
@ -148,12 +146,12 @@ func (o *MountOverlayOp) apply(state *setupState) error {
|
||||
|
||||
if o.upper == zeroString && o.work == zeroString { // readonly
|
||||
if len(o.Lower) < 2 {
|
||||
return msg.WrapErr(EINVAL, "readonly overlay requires at least two lowerdir")
|
||||
return msg.WrapErr(fs.ErrInvalid, "readonly overlay requires at least two lowerdir")
|
||||
}
|
||||
// "upperdir=" and "workdir=" may be omitted. In that case the overlay will be read-only
|
||||
} else {
|
||||
if len(o.Lower) == 0 {
|
||||
return msg.WrapErr(EINVAL, "overlay requires at least one lowerdir")
|
||||
return msg.WrapErr(fs.ErrInvalid, "overlay requires at least one lowerdir")
|
||||
}
|
||||
options = append(options,
|
||||
OptionOverlayUpperdir+"="+o.upper,
|
||||
@ -163,7 +161,7 @@ func (o *MountOverlayOp) apply(state *setupState) error {
|
||||
OptionOverlayLowerdir+"="+strings.Join(o.lower, SpecialOverlayPath),
|
||||
OptionOverlayUserxattr)
|
||||
|
||||
return wrapErrSuffix(Mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, SpecialOverlayOption)),
|
||||
return wrapErrSuffix(k.mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, SpecialOverlayOption)),
|
||||
fmt.Sprintf("cannot mount overlay on %q:", o.Target))
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,237 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMountOverlayOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"mkdirTemp invalid ephemeral", &Params{ParentPerm: 0705}, &MountOverlayOp{
|
||||
Target: MustAbs("/"),
|
||||
Lower: []*Absolute{
|
||||
MustAbs("/var/lib/planterette/base/debian:f92c9052"),
|
||||
MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"),
|
||||
},
|
||||
Upper: MustAbs("/proc/"),
|
||||
}, nil, msg.WrapErr(fs.ErrInvalid, `upperdir has unexpected value "/proc/"`), nil, nil},
|
||||
|
||||
{"mkdirTemp upper ephemeral", &Params{ParentPerm: 0705}, &MountOverlayOp{
|
||||
Target: MustAbs("/"),
|
||||
Lower: []*Absolute{
|
||||
MustAbs("/var/lib/planterette/base/debian:f92c9052"),
|
||||
MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"),
|
||||
},
|
||||
Upper: MustAbs("/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052"}, "/var/lib/planterette/base/debian:f92c9052", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"}, "/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot", os.FileMode(0705)}, nil, nil},
|
||||
{"mkdirTemp", expectArgs{"/", "overlay.upper.*"}, "overlay.upper.32768", errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"mkdirTemp work ephemeral", &Params{ParentPerm: 0705}, &MountOverlayOp{
|
||||
Target: MustAbs("/"),
|
||||
Lower: []*Absolute{
|
||||
MustAbs("/var/lib/planterette/base/debian:f92c9052"),
|
||||
MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"),
|
||||
},
|
||||
Upper: MustAbs("/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052"}, "/var/lib/planterette/base/debian:f92c9052", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"}, "/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot", os.FileMode(0705)}, nil, nil},
|
||||
{"mkdirTemp", expectArgs{"/", "overlay.upper.*"}, "overlay.upper.32768", nil},
|
||||
{"mkdirTemp", expectArgs{"/", "overlay.work.*"}, "overlay.work.32768", errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"success ephemeral", &Params{ParentPerm: 0705}, &MountOverlayOp{
|
||||
Target: MustAbs("/"),
|
||||
Lower: []*Absolute{
|
||||
MustAbs("/var/lib/planterette/base/debian:f92c9052"),
|
||||
MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"),
|
||||
},
|
||||
Upper: MustAbs("/"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/base/debian:f92c9052"}, "/var/lib/planterette/base/debian:f92c9052", nil},
|
||||
{"evalSymlinks", expectArgs{"/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"}, "/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot", os.FileMode(0705)}, nil, nil},
|
||||
{"mkdirTemp", expectArgs{"/", "overlay.upper.*"}, "overlay.upper.32768", nil},
|
||||
{"mkdirTemp", expectArgs{"/", "overlay.work.*"}, "overlay.work.32768", nil},
|
||||
{"mount", expectArgs{"overlay", "/sysroot", "overlay", uintptr(0), "" +
|
||||
"upperdir=overlay.upper.32768," +
|
||||
"workdir=overlay.work.32768," +
|
||||
"lowerdir=" +
|
||||
`/host/var/lib/planterette/base/debian\:f92c9052:` +
|
||||
`/host/var/lib/planterette/app/org.chromium.Chromium@debian\:f92c9052,` +
|
||||
"userxattr"}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"short lower ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{
|
||||
MustAbs("/mnt-root/nix/.ro-store"),
|
||||
},
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/.ro-store", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0755)}, nil, nil},
|
||||
}, msg.WrapErr(fs.ErrInvalid, "readonly overlay requires at least two lowerdir")},
|
||||
|
||||
{"success ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{
|
||||
MustAbs("/mnt-root/nix/.ro-store"),
|
||||
MustAbs("/mnt-root/nix/.ro-store0"),
|
||||
},
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/.ro-store", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0755)}, nil, nil},
|
||||
{"mount", expectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||
"lowerdir=" +
|
||||
"/host/mnt-root/nix/.ro-store:" +
|
||||
"/host/mnt-root/nix/.ro-store0," +
|
||||
"userxattr"}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"nil lower", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Upper: MustAbs("/mnt-root/nix/.rw-store/upper"),
|
||||
Work: MustAbs("/mnt-root/nix/.rw-store/work"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil},
|
||||
}, msg.WrapErr(fs.ErrInvalid, "overlay requires at least one lowerdir")},
|
||||
|
||||
{"evalSymlinks upper", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")},
|
||||
Upper: MustAbs("/mnt-root/nix/.rw-store/upper"),
|
||||
Work: MustAbs("/mnt-root/nix/.rw-store/work"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", errUnique},
|
||||
}, wrapErrSelf(errUnique), nil, nil},
|
||||
|
||||
{"evalSymlinks work", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")},
|
||||
Upper: MustAbs("/mnt-root/nix/.rw-store/upper"),
|
||||
Work: MustAbs("/mnt-root/nix/.rw-store/work"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", errUnique},
|
||||
}, wrapErrSelf(errUnique), nil, nil},
|
||||
|
||||
{"evalSymlinks lower", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")},
|
||||
Upper: MustAbs("/mnt-root/nix/.rw-store/upper"),
|
||||
Work: MustAbs("/mnt-root/nix/.rw-store/work"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", errUnique},
|
||||
}, wrapErrSelf(errUnique), nil, nil},
|
||||
|
||||
{"mkdirAll", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")},
|
||||
Upper: MustAbs("/mnt-root/nix/.rw-store/upper"),
|
||||
Work: MustAbs("/mnt-root/nix/.rw-store/work"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"mount", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")},
|
||||
Upper: MustAbs("/mnt-root/nix/.rw-store/upper"),
|
||||
Work: MustAbs("/mnt-root/nix/.rw-store/work"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil},
|
||||
{"mount", expectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "upperdir=/host/mnt-root/nix/.rw-store/.upper,workdir=/host/mnt-root/nix/.rw-store/.work,lowerdir=/host/mnt-root/nix/ro-store,userxattr"}, nil, errUnique},
|
||||
}, wrapErrSuffix(errUnique, `cannot mount overlay on "/nix/store":`)},
|
||||
|
||||
{"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")},
|
||||
Upper: MustAbs("/mnt-root/nix/.rw-store/upper"),
|
||||
Work: MustAbs("/mnt-root/nix/.rw-store/work"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil},
|
||||
{"mount", expectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||
"upperdir=/host/mnt-root/nix/.rw-store/.upper," +
|
||||
"workdir=/host/mnt-root/nix/.rw-store/.work," +
|
||||
"lowerdir=/host/mnt-root/nix/ro-store," +
|
||||
"userxattr"}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
Target: MustAbs("/nix/store"),
|
||||
Lower: []*Absolute{
|
||||
MustAbs("/mnt-root/nix/.ro-store"),
|
||||
MustAbs("/mnt-root/nix/.ro-store0"),
|
||||
MustAbs("/mnt-root/nix/.ro-store1"),
|
||||
MustAbs("/mnt-root/nix/.ro-store2"),
|
||||
MustAbs("/mnt-root/nix/.ro-store3"),
|
||||
},
|
||||
Upper: MustAbs("/mnt-root/nix/.rw-store/upper"),
|
||||
Work: MustAbs("/mnt-root/nix/.rw-store/work"),
|
||||
}, []kexpect{
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/ro-store0", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store1"}, "/mnt-root/nix/ro-store1", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store2"}, "/mnt-root/nix/ro-store2", nil},
|
||||
{"evalSymlinks", expectArgs{"/mnt-root/nix/.ro-store3"}, "/mnt-root/nix/ro-store3", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil},
|
||||
{"mount", expectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||
"upperdir=/host/mnt-root/nix/.rw-store/.upper," +
|
||||
"workdir=/host/mnt-root/nix/.rw-store/.work," +
|
||||
"lowerdir=" +
|
||||
"/host/mnt-root/nix/ro-store:" +
|
||||
"/host/mnt-root/nix/ro-store0:" +
|
||||
"/host/mnt-root/nix/ro-store1:" +
|
||||
"/host/mnt-root/nix/ro-store2:" +
|
||||
"/host/mnt-root/nix/ro-store3," +
|
||||
"userxattr"}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
t.Run("unreachable", func(t *testing.T) {
|
||||
t.Run("nil Upper non-nil Work not ephemeral", func(t *testing.T) {
|
||||
wantErr := msg.WrapErr(fs.ErrClosed, "impossible overlay state reached")
|
||||
if err := (&MountOverlayOp{
|
||||
Work: MustAbs("/"),
|
||||
}).early(nil, nil); !errors.Is(err, wantErr) {
|
||||
t.Errorf("apply: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*MountOverlayOp)(nil), false},
|
||||
{"zero", new(MountOverlayOp), false},
|
||||
|
@ -3,8 +3,7 @@ package container
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
. "syscall"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -35,11 +34,11 @@ type TmpfileOp struct {
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (t *TmpfileOp) Valid() bool { return t != nil && t.Path != nil }
|
||||
func (t *TmpfileOp) early(*setupState) error { return nil }
|
||||
func (t *TmpfileOp) apply(state *setupState) error {
|
||||
func (t *TmpfileOp) Valid() bool { return t != nil && t.Path != nil }
|
||||
func (t *TmpfileOp) early(*setupState, syscallDispatcher) error { return nil }
|
||||
func (t *TmpfileOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
var tmpPath string
|
||||
if f, err := os.CreateTemp(FHSRoot, intermediatePatternTmpfile); err != nil {
|
||||
if f, err := k.createTemp(FHSRoot, intermediatePatternTmpfile); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else if _, err = f.Write(t.Data); err != nil {
|
||||
return wrapErrSuffix(err,
|
||||
@ -52,16 +51,16 @@ func (t *TmpfileOp) apply(state *setupState) error {
|
||||
}
|
||||
|
||||
target := toSysroot(t.Path.String())
|
||||
if err := ensureFile(target, 0444, state.ParentPerm); err != nil {
|
||||
if err := k.ensureFile(target, 0444, state.ParentPerm); err != nil {
|
||||
return err
|
||||
} else if err = hostProc.bindMount(
|
||||
} else if err = k.bindMount(
|
||||
tmpPath,
|
||||
target,
|
||||
MS_RDONLY|MS_NODEV,
|
||||
syscall.MS_RDONLY|syscall.MS_NODEV,
|
||||
false,
|
||||
); err != nil {
|
||||
return err
|
||||
} else if err = os.Remove(tmpPath); err != nil {
|
||||
} else if err = k.remove(tmpPath); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
return nil
|
||||
|
@ -1,25 +1,94 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTmpfileOp(t *testing.T) {
|
||||
const sampleDataString = `chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`
|
||||
var (
|
||||
samplePath = MustAbs("/etc/passwd")
|
||||
sampleData = []byte(sampleDataString)
|
||||
)
|
||||
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"createTemp", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []kexpect{
|
||||
{"createTemp", expectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"Write", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []kexpect{
|
||||
{"createTemp", expectArgs{"/", "tmp.*"}, writeErrOsFile{errUnique}, nil},
|
||||
}, wrapErrSuffix(errUnique, "cannot write to intermediate file:")},
|
||||
|
||||
{"Close", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []kexpect{
|
||||
{"createTemp", expectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, errUnique), nil},
|
||||
}, wrapErrSuffix(errUnique, "cannot close intermediate file:")},
|
||||
|
||||
{"ensureFile", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []kexpect{
|
||||
{"createTemp", expectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"bindMount", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []kexpect{
|
||||
{"createTemp", expectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil},
|
||||
{"bindMount", expectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, errUnique},
|
||||
}, errUnique},
|
||||
|
||||
{"remove", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []kexpect{
|
||||
{"createTemp", expectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil},
|
||||
{"bindMount", expectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil},
|
||||
{"remove", expectArgs{"tmp.32768"}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"success", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []kexpect{
|
||||
{"createTemp", expectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil},
|
||||
{"ensureFile", expectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil},
|
||||
{"bindMount", expectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil},
|
||||
{"remove", expectArgs{"tmp.32768"}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*TmpfileOp)(nil), false},
|
||||
{"zero", new(TmpfileOp), false},
|
||||
{"valid", &TmpfileOp{Path: MustAbs("/etc/passwd")}, true},
|
||||
{"valid", &TmpfileOp{Path: samplePath}, true},
|
||||
})
|
||||
|
||||
checkOpsBuilder(t, []opsBuilderTestCase{
|
||||
{"noref", new(Ops).Place(MustAbs("/etc/passwd"), []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`)), Ops{
|
||||
{"noref", new(Ops).Place(samplePath, sampleData), Ops{
|
||||
&TmpfileOp{
|
||||
Path: MustAbs("/etc/passwd"),
|
||||
Data: []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`),
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
},
|
||||
}},
|
||||
|
||||
{"ref", new(Ops).PlaceP(MustAbs("/etc/passwd"), new(*[]byte)), Ops{
|
||||
{"ref", new(Ops).PlaceP(samplePath, new(*[]byte)), Ops{
|
||||
&TmpfileOp{
|
||||
Path: MustAbs("/etc/passwd"),
|
||||
Path: samplePath,
|
||||
Data: []byte{},
|
||||
},
|
||||
}},
|
||||
@ -30,33 +99,33 @@ func TestTmpfileOp(t *testing.T) {
|
||||
|
||||
{"differs path", &TmpfileOp{
|
||||
Path: MustAbs("/etc/group"),
|
||||
Data: []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`),
|
||||
Data: sampleData,
|
||||
}, &TmpfileOp{
|
||||
Path: MustAbs("/etc/passwd"),
|
||||
Data: []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`),
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, false},
|
||||
|
||||
{"differs data", &TmpfileOp{
|
||||
Path: MustAbs("/etc/passwd"),
|
||||
Data: []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh` + "\x00"),
|
||||
Path: samplePath,
|
||||
Data: append(sampleData, 0),
|
||||
}, &TmpfileOp{
|
||||
Path: MustAbs("/etc/passwd"),
|
||||
Data: []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`),
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, false},
|
||||
|
||||
{"equals", &TmpfileOp{
|
||||
Path: MustAbs("/etc/passwd"),
|
||||
Data: []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`),
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, &TmpfileOp{
|
||||
Path: MustAbs("/etc/passwd"),
|
||||
Data: []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`),
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, true},
|
||||
})
|
||||
|
||||
checkOpMeta(t, []opMetaTestCase{
|
||||
{"passwd", &TmpfileOp{
|
||||
Path: MustAbs("/etc/passwd"),
|
||||
Data: []byte(`chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh`),
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, "placing", `tmpfile "/etc/passwd" (49 bytes)`},
|
||||
})
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package container
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
. "syscall"
|
||||
)
|
||||
|
||||
@ -18,14 +17,14 @@ func (f *Ops) Proc(target *Absolute) *Ops {
|
||||
// MountProcOp mounts a new instance of [FstypeProc] on container path Target.
|
||||
type MountProcOp struct{ Target *Absolute }
|
||||
|
||||
func (p *MountProcOp) Valid() bool { return p != nil && p.Target != nil }
|
||||
func (p *MountProcOp) early(*setupState) error { return nil }
|
||||
func (p *MountProcOp) apply(state *setupState) error {
|
||||
func (p *MountProcOp) Valid() bool { return p != nil && p.Target != nil }
|
||||
func (p *MountProcOp) early(*setupState, syscallDispatcher) error { return nil }
|
||||
func (p *MountProcOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
target := toSysroot(p.Target.String())
|
||||
if err := os.MkdirAll(target, state.ParentPerm); err != nil {
|
||||
if err := k.mkdirAll(target, state.ParentPerm); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
return wrapErrSuffix(Mount(SourceProc, target, FstypeProc, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString),
|
||||
return wrapErrSuffix(k.mount(SourceProc, target, FstypeProc, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString),
|
||||
fmt.Sprintf("cannot mount proc on %q:", p.Target.String()))
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,28 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMountProcOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"mkdir", &Params{ParentPerm: 0755},
|
||||
&MountProcOp{
|
||||
Target: MustAbs("/proc/"),
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"success", &Params{ParentPerm: 0700},
|
||||
&MountProcOp{
|
||||
Target: MustAbs("/proc/"),
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/proc", os.FileMode(0700)}, nil, nil},
|
||||
{"mount", expectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*MountProcOp)(nil), false},
|
||||
{"zero", new(MountProcOp), false},
|
||||
|
@ -19,10 +19,10 @@ type RemountOp struct {
|
||||
Flags uintptr
|
||||
}
|
||||
|
||||
func (r *RemountOp) Valid() bool { return r != nil && r.Target != nil }
|
||||
func (*RemountOp) early(*setupState) error { return nil }
|
||||
func (r *RemountOp) apply(*setupState) error {
|
||||
return wrapErrSuffix(hostProc.remount(toSysroot(r.Target.String()), r.Flags),
|
||||
func (r *RemountOp) Valid() bool { return r != nil && r.Target != nil }
|
||||
func (*RemountOp) early(*setupState, syscallDispatcher) error { return nil }
|
||||
func (r *RemountOp) apply(_ *setupState, k syscallDispatcher) error {
|
||||
return wrapErrSuffix(k.remount(toSysroot(r.Target.String()), r.Flags),
|
||||
fmt.Sprintf("cannot remount %q:", r.Target))
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,15 @@ import (
|
||||
)
|
||||
|
||||
func TestRemountOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"success", new(Params), &RemountOp{
|
||||
Target: MustAbs("/"),
|
||||
Flags: syscall.MS_RDONLY,
|
||||
}, nil, nil, []kexpect{
|
||||
{"remount", expectArgs{"/sysroot", uintptr(1)}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*RemountOp)(nil), false},
|
||||
{"zero", new(RemountOp), false},
|
||||
|
@ -3,9 +3,8 @@ package container
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
"io/fs"
|
||||
"path"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func init() { gob.Register(new(SymlinkOp)) }
|
||||
@ -28,12 +27,12 @@ type SymlinkOp struct {
|
||||
|
||||
func (l *SymlinkOp) Valid() bool { return l != nil && l.Target != nil && l.LinkName != zeroString }
|
||||
|
||||
func (l *SymlinkOp) early(*setupState) error {
|
||||
func (l *SymlinkOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
if l.Dereference {
|
||||
if !isAbs(l.LinkName) {
|
||||
return msg.WrapErr(syscall.EBADE, fmt.Sprintf("path %q is not absolute", l.LinkName))
|
||||
return msg.WrapErr(fs.ErrInvalid, fmt.Sprintf("path %q is not absolute", l.LinkName))
|
||||
}
|
||||
if name, err := os.Readlink(l.LinkName); err != nil {
|
||||
if name, err := k.readlink(l.LinkName); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
} else {
|
||||
l.LinkName = name
|
||||
@ -42,15 +41,12 @@ func (l *SymlinkOp) early(*setupState) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *SymlinkOp) apply(state *setupState) error {
|
||||
func (l *SymlinkOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
target := toSysroot(l.Target.String())
|
||||
if err := os.MkdirAll(path.Dir(target), state.ParentPerm); err != nil {
|
||||
if err := k.mkdirAll(path.Dir(target), state.ParentPerm); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
if err := os.Symlink(l.LinkName, target); err != nil {
|
||||
return wrapErrSelf(err)
|
||||
}
|
||||
return nil
|
||||
return wrapErrSelf(k.symlink(l.LinkName, target))
|
||||
}
|
||||
|
||||
func (l *SymlinkOp) Is(op Op) bool {
|
||||
|
@ -1,8 +1,54 @@
|
||||
package container
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSymlinkOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"mkdir", &Params{ParentPerm: 0700}, &SymlinkOp{
|
||||
Target: MustAbs("/etc/nixos"),
|
||||
LinkName: "/etc/static/nixos",
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc", os.FileMode(0700)}, nil, errUnique},
|
||||
}, wrapErrSelf(errUnique)},
|
||||
|
||||
{"abs", &Params{ParentPerm: 0755}, &SymlinkOp{
|
||||
Target: MustAbs("/etc/mtab"),
|
||||
LinkName: "etc/mtab",
|
||||
Dereference: true,
|
||||
}, nil, msg.WrapErr(fs.ErrInvalid, `path "etc/mtab" is not absolute`), nil, nil},
|
||||
|
||||
{"readlink", &Params{ParentPerm: 0755}, &SymlinkOp{
|
||||
Target: MustAbs("/etc/mtab"),
|
||||
LinkName: "/etc/mtab",
|
||||
Dereference: true,
|
||||
}, []kexpect{
|
||||
{"readlink", expectArgs{"/etc/mtab"}, "/proc/mounts", errUnique},
|
||||
}, wrapErrSelf(errUnique), nil, nil},
|
||||
|
||||
{"success noderef", &Params{ParentPerm: 0700}, &SymlinkOp{
|
||||
Target: MustAbs("/etc/nixos"),
|
||||
LinkName: "/etc/static/nixos",
|
||||
}, nil, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc", os.FileMode(0700)}, nil, nil},
|
||||
{"symlink", expectArgs{"/etc/static/nixos", "/sysroot/etc/nixos"}, nil, nil},
|
||||
}, nil},
|
||||
|
||||
{"success", &Params{ParentPerm: 0755}, &SymlinkOp{
|
||||
Target: MustAbs("/etc/mtab"),
|
||||
LinkName: "/etc/mtab",
|
||||
Dereference: true,
|
||||
}, []kexpect{
|
||||
{"readlink", expectArgs{"/etc/mtab"}, "/proc/mounts", nil},
|
||||
}, nil, []kexpect{
|
||||
{"mkdirAll", expectArgs{"/sysroot/etc", os.FileMode(0755)}, nil, nil},
|
||||
{"symlink", expectArgs{"/proc/mounts", "/sysroot/etc/mtab"}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*SymlinkOp)(nil), false},
|
||||
{"zero", new(SymlinkOp), false},
|
||||
|
@ -3,6 +3,7 @@ package container
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"math"
|
||||
"os"
|
||||
. "syscall"
|
||||
@ -31,13 +32,13 @@ type MountTmpfsOp struct {
|
||||
Perm os.FileMode
|
||||
}
|
||||
|
||||
func (t *MountTmpfsOp) Valid() bool { return t != nil && t.Path != nil && t.FSName != zeroString }
|
||||
func (t *MountTmpfsOp) early(*setupState) error { return nil }
|
||||
func (t *MountTmpfsOp) apply(*setupState) error {
|
||||
func (t *MountTmpfsOp) Valid() bool { return t != nil && t.Path != nil && t.FSName != zeroString }
|
||||
func (t *MountTmpfsOp) early(*setupState, syscallDispatcher) error { return nil }
|
||||
func (t *MountTmpfsOp) apply(_ *setupState, k syscallDispatcher) error {
|
||||
if t.Size < 0 || t.Size > math.MaxUint>>1 {
|
||||
return msg.WrapErr(EBADE, fmt.Sprintf("size %d out of bounds", t.Size))
|
||||
return msg.WrapErr(fs.ErrInvalid, fmt.Sprintf("size %d out of bounds", t.Size))
|
||||
}
|
||||
return mountTmpfs(t.FSName, toSysroot(t.Path.String()), t.Flags, t.Size, t.Perm)
|
||||
return k.mountTmpfs(t.FSName, toSysroot(t.Path.String()), t.Flags, t.Size, t.Perm)
|
||||
}
|
||||
|
||||
func (t *MountTmpfsOp) Is(op Op) bool {
|
||||
|
@ -1,11 +1,34 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMountTmpfsOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"size oob", new(Params), &MountTmpfsOp{
|
||||
Size: -1,
|
||||
}, nil, nil, nil, msg.WrapErr(fs.ErrInvalid, "size -1 out of bounds")},
|
||||
|
||||
{"success", new(Params), &MountTmpfsOp{
|
||||
FSName: "ephemeral",
|
||||
Path: MustAbs("/run/user/1000/"),
|
||||
Size: 1 << 10,
|
||||
Perm: 0700,
|
||||
}, nil, nil, []kexpect{
|
||||
{"mountTmpfs", expectArgs{
|
||||
"ephemeral", // fsname
|
||||
"/sysroot/run/user/1000", // target
|
||||
uintptr(0), // flags
|
||||
0x400, // size
|
||||
os.FileMode(0700), // perm
|
||||
}, nil, nil},
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsValid(t, []opValidTestCase{
|
||||
{"nil", (*MountTmpfsOp)(nil), false},
|
||||
{"zero", new(MountTmpfsOp), false},
|
||||
|
@ -2,7 +2,6 @@ package container
|
||||
|
||||
import (
|
||||
"os"
|
||||
"slices"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -48,85 +47,3 @@ func TestEscapeOverlayDataSegment(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type opValidTestCase struct {
|
||||
name string
|
||||
op Op
|
||||
want bool
|
||||
}
|
||||
|
||||
func checkOpsValid(t *testing.T, testCases []opValidTestCase) {
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := tc.op.Valid(); got != tc.want {
|
||||
t.Errorf("Valid: %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type opsBuilderTestCase struct {
|
||||
name string
|
||||
ops *Ops
|
||||
want Ops
|
||||
}
|
||||
|
||||
func checkOpsBuilder(t *testing.T, testCases []opsBuilderTestCase) {
|
||||
t.Run("build", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if !slices.EqualFunc(*tc.ops, tc.want, func(op Op, v Op) bool { return op.Is(v) }) {
|
||||
t.Errorf("Ops: %#v, want %#v", tc.ops, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type opIsTestCase struct {
|
||||
name string
|
||||
op, v Op
|
||||
want bool
|
||||
}
|
||||
|
||||
func checkOpIs(t *testing.T, testCases []opIsTestCase) {
|
||||
t.Run("is", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := tc.op.Is(tc.v); got != tc.want {
|
||||
t.Errorf("Is: %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type opMetaTestCase struct {
|
||||
name string
|
||||
op Op
|
||||
|
||||
wantPrefix string
|
||||
wantString string
|
||||
}
|
||||
|
||||
func checkOpMeta(t *testing.T, testCases []opMetaTestCase) {
|
||||
t.Run("meta", func(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Run("prefix", func(t *testing.T) {
|
||||
if got := tc.op.prefix(); got != tc.wantPrefix {
|
||||
t.Errorf("prefix: %q, want %q", got, tc.wantPrefix)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("string", func(t *testing.T) {
|
||||
if got := tc.op.String(); got != tc.wantString {
|
||||
t.Errorf("String: %s, want %s", got, tc.wantString)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type Msg interface {
|
||||
@ -32,7 +37,27 @@ func (msg *DefaultMsg) Verbosef(format string, v ...any) {
|
||||
}
|
||||
}
|
||||
|
||||
// checkedWrappedErr implements error with strict checks for wrapped values.
|
||||
type checkedWrappedErr struct {
|
||||
err error
|
||||
a []any
|
||||
}
|
||||
|
||||
func (c *checkedWrappedErr) Error() string { return fmt.Sprintf("%v, a = %s", c.err, c.a) }
|
||||
func (c *checkedWrappedErr) Is(err error) bool {
|
||||
var concreteErr *checkedWrappedErr
|
||||
if !errors.As(err, &concreteErr) {
|
||||
return false
|
||||
}
|
||||
return reflect.DeepEqual(c, concreteErr)
|
||||
}
|
||||
|
||||
func (msg *DefaultMsg) WrapErr(err error, a ...any) error {
|
||||
// provide a mostly bulletproof path to bypass this behaviour in tests
|
||||
if testing.Testing() && os.Getenv("GOPATH") != Nonexistent {
|
||||
return &checkedWrappedErr{err, a}
|
||||
}
|
||||
|
||||
log.Println(a...)
|
||||
return err
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package container_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@ -12,6 +13,9 @@ import (
|
||||
)
|
||||
|
||||
func TestDefaultMsg(t *testing.T) {
|
||||
// bypass WrapErr testing behaviour
|
||||
t.Setenv("GOPATH", container.Nonexistent)
|
||||
|
||||
{
|
||||
w := log.Writer()
|
||||
f := log.Flags()
|
||||
@ -79,6 +83,25 @@ func TestDefaultMsg(t *testing.T) {
|
||||
|
||||
// the function is a noop
|
||||
t.Run("beforeExit", func(t *testing.T) { msg.BeforeExit() })
|
||||
|
||||
t.Run("checkedWrappedErr", func(t *testing.T) {
|
||||
// temporarily re-enable testing behaviour
|
||||
t.Setenv("GOPATH", "")
|
||||
wrappedErr := msg.WrapErr(syscall.ENOTRECOVERABLE, "cannot cuddle cat:", syscall.ENOTRECOVERABLE)
|
||||
|
||||
t.Run("string", func(t *testing.T) {
|
||||
want := "state not recoverable, a = [cannot cuddle cat: state not recoverable]"
|
||||
if got := wrappedErr.Error(); got != want {
|
||||
t.Errorf("Error: %q, want %q", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("bad concrete type", func(t *testing.T) {
|
||||
if errors.Is(wrappedErr, syscall.ENOTRECOVERABLE) {
|
||||
t.Error("incorrect type assertion")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type panicWriter struct{}
|
||||
|
@ -151,8 +151,7 @@ func (p *procPaths) mountinfo(f func(d *vfs.MountInfoDecoder) error) error {
|
||||
d := vfs.NewMountInfoDecoder(r)
|
||||
err0 := f(d)
|
||||
if err = r.Close(); err != nil {
|
||||
return wrapErrSuffix(err,
|
||||
"cannot close mountinfo:")
|
||||
return wrapErrSelf(err)
|
||||
} else if err = d.Err(); err != nil {
|
||||
return wrapErrSuffix(err,
|
||||
"cannot parse mountinfo:")
|
||||
|
@ -2,6 +2,7 @@ package container
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
@ -55,10 +56,18 @@ func InternalToHostOvlEscape(s string) string { return EscapeOverlayDataSegment(
|
||||
|
||||
func TestCreateFile(t *testing.T) {
|
||||
t.Run("nonexistent", func(t *testing.T) {
|
||||
if err := createFile(path.Join(Nonexistent, ":3"), 0644, 0755, nil); !os.IsNotExist(err) {
|
||||
if err := createFile(path.Join(Nonexistent, ":3"), 0644, 0755, nil); !errors.Is(err, wrapErrSelf(&os.PathError{
|
||||
Op: "mkdir",
|
||||
Path: "/proc/nonexistent",
|
||||
Err: syscall.ENOENT,
|
||||
})) {
|
||||
t.Errorf("createFile: error = %v", err)
|
||||
}
|
||||
if err := createFile(path.Join(Nonexistent), 0644, 0755, nil); !os.IsNotExist(err) {
|
||||
if err := createFile(path.Join(Nonexistent), 0644, 0755, nil); !errors.Is(err, wrapErrSelf(&os.PathError{
|
||||
Op: "open",
|
||||
Path: "/proc/nonexistent",
|
||||
Err: syscall.ENOENT,
|
||||
})) {
|
||||
t.Errorf("createFile: error = %v", err)
|
||||
}
|
||||
})
|
||||
@ -110,17 +119,26 @@ func TestEnsureFile(t *testing.T) {
|
||||
if err := os.Chmod(tempDir, 0); err != nil {
|
||||
t.Fatalf("Chmod: error = %v", err)
|
||||
}
|
||||
if err := ensureFile(pathname, 0644, 0755); !errors.Is(err, syscall.EACCES) {
|
||||
t.Errorf("ensureFile: error = %v, want %v", err, syscall.EACCES)
|
||||
|
||||
wantErr := wrapErrSelf(&os.PathError{
|
||||
Op: "stat",
|
||||
Path: pathname,
|
||||
Err: syscall.EACCES,
|
||||
})
|
||||
if err := ensureFile(pathname, 0644, 0755); !errors.Is(err, wantErr) {
|
||||
t.Errorf("ensureFile: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
|
||||
if err := os.Chmod(tempDir, 0755); err != nil {
|
||||
t.Fatalf("Chmod: error = %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("directory", func(t *testing.T) {
|
||||
if err := ensureFile(t.TempDir(), 0644, 0755); !errors.Is(err, syscall.EISDIR) {
|
||||
t.Errorf("ensureFile: error = %v, want %v", err, syscall.EISDIR)
|
||||
pathname := t.TempDir()
|
||||
wantErr := msg.WrapErr(syscall.EISDIR, fmt.Sprintf("path %q is a directory", pathname))
|
||||
if err := ensureFile(pathname, 0644, 0755); !errors.Is(err, wantErr) {
|
||||
t.Errorf("ensureFile: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
|
||||
@ -159,8 +177,13 @@ func TestProcPaths(t *testing.T) {
|
||||
t.Run("mountinfo", func(t *testing.T) {
|
||||
t.Run("nonexistent", func(t *testing.T) {
|
||||
nonexistentProc := newProcPaths(t.TempDir())
|
||||
if err := nonexistentProc.mountinfo(func(*vfs.MountInfoDecoder) error { return syscall.EINVAL }); !os.IsNotExist(err) {
|
||||
t.Errorf("mountinfo: error = %v", err)
|
||||
wantErr := wrapErrSelf(&os.PathError{
|
||||
Op: "open",
|
||||
Path: nonexistentProc.self + "/mountinfo",
|
||||
Err: syscall.ENOENT,
|
||||
})
|
||||
if err := nonexistentProc.mountinfo(func(*vfs.MountInfoDecoder) error { return syscall.EINVAL }); !errors.Is(err, wantErr) {
|
||||
t.Errorf("mountinfo: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
|
||||
@ -193,7 +216,13 @@ func TestProcPaths(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("closed", func(t *testing.T) {
|
||||
if err := newProcPaths(tempDir).mountinfo(func(d *vfs.MountInfoDecoder) error {
|
||||
p := newProcPaths(tempDir)
|
||||
wantErr := wrapErrSelf(&os.PathError{
|
||||
Op: "close",
|
||||
Path: p.self + "/mountinfo",
|
||||
Err: os.ErrClosed,
|
||||
})
|
||||
if err := p.mountinfo(func(d *vfs.MountInfoDecoder) error {
|
||||
v := reflect.ValueOf(d).Elem().FieldByName("s").Elem().FieldByName("r")
|
||||
v = reflect.NewAt(v.Type(), unsafe.Pointer(v.UnsafeAddr()))
|
||||
if f, ok := v.Elem().Interface().(io.ReadCloser); !ok {
|
||||
@ -202,8 +231,8 @@ func TestProcPaths(t *testing.T) {
|
||||
} else {
|
||||
return f.Close()
|
||||
}
|
||||
}); !errors.Is(err, os.ErrClosed) {
|
||||
t.Errorf("mountinfo: error = %v, want %v", err, os.ErrClosed)
|
||||
}); !errors.Is(err, wantErr) {
|
||||
t.Errorf("mountinfo: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
|
||||
@ -213,8 +242,9 @@ func TestProcPaths(t *testing.T) {
|
||||
t.Fatalf("WriteFile: error = %v", err)
|
||||
}
|
||||
|
||||
if err := newProcPaths(tempDir).mountinfo(func(d *vfs.MountInfoDecoder) error { return d.Decode(new(*vfs.MountInfo)) }); !errors.Is(err, vfs.ErrMountInfoFields) {
|
||||
t.Fatalf("mountinfo: error = %v, want %v", err, vfs.ErrMountInfoFields)
|
||||
wantErr := wrapErrSuffix(vfs.ErrMountInfoFields, "cannot parse mountinfo:")
|
||||
if err := newProcPaths(tempDir).mountinfo(func(d *vfs.MountInfoDecoder) error { return d.Decode(new(*vfs.MountInfo)) }); !errors.Is(err, wantErr) {
|
||||
t.Fatalf("mountinfo: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -2,6 +2,7 @@ package container
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// SetPtracer allows processes to ptrace(2) the calling process.
|
||||
@ -37,6 +38,18 @@ func SetNoNewPrivs() error {
|
||||
return errno
|
||||
}
|
||||
|
||||
// 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,
|
||||
uintptr(fd),
|
||||
syscall.TIOCGWINSZ,
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
)
|
||||
return r == 0
|
||||
}
|
||||
|
||||
// IgnoringEINTR makes a function call and repeats it if it returns an
|
||||
// EINTR error. This appears to be required even though we install all
|
||||
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
|
||||
|
Loading…
x
Reference in New Issue
Block a user