helper/bwrap: separate sequential/static args
Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
562f5ed797
commit
3e11ce6868
@ -20,7 +20,7 @@ type bubblewrap struct {
|
|||||||
name string
|
name string
|
||||||
|
|
||||||
// bwrap pipes
|
// bwrap pipes
|
||||||
p *pipes
|
control *pipes
|
||||||
// sync pipe
|
// sync pipe
|
||||||
sync *os.File
|
sync *os.File
|
||||||
// returns an array of arguments passed directly
|
// returns an array of arguments passed directly
|
||||||
@ -29,7 +29,7 @@ type bubblewrap struct {
|
|||||||
|
|
||||||
// pipes received by the child
|
// pipes received by the child
|
||||||
// nil if no pipes are required
|
// nil if no pipes are required
|
||||||
cp *pipes
|
controlPt *pipes
|
||||||
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
*exec.Cmd
|
*exec.Cmd
|
||||||
@ -39,7 +39,7 @@ func (b *bubblewrap) StartNotify(ready chan error) error {
|
|||||||
b.lock.Lock()
|
b.lock.Lock()
|
||||||
defer b.lock.Unlock()
|
defer b.lock.Unlock()
|
||||||
|
|
||||||
if ready != nil && b.cp == nil {
|
if ready != nil && b.controlPt == nil {
|
||||||
panic("attempted to start with status monitoring on a bwrap child initialised without pipes")
|
panic("attempted to start with status monitoring on a bwrap child initialised without pipes")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,16 +50,16 @@ func (b *bubblewrap) StartNotify(ready chan error) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare bwrap pipe and args
|
// prepare bwrap pipe and args
|
||||||
if argsFD, _, err := b.p.prepareCmd(b.Cmd); err != nil {
|
if argsFD, _, err := b.control.prepareCmd(b.Cmd); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
b.Cmd.Args = append(b.Cmd.Args, "--args", strconv.Itoa(argsFD), "--", b.name)
|
b.Cmd.Args = append(b.Cmd.Args, "--args", strconv.Itoa(argsFD), "--", b.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare child args and pipes if enabled
|
// prepare child args and pipes if enabled
|
||||||
if b.cp != nil {
|
if b.controlPt != nil {
|
||||||
b.cp.ready = ready
|
b.controlPt.ready = ready
|
||||||
if argsFD, statFD, err := b.cp.prepareCmd(b.Cmd); err != nil {
|
if argsFD, statFD, err := b.controlPt.prepareCmd(b.Cmd); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
b.Cmd.Args = append(b.Cmd.Args, b.argF(argsFD, statFD)...)
|
b.Cmd.Args = append(b.Cmd.Args, b.argF(argsFD, statFD)...)
|
||||||
@ -70,7 +70,7 @@ func (b *bubblewrap) StartNotify(ready chan error) error {
|
|||||||
|
|
||||||
if ready != nil {
|
if ready != nil {
|
||||||
b.Cmd.Env = append(b.Cmd.Env, FortifyHelper+"=1", FortifyStatus+"=1")
|
b.Cmd.Env = append(b.Cmd.Env, FortifyHelper+"=1", FortifyStatus+"=1")
|
||||||
} else if b.cp != nil {
|
} else if b.controlPt != nil {
|
||||||
b.Cmd.Env = append(b.Cmd.Env, FortifyHelper+"=1", FortifyStatus+"=0")
|
b.Cmd.Env = append(b.Cmd.Env, FortifyHelper+"=1", FortifyStatus+"=0")
|
||||||
} else {
|
} else {
|
||||||
b.Cmd.Env = append(b.Cmd.Env, FortifyHelper+"=1", FortifyStatus+"=-1")
|
b.Cmd.Env = append(b.Cmd.Env, FortifyHelper+"=1", FortifyStatus+"=-1")
|
||||||
@ -85,13 +85,13 @@ func (b *bubblewrap) StartNotify(ready chan error) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write bwrap args first
|
// write bwrap args first
|
||||||
if err := b.p.readyWriteArgs(); err != nil {
|
if err := b.control.readyWriteArgs(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// write child args if enabled
|
// write child args if enabled
|
||||||
if b.cp != nil {
|
if b.controlPt != nil {
|
||||||
if err := b.cp.readyWriteArgs(); err != nil {
|
if err := b.controlPt.readyWriteArgs(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,11 +100,11 @@ func (b *bubblewrap) StartNotify(ready chan error) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *bubblewrap) Close() error {
|
func (b *bubblewrap) Close() error {
|
||||||
if b.cp == nil {
|
if b.controlPt == nil {
|
||||||
panic("attempted to close bwrap child initialised without pipes")
|
panic("attempted to close bwrap child initialised without pipes")
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.cp.closeStatus()
|
return b.controlPt.closeStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bubblewrap) Start() error {
|
func (b *bubblewrap) Start() error {
|
||||||
@ -136,14 +136,14 @@ func NewBwrap(conf *bwrap.Config, wt io.WriterTo, name string, argF func(argsFD,
|
|||||||
if args, err := NewCheckedArgs(conf.Args()); err != nil {
|
if args, err := NewCheckedArgs(conf.Args()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
b.p = &pipes{args: args}
|
b.control = &pipes{args: args}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.sync = conf.Sync()
|
b.sync = conf.Sync()
|
||||||
b.argF = argF
|
b.argF = argF
|
||||||
b.name = name
|
b.name = name
|
||||||
if wt != nil {
|
if wt != nil {
|
||||||
b.cp = &pipes{args: wt}
|
b.controlPt = &pipes{args: wt}
|
||||||
}
|
}
|
||||||
b.Cmd = execCommand(BubblewrapName)
|
b.Cmd = execCommand(BubblewrapName)
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package bwrap
|
|
||||||
|
|
||||||
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",
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
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]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
package bwrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"slices"
|
|
||||||
)
|
|
||||||
|
|
||||||
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, len(c.SetEnv))
|
|
||||||
keys := make([]string, 0, len(c.SetEnv))
|
|
||||||
for k := range c.SetEnv {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
slices.Sort(keys)
|
|
||||||
for i, k := range keys {
|
|
||||||
n[SetEnv][i] = [2]string{k, c.SetEnv[k]}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -39,46 +39,60 @@ func (c *Config) Bind(src, dest string, opts ...bool) *Config {
|
|||||||
|
|
||||||
if dev {
|
if dev {
|
||||||
if try {
|
if try {
|
||||||
c.Filesystem = append(c.Filesystem, &pairF{pairArgs[DevBindTry], src, dest})
|
c.Filesystem = append(c.Filesystem, &pairF{DevBindTry.Unwrap(), src, dest})
|
||||||
} else {
|
} else {
|
||||||
c.Filesystem = append(c.Filesystem, &pairF{pairArgs[DevBind], src, dest})
|
c.Filesystem = append(c.Filesystem, &pairF{DevBind.Unwrap(), src, dest})
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
} else if write {
|
} else if write {
|
||||||
if try {
|
if try {
|
||||||
c.Filesystem = append(c.Filesystem, &pairF{pairArgs[BindTry], src, dest})
|
c.Filesystem = append(c.Filesystem, &pairF{BindTry.Unwrap(), src, dest})
|
||||||
} else {
|
} else {
|
||||||
c.Filesystem = append(c.Filesystem, &pairF{pairArgs[Bind], src, dest})
|
c.Filesystem = append(c.Filesystem, &pairF{Bind.Unwrap(), src, dest})
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
} else {
|
} else {
|
||||||
if try {
|
if try {
|
||||||
c.Filesystem = append(c.Filesystem, &pairF{pairArgs[ROBindTry], src, dest})
|
c.Filesystem = append(c.Filesystem, &pairF{ROBindTry.Unwrap(), src, dest})
|
||||||
} else {
|
} else {
|
||||||
c.Filesystem = append(c.Filesystem, &pairF{pairArgs[ROBind], src, dest})
|
c.Filesystem = append(c.Filesystem, &pairF{ROBind.Unwrap(), src, dest})
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dir create dir in sandbox
|
||||||
|
// (--dir DEST)
|
||||||
|
func (c *Config) Dir(dest string) *Config {
|
||||||
|
c.Filesystem = append(c.Filesystem, &stringF{Dir.Unwrap(), dest})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// RemountRO remount path as readonly; does not recursively remount
|
// RemountRO remount path as readonly; does not recursively remount
|
||||||
// (--remount-ro DEST)
|
// (--remount-ro DEST)
|
||||||
func (c *Config) RemountRO(dest string) *Config {
|
func (c *Config) RemountRO(dest string) *Config {
|
||||||
c.Filesystem = append(c.Filesystem, &stringF{stringArgs[RemountRO], dest})
|
c.Filesystem = append(c.Filesystem, &stringF{RemountRO.Unwrap(), dest})
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Procfs mount new procfs in sandbox
|
// Procfs mount new procfs in sandbox
|
||||||
// (--proc DEST)
|
// (--proc DEST)
|
||||||
func (c *Config) Procfs(dest string) *Config {
|
func (c *Config) Procfs(dest string) *Config {
|
||||||
c.Filesystem = append(c.Filesystem, &stringF{stringArgs[Procfs], dest})
|
c.Filesystem = append(c.Filesystem, &stringF{Procfs.Unwrap(), dest})
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// DevTmpfs mount new dev in sandbox
|
// DevTmpfs mount new dev in sandbox
|
||||||
// (--dev DEST)
|
// (--dev DEST)
|
||||||
func (c *Config) DevTmpfs(dest string) *Config {
|
func (c *Config) DevTmpfs(dest string) *Config {
|
||||||
c.Filesystem = append(c.Filesystem, &stringF{stringArgs[DevTmpfs], dest})
|
c.Filesystem = append(c.Filesystem, &stringF{DevTmpfs.Unwrap(), dest})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mqueue mount new mqueue in sandbox
|
||||||
|
// (--mqueue DEST)
|
||||||
|
func (c *Config) Mqueue(dest string) *Config {
|
||||||
|
c.Filesystem = append(c.Filesystem, &stringF{Mqueue.Unwrap(), dest})
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,20 +135,6 @@ func (c *Config) Persist(dest, rwsrc, workdir string, src ...string) *Config {
|
|||||||
return c
|
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{awkwardArgs[Dir], dest})
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symlink create symlink within sandbox
|
// Symlink create symlink within sandbox
|
||||||
// (--symlink SRC DEST)
|
// (--symlink SRC DEST)
|
||||||
func (c *Config) Symlink(src, dest string, perm ...os.FileMode) *Config {
|
func (c *Config) Symlink(src, dest string, perm ...os.FileMode) *Config {
|
@ -1,17 +1,9 @@
|
|||||||
package bwrap
|
package bwrap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/gob"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
gob.Register(new(PermConfig[SymlinkConfig]))
|
|
||||||
gob.Register(new(PermConfig[*TmpfsConfig]))
|
|
||||||
gob.Register(new(OverlayConfig))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// unshare every namespace we support by default if nil
|
// unshare every namespace we support by default if nil
|
||||||
// (--unshare-all)
|
// (--unshare-all)
|
||||||
@ -124,153 +116,3 @@ type UnshareConfig struct {
|
|||||||
// create new cgroup namespace
|
// create new cgroup namespace
|
||||||
CGroup bool `json:"cgroup"`
|
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)
|
|
||||||
Size int `json:"size,omitempty"`
|
|
||||||
// mount point of new tmpfs
|
|
||||||
// (--tmpfs DEST)
|
|
||||||
Dir string `json:"dir"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TmpfsConfig) Path() string {
|
|
||||||
return t.Dir
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TmpfsConfig) Len() int {
|
|
||||||
if t.Size > 0 {
|
|
||||||
return 4
|
|
||||||
} else {
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return s[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s SymlinkConfig) Len() int {
|
|
||||||
return 3
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s SymlinkConfig) Append(args *[]string) {
|
|
||||||
*args = append(*args, awkwardArgs[Symlink], s[0], s[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChmodConfig map[string]os.FileMode
|
|
||||||
|
|
||||||
func (c ChmodConfig) Len() int {
|
|
||||||
return len(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ChmodConfig) Append(args *[]string) {
|
|
||||||
for path, mode := range c {
|
|
||||||
*args = append(*args, pairArgs[Chmod], strconv.FormatInt(int64(mode), 8), path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package bwrap_test
|
package bwrap_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -13,6 +14,83 @@ func TestConfig_Args(t *testing.T) {
|
|||||||
conf *bwrap.Config
|
conf *bwrap.Config
|
||||||
want []string
|
want []string
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
name: "bind",
|
||||||
|
conf: (new(bwrap.Config)).
|
||||||
|
Bind("/etc", "/.fortify/etc").
|
||||||
|
Bind("/etc", "/.fortify/etc", true).
|
||||||
|
Bind("/run", "/.fortify/run", false, true).
|
||||||
|
Bind("/sys/devices", "/.fortify/sys/devices", true, true).
|
||||||
|
Bind("/dev/dri", "/.fortify/dev/dri", false, true, true).
|
||||||
|
Bind("/dev/dri", "/.fortify/dev/dri", true, true, true),
|
||||||
|
want: []string{
|
||||||
|
"--unshare-all", "--unshare-user",
|
||||||
|
"--disable-userns", "--assert-userns-disabled",
|
||||||
|
// Bind("/etc", "/.fortify/etc")
|
||||||
|
"--ro-bind", "/etc", "/.fortify/etc",
|
||||||
|
// Bind("/etc", "/.fortify/etc", true)
|
||||||
|
"--ro-bind-try", "/etc", "/.fortify/etc",
|
||||||
|
// Bind("/run", "/.fortify/run", false, true)
|
||||||
|
"--bind", "/run", "/.fortify/run",
|
||||||
|
// Bind("/sys/devices", "/.fortify/sys/devices", true, true)
|
||||||
|
"--bind-try", "/sys/devices", "/.fortify/sys/devices",
|
||||||
|
// Bind("/dev/dri", "/.fortify/dev/dri", false, true, true)
|
||||||
|
"--dev-bind", "/dev/dri", "/.fortify/dev/dri",
|
||||||
|
// Bind("/dev/dri", "/.fortify/dev/dri", true, true, true)
|
||||||
|
"--dev-bind-try", "/dev/dri", "/.fortify/dev/dri",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dir remount-ro proc dev mqueue",
|
||||||
|
conf: (new(bwrap.Config)).
|
||||||
|
Dir("/.fortify").
|
||||||
|
RemountRO("/home").
|
||||||
|
Procfs("/proc").
|
||||||
|
DevTmpfs("/dev").
|
||||||
|
Mqueue("/dev/mqueue"),
|
||||||
|
want: []string{
|
||||||
|
"--unshare-all", "--unshare-user",
|
||||||
|
"--disable-userns", "--assert-userns-disabled",
|
||||||
|
// Dir("/.fortify")
|
||||||
|
"--dir", "/.fortify",
|
||||||
|
// RemountRO("/home")
|
||||||
|
"--remount-ro", "/home",
|
||||||
|
// Procfs("/proc")
|
||||||
|
"--proc", "/proc",
|
||||||
|
// DevTmpfs("/dev")
|
||||||
|
"--dev", "/dev",
|
||||||
|
// Mqueue("/dev/mqueue")
|
||||||
|
"--mqueue", "/dev/mqueue",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tmpfs",
|
||||||
|
conf: (new(bwrap.Config)).
|
||||||
|
Tmpfs("/run/user", 8192).
|
||||||
|
Tmpfs("/run/dbus", 8192, 0755),
|
||||||
|
want: []string{
|
||||||
|
"--unshare-all", "--unshare-user",
|
||||||
|
"--disable-userns", "--assert-userns-disabled",
|
||||||
|
// Tmpfs("/run/user", 8192)
|
||||||
|
"--size", "8192", "--tmpfs", "/run/user",
|
||||||
|
// Tmpfs("/run/dbus", 8192, 0755)
|
||||||
|
"--perms", "755", "--size", "8192", "--tmpfs", "/run/dbus",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "symlink",
|
||||||
|
conf: (new(bwrap.Config)).
|
||||||
|
Symlink("/.fortify/sbin/init", "/sbin/init").
|
||||||
|
Symlink("/.fortify/sbin/init", "/sbin/init", 0755),
|
||||||
|
want: []string{
|
||||||
|
"--unshare-all", "--unshare-user",
|
||||||
|
"--disable-userns", "--assert-userns-disabled",
|
||||||
|
// Symlink("/.fortify/sbin/init", "/sbin/init")
|
||||||
|
"--symlink", "/.fortify/sbin/init", "/sbin/init",
|
||||||
|
// Symlink("/.fortify/sbin/init", "/sbin/init", 0755)
|
||||||
|
"--perms", "755", "--symlink", "/.fortify/sbin/init", "/sbin/init",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "overlayfs",
|
name: "overlayfs",
|
||||||
conf: (new(bwrap.Config)).
|
conf: (new(bwrap.Config)).
|
||||||
@ -32,6 +110,64 @@ func TestConfig_Args(t *testing.T) {
|
|||||||
"--overlay", "/data/data/org.chromium.Chromium/overlay/rwsrc", "/data/data/org.chromium.Chromium/workdir", "/nix",
|
"--overlay", "/data/data/org.chromium.Chromium/overlay/rwsrc", "/data/data/org.chromium.Chromium/workdir", "/nix",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "unshare",
|
||||||
|
conf: &bwrap.Config{Unshare: &bwrap.UnshareConfig{
|
||||||
|
User: false,
|
||||||
|
IPC: false,
|
||||||
|
PID: false,
|
||||||
|
Net: false,
|
||||||
|
UTS: false,
|
||||||
|
CGroup: false,
|
||||||
|
}},
|
||||||
|
want: []string{"--disable-userns", "--assert-userns-disabled"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "uid gid sync",
|
||||||
|
conf: (new(bwrap.Config)).
|
||||||
|
SetUID(1971).
|
||||||
|
SetGID(100).
|
||||||
|
SetSync(os.Stdin),
|
||||||
|
want: []string{
|
||||||
|
"--unshare-all", "--unshare-user",
|
||||||
|
"--disable-userns", "--assert-userns-disabled",
|
||||||
|
// SetUID(1971)
|
||||||
|
"--uid", "1971",
|
||||||
|
// SetGID(100)
|
||||||
|
"--gid", "100",
|
||||||
|
// SetSync(os.Stdin)
|
||||||
|
// this is set when the process is created
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hostname chdir setenv unsetenv lockfile chmod",
|
||||||
|
conf: &bwrap.Config{
|
||||||
|
Hostname: "fortify",
|
||||||
|
Chdir: "/.fortify",
|
||||||
|
SetEnv: map[string]string{"FORTIFY_INIT": "/.fortify/sbin/init"},
|
||||||
|
UnsetEnv: []string{"HOME", "HOST"},
|
||||||
|
LockFile: []string{"/.fortify/lock"},
|
||||||
|
Chmod: map[string]os.FileMode{"/.fortify/sbin/init": 0755},
|
||||||
|
},
|
||||||
|
want: []string{
|
||||||
|
"--unshare-all", "--unshare-user",
|
||||||
|
"--disable-userns", "--assert-userns-disabled",
|
||||||
|
// Hostname: "fortify"
|
||||||
|
"--hostname", "fortify",
|
||||||
|
// Chdir: "/.fortify"
|
||||||
|
"--chdir", "/.fortify",
|
||||||
|
// UnsetEnv: []string{"HOME", "HOST"}
|
||||||
|
"--unsetenv", "HOME",
|
||||||
|
"--unsetenv", "HOST",
|
||||||
|
// LockFile: []string{"/.fortify/lock"},
|
||||||
|
"--lock-file", "/.fortify/lock",
|
||||||
|
// SetEnv: map[string]string{"FORTIFY_INIT": "/.fortify/sbin/init"}
|
||||||
|
"--setenv", "FORTIFY_INIT", "/.fortify/sbin/init",
|
||||||
|
// Chmod: map[string]os.FileMode{"/.fortify/sbin/init": 0755}
|
||||||
|
"--chmod", "755", "/.fortify/sbin/init",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "xdg-dbus-proxy constraint sample",
|
name: "xdg-dbus-proxy constraint sample",
|
||||||
conf: (&bwrap.Config{
|
conf: (&bwrap.Config{
|
||||||
@ -90,148 +226,6 @@ func TestConfig_Args(t *testing.T) {
|
|||||||
"--ro-bind", "/etc", "/etc",
|
"--ro-bind", "/etc", "/etc",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "fortify permissive default nixos",
|
|
||||||
conf: (&bwrap.Config{
|
|
||||||
Unshare: nil,
|
|
||||||
Net: true,
|
|
||||||
UserNS: true,
|
|
||||||
Clearenv: true,
|
|
||||||
SetEnv: map[string]string{
|
|
||||||
"HOME": "/home/chronos",
|
|
||||||
"TERM": "xterm-256color",
|
|
||||||
"FORTIFY_INIT": "3",
|
|
||||||
"XDG_RUNTIME_DIR": "/run/user/150",
|
|
||||||
"XDG_SESSION_CLASS": "user",
|
|
||||||
"XDG_SESSION_TYPE": "tty",
|
|
||||||
"SHELL": "/run/current-system/sw/bin/zsh",
|
|
||||||
"USER": "chronos",
|
|
||||||
},
|
|
||||||
DieWithParent: true,
|
|
||||||
AsInit: true,
|
|
||||||
}).SetUID(65534).SetGID(65534).
|
|
||||||
Procfs("/proc").DevTmpfs("/dev").Mqueue("/dev/mqueue").
|
|
||||||
Bind("/bin", "/bin", false, true).
|
|
||||||
Bind("/boot", "/boot", false, true).
|
|
||||||
Bind("/etc", "/etc", false, true).
|
|
||||||
Bind("/home", "/home", false, true).
|
|
||||||
Bind("/lib", "/lib", false, true).
|
|
||||||
Bind("/lib64", "/lib64", false, true).
|
|
||||||
Bind("/nix", "/nix", false, true).
|
|
||||||
Bind("/root", "/root", false, true).
|
|
||||||
Bind("/srv", "/srv", false, true).
|
|
||||||
Bind("/sys", "/sys", false, true).
|
|
||||||
Bind("/usr", "/usr", false, true).
|
|
||||||
Bind("/var", "/var", false, true).
|
|
||||||
Bind("/run/NetworkManager", "/run/NetworkManager", false, true).
|
|
||||||
Bind("/run/agetty.reload", "/run/agetty.reload", false, true).
|
|
||||||
Bind("/run/binfmt", "/run/binfmt", false, true).
|
|
||||||
Bind("/run/booted-system", "/run/booted-system", false, true).
|
|
||||||
Bind("/run/credentials", "/run/credentials", false, true).
|
|
||||||
Bind("/run/cryptsetup", "/run/cryptsetup", false, true).
|
|
||||||
Bind("/run/current-system", "/run/current-system", false, true).
|
|
||||||
Bind("/run/host", "/run/host", false, true).
|
|
||||||
Bind("/run/keys", "/run/keys", false, true).
|
|
||||||
Bind("/run/libvirt", "/run/libvirt", false, true).
|
|
||||||
Bind("/run/libvirtd.pid", "/run/libvirtd.pid", false, true).
|
|
||||||
Bind("/run/lock", "/run/lock", false, true).
|
|
||||||
Bind("/run/log", "/run/log", false, true).
|
|
||||||
Bind("/run/lvm", "/run/lvm", false, true).
|
|
||||||
Bind("/run/mount", "/run/mount", false, true).
|
|
||||||
Bind("/run/nginx", "/run/nginx", false, true).
|
|
||||||
Bind("/run/nscd", "/run/nscd", false, true).
|
|
||||||
Bind("/run/opengl-driver", "/run/opengl-driver", false, true).
|
|
||||||
Bind("/run/pppd", "/run/pppd", false, true).
|
|
||||||
Bind("/run/resolvconf", "/run/resolvconf", false, true).
|
|
||||||
Bind("/run/sddm", "/run/sddm", false, true).
|
|
||||||
Bind("/run/syncoid", "/run/syncoid", false, true).
|
|
||||||
Bind("/run/systemd", "/run/systemd", false, true).
|
|
||||||
Bind("/run/tmpfiles.d", "/run/tmpfiles.d", false, true).
|
|
||||||
Bind("/run/udev", "/run/udev", false, true).
|
|
||||||
Bind("/run/udisks2", "/run/udisks2", false, true).
|
|
||||||
Bind("/run/utmp", "/run/utmp", false, true).
|
|
||||||
Bind("/run/virtlogd.pid", "/run/virtlogd.pid", false, true).
|
|
||||||
Bind("/run/wrappers", "/run/wrappers", false, true).
|
|
||||||
Bind("/run/zed.pid", "/run/zed.pid", false, true).
|
|
||||||
Bind("/run/zed.state", "/run/zed.state", false, true).
|
|
||||||
Bind("/tmp/fortify.1971/tmpdir/150", "/tmp", false, true).
|
|
||||||
Tmpfs("/tmp/fortify.1971", 1048576).
|
|
||||||
Tmpfs("/run/user", 1048576).
|
|
||||||
Tmpfs("/run/user/150", 8388608).
|
|
||||||
Bind("/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/passwd", "/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/passwd").
|
|
||||||
Bind("/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/group", "/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/group").
|
|
||||||
Bind("/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/passwd", "/etc/passwd").
|
|
||||||
Bind("/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/group", "/etc/group").
|
|
||||||
Tmpfs("/var/run/nscd", 8192),
|
|
||||||
want: []string{
|
|
||||||
"--unshare-all", "--unshare-user", "--share-net",
|
|
||||||
"--clearenv", "--die-with-parent", "--as-pid-1",
|
|
||||||
"--uid", "65534",
|
|
||||||
"--gid", "65534",
|
|
||||||
"--setenv", "FORTIFY_INIT", "3",
|
|
||||||
"--setenv", "HOME", "/home/chronos",
|
|
||||||
"--setenv", "SHELL", "/run/current-system/sw/bin/zsh",
|
|
||||||
"--setenv", "TERM", "xterm-256color",
|
|
||||||
"--setenv", "USER", "chronos",
|
|
||||||
"--setenv", "XDG_RUNTIME_DIR", "/run/user/150",
|
|
||||||
"--setenv", "XDG_SESSION_CLASS", "user",
|
|
||||||
"--setenv", "XDG_SESSION_TYPE", "tty",
|
|
||||||
"--proc", "/proc", "--dev", "/dev",
|
|
||||||
"--mqueue", "/dev/mqueue",
|
|
||||||
"--bind", "/bin", "/bin",
|
|
||||||
"--bind", "/boot", "/boot",
|
|
||||||
"--bind", "/etc", "/etc",
|
|
||||||
"--bind", "/home", "/home",
|
|
||||||
"--bind", "/lib", "/lib",
|
|
||||||
"--bind", "/lib64", "/lib64",
|
|
||||||
"--bind", "/nix", "/nix",
|
|
||||||
"--bind", "/root", "/root",
|
|
||||||
"--bind", "/srv", "/srv",
|
|
||||||
"--bind", "/sys", "/sys",
|
|
||||||
"--bind", "/usr", "/usr",
|
|
||||||
"--bind", "/var", "/var",
|
|
||||||
"--bind", "/run/NetworkManager", "/run/NetworkManager",
|
|
||||||
"--bind", "/run/agetty.reload", "/run/agetty.reload",
|
|
||||||
"--bind", "/run/binfmt", "/run/binfmt",
|
|
||||||
"--bind", "/run/booted-system", "/run/booted-system",
|
|
||||||
"--bind", "/run/credentials", "/run/credentials",
|
|
||||||
"--bind", "/run/cryptsetup", "/run/cryptsetup",
|
|
||||||
"--bind", "/run/current-system", "/run/current-system",
|
|
||||||
"--bind", "/run/host", "/run/host",
|
|
||||||
"--bind", "/run/keys", "/run/keys",
|
|
||||||
"--bind", "/run/libvirt", "/run/libvirt",
|
|
||||||
"--bind", "/run/libvirtd.pid", "/run/libvirtd.pid",
|
|
||||||
"--bind", "/run/lock", "/run/lock",
|
|
||||||
"--bind", "/run/log", "/run/log",
|
|
||||||
"--bind", "/run/lvm", "/run/lvm",
|
|
||||||
"--bind", "/run/mount", "/run/mount",
|
|
||||||
"--bind", "/run/nginx", "/run/nginx",
|
|
||||||
"--bind", "/run/nscd", "/run/nscd",
|
|
||||||
"--bind", "/run/opengl-driver", "/run/opengl-driver",
|
|
||||||
"--bind", "/run/pppd", "/run/pppd",
|
|
||||||
"--bind", "/run/resolvconf", "/run/resolvconf",
|
|
||||||
"--bind", "/run/sddm", "/run/sddm",
|
|
||||||
"--bind", "/run/syncoid", "/run/syncoid",
|
|
||||||
"--bind", "/run/systemd", "/run/systemd",
|
|
||||||
"--bind", "/run/tmpfiles.d", "/run/tmpfiles.d",
|
|
||||||
"--bind", "/run/udev", "/run/udev",
|
|
||||||
"--bind", "/run/udisks2", "/run/udisks2",
|
|
||||||
"--bind", "/run/utmp", "/run/utmp",
|
|
||||||
"--bind", "/run/virtlogd.pid", "/run/virtlogd.pid",
|
|
||||||
"--bind", "/run/wrappers", "/run/wrappers",
|
|
||||||
"--bind", "/run/zed.pid", "/run/zed.pid",
|
|
||||||
"--bind", "/run/zed.state", "/run/zed.state",
|
|
||||||
"--bind", "/tmp/fortify.1971/tmpdir/150", "/tmp",
|
|
||||||
"--size", "1048576", "--tmpfs", "/tmp/fortify.1971",
|
|
||||||
"--size", "1048576", "--tmpfs", "/run/user",
|
|
||||||
"--size", "8388608", "--tmpfs", "/run/user/150",
|
|
||||||
"--ro-bind", "/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/passwd", "/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/passwd",
|
|
||||||
"--ro-bind", "/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/group", "/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/group",
|
|
||||||
"--ro-bind", "/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/passwd", "/etc/passwd",
|
|
||||||
"--ro-bind", "/tmp/fortify.1971/67a97cc824a64ef789f16b20ca6ce311/group", "/etc/group",
|
|
||||||
"--size", "8192", "--tmpfs", "/var/run/nscd",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
@ -241,4 +235,21 @@ func TestConfig_Args(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test persist validation
|
||||||
|
t.Run("invalid persist", func(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
wantPanic := "persist called without required paths"
|
||||||
|
if r := recover(); r != wantPanic {
|
||||||
|
t.Errorf("Persist() panic = %v; wantPanic %v", r, wantPanic)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
(new(bwrap.Config)).Persist("/run", "", "")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("sync file", func(t *testing.T) {
|
||||||
|
if s := (new(bwrap.Config)).SetSync(os.Stdout).Sync(); s != os.Stdout {
|
||||||
|
t.Errorf("Sync() = %v", s)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
223
helper/bwrap/sequential.go
Normal file
223
helper/bwrap/sequential.go
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
package bwrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register(new(PermConfig[SymlinkConfig]))
|
||||||
|
gob.Register(new(PermConfig[*TmpfsConfig]))
|
||||||
|
gob.Register(new(OverlayConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
type PositionalArg int
|
||||||
|
|
||||||
|
func (p PositionalArg) Unwrap() string {
|
||||||
|
return positionalArgs[p]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Tmpfs PositionalArg = iota
|
||||||
|
Symlink
|
||||||
|
|
||||||
|
Bind
|
||||||
|
BindTry
|
||||||
|
DevBind
|
||||||
|
DevBindTry
|
||||||
|
ROBind
|
||||||
|
ROBindTry
|
||||||
|
|
||||||
|
Chmod
|
||||||
|
Dir
|
||||||
|
RemountRO
|
||||||
|
Procfs
|
||||||
|
DevTmpfs
|
||||||
|
Mqueue
|
||||||
|
|
||||||
|
Perms
|
||||||
|
Size
|
||||||
|
|
||||||
|
OverlaySrc
|
||||||
|
Overlay
|
||||||
|
TmpOverlay
|
||||||
|
ROOverlay
|
||||||
|
)
|
||||||
|
|
||||||
|
var positionalArgs = [...]string{
|
||||||
|
Tmpfs: "--tmpfs",
|
||||||
|
Symlink: "--symlink",
|
||||||
|
|
||||||
|
Bind: "--bind",
|
||||||
|
BindTry: "--bind-try",
|
||||||
|
DevBind: "--dev-bind",
|
||||||
|
DevBindTry: "--dev-bind-try",
|
||||||
|
ROBind: "--ro-bind",
|
||||||
|
ROBindTry: "--ro-bind-try",
|
||||||
|
|
||||||
|
Chmod: "--chmod",
|
||||||
|
Dir: "--dir",
|
||||||
|
RemountRO: "--remount-ro",
|
||||||
|
Procfs: "--proc",
|
||||||
|
DevTmpfs: "--dev",
|
||||||
|
Mqueue: "--mqueue",
|
||||||
|
|
||||||
|
Perms: "--perms",
|
||||||
|
Size: "--size",
|
||||||
|
|
||||||
|
OverlaySrc: "--overlay-src",
|
||||||
|
Overlay: "--overlay",
|
||||||
|
TmpOverlay: "--tmp-overlay",
|
||||||
|
ROOverlay: "--ro-overlay",
|
||||||
|
}
|
||||||
|
|
||||||
|
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, Perms.Unwrap(), strconv.FormatInt(int64(*p.Mode), 8))
|
||||||
|
}
|
||||||
|
p.Inner.Append(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TmpfsConfig struct {
|
||||||
|
// set size of tmpfs
|
||||||
|
// (--size BYTES)
|
||||||
|
Size int `json:"size,omitempty"`
|
||||||
|
// mount point of new tmpfs
|
||||||
|
// (--tmpfs DEST)
|
||||||
|
Dir string `json:"dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TmpfsConfig) Path() string {
|
||||||
|
return t.Dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TmpfsConfig) Len() int {
|
||||||
|
if t.Size > 0 {
|
||||||
|
return 4
|
||||||
|
} else {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TmpfsConfig) Append(args *[]string) {
|
||||||
|
if t.Size > 0 {
|
||||||
|
*args = append(*args, Size.Unwrap(), strconv.Itoa(t.Size))
|
||||||
|
}
|
||||||
|
*args = append(*args, Tmpfs.Unwrap(), 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, OverlaySrc.Unwrap(), src)
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.Persist != nil {
|
||||||
|
if o.Persist[0] != "" && o.Persist[1] != "" {
|
||||||
|
// --overlay RWSRC WORKDIR
|
||||||
|
*args = append(*args, Overlay.Unwrap(), o.Persist[0], o.Persist[1])
|
||||||
|
} else {
|
||||||
|
// --ro-overlay
|
||||||
|
*args = append(*args, ROOverlay.Unwrap())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// --tmp-overlay
|
||||||
|
*args = append(*args, TmpOverlay.Unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEST
|
||||||
|
*args = append(*args, o.Dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SymlinkConfig [2]string
|
||||||
|
|
||||||
|
func (s SymlinkConfig) Path() string {
|
||||||
|
return s[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SymlinkConfig) Len() int {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SymlinkConfig) Append(args *[]string) {
|
||||||
|
*args = append(*args, Symlink.Unwrap(), s[0], s[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChmodConfig map[string]os.FileMode
|
||||||
|
|
||||||
|
func (c ChmodConfig) Len() int {
|
||||||
|
return len(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ChmodConfig) Append(args *[]string) {
|
||||||
|
for path, mode := range c {
|
||||||
|
*args = append(*args, Chmod.Unwrap(), strconv.FormatInt(int64(mode), 8), path)
|
||||||
|
}
|
||||||
|
}
|
249
helper/bwrap/static.go
Normal file
249
helper/bwrap/static.go
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
package bwrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
static boolean args
|
||||||
|
*/
|
||||||
|
|
||||||
|
type BoolArg int
|
||||||
|
|
||||||
|
func (b BoolArg) Unwrap() []string {
|
||||||
|
return boolArgs[b]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
UnshareAll BoolArg = 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, BoolArg(i).Unwrap()...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static integer args
|
||||||
|
*/
|
||||||
|
|
||||||
|
type IntArg int
|
||||||
|
|
||||||
|
func (i IntArg) Unwrap() string {
|
||||||
|
return intArgs[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
UID IntArg = iota
|
||||||
|
GID
|
||||||
|
)
|
||||||
|
|
||||||
|
var intArgs = [...]string{
|
||||||
|
UID: "--uid",
|
||||||
|
GID: "--gid",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) intArgs() 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, IntArg(i).Unwrap(), strconv.Itoa(*v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static string args
|
||||||
|
*/
|
||||||
|
|
||||||
|
type StringArg int
|
||||||
|
|
||||||
|
func (s StringArg) Unwrap() string {
|
||||||
|
return stringArgs[s]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Hostname StringArg = iota
|
||||||
|
Chdir
|
||||||
|
UnsetEnv
|
||||||
|
LockFile
|
||||||
|
)
|
||||||
|
|
||||||
|
var stringArgs = [...]string{
|
||||||
|
Hostname: "--hostname",
|
||||||
|
Chdir: "--chdir",
|
||||||
|
UnsetEnv: "--unsetenv",
|
||||||
|
LockFile: "--lock-file",
|
||||||
|
}
|
||||||
|
|
||||||
|
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}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, StringArg(i).Unwrap(), v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static pair args
|
||||||
|
*/
|
||||||
|
|
||||||
|
type PairArg int
|
||||||
|
|
||||||
|
func (p PairArg) Unwrap() string {
|
||||||
|
return pairArgs[p]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SetEnv PairArg = iota
|
||||||
|
)
|
||||||
|
|
||||||
|
var pairArgs = [...]string{
|
||||||
|
SetEnv: "--setenv",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) pairArgs() Builder {
|
||||||
|
var n pairArg
|
||||||
|
n[SetEnv] = make([][2]string, len(c.SetEnv))
|
||||||
|
keys := make([]string, 0, len(c.SetEnv))
|
||||||
|
for k := range c.SetEnv {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
slices.Sort(keys)
|
||||||
|
for i, k := range keys {
|
||||||
|
n[SetEnv][i] = [2]string{k, c.SetEnv[k]}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, PairArg(i).Unwrap(), v[0], v[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user