diff --git a/cmd/app/main.go b/cmd/app/main.go index 0ffa0d53..07c2cdb8 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -103,7 +103,8 @@ func main() { }}, }, Username: "chronos", - Flags: hst.FMultiarch | + Flags: hst.FNoPlace | + hst.FMultiarch | hst.FDevel | hst.FUserns | hst.FHostNet | diff --git a/cmd/hakurei/print_test.go b/cmd/hakurei/print_test.go index 71eb8caa..a6e213c2 100644 --- a/cmd/hakurei/print_test.go +++ b/cmd/hakurei/print_test.go @@ -64,7 +64,7 @@ func TestPrintShowInstance(t *testing.T) { Identity: 9 (org.chromium.Chromium) Enablements: wayland, dbus, pipewire Groups: video, dialout, plugdev - Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir + Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir Home: /data/data/org.chromium.Chromium Hostname: localhost Path: /run/current-system/sw/bin/chromium @@ -161,7 +161,7 @@ App Identity: 9 (org.chromium.Chromium) Enablements: wayland, dbus, pipewire Groups: video, dialout, plugdev - Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir + Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir Home: /data/data/org.chromium.Chromium Hostname: localhost Path: /run/current-system/sw/bin/chromium @@ -354,6 +354,7 @@ App "tty": true, "multiarch": true, "map_real_uid": true, + "noplace": true, "device": true, "cover_run": true, "share_runtime": true, @@ -506,6 +507,7 @@ App "tty": true, "multiarch": true, "map_real_uid": true, + "noplace": true, "device": true, "cover_run": true, "share_runtime": true, @@ -705,6 +707,7 @@ func TestPrintPs(t *testing.T) { "tty": true, "multiarch": true, "map_real_uid": true, + "noplace": true, "device": true, "cover_run": true, "share_runtime": true, diff --git a/hst/container.go b/hst/container.go index a34efc32..824b0982 100644 --- a/hst/container.go +++ b/hst/container.go @@ -65,6 +65,8 @@ const ( // Some programs fail to connect to dbus session running as a different uid, // this option works around it by mapping priv-side caller uid in container. FMapRealUID + // FNoPlace disables placement of /etc/passwd and /etc/group. + FNoPlace // FDevice mount /dev/ from the init mount namespace as is in the container // mount namespace. @@ -101,6 +103,8 @@ func (flags Flags) String() string { return "tty" case FMapRealUID: return "mapuid" + case FNoPlace: + return "noplace" case FDevice: return "device" case FCoverRun: @@ -197,6 +201,8 @@ type containerConfigJSON = struct { // Corresponds to [FMapRealUID]. MapRealUID bool `json:"map_real_uid"` + // Corresponds to [FNoPlace]. + NoPlace bool `json:"noplace,omitempty"` // Corresponds to [FDevice]. Device bool `json:"device,omitempty"` @@ -224,6 +230,7 @@ func (c *ContainerConfig) MarshalJSON() ([]byte, error) { Tty: c.Flags&FTty != 0, Multiarch: c.Flags&FMultiarch != 0, MapRealUID: c.Flags&FMapRealUID != 0, + NoPlace: c.Flags&FNoPlace != 0, Device: c.Flags&FDevice != 0, CoverRun: c.Flags&FCoverRun != 0, ShareRuntime: c.Flags&FShareRuntime != 0, @@ -266,6 +273,9 @@ func (c *ContainerConfig) UnmarshalJSON(data []byte) error { if v.MapRealUID { c.Flags |= FMapRealUID } + if v.NoPlace { + c.Flags |= FNoPlace + } if v.Device { c.Flags |= FDevice } diff --git a/hst/container_test.go b/hst/container_test.go index 309c0a63..a44014ea 100644 --- a/hst/container_test.go +++ b/hst/container_test.go @@ -21,8 +21,8 @@ func TestFlagsString(t *testing.T) { }{ {"none", 0, "none"}, {"none high", hst.FAll + 1, "none"}, - {"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir"}, - {"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir"}, + {"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir"}, + {"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir"}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -53,7 +53,7 @@ func TestContainerConfig(t *testing.T) { {"hostnet hostabstract mapuid", &hst.ContainerConfig{Flags: hst.FHostNet | hst.FHostAbstract | hst.FMapRealUID}, `{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"host_net":true,"host_abstract":true,"map_real_uid":true}`}, {"all", &hst.ContainerConfig{Flags: hst.FAll}, - `{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"seccomp_compat":true,"devel":true,"userns":true,"host_net":true,"host_abstract":true,"tty":true,"multiarch":true,"map_real_uid":true,"device":true,"cover_run":true,"share_runtime":true,"share_tmpdir":true}`}, + `{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"seccomp_compat":true,"devel":true,"userns":true,"host_net":true,"host_abstract":true,"tty":true,"multiarch":true,"map_real_uid":true,"noplace":true,"device":true,"cover_run":true,"share_runtime":true,"share_tmpdir":true}`}, } for _, tc := range testCases { diff --git a/hst/hst_test.go b/hst/hst_test.go index c5e2cb12..83ea225e 100644 --- a/hst/hst_test.go +++ b/hst/hst_test.go @@ -244,6 +244,7 @@ func TestTemplate(t *testing.T) { "tty": true, "multiarch": true, "map_real_uid": true, + "noplace": true, "device": true, "cover_run": true, "share_runtime": true, diff --git a/internal/outcome/run_test.go b/internal/outcome/run_test.go index faa322ec..2a412d8b 100644 --- a/internal/outcome/run_test.go +++ b/internal/outcome/run_test.go @@ -143,10 +143,6 @@ func TestOutcomeRun(t *testing.T) { // spTmpdirOp Bind(m("/tmp/hakurei.0/tmpdir/9"), fhs.AbsTmp, std.BindWritable). - // spAccountOp - Place(m("/etc/passwd"), []byte("chronos:x:1971:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")). - Place(m("/etc/group"), []byte("hakurei:x:100:\n")). - // spWaylandOp Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1971/wayland-0"), 0). @@ -453,7 +449,7 @@ func TestOutcomeRun(t *testing.T) { Path: m("/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"), - Flags: hst.FUserns | hst.FHostNet | hst.FMapRealUID | hst.FShareRuntime | hst.FShareTmpdir, + Flags: hst.FUserns | hst.FHostNet | hst.FMapRealUID | hst.FNoPlace | hst.FShareRuntime | hst.FShareTmpdir, }, SystemBus: &hst.BusConfig{ Talk: []string{"org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"}, @@ -548,8 +544,6 @@ func TestOutcomeRun(t *testing.T) { Tmpfs(m("/run/user/"), xdgRuntimeDirSize, 0755). Bind(m("/tmp/hakurei.0/runtime/1"), m("/run/user/1971"), std.BindWritable). Bind(m("/tmp/hakurei.0/tmpdir/1"), m("/tmp/"), std.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("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire"), m("/run/user/1971/pipewire-0"), 0). Bind(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/bus"), m("/run/user/1971/bus"), 0). diff --git a/internal/outcome/shim_test.go b/internal/outcome/shim_test.go index 2dc7a4cd..5d7dab76 100644 --- a/internal/outcome/shim_test.go +++ b/internal/outcome/shim_test.go @@ -78,10 +78,6 @@ func TestShimEntrypoint(t *testing.T) { // spTmpdirOp Bind(m("/tmp/hakurei.10/tmpdir/9999"), fhs.AbsTmp, std.BindWritable). - // spAccountOp - Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")). - Place(m("/etc/group"), []byte("hakurei:x:100:\n")). - // spWaylandOp Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1000/wayland-0"), 0). diff --git a/internal/outcome/spaccount.go b/internal/outcome/spaccount.go index 1a849cb5..ccc64479 100644 --- a/internal/outcome/spaccount.go +++ b/internal/outcome/spaccount.go @@ -6,6 +6,7 @@ import ( "syscall" "hakurei.app/fhs" + "hakurei.app/hst" "hakurei.app/internal/validate" ) @@ -41,16 +42,18 @@ func (s spAccountOp) toContainer(state *outcomeStateParams) error { state.env["USER"] = username state.env["SHELL"] = state.Container.Shell.String() - state.params. - Place(fhs.AbsEtc.Append("passwd"), - []byte(username+":x:"+ - state.mapuid.String()+":"+ - state.mapgid.String()+ - ":Hakurei:"+ - state.Container.Home.String()+":"+ - state.Container.Shell.String()+"\n")). - Place(fhs.AbsEtc.Append("group"), - []byte("hakurei:x:"+state.mapgid.String()+":\n")) + if state.Container.Flags&hst.FNoPlace == 0 { + state.params. + Place(fhs.AbsEtc.Append("passwd"), + []byte(username+":x:"+ + state.mapuid.String()+":"+ + state.mapgid.String()+ + ":Hakurei:"+ + state.Container.Home.String()+":"+ + state.Container.Shell.String()+"\n")). + Place(fhs.AbsEtc.Append("group"), + []byte("hakurei:x:"+state.mapgid.String()+":\n")) + } return nil } diff --git a/internal/outcome/spaccount_test.go b/internal/outcome/spaccount_test.go index f94e4591..fb20d8df 100644 --- a/internal/outcome/spaccount_test.go +++ b/internal/outcome/spaccount_test.go @@ -38,6 +38,7 @@ func TestSpAccountOp(t *testing.T) { {"success fallback username", func(bool, bool) outcomeOp { return spAccountOp{} }, func() *hst.Config { c := hst.Template() c.Container.Username = "" + c.Container.Flags = hst.FMapRealUID return c }, nil, []stub.Call{ // this op performs basic validation and does not make calls during toSystem @@ -60,9 +61,7 @@ func TestSpAccountOp(t *testing.T) { // this op configures the container state and does not make calls during toContainer }, &container.Params{ Dir: config.Container.Home, - Ops: new(container.Ops). - Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")). - Place(m("/etc/group"), []byte("hakurei:x:100:\n")), + Ops: new(container.Ops), }, paramsWantEnv(config, map[string]string{ "HOME": config.Container.Home.String(), "USER": config.Container.Username,