From b3ef53b193bdf764d8f04e19ea47901b71eec10b Mon Sep 17 00:00:00 2001 From: Ophestra Umiker Date: Fri, 6 Dec 2024 04:25:33 +0900 Subject: app: integrate security-context-v1 Should be able to get rid of XDG_RUNTIME_DIR share after this. Signed-off-by: Ophestra Umiker --- internal/app/app_nixos_test.go | 4 ++-- internal/app/app_pd_test.go | 6 +++--- internal/app/config.go | 18 +++++++++--------- internal/app/seal.go | 12 +++--------- internal/app/share.display.go | 25 +++++++++++++++++++------ internal/app/start.go | 12 +++--------- 6 files changed, 39 insertions(+), 38 deletions(-) (limited to 'internal/app') diff --git a/internal/app/app_nixos_test.go b/internal/app/app_nixos_test.go index 06bde05c..33380793 100644 --- a/internal/app/app_nixos_test.go +++ b/internal/app/app_nixos_test.go @@ -10,7 +10,7 @@ import ( var testCasesNixos = []sealTestCase{ { - "nixos chromium", new(stubNixOS), + "nixos chromium direct wayland", new(stubNixOS), &app.Config{ ID: "org.chromium.Chromium", Command: []string{"/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"}, @@ -18,7 +18,7 @@ var testCasesNixos = []sealTestCase{ AppID: 1, Groups: []string{}, Username: "u0_a1", Outer: "/var/lib/persist/module/fortify/0/1", Sandbox: &app.SandboxConfig{ - UserNS: true, Net: true, MapRealUID: true, Env: nil, + UserNS: true, Net: true, MapRealUID: true, DirectWayland: true, Env: nil, Filesystem: []*app.FilesystemConfig{ {Src: "/bin", Must: true}, {Src: "/usr/bin", Must: true}, {Src: "/nix/store", Must: true}, {Src: "/run/current-system", Must: true}, diff --git a/internal/app/app_pd_test.go b/internal/app/app_pd_test.go index 224d2636..a97bbcf7 100644 --- a/internal/app/app_pd_test.go +++ b/internal/app/app_pd_test.go @@ -248,8 +248,8 @@ var testCasesPd = []sealTestCase{ Ephemeral(system.Process, "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c", 0700).UpdatePermType(system.Process, "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c", acl.Execute). WriteType(system.Process, "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/passwd", "chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n"). WriteType(system.Process, "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/group", "fortify:x:65534:\n"). - Link("/run/user/1971/wayland-0", "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/wayland"). - UpdatePermType(system.EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute). + Ensure("/tmp/fortify.1971/wayland", 0711). + Wayland("/tmp/fortify.1971/wayland/ebf083d1b175911782d413369b64ce7c", "/run/user/1971/wayland-0", "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c"). Link("/run/user/1971/pulse/native", "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/pulse"). CopyFile("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/pulse-cookie", "/home/ophestra/xdg/config/pulse/cookie"). MustProxyDBus("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", &dbus.Config{ @@ -442,7 +442,7 @@ var testCasesPd = []sealTestCase{ Bind("/home/chronos", "/home/chronos", false, true). Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/passwd", "/etc/passwd"). Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/group", "/etc/group"). - Bind("/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/65534/wayland-0"). + Bind("/tmp/fortify.1971/wayland/ebf083d1b175911782d413369b64ce7c", "/run/user/65534/wayland-0"). Bind("/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/pulse", "/run/user/65534/pulse/native"). Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/pulse-cookie", "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/pulse-cookie"). Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", "/run/user/65534/bus"). diff --git a/internal/app/config.go b/internal/app/config.go index 298925de..758dcd08 100644 --- a/internal/app/config.go +++ b/internal/app/config.go @@ -62,8 +62,8 @@ type SandboxConfig struct { NoNewSession bool `json:"no_new_session,omitempty"` // map target user uid to privileged user uid in the user namespace MapRealUID bool `json:"map_real_uid"` - // mediated access to wayland socket - Wayland bool `json:"wayland,omitempty"` + // direct access to wayland socket + DirectWayland bool `json:"direct_wayland,omitempty"` // final environment variables Env map[string]string `json:"env"` @@ -190,13 +190,13 @@ func Template() *Config { Outer: "/var/lib/persist/home/org.chromium.Chromium", Inner: "/var/lib/fortify", Sandbox: &SandboxConfig{ - Hostname: "localhost", - UserNS: true, - Net: true, - NoNewSession: true, - MapRealUID: true, - Dev: true, - Wayland: false, + Hostname: "localhost", + UserNS: true, + Net: true, + NoNewSession: true, + MapRealUID: true, + Dev: true, + DirectWayland: false, // example API credentials pulled from Google Chrome // DO NOT USE THESE IN A REAL BROWSER Env: map[string]string{ diff --git a/internal/app/seal.go b/internal/app/seal.go index d3c7a875..94c9e061 100644 --- a/internal/app/seal.go +++ b/internal/app/seal.go @@ -8,7 +8,6 @@ import ( "regexp" "strconv" - shim "git.ophivana.moe/security/fortify/cmd/fshim/ipc" "git.ophivana.moe/security/fortify/dbus" "git.ophivana.moe/security/fortify/internal/fmsg" "git.ophivana.moe/security/fortify/internal/linux" @@ -29,8 +28,6 @@ var posixUsername = regexp.MustCompilePOSIX("^[a-z_]([A-Za-z0-9_-]{0,31}|[A-Za-z type appSeal struct { // app unique ID string representation id string - // wayland mediation, disabled if nil - wl *shim.Wayland // dbus proxy message buffer retriever dbusMsg func(f func(msgbuf []string)) @@ -48,6 +45,8 @@ type appSeal struct { // pass-through enablement tracking from config et system.Enablements + // wayland socket direct access + directWayland bool // prevents sharing from happening twice shared bool @@ -204,6 +203,7 @@ func (a *app) Seal(config *Config) error { config.Confinement.Sandbox = conf } + seal.directWayland = config.Confinement.Sandbox.DirectWayland if b, err := config.Confinement.Sandbox.Bwrap(a.os); err != nil { return err } else { @@ -214,12 +214,6 @@ func (a *app) Seal(config *Config) error { seal.sys.bwrap.SetEnv = make(map[string]string) } - // create wayland struct and client wait channel if mediated wayland is enabled - // this field being set enables mediated wayland setup later on - if config.Confinement.Sandbox.Wayland { - seal.wl = shim.NewWayland() - } - // open process state store // the simple store only starts holding an open file after first action // store activity begins after Start is called and must end before Wait diff --git a/internal/app/share.display.go b/internal/app/share.display.go index 801ca54c..b1d98342 100644 --- a/internal/app/share.display.go +++ b/internal/app/share.display.go @@ -31,23 +31,36 @@ func (seal *appSeal) shareDisplay(os linux.System) error { // set up wayland if seal.et.Has(system.EWayland) { + var wp string if wd, ok := os.LookupEnv(waylandDisplay); !ok { return fmsg.WrapError(ErrWayland, "WAYLAND_DISPLAY is not set") - } else if seal.wl == nil { + } else { + wp = path.Join(seal.RuntimePath, wd) + } + + w := path.Join(seal.sys.runtime, "wayland-0") + seal.sys.bwrap.SetEnv[waylandDisplay] = w + + if seal.directWayland { // hardlink wayland socket - wp := path.Join(seal.RuntimePath, wd) wpi := path.Join(seal.shareLocal, "wayland") - w := path.Join(seal.sys.runtime, "wayland-0") seal.sys.Link(wp, wpi) - seal.sys.bwrap.SetEnv[waylandDisplay] = w seal.sys.bwrap.Bind(wpi, w) // ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`) seal.sys.UpdatePermType(system.EWayland, wp, acl.Read, acl.Write, acl.Execute) } else { - // set wayland socket path for mediation (e.g. `/run/user/%d/wayland-%d`) - seal.wl.Path = path.Join(seal.RuntimePath, wd) + wc := path.Join(seal.SharePath, "wayland") + wt := path.Join(wc, seal.id) + seal.sys.Ensure(wc, 0711) + appID := seal.fid + if appID == "" { + // use instance ID in case app id is not set + appID = "moe.ophivana.fortify." + seal.id + } + seal.sys.Wayland(wt, wp, appID, seal.id) + seal.sys.bwrap.Bind(wt, w) } } diff --git a/internal/app/start.go b/internal/app/start.go index c33d26fb..e1247d4c 100644 --- a/internal/app/start.go +++ b/internal/app/start.go @@ -47,12 +47,10 @@ func (a *app) Start() error { a.seal.sys.user.as, a.seal.sys.user.supp, path.Join(a.seal.share, "shim"), - a.seal.wl, &shim0.Payload{ Argv: a.seal.command, Exec: shimExec, Bwrap: a.seal.sys.bwrap, - WL: a.seal.wl != nil, Verbose: fmsg.Verbose(), }, @@ -64,6 +62,9 @@ func (a *app) Start() error { } a.seal.sys.needRevert = true + // export sync pipe from sys + a.seal.sys.bwrap.SetSync(a.seal.sys.Sync()) + if startTime, err := a.shim.Start(); err != nil { return err } else { @@ -199,13 +200,6 @@ func (a *app) Wait() (int, error) { }) } - // close wayland connection - if a.seal.wl != nil { - if err := a.seal.wl.Close(); err != nil { - fmsg.Println("cannot close wayland connection:", err) - } - } - // update store and revert app setup transaction e := new(StateStoreError) e.Inner, e.DoErr = a.seal.store.Do(func(b state.Backend) { -- cgit v1.3.1