aboutsummaryrefslogtreecommitdiffhomepage
path: root/helper
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-10-15 02:15:55 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-10-15 02:15:55 +0900
commit2faf510146733c28a5dbc3245175700abcf4f966 (patch)
tree707b5fec5d210c19123205969731837b780e318d /helper
parenta0db19b9ad7def33eacdfc23d462604dce3af3bb (diff)
helper/bwrap: ordered filesystem args
The argument builder was written based on the incorrect assumption that bwrap arguments are unordered. The argument builder is replaced in this commit to correct that mistake. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'helper')
-rw-r--r--helper/bwrap/arg.go77
-rw-r--r--helper/bwrap/arg.static.awkward.go13
-rw-r--r--helper/bwrap/arg.static.bool.go81
-rw-r--r--helper/bwrap/arg.static.int.go47
-rw-r--r--helper/bwrap/arg.static.pair.go64
-rw-r--r--helper/bwrap/arg.static.string.go65
-rw-r--r--helper/bwrap/config.bool.go64
-rw-r--r--helper/bwrap/config.go219
-rw-r--r--helper/bwrap/config.int.go22
-rw-r--r--helper/bwrap/config.interface.go25
-rw-r--r--helper/bwrap/config.pair.go54
-rw-r--r--helper/bwrap/config.set.go138
-rw-r--r--helper/bwrap/config.string.go44
-rw-r--r--helper/bwrap/config_test.go60
14 files changed, 573 insertions, 400 deletions
diff --git a/helper/bwrap/arg.go b/helper/bwrap/arg.go
new file mode 100644
index 00000000..efdab823
--- /dev/null
+++ b/helper/bwrap/arg.go
@@ -0,0 +1,77 @@
+package bwrap
+
+import "encoding/gob"
+
+type Builder interface {
+ Len() int
+ Append(args *[]string)
+}
+
+type FSBuilder interface {
+ Path() string
+ Builder
+}
+
+func init() {
+ gob.Register(new(pairF))
+ gob.Register(new(stringF))
+}
+
+type pairF [3]string
+
+func (p *pairF) Path() string {
+ return p[2]
+}
+
+func (p *pairF) Len() int {
+ return len(p) // compiler replaces this with 3
+}
+
+func (p *pairF) Append(args *[]string) {
+ *args = append(*args, p[0], p[1], p[2])
+}
+
+type stringF [2]string
+
+func (s stringF) Path() string {
+ return s[1]
+}
+
+func (s stringF) Len() int {
+ return len(s) // compiler replaces this with 2
+}
+
+func (s stringF) Append(args *[]string) {
+ *args = append(*args, s[0], s[1])
+}
+
+// Args returns a slice of bwrap args corresponding to c.
+func (c *Config) Args() (args []string) {
+ builders := []Builder{
+ c.boolArgs(),
+ c.intArgs(),
+ c.stringArgs(),
+ c.pairArgs(),
+ }
+
+ // copy FSBuilder slice to builder slice
+ fb := make([]Builder, len(c.Filesystem)+1)
+ for i, f := range c.Filesystem {
+ fb[i] = f
+ }
+ fb[len(fb)-1] = c.Chmod
+ builders = append(builders, fb...)
+
+ // accumulate arg count
+ argc := 0
+ for _, b := range builders {
+ argc += b.Len()
+ }
+
+ args = make([]string, 0, argc)
+ for _, b := range builders {
+ b.Append(&args)
+ }
+
+ return
+}
diff --git a/helper/bwrap/arg.static.awkward.go b/helper/bwrap/arg.static.awkward.go
new file mode 100644
index 00000000..0848d1fb
--- /dev/null
+++ b/helper/bwrap/arg.static.awkward.go
@@ -0,0 +1,13 @@
+package bwrap
+
+const (
+ Tmpfs = iota
+ Dir
+ Symlink
+)
+
+var awkwardArgs = [...]string{
+ Tmpfs: "--tmpfs",
+ Dir: "--dir",
+ Symlink: "--symlink",
+}
diff --git a/helper/bwrap/arg.static.bool.go b/helper/bwrap/arg.static.bool.go
new file mode 100644
index 00000000..6c3ca0c4
--- /dev/null
+++ b/helper/bwrap/arg.static.bool.go
@@ -0,0 +1,81 @@
+package bwrap
+
+const (
+ UnshareAll = iota
+ UnshareUser
+ UnshareIPC
+ UnsharePID
+ UnshareNet
+ UnshareUTS
+ UnshareCGroup
+ ShareNet
+
+ UserNS
+ Clearenv
+
+ NewSession
+ DieWithParent
+ AsInit
+)
+
+var boolArgs = [...][]string{
+ UnshareAll: {"--unshare-all", "--unshare-user"},
+ UnshareUser: {"--unshare-user"},
+ UnshareIPC: {"--unshare-ipc"},
+ UnsharePID: {"--unshare-pid"},
+ UnshareNet: {"--unshare-net"},
+ UnshareUTS: {"--unshare-uts"},
+ UnshareCGroup: {"--unshare-cgroup"},
+ ShareNet: {"--share-net"},
+
+ UserNS: {"--disable-userns", "--assert-userns-disabled"},
+ Clearenv: {"--clearenv"},
+
+ NewSession: {"--new-session"},
+ DieWithParent: {"--die-with-parent"},
+ AsInit: {"--as-pid-1"},
+}
+
+func (c *Config) boolArgs() Builder {
+ b := boolArg{
+ UserNS: !c.UserNS,
+ Clearenv: c.Clearenv,
+
+ NewSession: c.NewSession,
+ DieWithParent: c.DieWithParent,
+ AsInit: c.AsInit,
+ }
+
+ if c.Unshare == nil {
+ b[UnshareAll] = true
+ b[ShareNet] = c.Net
+ } else {
+ b[UnshareUser] = c.Unshare.User
+ b[UnshareIPC] = c.Unshare.IPC
+ b[UnsharePID] = c.Unshare.PID
+ b[UnshareNet] = c.Unshare.Net
+ b[UnshareUTS] = c.Unshare.UTS
+ b[UnshareCGroup] = c.Unshare.CGroup
+ }
+
+ return &b
+}
+
+type boolArg [len(boolArgs)]bool
+
+func (b *boolArg) Len() (l int) {
+ for i, v := range b {
+ if v {
+ l += len(boolArgs[i])
+ }
+ }
+ return
+}
+
+func (b *boolArg) Append(args *[]string) {
+ for i, v := range b {
+ if v {
+ *args = append(*args, boolArgs[i]...)
+ }
+ }
+}
diff --git a/helper/bwrap/arg.static.int.go b/helper/bwrap/arg.static.int.go
new file mode 100644
index 00000000..cba3b1f7
--- /dev/null
+++ b/helper/bwrap/arg.static.int.go
@@ -0,0 +1,47 @@
+package bwrap
+
+import "strconv"
+
+const (
+ UID = iota
+ GID
+ Perms
+ Size
+)
+
+var intArgs = [...]string{
+ UID: "--uid",
+ GID: "--gid",
+ Perms: "--perms",
+ Size: "--size",
+}
+
+func (c *Config) intArgs() Builder {
+ // Arg types:
+ // Perms
+ // are handled by the sequential builder
+
+ return &intArg{
+ UID: c.UID,
+ GID: c.GID,
+ }
+}
+
+type intArg [len(intArgs)]*int
+
+func (n *intArg) Len() (l int) {
+ for _, v := range n {
+ if v != nil {
+ l += 2
+ }
+ }
+ return
+}
+
+func (n *intArg) Append(args *[]string) {
+ for i, v := range n {
+ if v != nil {
+ *args = append(*args, intArgs[i], strconv.Itoa(*v))
+ }
+ }
+}
diff --git a/helper/bwrap/arg.static.pair.go b/helper/bwrap/arg.static.pair.go
new file mode 100644
index 00000000..cc1765ae
--- /dev/null
+++ b/helper/bwrap/arg.static.pair.go
@@ -0,0 +1,64 @@
+package bwrap
+
+const (
+ SetEnv = iota
+
+ Bind
+ BindTry
+ DevBind
+ DevBindTry
+ ROBind
+ ROBindTry
+
+ Chmod
+)
+
+var pairArgs = [...]string{
+ SetEnv: "--setenv",
+
+ Bind: "--bind",
+ BindTry: "--bind-try",
+ DevBind: "--dev-bind",
+ DevBindTry: "--dev-bind-try",
+ ROBind: "--ro-bind",
+ ROBindTry: "--ro-bind-try",
+
+ Chmod: "--chmod",
+}
+
+func (c *Config) pairArgs() Builder {
+ var n pairArg
+ n[SetEnv] = make([][2]string, 0, len(c.SetEnv))
+ for k, v := range c.SetEnv {
+ n[SetEnv] = append(n[SetEnv], [2]string{k, v})
+ }
+
+ // Arg types:
+ // Bind
+ // BindTry
+ // DevBind
+ // DevBindTry
+ // ROBind
+ // ROBindTry
+ // Chmod
+ // are handled by the sequential builder
+
+ return &n
+}
+
+type pairArg [len(pairArgs)][][2]string
+
+func (p *pairArg) Len() (l int) {
+ for _, v := range p {
+ l += len(v) * 3
+ }
+ return
+}
+
+func (p *pairArg) Append(args *[]string) {
+ for i, arg := range p {
+ for _, v := range arg {
+ *args = append(*args, pairArgs[i], v[0], v[1])
+ }
+ }
+}
diff --git a/helper/bwrap/arg.static.string.go b/helper/bwrap/arg.static.string.go
new file mode 100644
index 00000000..e7f5c332
--- /dev/null
+++ b/helper/bwrap/arg.static.string.go
@@ -0,0 +1,65 @@
+package bwrap
+
+const (
+ Hostname = iota
+ Chdir
+ UnsetEnv
+ LockFile
+
+ RemountRO
+ Procfs
+ DevTmpfs
+ Mqueue
+)
+
+var stringArgs = [...]string{
+ Hostname: "--hostname",
+ Chdir: "--chdir",
+ UnsetEnv: "--unsetenv",
+ LockFile: "--lock-file",
+
+ RemountRO: "--remount-ro",
+ Procfs: "--proc",
+ DevTmpfs: "--dev",
+ Mqueue: "--mqueue",
+}
+
+func (c *Config) stringArgs() Builder {
+ n := stringArg{
+ UnsetEnv: c.UnsetEnv,
+ LockFile: c.LockFile,
+ }
+
+ if c.Hostname != "" {
+ n[Hostname] = []string{c.Hostname}
+ }
+ if c.Chdir != "" {
+ n[Chdir] = []string{c.Chdir}
+ }
+
+ // Arg types:
+ // RemountRO
+ // Procfs
+ // DevTmpfs
+ // Mqueue
+ // are handled by the sequential builder
+
+ return &n
+}
+
+type stringArg [len(stringArgs)][]string
+
+func (s *stringArg) Len() (l int) {
+ for _, arg := range s {
+ l += len(arg) * 2
+ }
+ return
+}
+
+func (s *stringArg) Append(args *[]string) {
+ for i, arg := range s {
+ for _, v := range arg {
+ *args = append(*args, stringArgs[i], v)
+ }
+ }
+}
diff --git a/helper/bwrap/config.bool.go b/helper/bwrap/config.bool.go
deleted file mode 100644
index c30f4df9..00000000
--- a/helper/bwrap/config.bool.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package bwrap
-
-const (
- UnshareAll = iota
- UnshareUser
- UnshareIPC
- UnsharePID
- UnshareNet
- UnshareUTS
- UnshareCGroup
- ShareNet
-
- UserNS
- Clearenv
-
- NewSession
- DieWithParent
- AsInit
-
- boolC
-)
-
-var boolArgs = func() (b [boolC][]string) {
- b[UnshareAll] = []string{"--unshare-all", "--unshare-user"}
- b[UnshareUser] = []string{"--unshare-user"}
- b[UnshareIPC] = []string{"--unshare-ipc"}
- b[UnsharePID] = []string{"--unshare-pid"}
- b[UnshareNet] = []string{"--unshare-net"}
- b[UnshareUTS] = []string{"--unshare-uts"}
- b[UnshareCGroup] = []string{"--unshare-cgroup"}
- b[ShareNet] = []string{"--share-net"}
-
- b[UserNS] = []string{"--disable-userns", "--assert-userns-disabled"}
- b[Clearenv] = []string{"--clearenv"}
-
- b[NewSession] = []string{"--new-session"}
- b[DieWithParent] = []string{"--die-with-parent"}
- b[AsInit] = []string{"--as-pid-1"}
-
- return
-}()
-
-func (c *Config) boolArgs() (b [boolC]bool) {
- if c.Unshare == nil {
- b[UnshareAll] = true
- b[ShareNet] = c.Net
- } else {
- b[UnshareUser] = c.Unshare.User
- b[UnshareIPC] = c.Unshare.IPC
- b[UnsharePID] = c.Unshare.PID
- b[UnshareNet] = c.Unshare.Net
- b[UnshareUTS] = c.Unshare.UTS
- b[UnshareCGroup] = c.Unshare.CGroup
- }
-
- b[UserNS] = !c.UserNS
- b[Clearenv] = c.Clearenv
-
- b[NewSession] = c.NewSession
- b[DieWithParent] = c.DieWithParent
- b[AsInit] = c.AsInit
-
- return
-}
diff --git a/helper/bwrap/config.go b/helper/bwrap/config.go
index 3ddb80b5..f62cc24e 100644
--- a/helper/bwrap/config.go
+++ b/helper/bwrap/config.go
@@ -5,75 +5,6 @@ import (
"strconv"
)
-func (c *Config) Args() (args []string) {
- b := c.boolArgs()
- n := c.intArgs()
- g := c.interfaceArgs()
- s := c.stringArgs()
- p := c.pairArgs()
-
- argc := 0
- for i, arg := range b {
- if arg {
- argc += len(boolArgs[i])
- }
- }
- for _, arg := range n {
- if arg != nil {
- argc += 2
- }
- }
- for _, arg := range g {
- argc += len(arg) * 3
- }
- for _, arg := range s {
- argc += len(arg) * 2
- }
- for _, arg := range p {
- argc += len(arg) * 3
- }
-
- args = make([]string, 0, argc)
- for i, arg := range b {
- if arg {
- args = append(args, boolArgs[i]...)
- }
- }
- for i, arg := range n {
- if arg != nil {
- args = append(args, intArgs[i], strconv.Itoa(*arg))
- }
- }
- for i, arg := range g {
- for _, v := range arg {
- if v.Later() {
- continue
- }
- args = append(args, v.Value(interfaceArgs[i])...)
- }
- }
- for i, arg := range s {
- for _, v := range arg {
- args = append(args, stringArgs[i], v)
- }
- }
- for i, arg := range p {
- for _, v := range arg {
- args = append(args, pairArgs[i], v[0], v[1])
- }
- }
- for i, arg := range g {
- for _, v := range arg {
- if !v.Later() {
- continue
- }
- args = append(args, v.Value(interfaceArgs[i])...)
- }
- }
-
- return
-}
-
type Config struct {
// unshare every namespace we support by default if nil
// (--unshare-all)
@@ -114,53 +45,12 @@ type Config struct {
// (--lock-file DEST)
LockFile []string `json:"lock_file,omitempty"`
- // bind mount host path on sandbox
- // (--bind SRC DEST)
- Bind [][2]string `json:"bind,omitempty"`
- // equal to Bind but ignores non-existent host path
- // (--bind-try SRC DEST)
- BindTry [][2]string `json:"bind_try,omitempty"`
-
- // bind mount host path on sandbox, allowing device access
- // (--dev-bind SRC DEST)
- DevBind [][2]string `json:"dev_bind,omitempty"`
- // equal to DevBind but ignores non-existent host path
- // (--dev-bind-try SRC DEST)
- DevBindTry [][2]string `json:"dev_bind_try,omitempty"`
-
- // bind mount host path readonly on sandbox
- // (--ro-bind SRC DEST)
- ROBind [][2]string `json:"ro_bind,omitempty"`
- // equal to ROBind but ignores non-existent host path
- // (--ro-bind-try SRC DEST)
- ROBindTry [][2]string `json:"ro_bind_try,omitempty"`
-
- // remount path as readonly; does not recursively remount
- // (--remount-ro DEST)
- RemountRO []string `json:"remount_ro,omitempty"`
-
- // mount new procfs in sandbox
- // (--proc DEST)
- Procfs []string `json:"proc,omitempty"`
- // mount new dev in sandbox
- // (--dev DEST)
- DevTmpfs []string `json:"dev,omitempty"`
- // mount new tmpfs in sandbox
- // (--tmpfs DEST)
- Tmpfs []PermConfig[TmpfsConfig] `json:"tmpfs,omitempty"`
- // mount new mqueue in sandbox
- // (--mqueue DEST)
- Mqueue []string `json:"mqueue,omitempty"`
- // create dir in sandbox
- // (--dir DEST)
- Dir []PermConfig[string] `json:"dir,omitempty"`
- // create symlink within sandbox
- // (--symlink SRC DEST)
- Symlink []PermConfig[[2]string] `json:"symlink,omitempty"`
+ // ordered filesystem args
+ Filesystem []FSBuilder
// change permissions (must already exist)
// (--chmod OCTAL PATH)
- Chmod map[string]os.FileMode `json:"chmod,omitempty"`
+ Chmod ChmodConfig `json:"chmod,omitempty"`
// create a new terminal session
// (--new-session)
@@ -217,6 +107,34 @@ type UnshareConfig struct {
CGroup bool `json:"cgroup"`
}
+type PermConfig[T FSBuilder] struct {
+ // set permissions of next argument
+ // (--perms OCTAL)
+ Mode *os.FileMode `json:"mode,omitempty"`
+ // path to get the new permission
+ // (--bind-data, --file, etc.)
+ Inner T `json:"path"`
+}
+
+func (p *PermConfig[T]) Path() string {
+ return p.Inner.Path()
+}
+
+func (p *PermConfig[T]) Len() int {
+ if p.Mode != nil {
+ return p.Inner.Len() + 2
+ } else {
+ return p.Inner.Len()
+ }
+}
+
+func (p *PermConfig[T]) Append(args *[]string) {
+ if p.Mode != nil {
+ *args = append(*args, intArgs[Perms], strconv.FormatInt(int64(*p.Mode), 8))
+ }
+ p.Inner.Append(args)
+}
+
type TmpfsConfig struct {
// set size of tmpfs
// (--size BYTES)
@@ -226,62 +144,47 @@ type TmpfsConfig struct {
Dir string `json:"dir"`
}
-type argOf interface {
- Value(arg string) (args []string)
- Later() bool
+func (t *TmpfsConfig) Path() string {
+ return t.Dir
}
-func copyToArgOfSlice[T [2]string | string | TmpfsConfig](src []PermConfig[T]) (dst []argOf) {
- dst = make([]argOf, len(src))
- for i, arg := range src {
- dst[i] = arg
+func (t *TmpfsConfig) Len() int {
+ if t.Size > 0 {
+ return 4
+ } else {
+ return 2
}
- return
}
-type PermConfig[T [2]string | string | TmpfsConfig] struct {
- // append this at the end of the argument stream
- Last bool
+func (t *TmpfsConfig) Append(args *[]string) {
+ if t.Size > 0 {
+ *args = append(*args, intArgs[Size], strconv.Itoa(t.Size))
+ }
+ *args = append(*args, awkwardArgs[Tmpfs], t.Dir)
+}
- // set permissions of next argument
- // (--perms OCTAL)
- Mode *os.FileMode `json:"mode,omitempty"`
- // path to get the new permission
- // (--bind-data, --file, etc.)
- Path T
+type SymlinkConfig [2]string
+
+func (s SymlinkConfig) Path() string {
+ return s[1]
}
-func (p PermConfig[T]) Later() bool {
- return p.Last
+func (s SymlinkConfig) Len() int {
+ return 3
}
-func (p PermConfig[T]) Value(arg string) (args []string) {
- // max possible size
- if p.Mode != nil {
- args = make([]string, 0, 6)
- args = append(args, "--perms", strconv.FormatInt(int64(*p.Mode), 8))
- } else {
- args = make([]string, 0, 4)
- }
+func (s SymlinkConfig) Append(args *[]string) {
+ *args = append(*args, awkwardArgs[Symlink], s[0], s[1])
+}
+
+type ChmodConfig map[string]os.FileMode
- switch v := any(p.Path).(type) {
- case string:
- args = append(args, arg, v)
- return
- case [2]string:
- args = append(args, arg, v[0], v[1])
- return
- case TmpfsConfig:
- if arg != "--tmpfs" {
- panic("unreachable")
- }
+func (c ChmodConfig) Len() int {
+ return len(c)
+}
- if v.Size > 0 {
- args = append(args, "--size", strconv.Itoa(v.Size))
- }
- args = append(args, arg, v.Dir)
- return
- default:
- panic("unreachable")
+func (c ChmodConfig) Append(args *[]string) {
+ for path, mode := range c {
+ *args = append(*args, pairArgs[Chmod], strconv.FormatInt(int64(mode), 8), path)
}
}
diff --git a/helper/bwrap/config.int.go b/helper/bwrap/config.int.go
deleted file mode 100644
index 27c88c36..00000000
--- a/helper/bwrap/config.int.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package bwrap
-
-const (
- UID = iota
- GID
-
- intC
-)
-
-var intArgs = func() (n [intC]string) {
- n[UID] = "--uid"
- n[GID] = "--gid"
-
- return
-}()
-
-func (c *Config) intArgs() (n [intC]*int) {
- n[UID] = c.UID
- n[GID] = c.GID
-
- return
-}
diff --git a/helper/bwrap/config.interface.go b/helper/bwrap/config.interface.go
deleted file mode 100644
index f68df83c..00000000
--- a/helper/bwrap/config.interface.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package bwrap
-
-const (
- Tmpfs = iota
- Dir
- Symlink
-
- interfaceC
-)
-
-var interfaceArgs = func() (g [interfaceC]string) {
- g[Tmpfs] = "--tmpfs"
- g[Dir] = "--dir"
- g[Symlink] = "--symlink"
-
- return
-}()
-
-func (c *Config) interfaceArgs() (g [interfaceC][]argOf) {
- g[Tmpfs] = copyToArgOfSlice(c.Tmpfs)
- g[Dir] = copyToArgOfSlice(c.Dir)
- g[Symlink] = copyToArgOfSlice(c.Symlink)
-
- return
-}
diff --git a/helper/bwrap/config.pair.go b/helper/bwrap/config.pair.go
deleted file mode 100644
index 049edafe..00000000
--- a/helper/bwrap/config.pair.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package bwrap
-
-import "strconv"
-
-const (
- SetEnv = iota
-
- Bind
- BindTry
- DevBind
- DevBindTry
- ROBind
- ROBindTry
-
- Chmod
-
- pairC
-)
-
-var pairArgs = func() (n [pairC]string) {
- n[SetEnv] = "--setenv"
-
- n[Bind] = "--bind"
- n[BindTry] = "--bind-try"
- n[DevBind] = "--dev-bind"
- n[DevBindTry] = "--dev-bind-try"
- n[ROBind] = "--ro-bind"
- n[ROBindTry] = "--ro-bind-try"
-
- n[Chmod] = "--chmod"
-
- return
-}()
-
-func (c *Config) pairArgs() (n [pairC][][2]string) {
- n[SetEnv] = make([][2]string, 0, len(c.SetEnv))
- for k, v := range c.SetEnv {
- n[SetEnv] = append(n[SetEnv], [2]string{k, v})
- }
-
- n[Bind] = c.Bind
- n[BindTry] = c.BindTry
- n[DevBind] = c.DevBind
- n[DevBindTry] = c.DevBindTry
- n[ROBind] = c.ROBind
- n[ROBindTry] = c.ROBindTry
-
- n[Chmod] = make([][2]string, 0, len(c.Chmod))
- for path, octal := range c.Chmod {
- n[Chmod] = append(n[Chmod], [2]string{strconv.FormatInt(int64(octal), 8), path})
- }
-
- return
-}
diff --git a/helper/bwrap/config.set.go b/helper/bwrap/config.set.go
new file mode 100644
index 00000000..318ad7f2
--- /dev/null
+++ b/helper/bwrap/config.set.go
@@ -0,0 +1,138 @@
+package bwrap
+
+import "os"
+
+/*
+Bind binds mount src on host to dest in sandbox.
+
+Bind(src, dest) bind mount host path readonly on sandbox
+(--ro-bind SRC DEST).
+Bind(src, dest, true) equal to ROBind but ignores non-existent host path
+(--ro-bind-try SRC DEST).
+
+Bind(src, dest, false, true) bind mount host path on sandbox.
+(--bind SRC DEST).
+Bind(src, dest, true, true) equal to Bind but ignores non-existent host path
+(--bind-try SRC DEST).
+
+Bind(src, dest, false, true, true) bind mount host path on sandbox, allowing device access
+(--dev-bind SRC DEST).
+Bind(src, dest, true, true, true) equal to DevBind but ignores non-existent host path
+(--dev-bind-try SRC DEST).
+*/
+func (c *Config) Bind(src, dest string, opts ...bool) *Config {
+ var (
+ try bool
+ write bool
+ dev bool
+ )
+
+ if len(opts) > 0 {
+ try = opts[0]
+ }
+ if len(opts) > 1 {
+ write = opts[1]
+ }
+ if len(opts) > 2 {
+ dev = opts[2]
+ }
+
+ if dev {
+ if try {
+ c.Filesystem = append(c.Filesystem, &pairF{pairArgs[DevBindTry], src, dest})
+ } else {
+ c.Filesystem = append(c.Filesystem, &pairF{pairArgs[DevBind], src, dest})
+ }
+ return c
+ } else if write {
+ if try {
+ c.Filesystem = append(c.Filesystem, &pairF{pairArgs[BindTry], src, dest})
+ } else {
+ c.Filesystem = append(c.Filesystem, &pairF{pairArgs[Bind], src, dest})
+ }
+ return c
+ } else {
+ if try {
+ c.Filesystem = append(c.Filesystem, &pairF{pairArgs[ROBindTry], src, dest})
+ } else {
+ c.Filesystem = append(c.Filesystem, &pairF{pairArgs[ROBind], src, dest})
+ }
+ return c
+ }
+}
+
+// RemountRO remount path as readonly; does not recursively remount
+// (--remount-ro DEST)
+func (c *Config) RemountRO(dest string) *Config {
+ c.Filesystem = append(c.Filesystem, &stringF{stringArgs[RemountRO], dest})
+ return c
+}
+
+// Procfs mount new procfs in sandbox
+// (--proc DEST)
+func (c *Config) Procfs(dest string) *Config {
+ c.Filesystem = append(c.Filesystem, &stringF{stringArgs[Procfs], dest})
+ return c
+}
+
+// DevTmpfs mount new dev in sandbox
+// (--dev DEST)
+func (c *Config) DevTmpfs(dest string) *Config {
+ c.Filesystem = append(c.Filesystem, &stringF{stringArgs[DevTmpfs], dest})
+ return c
+}
+
+// Tmpfs mount new tmpfs in sandbox
+// (--tmpfs DEST)
+func (c *Config) Tmpfs(dest string, size int, perm ...os.FileMode) *Config {
+ tmpfs := &PermConfig[*TmpfsConfig]{Inner: &TmpfsConfig{Dir: dest}}
+ if size >= 0 {
+ tmpfs.Inner.Size = size
+ }
+ if len(perm) == 1 {
+ tmpfs.Mode = &perm[0]
+ }
+ c.Filesystem = append(c.Filesystem, tmpfs)
+ return c
+}
+
+// Mqueue mount new mqueue in sandbox
+// (--mqueue DEST)
+func (c *Config) Mqueue(dest string) *Config {
+ c.Filesystem = append(c.Filesystem, &stringF{stringArgs[Mqueue], dest})
+ return c
+}
+
+// Dir create dir in sandbox
+// (--dir DEST)
+func (c *Config) Dir(dest string) *Config {
+ c.Filesystem = append(c.Filesystem, &stringF{stringArgs[Dir], dest})
+ return c
+}
+
+// Symlink create symlink within sandbox
+// (--symlink SRC DEST)
+func (c *Config) Symlink(src, dest string, perm ...os.FileMode) *Config {
+ symlink := &PermConfig[SymlinkConfig]{Inner: SymlinkConfig{src, dest}}
+ if len(perm) == 1 {
+ symlink.Mode = &perm[0]
+ }
+ c.Filesystem = append(c.Filesystem, symlink)
+ return c
+}
+
+// SetUID sets custom uid in the sandbox, requires new user namespace (--uid UID).
+func (c *Config) SetUID(uid int) *Config {
+ if uid >= 0 {
+ c.UID = &uid
+ }
+ return c
+}
+
+// SetGID sets custom gid in the sandbox, requires new user namespace (--gid GID).
+func (c *Config) SetGID(gid int) *Config {
+ if gid >= 0 {
+ c.GID = &gid
+ }
+ return c
+}
diff --git a/helper/bwrap/config.string.go b/helper/bwrap/config.string.go
deleted file mode 100644
index 2aa05bee..00000000
--- a/helper/bwrap/config.string.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package bwrap
-
-const (
- Hostname = iota
- Chdir
- UnsetEnv
- LockFile
- RemountRO
- Procfs
- DevTmpfs
- Mqueue
-
- stringC
-)
-
-var stringArgs = func() (n [stringC]string) {
- n[Hostname] = "--hostname"
- n[Chdir] = "--chdir"
- n[UnsetEnv] = "--unsetenv"
- n[LockFile] = "--lock-file"
- n[RemountRO] = "--remount-ro"
- n[Procfs] = "--proc"
- n[DevTmpfs] = "--dev"
- n[Mqueue] = "--mqueue"
-
- return
-}()
-
-func (c *Config) stringArgs() (n [stringC][]string) {
- if c.Hostname != "" {
- n[Hostname] = []string{c.Hostname}
- }
- if c.Chdir != "" {
- n[Chdir] = []string{c.Chdir}
- }
- n[UnsetEnv] = c.UnsetEnv
- n[LockFile] = c.LockFile
- n[RemountRO] = c.RemountRO
- n[Procfs] = c.Procfs
- n[DevTmpfs] = c.DevTmpfs
- n[Mqueue] = c.Mqueue
-
- return
-}
diff --git a/helper/bwrap/config_test.go b/helper/bwrap/config_test.go
index a14e310c..30b9ab06 100644
--- a/helper/bwrap/config_test.go
+++ b/helper/bwrap/config_test.go
@@ -13,40 +13,34 @@ func TestConfig_Args(t *testing.T) {
}{
{
name: "xdg-dbus-proxy constraint sample",
- conf: &Config{
- Unshare: nil,
- UserNS: false,
- Clearenv: true,
- Symlink: []PermConfig[[2]string]{
- {Path: [2]string{"usr/bin", "/bin"}},
- {Path: [2]string{"var/home", "/home"}},
- {Path: [2]string{"usr/lib", "/lib"}},
- {Path: [2]string{"usr/lib64", "/lib64"}},
- {Path: [2]string{"run/media", "/media"}},
- {Path: [2]string{"var/mnt", "/mnt"}},
- {Path: [2]string{"var/opt", "/opt"}},
- {Path: [2]string{"sysroot/ostree", "/ostree"}},
- {Path: [2]string{"var/roothome", "/root"}},
- {Path: [2]string{"usr/sbin", "/sbin"}},
- {Path: [2]string{"var/srv", "/srv"}},
- },
- Bind: [][2]string{
- {"/run", "/run"},
- {"/tmp", "/tmp"},
- {"/var", "/var"},
- {"/run/user/1971/.dbus-proxy/", "/run/user/1971/.dbus-proxy/"},
- },
- ROBind: [][2]string{
- {"/boot", "/boot"},
- {"/dev", "/dev"},
- {"/proc", "/proc"},
- {"/sys", "/sys"},
- {"/sysroot", "/sysroot"},
- {"/usr", "/usr"},
- {"/etc", "/etc"},
- },
+ conf: (&Config{
+ Unshare: nil,
+ UserNS: false,
+ Clearenv: true,
DieWithParent: true,
- },
+ }).
+ Symlink("usr/bin", "/bin").
+ Symlink("var/home", "/home").
+ Symlink("usr/lib", "/lib").
+ Symlink("usr/lib64", "/lib64").
+ Symlink("run/media", "/media").
+ Symlink("var/mnt", "/mnt").
+ Symlink("var/opt", "/opt").
+ Symlink("sysroot/ostree", "/ostree").
+ Symlink("var/roothome", "/root").
+ Symlink("usr/sbin", "/sbin").
+ Symlink("var/srv", "/srv").
+ Bind("/run", "/run", false, true).
+ Bind("/tmp", "/tmp", false, true).
+ Bind("/var", "/var", false, true).
+ Bind("/run/user/1971/.dbus-proxy/", "/run/user/1971/.dbus-proxy/", false, true).
+ Bind("/boot", "/boot").
+ Bind("/dev", "/dev").
+ Bind("/proc", "/proc").
+ Bind("/sys", "/sys").
+ Bind("/sysroot", "/sysroot").
+ Bind("/usr", "/usr").
+ Bind("/etc", "/etc"),
want: []string{
"--unshare-all",
"--unshare-user",