container: use absolute for pathname
All checks were successful
Test / Flake checks (push) Successful in 1m26s
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 1m59s
Test / Hakurei (push) Successful in 2m58s
Test / Hpkg (push) Successful in 3m45s
Test / Sandbox (race detector) (push) Successful in 4m11s
Test / Hakurei (race detector) (push) Successful in 4m47s
All checks were successful
Test / Flake checks (push) Successful in 1m26s
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 1m59s
Test / Hakurei (push) Successful in 2m58s
Test / Hpkg (push) Successful in 3m45s
Test / Sandbox (race detector) (push) Successful in 4m11s
Test / Hakurei (race detector) (push) Successful in 4m47s
This is simultaneously more efficient and less error-prone. This change caused minor API changes in multiple other packages. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/app/state"
|
||||
"hakurei.app/internal/hlog"
|
||||
"hakurei.app/internal/sys"
|
||||
)
|
||||
|
||||
@@ -59,10 +58,6 @@ func (a *app) Seal(config *hst.Config) (SealedApp, error) {
|
||||
if a.outcome != nil {
|
||||
panic("app sealed twice")
|
||||
}
|
||||
if config == nil {
|
||||
return nil, hlog.WrapErr(ErrConfig,
|
||||
"attempted to seal app with nil config")
|
||||
}
|
||||
|
||||
seal := new(outcome)
|
||||
seal.id = a.id
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/app"
|
||||
"hakurei.app/internal/app/state"
|
||||
"hakurei.app/internal/hlog"
|
||||
"hakurei.app/internal/sys"
|
||||
"hakurei.app/system"
|
||||
)
|
||||
@@ -36,6 +37,7 @@ func TestApp(t *testing.T) {
|
||||
)
|
||||
if !t.Run("seal", func(t *testing.T) {
|
||||
if sa, err := a.Seal(tc.config); err != nil {
|
||||
hlog.PrintBaseError(err, "got generic error:")
|
||||
t.Errorf("Seal: error = %v", err)
|
||||
return
|
||||
} else {
|
||||
|
||||
@@ -12,21 +12,24 @@ import (
|
||||
"hakurei.app/system/dbus"
|
||||
)
|
||||
|
||||
func m(pathname string) *container.Absolute { return container.MustAbs(pathname) }
|
||||
|
||||
var testCasesNixos = []sealTestCase{
|
||||
{
|
||||
"nixos chromium direct wayland", new(stubNixOS),
|
||||
&hst.Config{
|
||||
ID: "org.chromium.Chromium",
|
||||
Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
|
||||
Path: m("/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"),
|
||||
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
||||
Shell: m("/run/current-system/sw/bin/zsh"),
|
||||
|
||||
Container: &hst.ContainerConfig{
|
||||
Userns: true, Net: true, MapRealUID: true, Env: nil, AutoEtc: true,
|
||||
Filesystem: []*hst.FilesystemConfig{
|
||||
{Src: "/bin", Must: true}, {Src: "/usr/bin/", Must: true},
|
||||
{Src: "/nix/store", Must: true}, {Src: "/run/current-system", Must: true},
|
||||
{Src: "/sys/block"}, {Src: "/sys/bus"}, {Src: "/sys/class"}, {Src: "/sys/dev"}, {Src: "/sys/devices"},
|
||||
{Src: "/run/opengl-driver", Must: true}, {Src: "/dev/dri", Device: true},
|
||||
Filesystem: []hst.FilesystemConfig{
|
||||
{Src: m("/bin"), Must: true}, {Src: m("/usr/bin/"), Must: true},
|
||||
{Src: m("/nix/store"), Must: true}, {Src: m("/run/current-system"), Must: true},
|
||||
{Src: m("/sys/block")}, {Src: m("/sys/bus")}, {Src: m("/sys/class")}, {Src: m("/sys/dev")}, {Src: m("/sys/devices")},
|
||||
{Src: m("/run/opengl-driver"), Must: true}, {Src: m("/dev/dri"), Device: true},
|
||||
},
|
||||
},
|
||||
SystemBus: &dbus.Config{
|
||||
@@ -50,7 +53,7 @@ var testCasesNixos = []sealTestCase{
|
||||
DirectWayland: true,
|
||||
|
||||
Username: "u0_a1",
|
||||
Data: "/var/lib/persist/module/hakurei/0/1",
|
||||
Data: m("/var/lib/persist/module/hakurei/0/1"),
|
||||
Identity: 1, Groups: []string{},
|
||||
},
|
||||
state.ID{
|
||||
@@ -98,8 +101,8 @@ var testCasesNixos = []sealTestCase{
|
||||
&container.Params{
|
||||
Uid: 1971,
|
||||
Gid: 100,
|
||||
Dir: "/var/lib/persist/module/hakurei/0/1",
|
||||
Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
|
||||
Dir: m("/var/lib/persist/module/hakurei/0/1"),
|
||||
Path: m("/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"),
|
||||
Args: []string{"/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"},
|
||||
Env: []string{
|
||||
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1971/bus",
|
||||
@@ -116,34 +119,34 @@ var testCasesNixos = []sealTestCase{
|
||||
"XDG_SESSION_TYPE=tty",
|
||||
},
|
||||
Ops: new(container.Ops).
|
||||
Proc("/proc/").
|
||||
Tmpfs(hst.Tmp, 4096, 0755).
|
||||
DevWritable("/dev/", true).
|
||||
Bind("/bin", "/bin", 0).
|
||||
Bind("/usr/bin/", "/usr/bin/", 0).
|
||||
Bind("/nix/store", "/nix/store", 0).
|
||||
Bind("/run/current-system", "/run/current-system", 0).
|
||||
Bind("/sys/block", "/sys/block", container.BindOptional).
|
||||
Bind("/sys/bus", "/sys/bus", container.BindOptional).
|
||||
Bind("/sys/class", "/sys/class", container.BindOptional).
|
||||
Bind("/sys/dev", "/sys/dev", container.BindOptional).
|
||||
Bind("/sys/devices", "/sys/devices", container.BindOptional).
|
||||
Bind("/run/opengl-driver", "/run/opengl-driver", 0).
|
||||
Bind("/dev/dri", "/dev/dri", container.BindDevice|container.BindWritable|container.BindOptional).
|
||||
Etc("/etc/", "8e2c76b066dabe574cf073bdb46eb5c1").
|
||||
Remount("/dev/", syscall.MS_RDONLY).
|
||||
Tmpfs("/run/user/", 4096, 0755).
|
||||
Bind("/tmp/hakurei.1971/runtime/1", "/run/user/1971", container.BindWritable).
|
||||
Bind("/tmp/hakurei.1971/tmpdir/1", "/tmp/", container.BindWritable).
|
||||
Bind("/var/lib/persist/module/hakurei/0/1", "/var/lib/persist/module/hakurei/0/1", container.BindWritable).
|
||||
Place("/etc/passwd", []byte("u0_a1:x:1971:100:Hakurei:/var/lib/persist/module/hakurei/0/1:/run/current-system/sw/bin/zsh\n")).
|
||||
Place("/etc/group", []byte("hakurei:x:100:\n")).
|
||||
Bind("/run/user/1971/wayland-0", "/run/user/1971/wayland-0", 0).
|
||||
Bind("/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1/pulse", "/run/user/1971/pulse/native", 0).
|
||||
Place(hst.Tmp+"/pulse-cookie", nil).
|
||||
Bind("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", "/run/user/1971/bus", 0).
|
||||
Bind("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", "/run/dbus/system_bus_socket", 0).
|
||||
Remount("/", syscall.MS_RDONLY),
|
||||
Proc(m("/proc/")).
|
||||
Tmpfs(hst.AbsTmp, 4096, 0755).
|
||||
DevWritable(m("/dev/"), true).
|
||||
Bind(m("/bin"), m("/bin"), 0).
|
||||
Bind(m("/usr/bin/"), m("/usr/bin/"), 0).
|
||||
Bind(m("/nix/store"), m("/nix/store"), 0).
|
||||
Bind(m("/run/current-system"), m("/run/current-system"), 0).
|
||||
Bind(m("/sys/block"), m("/sys/block"), container.BindOptional).
|
||||
Bind(m("/sys/bus"), m("/sys/bus"), container.BindOptional).
|
||||
Bind(m("/sys/class"), m("/sys/class"), container.BindOptional).
|
||||
Bind(m("/sys/dev"), m("/sys/dev"), container.BindOptional).
|
||||
Bind(m("/sys/devices"), m("/sys/devices"), container.BindOptional).
|
||||
Bind(m("/run/opengl-driver"), m("/run/opengl-driver"), 0).
|
||||
Bind(m("/dev/dri"), m("/dev/dri"), container.BindDevice|container.BindWritable|container.BindOptional).
|
||||
Etc(m("/etc/"), "8e2c76b066dabe574cf073bdb46eb5c1").
|
||||
Remount(m("/dev/"), syscall.MS_RDONLY).
|
||||
Tmpfs(m("/run/user/"), 4096, 0755).
|
||||
Bind(m("/tmp/hakurei.1971/runtime/1"), m("/run/user/1971"), container.BindWritable).
|
||||
Bind(m("/tmp/hakurei.1971/tmpdir/1"), m("/tmp/"), container.BindWritable).
|
||||
Bind(m("/var/lib/persist/module/hakurei/0/1"), m("/var/lib/persist/module/hakurei/0/1"), container.BindWritable).
|
||||
Place(m("/etc/passwd"), []byte("u0_a1:x:1971:100:Hakurei:/var/lib/persist/module/hakurei/0/1:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
Bind(m("/run/user/1971/wayland-0"), m("/run/user/1971/wayland-0"), 0).
|
||||
Bind(m("/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1/pulse"), m("/run/user/1971/pulse/native"), 0).
|
||||
Place(m(hst.Tmp+"/pulse-cookie"), nil).
|
||||
Bind(m("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus"), m("/run/user/1971/bus"), 0).
|
||||
Bind(m("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket"), m("/run/dbus/system_bus_socket"), 0).
|
||||
Remount(m("/"), syscall.MS_RDONLY),
|
||||
SeccompPresets: seccomp.PresetExt | seccomp.PresetDenyTTY | seccomp.PresetDenyDevel,
|
||||
HostNet: true,
|
||||
ForwardCancel: true,
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
var testCasesPd = []sealTestCase{
|
||||
{
|
||||
"nixos permissive defaults no enablements", new(stubNixOS),
|
||||
&hst.Config{Username: "chronos", Data: "/home/chronos"},
|
||||
&hst.Config{Username: "chronos", Data: m("/home/chronos")},
|
||||
state.ID{
|
||||
0x4a, 0x45, 0x0b, 0x65,
|
||||
0x96, 0xd7, 0xbc, 0x15,
|
||||
@@ -30,8 +30,8 @@ var testCasesPd = []sealTestCase{
|
||||
Ensure("/tmp/hakurei.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir", acl.Execute).
|
||||
Ensure("/tmp/hakurei.1971/tmpdir/0", 01700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir/0", acl.Read, acl.Write, acl.Execute),
|
||||
&container.Params{
|
||||
Dir: "/home/chronos",
|
||||
Path: "/run/current-system/sw/bin/zsh",
|
||||
Dir: m("/home/chronos"),
|
||||
Path: m("/run/current-system/sw/bin/zsh"),
|
||||
Args: []string{"/run/current-system/sw/bin/zsh"},
|
||||
Env: []string{
|
||||
"HOME=/home/chronos",
|
||||
@@ -43,23 +43,23 @@ var testCasesPd = []sealTestCase{
|
||||
"XDG_SESSION_TYPE=tty",
|
||||
},
|
||||
Ops: new(container.Ops).
|
||||
Root("/", "4a450b6596d7bc15bd01780eb9a607ac", container.BindWritable).
|
||||
Proc("/proc/").
|
||||
Tmpfs(hst.Tmp, 4096, 0755).
|
||||
DevWritable("/dev/", true).
|
||||
Bind("/dev/kvm", "/dev/kvm", container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Readonly("/var/run/nscd", 0755).
|
||||
Tmpfs("/run/user/1971", 8192, 0755).
|
||||
Tmpfs("/run/dbus", 8192, 0755).
|
||||
Etc("/etc/", "4a450b6596d7bc15bd01780eb9a607ac").
|
||||
Remount("/dev/", syscall.MS_RDONLY).
|
||||
Tmpfs("/run/user/", 4096, 0755).
|
||||
Bind("/tmp/hakurei.1971/runtime/0", "/run/user/65534", container.BindWritable).
|
||||
Bind("/tmp/hakurei.1971/tmpdir/0", "/tmp/", container.BindWritable).
|
||||
Bind("/home/chronos", "/home/chronos", container.BindWritable).
|
||||
Place("/etc/passwd", []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
||||
Place("/etc/group", []byte("hakurei:x:65534:\n")).
|
||||
Remount("/", syscall.MS_RDONLY),
|
||||
Root(m("/"), "4a450b6596d7bc15bd01780eb9a607ac", container.BindWritable).
|
||||
Proc(m("/proc/")).
|
||||
Tmpfs(hst.AbsTmp, 4096, 0755).
|
||||
DevWritable(m("/dev/"), true).
|
||||
Bind(m("/dev/kvm"), m("/dev/kvm"), container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Readonly(m("/var/run/nscd"), 0755).
|
||||
Tmpfs(m("/run/user/1971"), 8192, 0755).
|
||||
Tmpfs(m("/run/dbus"), 8192, 0755).
|
||||
Etc(m("/etc/"), "4a450b6596d7bc15bd01780eb9a607ac").
|
||||
Remount(m("/dev/"), syscall.MS_RDONLY).
|
||||
Tmpfs(m("/run/user/"), 4096, 0755).
|
||||
Bind(m("/tmp/hakurei.1971/runtime/0"), m("/run/user/65534"), container.BindWritable).
|
||||
Bind(m("/tmp/hakurei.1971/tmpdir/0"), m("/tmp/"), container.BindWritable).
|
||||
Bind(m("/home/chronos"), m("/home/chronos"), container.BindWritable).
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:65534:\n")).
|
||||
Remount(m("/"), syscall.MS_RDONLY),
|
||||
SeccompPresets: seccomp.PresetExt | seccomp.PresetDenyDevel,
|
||||
HostNet: true,
|
||||
RetainSession: true,
|
||||
@@ -74,7 +74,7 @@ var testCasesPd = []sealTestCase{
|
||||
Identity: 9,
|
||||
Groups: []string{"video"},
|
||||
Username: "chronos",
|
||||
Data: "/home/chronos",
|
||||
Data: m("/home/chronos"),
|
||||
SessionBus: &dbus.Config{
|
||||
Talk: []string{
|
||||
"org.freedesktop.Notifications",
|
||||
@@ -160,8 +160,8 @@ var testCasesPd = []sealTestCase{
|
||||
UpdatePerm("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus", acl.Read, acl.Write).
|
||||
UpdatePerm("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", acl.Read, acl.Write),
|
||||
&container.Params{
|
||||
Dir: "/home/chronos",
|
||||
Path: "/run/current-system/sw/bin/zsh",
|
||||
Dir: m("/home/chronos"),
|
||||
Path: m("/run/current-system/sw/bin/zsh"),
|
||||
Args: []string{"zsh", "-c", "exec chromium "},
|
||||
Env: []string{
|
||||
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus",
|
||||
@@ -178,29 +178,29 @@ var testCasesPd = []sealTestCase{
|
||||
"XDG_SESSION_TYPE=tty",
|
||||
},
|
||||
Ops: new(container.Ops).
|
||||
Root("/", "ebf083d1b175911782d413369b64ce7c", container.BindWritable).
|
||||
Proc("/proc/").
|
||||
Tmpfs(hst.Tmp, 4096, 0755).
|
||||
DevWritable("/dev/", true).
|
||||
Bind("/dev/dri", "/dev/dri", container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Bind("/dev/kvm", "/dev/kvm", container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Readonly("/var/run/nscd", 0755).
|
||||
Tmpfs("/run/user/1971", 8192, 0755).
|
||||
Tmpfs("/run/dbus", 8192, 0755).
|
||||
Etc("/etc/", "ebf083d1b175911782d413369b64ce7c").
|
||||
Remount("/dev/", syscall.MS_RDONLY).
|
||||
Tmpfs("/run/user/", 4096, 0755).
|
||||
Bind("/tmp/hakurei.1971/runtime/9", "/run/user/65534", container.BindWritable).
|
||||
Bind("/tmp/hakurei.1971/tmpdir/9", "/tmp/", container.BindWritable).
|
||||
Bind("/home/chronos", "/home/chronos", container.BindWritable).
|
||||
Place("/etc/passwd", []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
||||
Place("/etc/group", []byte("hakurei:x:65534:\n")).
|
||||
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/65534/wayland-0", 0).
|
||||
Bind("/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c/pulse", "/run/user/65534/pulse/native", 0).
|
||||
Place(hst.Tmp+"/pulse-cookie", nil).
|
||||
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus", "/run/user/65534/bus", 0).
|
||||
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", "/run/dbus/system_bus_socket", 0).
|
||||
Remount("/", syscall.MS_RDONLY),
|
||||
Root(m("/"), "ebf083d1b175911782d413369b64ce7c", container.BindWritable).
|
||||
Proc(m("/proc/")).
|
||||
Tmpfs(hst.AbsTmp, 4096, 0755).
|
||||
DevWritable(m("/dev/"), true).
|
||||
Bind(m("/dev/dri"), m("/dev/dri"), container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Bind(m("/dev/kvm"), m("/dev/kvm"), container.BindWritable|container.BindDevice|container.BindOptional).
|
||||
Readonly(m("/var/run/nscd"), 0755).
|
||||
Tmpfs(m("/run/user/1971"), 8192, 0755).
|
||||
Tmpfs(m("/run/dbus"), 8192, 0755).
|
||||
Etc(m("/etc/"), "ebf083d1b175911782d413369b64ce7c").
|
||||
Remount(m("/dev/"), syscall.MS_RDONLY).
|
||||
Tmpfs(m("/run/user/"), 4096, 0755).
|
||||
Bind(m("/tmp/hakurei.1971/runtime/9"), m("/run/user/65534"), container.BindWritable).
|
||||
Bind(m("/tmp/hakurei.1971/tmpdir/9"), m("/tmp/"), container.BindWritable).
|
||||
Bind(m("/home/chronos"), m("/home/chronos"), container.BindWritable).
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:65534:\n")).
|
||||
Bind(m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland"), m("/run/user/65534/wayland-0"), 0).
|
||||
Bind(m("/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c/pulse"), m("/run/user/65534/pulse/native"), 0).
|
||||
Place(m(hst.Tmp+"/pulse-cookie"), nil).
|
||||
Bind(m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus"), m("/run/user/65534/bus"), 0).
|
||||
Bind(m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket"), m("/run/dbus/system_bus_socket"), 0).
|
||||
Remount(m("/"), syscall.MS_RDONLY),
|
||||
SeccompPresets: seccomp.PresetExt | seccomp.PresetDenyDevel,
|
||||
HostNet: true,
|
||||
RetainSession: true,
|
||||
|
||||
@@ -127,8 +127,8 @@ func (s *stubNixOS) Open(name string) (fs.File, error) {
|
||||
|
||||
func (s *stubNixOS) Paths() hst.Paths {
|
||||
return hst.Paths{
|
||||
SharePath: "/tmp/hakurei.1971",
|
||||
RuntimePath: "/run/user/1971",
|
||||
RunDirPath: "/run/user/1971/hakurei",
|
||||
SharePath: m("/tmp/hakurei.1971"),
|
||||
RuntimePath: m("/run/user/1971"),
|
||||
RunDirPath: m("/run/user/1971/hakurei"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/hlog"
|
||||
"hakurei.app/internal/sys"
|
||||
"hakurei.app/system/dbus"
|
||||
)
|
||||
@@ -24,7 +25,7 @@ const preallocateOpsCount = 1 << 5
|
||||
// Note that remaining container setup must be queued by the caller.
|
||||
func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid *int) (*container.Params, map[string]string, error) {
|
||||
if s == nil {
|
||||
return nil, nil, syscall.EBADE
|
||||
return nil, nil, hlog.WrapErr(syscall.EBADE, "invalid container configuration")
|
||||
}
|
||||
|
||||
params := &container.Params{
|
||||
@@ -73,21 +74,18 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
|
||||
*gid = container.OverflowGid()
|
||||
}
|
||||
|
||||
if s.AutoRoot != "" {
|
||||
if !path.IsAbs(s.AutoRoot) {
|
||||
return nil, nil, fmt.Errorf("auto root target %q not absolute", s.AutoRoot)
|
||||
}
|
||||
if s.AutoRoot != nil {
|
||||
params.Root(s.AutoRoot, prefix, s.RootFlags)
|
||||
}
|
||||
|
||||
params.
|
||||
Proc(container.FHSProc).
|
||||
Tmpfs(hst.Tmp, 1<<12, 0755)
|
||||
Proc(container.AbsFHSProc).
|
||||
Tmpfs(hst.AbsTmp, 1<<12, 0755)
|
||||
|
||||
if !s.Device {
|
||||
params.DevWritable(container.FHSDev, true)
|
||||
params.DevWritable(container.AbsFHSDev, true)
|
||||
} else {
|
||||
params.Bind(container.FHSDev, container.FHSDev, container.BindWritable|container.BindDevice)
|
||||
params.Bind(container.AbsFHSDev, container.AbsFHSDev, container.BindWritable|container.BindDevice)
|
||||
}
|
||||
|
||||
/* retrieve paths and hide them if they're made available in the sandbox;
|
||||
@@ -96,7 +94,7 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
|
||||
and should not be treated as such, ALWAYS be careful with what you bind */
|
||||
var hidePaths []string
|
||||
sc := os.Paths()
|
||||
hidePaths = append(hidePaths, sc.RuntimePath, sc.SharePath)
|
||||
hidePaths = append(hidePaths, sc.RuntimePath.String(), sc.SharePath.String())
|
||||
_, systemBusAddr := dbus.Address()
|
||||
if entries, err := dbus.Parse([]byte(systemBusAddr)); err != nil {
|
||||
return nil, nil, err
|
||||
@@ -132,15 +130,15 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
|
||||
hidePathSource := make([][2]string, 0, len(s.Filesystem))
|
||||
|
||||
// AutoRoot is a collection of many BindMountOp internally
|
||||
if s.AutoRoot != "" {
|
||||
if d, err := os.ReadDir(s.AutoRoot); err != nil {
|
||||
if s.AutoRoot != nil {
|
||||
if d, err := os.ReadDir(s.AutoRoot.String()); err != nil {
|
||||
return nil, nil, err
|
||||
} else {
|
||||
hidePathSource = slices.Grow(hidePathSource, len(d))
|
||||
for _, ent := range d {
|
||||
name := ent.Name()
|
||||
if container.IsAutoRootBindable(name) {
|
||||
name = path.Join(s.AutoRoot, name)
|
||||
name = path.Join(s.AutoRoot.String(), name)
|
||||
srcP := [2]string{name, name}
|
||||
if err = evalSymlinks(os, &srcP[0]); err != nil {
|
||||
return nil, nil, err
|
||||
@@ -151,16 +149,16 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range s.Filesystem {
|
||||
if c == nil {
|
||||
continue
|
||||
for i, c := range s.Filesystem {
|
||||
if c.Src == nil {
|
||||
return nil, nil, fmt.Errorf("invalid filesystem at index %d", i)
|
||||
}
|
||||
|
||||
// special filesystems
|
||||
switch c.Src {
|
||||
case hst.SourceTmpfs:
|
||||
if !path.IsAbs(c.Dst) {
|
||||
return nil, nil, fmt.Errorf("tmpfs dst %q is not absolute", c.Dst)
|
||||
switch c.Src.String() {
|
||||
case container.Nonexistent:
|
||||
if c.Dst == nil {
|
||||
return nil, nil, errors.New("tmpfs dst must not be nil")
|
||||
}
|
||||
if c.Write {
|
||||
params.Tmpfs(c.Dst, hst.TmpfsSize, hst.TmpfsPerm)
|
||||
@@ -170,18 +168,12 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
|
||||
continue
|
||||
}
|
||||
|
||||
if !path.IsAbs(c.Src) {
|
||||
return nil, nil, fmt.Errorf("src path %q is not absolute", c.Src)
|
||||
dst := c.Dst
|
||||
if dst == nil {
|
||||
dst = c.Src
|
||||
}
|
||||
|
||||
dest := c.Dst
|
||||
if c.Dst == "" {
|
||||
dest = c.Src
|
||||
} else if !path.IsAbs(dest) {
|
||||
return nil, nil, fmt.Errorf("dst path %q is not absolute", dest)
|
||||
}
|
||||
|
||||
p := [2]string{c.Src, c.Src}
|
||||
p := [2]string{c.Src.String(), c.Src.String()}
|
||||
if err := evalSymlinks(os, &p[0]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -197,7 +189,7 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
|
||||
if !c.Must {
|
||||
flags |= container.BindOptional
|
||||
}
|
||||
params.Bind(c.Src, dest, flags)
|
||||
params.Bind(c.Src, dst, flags)
|
||||
}
|
||||
|
||||
for _, p := range hidePathSource {
|
||||
@@ -219,29 +211,49 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
|
||||
// cover matched paths
|
||||
for i, ok := range hidePathMatch {
|
||||
if ok {
|
||||
params.Tmpfs(hidePaths[i], 1<<13, 0755)
|
||||
if a, err := container.NewAbs(hidePaths[i]); err != nil {
|
||||
var absoluteError *container.AbsoluteError
|
||||
if !errors.As(err, &absoluteError) {
|
||||
return nil, nil, err
|
||||
}
|
||||
if absoluteError == nil {
|
||||
return nil, nil, syscall.ENOTRECOVERABLE
|
||||
}
|
||||
return nil, nil, fmt.Errorf("invalid path hiding candidate %q", absoluteError.Pathname)
|
||||
} else {
|
||||
params.Tmpfs(a, 1<<13, 0755)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, l := range s.Link {
|
||||
params.Link(l[0], l[1])
|
||||
for i, l := range s.Link {
|
||||
if l.Target == nil || l.Linkname == "" {
|
||||
return nil, nil, fmt.Errorf("invalid link at index %d", i)
|
||||
}
|
||||
linkname := l.Linkname
|
||||
var dereference bool
|
||||
if linkname[0] == '*' && path.IsAbs(linkname[1:]) {
|
||||
linkname = linkname[1:]
|
||||
dereference = true
|
||||
}
|
||||
params.Link(l.Target, linkname, dereference)
|
||||
}
|
||||
|
||||
if !s.AutoEtc {
|
||||
if s.Etc != "" {
|
||||
params.Bind(s.Etc, container.FHSEtc, 0)
|
||||
if s.Etc != nil {
|
||||
params.Bind(s.Etc, container.AbsFHSEtc, 0)
|
||||
}
|
||||
} else {
|
||||
etcPath := s.Etc
|
||||
if etcPath == "" {
|
||||
etcPath = container.FHSEtc
|
||||
if s.Etc == nil {
|
||||
params.Etc(container.AbsFHSEtc, prefix)
|
||||
} else {
|
||||
params.Etc(s.Etc, prefix)
|
||||
}
|
||||
params.Etc(etcPath, prefix)
|
||||
}
|
||||
|
||||
// no more ContainerConfig paths beyond this point
|
||||
if !s.Device {
|
||||
params.Remount(container.FHSDev, syscall.MS_RDONLY)
|
||||
params.Remount(container.AbsFHSDev, syscall.MS_RDONLY)
|
||||
}
|
||||
|
||||
return params, maps.Clone(s.Env), nil
|
||||
|
||||
@@ -39,7 +39,7 @@ func (seal *outcome) Run(rs *RunState) error {
|
||||
if err := seal.sys.Commit(seal.ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
store := state.NewMulti(seal.runDirPath)
|
||||
store := state.NewMulti(seal.runDirPath.String())
|
||||
deferredStoreFunc := func(c state.Cursor) error { return nil } // noop until state in store
|
||||
defer func() {
|
||||
var revertErr error
|
||||
@@ -128,7 +128,7 @@ func (seal *outcome) Run(rs *RunState) error {
|
||||
os.Getpid(),
|
||||
seal.waitDelay,
|
||||
seal.container,
|
||||
seal.user.data,
|
||||
seal.user.data.String(),
|
||||
hlog.Load(),
|
||||
})
|
||||
}()
|
||||
|
||||
@@ -49,10 +49,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrConfig = errors.New("no configuration to seal")
|
||||
ErrUser = errors.New("invalid aid")
|
||||
ErrHome = errors.New("invalid home directory")
|
||||
ErrName = errors.New("invalid username")
|
||||
ErrIdent = errors.New("invalid identity")
|
||||
ErrName = errors.New("invalid username")
|
||||
|
||||
ErrXDisplay = errors.New(display + " unset")
|
||||
|
||||
@@ -67,8 +65,8 @@ var posixUsername = regexp.MustCompilePOSIX("^[a-z_]([A-Za-z0-9_-]{0,31}|[A-Za-z
|
||||
type outcome struct {
|
||||
// copied from initialising [app]
|
||||
id *stringPair[state.ID]
|
||||
// copied from [sys.State] response
|
||||
runDirPath string
|
||||
// copied from [sys.State]
|
||||
runDirPath *container.Absolute
|
||||
|
||||
// initial [hst.Config] gob stream for state data;
|
||||
// this is prepared ahead of time as config is clobbered during seal creation
|
||||
@@ -93,9 +91,9 @@ type shareHost struct {
|
||||
// whether XDG_RUNTIME_DIR is used post hsu
|
||||
useRuntimeDir bool
|
||||
// process-specific directory in tmpdir, empty if unused
|
||||
sharePath string
|
||||
sharePath *container.Absolute
|
||||
// process-specific directory in XDG_RUNTIME_DIR, empty if unused
|
||||
runtimeSharePath string
|
||||
runtimeSharePath *container.Absolute
|
||||
|
||||
seal *outcome
|
||||
sc hst.Paths
|
||||
@@ -107,48 +105,48 @@ func (share *shareHost) ensureRuntimeDir() {
|
||||
return
|
||||
}
|
||||
share.useRuntimeDir = true
|
||||
share.seal.sys.Ensure(share.sc.RunDirPath, 0700)
|
||||
share.seal.sys.UpdatePermType(system.User, share.sc.RunDirPath, acl.Execute)
|
||||
share.seal.sys.Ensure(share.sc.RuntimePath, 0700) // ensure this dir in case XDG_RUNTIME_DIR is unset
|
||||
share.seal.sys.UpdatePermType(system.User, share.sc.RuntimePath, acl.Execute)
|
||||
share.seal.sys.Ensure(share.sc.RunDirPath.String(), 0700)
|
||||
share.seal.sys.UpdatePermType(system.User, share.sc.RunDirPath.String(), acl.Execute)
|
||||
share.seal.sys.Ensure(share.sc.RuntimePath.String(), 0700) // ensure this dir in case XDG_RUNTIME_DIR is unset
|
||||
share.seal.sys.UpdatePermType(system.User, share.sc.RuntimePath.String(), acl.Execute)
|
||||
}
|
||||
|
||||
// instance returns a process-specific share path within tmpdir
|
||||
func (share *shareHost) instance() string {
|
||||
if share.sharePath != "" {
|
||||
func (share *shareHost) instance() *container.Absolute {
|
||||
if share.sharePath != nil {
|
||||
return share.sharePath
|
||||
}
|
||||
share.sharePath = path.Join(share.sc.SharePath, share.seal.id.String())
|
||||
share.seal.sys.Ephemeral(system.Process, share.sharePath, 0711)
|
||||
share.sharePath = share.sc.SharePath.Append(share.seal.id.String())
|
||||
share.seal.sys.Ephemeral(system.Process, share.sharePath.String(), 0711)
|
||||
return share.sharePath
|
||||
}
|
||||
|
||||
// runtime returns a process-specific share path within XDG_RUNTIME_DIR
|
||||
func (share *shareHost) runtime() string {
|
||||
if share.runtimeSharePath != "" {
|
||||
func (share *shareHost) runtime() *container.Absolute {
|
||||
if share.runtimeSharePath != nil {
|
||||
return share.runtimeSharePath
|
||||
}
|
||||
share.ensureRuntimeDir()
|
||||
share.runtimeSharePath = path.Join(share.sc.RunDirPath, share.seal.id.String())
|
||||
share.seal.sys.Ephemeral(system.Process, share.runtimeSharePath, 0700)
|
||||
share.seal.sys.UpdatePerm(share.runtimeSharePath, acl.Execute)
|
||||
share.runtimeSharePath = share.sc.RunDirPath.Append(share.seal.id.String())
|
||||
share.seal.sys.Ephemeral(system.Process, share.runtimeSharePath.String(), 0700)
|
||||
share.seal.sys.UpdatePerm(share.runtimeSharePath.String(), acl.Execute)
|
||||
return share.runtimeSharePath
|
||||
}
|
||||
|
||||
// hsuUser stores post-hsu credentials and metadata
|
||||
type hsuUser struct {
|
||||
// application id
|
||||
// identity
|
||||
aid *stringPair[int]
|
||||
// target uid resolved by fid:aid
|
||||
// target uid resolved by hid:aid
|
||||
uid *stringPair[int]
|
||||
|
||||
// supplementary group ids
|
||||
supp []string
|
||||
|
||||
// home directory host path
|
||||
data string
|
||||
data *container.Absolute
|
||||
// app user home directory
|
||||
home string
|
||||
home *container.Absolute
|
||||
// passwd database username
|
||||
username string
|
||||
}
|
||||
@@ -159,6 +157,13 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
}
|
||||
seal.ctx = ctx
|
||||
|
||||
if config == nil {
|
||||
return hlog.WrapErr(syscall.EINVAL, syscall.EINVAL.Error())
|
||||
}
|
||||
if config.Data == nil {
|
||||
return hlog.WrapErr(os.ErrInvalid, "invalid data directory")
|
||||
}
|
||||
|
||||
{
|
||||
// encode initial configuration for state tracking
|
||||
ct := new(bytes.Buffer)
|
||||
@@ -171,7 +176,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
|
||||
// allowed aid range 0 to 9999, this is checked again in hsu
|
||||
if config.Identity < 0 || config.Identity > 9999 {
|
||||
return hlog.WrapErr(ErrUser,
|
||||
return hlog.WrapErr(ErrIdent,
|
||||
fmt.Sprintf("identity %d out of range", config.Identity))
|
||||
}
|
||||
|
||||
@@ -188,11 +193,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
return hlog.WrapErr(ErrName,
|
||||
fmt.Sprintf("invalid user name %q", seal.user.username))
|
||||
}
|
||||
if seal.user.data == "" || !path.IsAbs(seal.user.data) {
|
||||
return hlog.WrapErr(ErrHome,
|
||||
fmt.Sprintf("invalid home directory %q", seal.user.data))
|
||||
}
|
||||
if seal.user.home == "" {
|
||||
if seal.user.home == nil {
|
||||
seal.user.home = seal.user.data
|
||||
}
|
||||
if u, err := sys.Uid(seal.user.aid.unwrap()); err != nil {
|
||||
@@ -210,26 +211,25 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
}
|
||||
}
|
||||
|
||||
// this also falls back to host path if encountering an invalid path
|
||||
if !path.IsAbs(config.Shell) {
|
||||
config.Shell = "/bin/sh"
|
||||
if s, ok := sys.LookupEnv(shell); ok && path.IsAbs(s) {
|
||||
config.Shell = s
|
||||
}
|
||||
}
|
||||
// do not use the value of shell before this point
|
||||
|
||||
// permissive defaults
|
||||
if config.Container == nil {
|
||||
hlog.Verbose("container configuration not supplied, PROCEED WITH CAUTION")
|
||||
|
||||
if config.Shell == nil {
|
||||
config.Shell = container.AbsFHSRoot.Append("bin", "sh")
|
||||
s, _ := sys.LookupEnv(shell)
|
||||
if a, err := container.NewAbs(s); err == nil {
|
||||
config.Shell = a
|
||||
}
|
||||
}
|
||||
|
||||
// hsu clears the environment so resolve paths early
|
||||
if !path.IsAbs(config.Path) {
|
||||
if config.Path == nil {
|
||||
if len(config.Args) > 0 {
|
||||
if p, err := sys.LookPath(config.Args[0]); err != nil {
|
||||
return hlog.WrapErr(err, err.Error())
|
||||
} else {
|
||||
config.Path = p
|
||||
} else if config.Path, err = container.NewAbs(p); err != nil {
|
||||
return hlog.WrapErr(err, err.Error())
|
||||
}
|
||||
} else {
|
||||
config.Path = config.Shell
|
||||
@@ -242,26 +242,34 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
Tty: true,
|
||||
AutoEtc: true,
|
||||
|
||||
AutoRoot: container.FHSRoot,
|
||||
AutoRoot: container.AbsFHSRoot,
|
||||
RootFlags: container.BindWritable,
|
||||
}
|
||||
|
||||
// bind GPU stuff
|
||||
if config.Enablements&(system.EX11|system.EWayland) != 0 {
|
||||
conf.Filesystem = append(conf.Filesystem, &hst.FilesystemConfig{Src: container.FHSDev + "dri", Device: true})
|
||||
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Src: container.AbsFHSDev.Append("dri"), Device: true})
|
||||
}
|
||||
// opportunistically bind kvm
|
||||
conf.Filesystem = append(conf.Filesystem, &hst.FilesystemConfig{Src: container.FHSDev + "kvm", Device: true})
|
||||
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Src: container.AbsFHSDev.Append("kvm"), Device: true})
|
||||
|
||||
// hide nscd from container if present
|
||||
const nscd = container.FHSVar + "run/nscd"
|
||||
if _, err := sys.Stat(nscd); !errors.Is(err, fs.ErrNotExist) {
|
||||
conf.Filesystem = append(conf.Filesystem, &hst.FilesystemConfig{Dst: nscd, Src: hst.SourceTmpfs})
|
||||
nscd := container.AbsFHSVar.Append("run/nscd")
|
||||
if _, err := sys.Stat(nscd.String()); !errors.Is(err, fs.ErrNotExist) {
|
||||
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Dst: nscd, Src: container.AbsNonexistent})
|
||||
}
|
||||
|
||||
config.Container = conf
|
||||
}
|
||||
|
||||
// late nil checks for pd behaviour
|
||||
if config.Shell == nil {
|
||||
return hlog.WrapErr(syscall.EINVAL, "invalid shell path")
|
||||
}
|
||||
if config.Path == nil {
|
||||
return hlog.WrapErr(syscall.EINVAL, "invalid program path")
|
||||
}
|
||||
|
||||
var mapuid, mapgid *stringPair[int]
|
||||
{
|
||||
var uid, gid int
|
||||
@@ -272,12 +280,8 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
return hlog.WrapErrSuffix(err,
|
||||
"cannot initialise container configuration:")
|
||||
}
|
||||
if !path.IsAbs(config.Path) {
|
||||
return hlog.WrapErr(syscall.EINVAL,
|
||||
"invalid program path")
|
||||
}
|
||||
if len(config.Args) == 0 {
|
||||
config.Args = []string{config.Path}
|
||||
config.Args = []string{config.Path.String()}
|
||||
}
|
||||
seal.container.Path = config.Path
|
||||
seal.container.Args = config.Args
|
||||
@@ -290,56 +294,52 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
}
|
||||
|
||||
// inner XDG_RUNTIME_DIR default formatting of `/run/user/%d` as mapped uid
|
||||
innerRuntimeDir := path.Join(container.FHSRunUser, mapuid.String())
|
||||
seal.env[xdgRuntimeDir] = innerRuntimeDir
|
||||
innerRuntimeDir := container.AbsFHSRunUser.Append(mapuid.String())
|
||||
seal.env[xdgRuntimeDir] = innerRuntimeDir.String()
|
||||
seal.env[xdgSessionClass] = "user"
|
||||
seal.env[xdgSessionType] = "tty"
|
||||
|
||||
share := &shareHost{seal: seal, sc: sys.Paths()}
|
||||
seal.runDirPath = share.sc.RunDirPath
|
||||
seal.sys = system.New(seal.user.uid.unwrap())
|
||||
seal.sys.Ensure(share.sc.SharePath, 0711)
|
||||
seal.sys.Ensure(share.sc.SharePath.String(), 0711)
|
||||
|
||||
{
|
||||
runtimeDir := path.Join(share.sc.SharePath, "runtime")
|
||||
seal.sys.Ensure(runtimeDir, 0700)
|
||||
seal.sys.UpdatePermType(system.User, runtimeDir, acl.Execute)
|
||||
runtimeDirInst := path.Join(runtimeDir, seal.user.aid.String())
|
||||
seal.sys.Ensure(runtimeDirInst, 0700)
|
||||
seal.sys.UpdatePermType(system.User, runtimeDirInst, acl.Read, acl.Write, acl.Execute)
|
||||
seal.container.Tmpfs(container.FHSRunUser, 1<<12, 0755)
|
||||
runtimeDir := share.sc.SharePath.Append("runtime")
|
||||
seal.sys.Ensure(runtimeDir.String(), 0700)
|
||||
seal.sys.UpdatePermType(system.User, runtimeDir.String(), acl.Execute)
|
||||
runtimeDirInst := runtimeDir.Append(seal.user.aid.String())
|
||||
seal.sys.Ensure(runtimeDirInst.String(), 0700)
|
||||
seal.sys.UpdatePermType(system.User, runtimeDirInst.String(), acl.Read, acl.Write, acl.Execute)
|
||||
seal.container.Tmpfs(container.AbsFHSRunUser, 1<<12, 0755)
|
||||
seal.container.Bind(runtimeDirInst, innerRuntimeDir, container.BindWritable)
|
||||
}
|
||||
|
||||
{
|
||||
tmpdir := path.Join(share.sc.SharePath, "tmpdir")
|
||||
seal.sys.Ensure(tmpdir, 0700)
|
||||
seal.sys.UpdatePermType(system.User, tmpdir, acl.Execute)
|
||||
tmpdirInst := path.Join(tmpdir, seal.user.aid.String())
|
||||
seal.sys.Ensure(tmpdirInst, 01700)
|
||||
seal.sys.UpdatePermType(system.User, tmpdirInst, acl.Read, acl.Write, acl.Execute)
|
||||
tmpdir := share.sc.SharePath.Append("tmpdir")
|
||||
seal.sys.Ensure(tmpdir.String(), 0700)
|
||||
seal.sys.UpdatePermType(system.User, tmpdir.String(), acl.Execute)
|
||||
tmpdirInst := tmpdir.Append(seal.user.aid.String())
|
||||
seal.sys.Ensure(tmpdirInst.String(), 01700)
|
||||
seal.sys.UpdatePermType(system.User, tmpdirInst.String(), acl.Read, acl.Write, acl.Execute)
|
||||
// mount inner /tmp from share so it shares persistence and storage behaviour of host /tmp
|
||||
seal.container.Bind(tmpdirInst, container.FHSTmp, container.BindWritable)
|
||||
seal.container.Bind(tmpdirInst, container.AbsFHSTmp, container.BindWritable)
|
||||
}
|
||||
|
||||
{
|
||||
homeDir := container.FHSVarEmpty
|
||||
if seal.user.home != "" {
|
||||
homeDir = seal.user.home
|
||||
}
|
||||
username := "chronos"
|
||||
if seal.user.username != "" {
|
||||
username = seal.user.username
|
||||
}
|
||||
seal.container.Bind(seal.user.data, homeDir, container.BindWritable)
|
||||
seal.container.Dir = homeDir
|
||||
seal.env["HOME"] = homeDir
|
||||
seal.container.Bind(seal.user.data, seal.user.home, container.BindWritable)
|
||||
seal.container.Dir = seal.user.home
|
||||
seal.env["HOME"] = seal.user.home.String()
|
||||
seal.env["USER"] = username
|
||||
seal.env[shell] = config.Shell
|
||||
seal.env[shell] = config.Shell.String()
|
||||
|
||||
seal.container.Place(container.FHSEtc+"passwd",
|
||||
[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Hakurei:"+homeDir+":"+config.Shell+"\n"))
|
||||
seal.container.Place(container.FHSEtc+"group",
|
||||
seal.container.Place(container.AbsFHSEtc.Append("passwd"),
|
||||
[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Hakurei:"+seal.user.home.String()+":"+config.Shell.String()+"\n"))
|
||||
seal.container.Place(container.AbsFHSEtc.Append("group"),
|
||||
[]byte("hakurei:x:"+mapgid.String()+":\n"))
|
||||
}
|
||||
|
||||
@@ -350,17 +350,17 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
|
||||
if config.Enablements&system.EWayland != 0 {
|
||||
// outer wayland socket (usually `/run/user/%d/wayland-%d`)
|
||||
var socketPath string
|
||||
var socketPath *container.Absolute
|
||||
if name, ok := sys.LookupEnv(wayland.WaylandDisplay); !ok {
|
||||
hlog.Verbose(wayland.WaylandDisplay + " is not set, assuming " + wayland.FallbackName)
|
||||
socketPath = path.Join(share.sc.RuntimePath, wayland.FallbackName)
|
||||
} else if !path.IsAbs(name) {
|
||||
socketPath = path.Join(share.sc.RuntimePath, name)
|
||||
socketPath = share.sc.RuntimePath.Append(wayland.FallbackName)
|
||||
} else if a, err := container.NewAbs(name); err != nil {
|
||||
socketPath = share.sc.RuntimePath.Append(name)
|
||||
} else {
|
||||
socketPath = name
|
||||
socketPath = a
|
||||
}
|
||||
|
||||
innerPath := path.Join(innerRuntimeDir, wayland.FallbackName)
|
||||
innerPath := innerRuntimeDir.Append(wayland.FallbackName)
|
||||
seal.env[wayland.WaylandDisplay] = wayland.FallbackName
|
||||
|
||||
if !config.DirectWayland { // set up security-context-v1
|
||||
@@ -370,14 +370,14 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
appID = "app.hakurei." + seal.id.String()
|
||||
}
|
||||
// downstream socket paths
|
||||
outerPath := path.Join(share.instance(), "wayland")
|
||||
seal.sys.Wayland(&seal.sync, outerPath, socketPath, appID, seal.id.String())
|
||||
outerPath := share.instance().Append("wayland")
|
||||
seal.sys.Wayland(&seal.sync, outerPath.String(), socketPath.String(), appID, seal.id.String())
|
||||
seal.container.Bind(outerPath, innerPath, 0)
|
||||
} else { // bind mount wayland socket (insecure)
|
||||
hlog.Verbose("direct wayland access, PROCEED WITH CAUTION")
|
||||
share.ensureRuntimeDir()
|
||||
seal.container.Bind(socketPath, innerPath, 0)
|
||||
seal.sys.UpdatePermType(system.EWayland, socketPath, acl.Read, acl.Write, acl.Execute)
|
||||
seal.sys.UpdatePermType(system.EWayland, socketPath.String(), acl.Read, acl.Write, acl.Execute)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,17 +388,18 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
} else {
|
||||
seal.sys.ChangeHosts("#" + seal.user.uid.String())
|
||||
seal.env[display] = d
|
||||
seal.container.Bind(container.FHSTmp+".X11-unix", container.FHSTmp+".X11-unix", 0)
|
||||
socketDir := container.AbsFHSTmp.Append(".X11-unix")
|
||||
seal.container.Bind(socketDir, socketDir, 0)
|
||||
}
|
||||
}
|
||||
|
||||
if config.Enablements&system.EPulse != 0 {
|
||||
// PulseAudio runtime directory (usually `/run/user/%d/pulse`)
|
||||
pulseRuntimeDir := path.Join(share.sc.RuntimePath, "pulse")
|
||||
pulseRuntimeDir := share.sc.RuntimePath.Append("pulse")
|
||||
// PulseAudio socket (usually `/run/user/%d/pulse/native`)
|
||||
pulseSocket := path.Join(pulseRuntimeDir, "native")
|
||||
pulseSocket := pulseRuntimeDir.Append("native")
|
||||
|
||||
if _, err := sys.Stat(pulseRuntimeDir); err != nil {
|
||||
if _, err := sys.Stat(pulseRuntimeDir.String()); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return hlog.WrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot access PulseAudio directory %q:", pulseRuntimeDir))
|
||||
@@ -407,7 +408,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
fmt.Sprintf("PulseAudio directory %q not found", pulseRuntimeDir))
|
||||
}
|
||||
|
||||
if s, err := sys.Stat(pulseSocket); err != nil {
|
||||
if s, err := sys.Stat(pulseSocket.String()); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return hlog.WrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot access PulseAudio socket %q:", pulseSocket))
|
||||
@@ -422,19 +423,19 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
}
|
||||
|
||||
// hard link pulse socket into target-executable share
|
||||
innerPulseRuntimeDir := path.Join(share.runtime(), "pulse")
|
||||
innerPulseSocket := path.Join(innerRuntimeDir, "pulse", "native")
|
||||
seal.sys.Link(pulseSocket, innerPulseRuntimeDir)
|
||||
innerPulseRuntimeDir := share.runtime().Append("pulse")
|
||||
innerPulseSocket := innerRuntimeDir.Append("pulse", "native")
|
||||
seal.sys.Link(pulseSocket.String(), innerPulseRuntimeDir.String())
|
||||
seal.container.Bind(innerPulseRuntimeDir, innerPulseSocket, 0)
|
||||
seal.env[pulseServer] = "unix:" + innerPulseSocket
|
||||
seal.env[pulseServer] = "unix:" + innerPulseSocket.String()
|
||||
|
||||
// publish current user's pulse cookie for target user
|
||||
if src, err := discoverPulseCookie(sys); err != nil {
|
||||
// not fatal
|
||||
hlog.Verbose(strings.TrimSpace(err.(*hlog.BaseError).Message()))
|
||||
} else {
|
||||
innerDst := hst.Tmp + "/pulse-cookie"
|
||||
seal.env[pulseCookie] = innerDst
|
||||
innerDst := hst.AbsTmp.Append("/pulse-cookie")
|
||||
seal.env[pulseCookie] = innerDst.String()
|
||||
var payload *[]byte
|
||||
seal.container.PlaceP(innerDst, &payload)
|
||||
seal.sys.CopyFile(payload, src, 256, 256)
|
||||
@@ -448,13 +449,12 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
}
|
||||
|
||||
// downstream socket paths
|
||||
sharePath := share.instance()
|
||||
sessionPath, systemPath := path.Join(sharePath, "bus"), path.Join(sharePath, "system_bus_socket")
|
||||
sessionPath, systemPath := share.instance().Append("bus"), share.instance().Append("system_bus_socket")
|
||||
|
||||
// configure dbus proxy
|
||||
if f, err := seal.sys.ProxyDBus(
|
||||
config.SessionBus, config.SystemBus,
|
||||
sessionPath, systemPath,
|
||||
sessionPath.String(), systemPath.String(),
|
||||
); err != nil {
|
||||
return err
|
||||
} else {
|
||||
@@ -462,20 +462,20 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
}
|
||||
|
||||
// share proxy sockets
|
||||
sessionInner := path.Join(innerRuntimeDir, "bus")
|
||||
seal.env[dbusSessionBusAddress] = "unix:path=" + sessionInner
|
||||
sessionInner := innerRuntimeDir.Append("bus")
|
||||
seal.env[dbusSessionBusAddress] = "unix:path=" + sessionInner.String()
|
||||
seal.container.Bind(sessionPath, sessionInner, 0)
|
||||
seal.sys.UpdatePerm(sessionPath, acl.Read, acl.Write)
|
||||
seal.sys.UpdatePerm(sessionPath.String(), acl.Read, acl.Write)
|
||||
if config.SystemBus != nil {
|
||||
systemInner := container.FHSRun + "dbus/system_bus_socket"
|
||||
seal.env[dbusSystemBusAddress] = "unix:path=" + systemInner
|
||||
systemInner := container.AbsFHSRun.Append("dbus/system_bus_socket")
|
||||
seal.env[dbusSystemBusAddress] = "unix:path=" + systemInner.String()
|
||||
seal.container.Bind(systemPath, systemInner, 0)
|
||||
seal.sys.UpdatePerm(systemPath, acl.Read, acl.Write)
|
||||
seal.sys.UpdatePerm(systemPath.String(), acl.Read, acl.Write)
|
||||
}
|
||||
}
|
||||
|
||||
// mount root read-only as the final setup Op
|
||||
seal.container.Remount(container.FHSRoot, syscall.MS_RDONLY)
|
||||
seal.container.Remount(container.AbsFHSRoot, syscall.MS_RDONLY)
|
||||
|
||||
// append ExtraPerms last
|
||||
for _, p := range config.ExtraPerms {
|
||||
@@ -484,7 +484,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
}
|
||||
|
||||
if p.Ensure {
|
||||
seal.sys.Ensure(p.Path, 0700)
|
||||
seal.sys.Ensure(p.Path.String(), 0700)
|
||||
}
|
||||
|
||||
perms := make(acl.Perms, 0, 3)
|
||||
@@ -497,7 +497,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
||||
if p.Execute {
|
||||
perms = append(perms, acl.Execute)
|
||||
}
|
||||
seal.sys.UpdatePermType(system.User, p.Path, perms...)
|
||||
seal.sys.UpdatePermType(system.User, p.Path.String(), perms...)
|
||||
}
|
||||
|
||||
// flatten and sort env for deterministic behaviour
|
||||
|
||||
Reference in New Issue
Block a user