aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-01-05 20:09:35 +0900
committerOphestra <cat@gensokyo.uk>2025-01-05 20:09:35 +0900
commite2489059c103800ab62250351db895415e0cdfed (patch)
treebc09c183d938adddc578145204d1eea115d1ec2c
parent2e3f6a4c5194e2f571f488e81cd1511fe3fbba48 (diff)
helper/bwrap: implement overlayfs builder
Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--helper/bwrap/arg.static.awkward.go10
-rw-r--r--helper/bwrap/config.go70
-rw-r--r--helper/bwrap/config.set.go25
-rw-r--r--helper/bwrap/config_test.go19
4 files changed, 124 insertions, 0 deletions
diff --git a/helper/bwrap/arg.static.awkward.go b/helper/bwrap/arg.static.awkward.go
index 0848d1fb..91fde87a 100644
--- a/helper/bwrap/arg.static.awkward.go
+++ b/helper/bwrap/arg.static.awkward.go
@@ -4,10 +4,20 @@ const (
Tmpfs = iota
Dir
Symlink
+
+ OverlaySrc
+ Overlay
+ TmpOverlay
+ ROOverlay
)
var awkwardArgs = [...]string{
Tmpfs: "--tmpfs",
Dir: "--dir",
Symlink: "--symlink",
+
+ OverlaySrc: "--overlay-src",
+ Overlay: "--overlay",
+ TmpOverlay: "--tmp-overlay",
+ ROOverlay: "--ro-overlay",
}
diff --git a/helper/bwrap/config.go b/helper/bwrap/config.go
index 5556f4c3..6bac6ef7 100644
--- a/helper/bwrap/config.go
+++ b/helper/bwrap/config.go
@@ -78,6 +78,8 @@ type Config struct {
--userns FD Use this user namespace (cannot combine with --unshare-user)
--userns2 FD After setup switch to this user namespace, only useful with --userns
--pidns FD Use this pid namespace (as parent namespace if using --unshare-pid)
+ --bind-fd FD DEST Bind open directory or path fd on DEST
+ --ro-bind-fd FD DEST Bind open directory or path fd read-only on DEST
--exec-label LABEL Exec label for the sandbox
--file-label LABEL File label for temporary sandbox content
--file FD DEST Copy from FD to destination DEST
@@ -178,6 +180,74 @@ func (t *TmpfsConfig) Append(args *[]string) {
*args = append(*args, awkwardArgs[Tmpfs], t.Dir)
}
+type OverlayConfig struct {
+ /*
+ read files from SRC in the following overlay
+ (--overlay-src SRC)
+ */
+ Src []string `json:"src,omitempty"`
+
+ /*
+ mount overlayfs on DEST, with RWSRC as the host path for writes and
+ WORKDIR an empty directory on the same filesystem as RWSRC
+ (--overlay RWSRC WORKDIR DEST)
+
+ if nil, mount overlayfs on DEST, with writes going to an invisible tmpfs
+ (--tmp-overlay DEST)
+
+ if either strings are empty, mount overlayfs read-only on DEST
+ (--ro-overlay DEST)
+ */
+ Persist *[2]string `json:"persist,omitempty"`
+
+ /*
+ --overlay RWSRC WORKDIR DEST
+
+ --tmp-overlay DEST
+
+ --ro-overlay DEST
+ */
+ Dest string `json:"dest"`
+}
+
+func (o *OverlayConfig) Path() string {
+ return o.Dest
+}
+
+func (o *OverlayConfig) Len() int {
+ // (--tmp-overlay DEST) or (--ro-overlay DEST)
+ p := 2
+ // (--overlay RWSRC WORKDIR DEST)
+ if o.Persist != nil && o.Persist[0] != "" && o.Persist[1] != "" {
+ p = 4
+ }
+
+ return p + len(o.Src)*2
+}
+
+func (o *OverlayConfig) Append(args *[]string) {
+ // --overlay-src SRC
+ for _, src := range o.Src {
+ *args = append(*args, awkwardArgs[OverlaySrc], src)
+ }
+
+ if o.Persist != nil {
+ if o.Persist[0] != "" && o.Persist[1] != "" {
+ // --overlay RWSRC WORKDIR
+ *args = append(*args, awkwardArgs[Overlay], o.Persist[0], o.Persist[1])
+ } else {
+ // --ro-overlay
+ *args = append(*args, awkwardArgs[ROOverlay])
+ }
+ } else {
+ // --tmp-overlay
+ *args = append(*args, awkwardArgs[TmpOverlay])
+ }
+
+ // DEST
+ *args = append(*args, o.Dest)
+}
+
type SymlinkConfig [2]string
func (s SymlinkConfig) Path() string {
diff --git a/helper/bwrap/config.set.go b/helper/bwrap/config.set.go
index ca2f8554..8cbafda3 100644
--- a/helper/bwrap/config.set.go
+++ b/helper/bwrap/config.set.go
@@ -96,6 +96,31 @@ func (c *Config) Tmpfs(dest string, size int, perm ...os.FileMode) *Config {
return c
}
+// Overlay mount overlayfs on DEST, with writes going to an invisible tmpfs
+// (--tmp-overlay DEST)
+func (c *Config) Overlay(dest string, src ...string) *Config {
+ c.Filesystem = append(c.Filesystem, &OverlayConfig{Src: src, Dest: dest})
+ return c
+}
+
+// Join mount overlayfs read-only on DEST
+// (--ro-overlay DEST)
+func (c *Config) Join(dest string, src ...string) *Config {
+ c.Filesystem = append(c.Filesystem, &OverlayConfig{Src: src, Dest: dest, Persist: new([2]string)})
+ return c
+}
+
+// Persist mount overlayfs on DEST, with RWSRC as the host path for writes and
+// WORKDIR an empty directory on the same filesystem as RWSRC
+// (--overlay RWSRC WORKDIR DEST)
+func (c *Config) Persist(dest, rwsrc, workdir string, src ...string) *Config {
+ if rwsrc == "" || workdir == "" {
+ panic("persist called without required paths")
+ }
+ c.Filesystem = append(c.Filesystem, &OverlayConfig{Src: src, Dest: dest, Persist: &[2]string{rwsrc, workdir}})
+ return c
+}
+
// Mqueue mount new mqueue in sandbox
// (--mqueue DEST)
func (c *Config) Mqueue(dest string) *Config {
diff --git a/helper/bwrap/config_test.go b/helper/bwrap/config_test.go
index 0170bcf8..afbcedea 100644
--- a/helper/bwrap/config_test.go
+++ b/helper/bwrap/config_test.go
@@ -14,6 +14,25 @@ func TestConfig_Args(t *testing.T) {
want []string
}{
{
+ name: "overlayfs",
+ conf: (new(bwrap.Config)).
+ Overlay("/etc", "/etc").
+ Join("/.fortify/bin", "/bin", "/usr/bin", "/usr/local/bin").
+ Persist("/nix", "/data/data/org.chromium.Chromium/overlay/rwsrc", "/data/data/org.chromium.Chromium/workdir", "/data/app/org.chromium.Chromium/nix"),
+ want: []string{
+ "--unshare-all", "--unshare-user",
+ "--disable-userns", "--assert-userns-disabled",
+ // Overlay("/etc", "/etc")
+ "--overlay-src", "/etc", "--tmp-overlay", "/etc",
+ // Join("/.fortify/bin", "/bin", "/usr/bin", "/usr/local/bin")
+ "--overlay-src", "/bin", "--overlay-src", "/usr/bin",
+ "--overlay-src", "/usr/local/bin", "--ro-overlay", "/.fortify/bin",
+ // Persist("/nix", "/data/data/org.chromium.Chromium/overlay/rwsrc", "/data/data/org.chromium.Chromium/workdir", "/data/app/org.chromium.Chromium/nix")
+ "--overlay-src", "/data/app/org.chromium.Chromium/nix",
+ "--overlay", "/data/data/org.chromium.Chromium/overlay/rwsrc", "/data/data/org.chromium.Chromium/workdir", "/nix",
+ },
+ },
+ {
name: "xdg-dbus-proxy constraint sample",
conf: (&bwrap.Config{
Unshare: nil,