mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-11-04 14:49:53 +08:00
add mount builder & fix rlimits unit
This commit is contained in:
parent
2b11c31b60
commit
c8d682f4b6
@ -12,6 +12,7 @@ import (
|
||||
"github.com/criyle/go-sandbox/daemon"
|
||||
"github.com/criyle/go-sandbox/pkg/cgroup"
|
||||
"github.com/criyle/go-sandbox/pkg/memfd"
|
||||
"github.com/criyle/go-sandbox/pkg/mount"
|
||||
"github.com/criyle/go-sandbox/pkg/rlimit"
|
||||
"github.com/criyle/go-sandbox/pkg/seccomp"
|
||||
"github.com/criyle/go-sandbox/pkg/seccomp/libseccomp"
|
||||
@ -205,8 +206,8 @@ func start() (*types.Result, error) {
|
||||
rlims := rlimit.RLimits{
|
||||
CPU: timeLimit,
|
||||
CPUHard: realTimeLimit,
|
||||
FileSize: outputLimit,
|
||||
Stack: stackLimit,
|
||||
FileSize: outputLimit << 20,
|
||||
Stack: stackLimit << 20,
|
||||
}
|
||||
|
||||
actionDefault := seccomp.ActionKill
|
||||
@ -255,26 +256,24 @@ func start() (*types.Result, error) {
|
||||
return nil, fmt.Errorf("cannot make temp root for new namespace")
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
mounts, err := mount.NewBuilder().WithMounts(unshare.DefaultMounts).WithBind(root, "w", true).Build(true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot make rootfs mounts")
|
||||
}
|
||||
runner = &unshare.Runner{
|
||||
Args: args,
|
||||
Env: []string{pathEnv},
|
||||
ExecFile: execFile,
|
||||
WorkDir: "/w",
|
||||
Files: fds,
|
||||
RLimits: rlims,
|
||||
RLimits: rlims.PrepareRLimit(),
|
||||
Limit: types.Limit{
|
||||
TimeLimit: timeLimit * 1e3,
|
||||
MemoryLimit: memoryLimit << 10,
|
||||
},
|
||||
Seccomp: filter,
|
||||
Root: root,
|
||||
Mounts: unshare.GetDefaultMounts(root, []unshare.AddBind{
|
||||
{
|
||||
Source: workPath,
|
||||
Target: "w",
|
||||
},
|
||||
}),
|
||||
Seccomp: filter,
|
||||
Root: root,
|
||||
Mounts: mounts,
|
||||
ShowDetails: showDetails,
|
||||
SyncFunc: syncFunc,
|
||||
HostName: "run_program",
|
||||
@ -295,7 +294,7 @@ func start() (*types.Result, error) {
|
||||
Env: []string{pathEnv},
|
||||
ExecFile: execFile,
|
||||
WorkDir: workPath,
|
||||
RLimits: rlims,
|
||||
RLimits: rlims.PrepareRLimit(),
|
||||
Limit: types.Limit{
|
||||
TimeLimit: timeLimit * 1e3,
|
||||
MemoryLimit: memoryLimit << 10,
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/criyle/go-sandbox/pkg/mount"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
bind = unix.MS_BIND | unix.MS_NOSUID | unix.MS_PRIVATE
|
||||
roBind = bind | unix.MS_RDONLY
|
||||
roBind = unix.MS_BIND | unix.MS_NOSUID | unix.MS_PRIVATE | unix.MS_RDONLY
|
||||
mFlag = unix.MS_NOSUID | unix.MS_NOATIME | unix.MS_NODEV
|
||||
)
|
||||
|
||||
@ -19,7 +16,7 @@ var (
|
||||
DefaultPath = "PATH=/usr/local/bin:/usr/bin:/bin"
|
||||
|
||||
// rootfs created by bind mounting
|
||||
DefaultMounts = []*mount.Mount{
|
||||
DefaultMounts = []mount.Mount{
|
||||
{
|
||||
Source: "/usr",
|
||||
Target: "usr",
|
||||
@ -56,18 +53,3 @@ var (
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
// check if bind mount source exists, e.g. /lib64 does not exists on arm
|
||||
mounts := make([]*mount.Mount, 0, len(DefaultMounts))
|
||||
for _, m := range DefaultMounts {
|
||||
if m.Source != "tmpfs" {
|
||||
if _, err := os.Stat(m.Source); !os.IsNotExist(err) {
|
||||
mounts = append(mounts, m)
|
||||
}
|
||||
} else {
|
||||
mounts = append(mounts, m)
|
||||
}
|
||||
}
|
||||
DefaultMounts = mounts
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/criyle/go-sandbox/pkg/forkexec"
|
||||
"github.com/criyle/go-sandbox/pkg/memfd"
|
||||
"github.com/criyle/go-sandbox/pkg/mount"
|
||||
"github.com/criyle/go-sandbox/pkg/unixsocket"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@ -43,23 +44,28 @@ func New(root string) (*Master, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("daemon: failed to create socket(%v)", err)
|
||||
}
|
||||
defer outs.Conn.Close()
|
||||
|
||||
outf, err := outs.Conn.File()
|
||||
if err != nil {
|
||||
ins.Conn.Close()
|
||||
outs.Conn.Close()
|
||||
return nil, fmt.Errorf("daemon: failed to dup file outs(%v)", err)
|
||||
}
|
||||
defer outf.Close()
|
||||
|
||||
if err = ins.SetPassCred(1); err != nil {
|
||||
ins.Conn.Close()
|
||||
outs.Conn.Close()
|
||||
return nil, fmt.Errorf("daemon: failed to set pass_cred ins(%v)", err)
|
||||
}
|
||||
if err = outs.SetPassCred(1); err != nil {
|
||||
ins.Conn.Close()
|
||||
outs.Conn.Close()
|
||||
return nil, fmt.Errorf("daemon: failed to set pass_cred outs(%v)", err)
|
||||
}
|
||||
mounts, err := mount.NewBuilder().WithMounts(DefaultMounts).Build(true)
|
||||
if err != nil {
|
||||
ins.Conn.Close()
|
||||
return nil, fmt.Errorf("daemon: failed to build rootfs mount %v", err)
|
||||
}
|
||||
|
||||
r := &forkexec.Runner{
|
||||
Args: []string{os.Args[0], initArg},
|
||||
@ -68,7 +74,7 @@ func New(root string) (*Master, error) {
|
||||
Files: []uintptr{fnull.Fd(), fnull.Fd(), fnull.Fd(), uintptr(outf.Fd())},
|
||||
WorkDir: "/w",
|
||||
UnshareFlags: forkexec.UnshareFlags,
|
||||
Mounts: DefaultMounts,
|
||||
Mounts: mounts,
|
||||
HostName: "daemon",
|
||||
DomainName: "daemon",
|
||||
PivotRoot: root,
|
||||
@ -76,11 +82,8 @@ func New(root string) (*Master, error) {
|
||||
pid, err := r.Start()
|
||||
if err != nil {
|
||||
ins.Conn.Close()
|
||||
outs.Conn.Close()
|
||||
return nil, fmt.Errorf("daemon: failed to execve(%v)", err)
|
||||
}
|
||||
|
||||
outs.Conn.Close()
|
||||
return &Master{pid, ins}, nil
|
||||
}
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@ -4,5 +4,5 @@ go 1.12
|
||||
|
||||
require (
|
||||
github.com/seccomp/libseccomp-golang v0.9.1
|
||||
golang.org/x/sys v0.0.0-20190913121621-c3b328c6e5a7
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@ -1,4 +1,4 @@
|
||||
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
golang.org/x/sys v0.0.0-20190913121621-c3b328c6e5a7 h1:wYqz/tQaWUgGKyx+B/rssSE6wkIKdY5Ee6ryOmzarIg=
|
||||
golang.org/x/sys v0.0.0-20190913121621-c3b328c6e5a7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
||||
@ -58,12 +58,6 @@ func (r *Runner) Start() (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// prepare mount param
|
||||
mountParams, dirsToMake, err := prepareMounts(r.Mounts)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// socketpair p used to notify child the uid / gid mapping have been setup
|
||||
// socketpair p is also used to sync with parent before final execve
|
||||
// p[0] is used by parent and p[1] is used by child
|
||||
@ -277,9 +271,9 @@ func (r *Runner) Start() (int, error) {
|
||||
}
|
||||
|
||||
// performing mounts
|
||||
for i, m := range mountParams {
|
||||
for _, m := range r.Mounts {
|
||||
// mkdirs(target)
|
||||
for _, p := range dirsToMake[i] {
|
||||
for _, p := range m.Prefixes {
|
||||
_, _, err1 = syscall.RawSyscall(syscall.SYS_MKDIRAT, uintptr(_AT_FDCWD), uintptr(unsafe.Pointer(p)), 0755)
|
||||
if err1 != 0 && err1 != syscall.EEXIST {
|
||||
goto childerror
|
||||
|
||||
@ -2,8 +2,6 @@ package forkexec
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/criyle/go-sandbox/pkg/mount"
|
||||
)
|
||||
|
||||
// prepareExec prepares execve parameters
|
||||
@ -63,47 +61,3 @@ func preparePivotRoot(r string) (*byte, *byte, error) {
|
||||
}
|
||||
return root, oldRoot, nil
|
||||
}
|
||||
|
||||
// prepareMounts prepare mkdir and mount syscall params
|
||||
func prepareMounts(ms []*mount.Mount) ([]*mount.SyscallParams, [][]*byte, error) {
|
||||
params, err := mount.ToSyscalls(ms)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// evaluate paths that need to be created
|
||||
pathsToCreate := make([][]*byte, 0, len(ms))
|
||||
for _, m := range ms {
|
||||
prefix := pathPrefix(m.Target)
|
||||
paths, err := arrayPtrFromStrings(prefix)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pathsToCreate = append(pathsToCreate, paths)
|
||||
}
|
||||
return params, pathsToCreate, nil
|
||||
}
|
||||
|
||||
// pathPrefix get all components from path
|
||||
func pathPrefix(path string) []string {
|
||||
ret := make([]string, 0)
|
||||
for i := 1; i < len(path); i++ {
|
||||
if path[i] == '/' {
|
||||
ret = append(ret, path[:i])
|
||||
}
|
||||
}
|
||||
ret = append(ret, path)
|
||||
return ret
|
||||
}
|
||||
|
||||
// arrayPtrFromStrings convers srings to c style strings
|
||||
func arrayPtrFromStrings(strs []string) ([]*byte, error) {
|
||||
bytes := make([]*byte, 0, len(strs))
|
||||
for _, s := range strs {
|
||||
b, err := syscall.BytePtrFromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bytes = append(bytes, b)
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
@ -56,17 +56,14 @@ type Runner struct {
|
||||
// need CAP_SYS_ADMIN inside the namespace (e.g. unshare user namespace)
|
||||
// if pivot root is provided, relative target is better for chdir-mount meta
|
||||
// and pivot root will mount as tmpfs before any mount
|
||||
Mounts []*mount.Mount
|
||||
|
||||
// HostName and DomainName to be set after unshare UTS & user (CAP_SYS_ADMIN)
|
||||
HostName, DomainName string
|
||||
Mounts []mount.SyscallParams
|
||||
|
||||
// pivot_root defines a readonly new root after unshare mount namespace
|
||||
// it should be a directory in absolute path
|
||||
// Before mounts, tt will call:
|
||||
// it should be a directory in absolute path and should used with mounts
|
||||
// Call path:
|
||||
// mount("tmpfs", root, "tmpfs", 0, nil)
|
||||
// chdir(root)
|
||||
// After mounts, it will call:
|
||||
// [do mounts]
|
||||
// mkdir("old_root")
|
||||
// pivot_root(root, "old_root")
|
||||
// umount("old_root", MNT_DETACH)
|
||||
@ -74,6 +71,9 @@ type Runner struct {
|
||||
// mount("tmpfs", "/", "tmpfs", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_NOATIME | MS_NOSUID, nil)
|
||||
PivotRoot string
|
||||
|
||||
// HostName and DomainName to be set after unshare UTS & user (CAP_SYS_ADMIN)
|
||||
HostName, DomainName string
|
||||
|
||||
// drop_caps calls cap_set(self, 0) to drop all capabilities
|
||||
// from effective, permitted, inheritable capability sets before execve
|
||||
// it should avoid calls to set ambient capabilities
|
||||
|
||||
90
pkg/mount/builder.go
Normal file
90
pkg/mount/builder.go
Normal file
@ -0,0 +1,90 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
bind = unix.MS_BIND | unix.MS_NOSUID | unix.MS_NOATIME | unix.MS_PRIVATE
|
||||
roBind = bind | unix.MS_RDONLY
|
||||
mFlag = unix.MS_NOSUID | unix.MS_NOATIME | unix.MS_NODEV | unix.MS_PRIVATE
|
||||
)
|
||||
|
||||
// Builder builds fork_exec friendly mount syscall format
|
||||
type Builder struct {
|
||||
Mounts []Mount
|
||||
}
|
||||
|
||||
// NewBuilder creates new mount builder instance
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{}
|
||||
}
|
||||
|
||||
// Build creates sequence of syscalls for fork_exec
|
||||
// skipNotExists skips bind mounts that source not exitst
|
||||
func (b *Builder) Build(skipNotExists bool) ([]SyscallParams, error) {
|
||||
ret := make([]SyscallParams, 0, len(b.Mounts))
|
||||
for _, m := range b.Mounts {
|
||||
if err := isBindMountNotExists(m); err != nil {
|
||||
if skipNotExists {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
sp, err := m.ToSyscall()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, *sp)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func isBindMountNotExists(m Mount) error {
|
||||
if m.Flags&unix.MS_BIND == unix.MS_BIND {
|
||||
if _, err := os.Stat(m.Source); os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithMounts add mounts to builder
|
||||
func (b *Builder) WithMounts(m []Mount) *Builder {
|
||||
b.Mounts = append(b.Mounts, m...)
|
||||
return b
|
||||
}
|
||||
|
||||
// WithMount add single mount to builder
|
||||
func (b *Builder) WithMount(m Mount) *Builder {
|
||||
b.Mounts = append(b.Mounts, m)
|
||||
return b
|
||||
}
|
||||
|
||||
// WithBind adds a bind mount to builder
|
||||
func (b *Builder) WithBind(source, target string, readonly bool) *Builder {
|
||||
var flags uintptr = bind
|
||||
if readonly {
|
||||
flags = roBind
|
||||
}
|
||||
b.Mounts = append(b.Mounts, Mount{
|
||||
Source: source,
|
||||
Target: target,
|
||||
Flags: flags,
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// WithTmpfs add a tmpfs mount to builder
|
||||
func (b *Builder) WithTmpfs(target, data string) *Builder {
|
||||
b.Mounts = append(b.Mounts, Mount{
|
||||
Source: "tmpfs",
|
||||
Target: target,
|
||||
FsType: "tmpfs",
|
||||
Flags: mFlag,
|
||||
Data: data,
|
||||
})
|
||||
return b
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
@ -15,6 +14,7 @@ type Mount struct {
|
||||
type SyscallParams struct {
|
||||
Source, Target, FsType, Data *byte
|
||||
Flags uintptr
|
||||
Prefixes []*byte
|
||||
}
|
||||
|
||||
// ToSyscall convert Mount to SyscallPrams
|
||||
@ -38,53 +38,42 @@ func (m *Mount) ToSyscall() (*SyscallParams, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
prefix := pathPrefix(m.Target)
|
||||
paths, err := arrayPtrFromStrings(prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SyscallParams{
|
||||
Source: source,
|
||||
Target: target,
|
||||
FsType: fsType,
|
||||
Flags: m.Flags,
|
||||
Data: data,
|
||||
Source: source,
|
||||
Target: target,
|
||||
FsType: fsType,
|
||||
Flags: m.Flags,
|
||||
Data: data,
|
||||
Prefixes: paths,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Mount calls mount syscall
|
||||
func (m *Mount) Mount() error {
|
||||
if err := os.MkdirAll(m.Target, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := syscall.Mount(m.Source, m.Target, m.FsType, m.Flags, m.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
// Read-only bind mount need to be remounted
|
||||
const bindRo = syscall.MS_BIND | syscall.MS_RDONLY
|
||||
if m.Flags&bindRo == bindRo {
|
||||
if err := syscall.Mount("", m.Target, m.FsType, m.Flags|syscall.MS_REMOUNT, m.Data); err != nil {
|
||||
return err
|
||||
// pathPrefix get all components from path
|
||||
func pathPrefix(path string) []string {
|
||||
ret := make([]string, 0)
|
||||
for i := 1; i < len(path); i++ {
|
||||
if path[i] == '/' {
|
||||
ret = append(ret, path[:i])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
ret = append(ret, path)
|
||||
return ret
|
||||
}
|
||||
|
||||
// ToSyscalls converts arrays of Mounts into SyscallParams
|
||||
func ToSyscalls(ms []*Mount) ([]*SyscallParams, error) {
|
||||
ret := make([]*SyscallParams, 0, len(ms))
|
||||
for _, m := range ms {
|
||||
sp, err := m.ToSyscall()
|
||||
// arrayPtrFromStrings converts srings to c style strings
|
||||
func arrayPtrFromStrings(strs []string) ([]*byte, error) {
|
||||
bytes := make([]*byte, 0, len(strs))
|
||||
for _, s := range strs {
|
||||
b, err := syscall.BytePtrFromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, sp)
|
||||
bytes = append(bytes, b)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Mounts calls multiple mount syscalls
|
||||
func Mounts(ms []*Mount) error {
|
||||
for _, m := range ms {
|
||||
err := m.Mount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
24
pkg/mount/mount_linux.go
Normal file
24
pkg/mount/mount_linux.go
Normal file
@ -0,0 +1,24 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Mount calls mount syscall
|
||||
func (m *Mount) Mount() error {
|
||||
if err := os.MkdirAll(m.Target, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := syscall.Mount(m.Source, m.Target, m.FsType, m.Flags, m.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
// Read-only bind mount need to be remounted
|
||||
const bindRo = syscall.MS_BIND | syscall.MS_RDONLY
|
||||
if m.Flags&bindRo == bindRo {
|
||||
if err := syscall.Mount("", m.Target, m.FsType, m.Flags|syscall.MS_REMOUNT, m.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -8,10 +8,10 @@ import (
|
||||
type RLimits struct {
|
||||
CPU uint64 // in s
|
||||
CPUHard uint64 // in s
|
||||
Data uint64 // in kb
|
||||
FileSize uint64 // in kb
|
||||
Stack uint64 // in kb
|
||||
AddressSpace uint64 // in kb
|
||||
Data uint64 // in bytes
|
||||
FileSize uint64 // in bytes
|
||||
Stack uint64 // in bytes
|
||||
AddressSpace uint64 // in bytes
|
||||
}
|
||||
|
||||
// RLimit is the resource limits defined by Linux setrlimit
|
||||
@ -23,7 +23,7 @@ type RLimit struct {
|
||||
}
|
||||
|
||||
func getRlimit(cur, max uint64) syscall.Rlimit {
|
||||
return syscall.Rlimit{Cur: uint64(cur), Max: uint64(max)}
|
||||
return syscall.Rlimit{Cur: cur, Max: max}
|
||||
}
|
||||
|
||||
// PrepareRLimit creates rlimit structures for tracee
|
||||
@ -44,25 +44,25 @@ func (r *RLimits) PrepareRLimit() []RLimit {
|
||||
if r.Data > 0 {
|
||||
ret = append(ret, RLimit{
|
||||
Res: syscall.RLIMIT_DATA,
|
||||
Rlim: getRlimit(r.Data<<10, r.Data<<10),
|
||||
Rlim: getRlimit(r.Data, r.Data),
|
||||
})
|
||||
}
|
||||
if r.FileSize > 0 {
|
||||
ret = append(ret, RLimit{
|
||||
Res: syscall.RLIMIT_FSIZE,
|
||||
Rlim: getRlimit(r.FileSize<<10, r.FileSize<<10),
|
||||
Rlim: getRlimit(r.FileSize, r.FileSize),
|
||||
})
|
||||
}
|
||||
if r.Stack > 0 {
|
||||
ret = append(ret, RLimit{
|
||||
Res: syscall.RLIMIT_STACK,
|
||||
Rlim: getRlimit(r.Stack<<10, r.Stack<<10),
|
||||
Rlim: getRlimit(r.Stack, r.Stack),
|
||||
})
|
||||
}
|
||||
if r.AddressSpace > 0 {
|
||||
ret = append(ret, RLimit{
|
||||
Res: syscall.RLIMIT_AS,
|
||||
Rlim: getRlimit(r.AddressSpace<<10, r.AddressSpace<<10),
|
||||
Rlim: getRlimit(r.AddressSpace, r.AddressSpace),
|
||||
})
|
||||
}
|
||||
return ret
|
||||
|
||||
@ -12,7 +12,7 @@ func (r *Runner) Start(done <-chan struct{}) (<-chan types.Result, error) {
|
||||
Args: r.Args,
|
||||
Env: r.Env,
|
||||
ExecFile: r.ExecFile,
|
||||
RLimits: r.RLimits.PrepareRLimit(),
|
||||
RLimits: r.RLimits,
|
||||
Files: r.Files,
|
||||
WorkDir: r.WorkDir,
|
||||
Seccomp: r.Seccomp.SockFprog(),
|
||||
|
||||
@ -24,7 +24,7 @@ type Runner struct {
|
||||
Files []uintptr
|
||||
|
||||
// Resource limit set by set rlimit
|
||||
RLimits rlimit.RLimits
|
||||
RLimits []rlimit.RLimit
|
||||
|
||||
// Res limit enforced by tracer
|
||||
Limit types.Limit
|
||||
|
||||
@ -1,36 +1,16 @@
|
||||
package unshare
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/criyle/go-sandbox/pkg/mount"
|
||||
)
|
||||
|
||||
// AddBind is the additional bind mounts besides the default one
|
||||
type AddBind struct {
|
||||
Source, Target string
|
||||
ReadOnly bool
|
||||
}
|
||||
const roBind = unix.MS_BIND | unix.MS_NOSUID | unix.MS_PRIVATE | unix.MS_RDONLY
|
||||
|
||||
const (
|
||||
bind2 = unix.MS_BIND | unix.MS_NOSUID | unix.MS_NOATIME | unix.MS_NODEV | unix.MS_NODIRATIME
|
||||
bind = unix.MS_BIND | unix.MS_NOSUID | unix.MS_PRIVATE
|
||||
roBind = bind | unix.MS_RDONLY
|
||||
noExecRoBind = roBind | unix.MS_NOEXEC
|
||||
remountRo = unix.MS_REMOUNT | unix.MS_RDONLY
|
||||
)
|
||||
|
||||
// default parameters. I was tend to reuse the configs but it is hard since there are some
|
||||
// cross device symblics
|
||||
var (
|
||||
DefaultMounts = []*mount.Mount{
|
||||
{
|
||||
Source: "/usr/lib/locale",
|
||||
Target: "usr/lib/locale",
|
||||
Flags: roBind,
|
||||
},
|
||||
// DefaultMounts is a example of minimal rootfs
|
||||
DefaultMounts = []mount.Mount{
|
||||
{
|
||||
Source: "/usr",
|
||||
Target: "usr",
|
||||
@ -53,26 +33,3 @@ var (
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// GetDefaultMounts returns default mount parameters for given root
|
||||
func GetDefaultMounts(root string, add []AddBind) []*mount.Mount {
|
||||
mounts := make([]*mount.Mount, 0, len(DefaultMounts)+len(add))
|
||||
// check if bind mount source exists, e.g. /lib64 does not exists on arm
|
||||
for _, m := range DefaultMounts {
|
||||
if _, err := os.Stat(m.Source); !os.IsNotExist(err) {
|
||||
mounts = append(mounts, m)
|
||||
}
|
||||
}
|
||||
for _, m := range add {
|
||||
flags := bind
|
||||
if m.ReadOnly {
|
||||
flags = roBind
|
||||
}
|
||||
mounts = append(mounts, &mount.Mount{
|
||||
Source: m.Source,
|
||||
Target: m.Target,
|
||||
Flags: uintptr(flags),
|
||||
})
|
||||
}
|
||||
return mounts
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ func (r *Runner) Start(done <-chan struct{}) (<-chan types.Result, error) {
|
||||
Args: r.Args,
|
||||
Env: r.Env,
|
||||
ExecFile: r.ExecFile,
|
||||
RLimits: r.RLimits.PrepareRLimit(),
|
||||
RLimits: r.RLimits,
|
||||
Files: r.Files,
|
||||
WorkDir: r.WorkDir,
|
||||
Seccomp: r.Seccomp.SockFprog(),
|
||||
|
||||
@ -23,7 +23,7 @@ type Runner struct {
|
||||
Files []uintptr
|
||||
|
||||
// Resource limit set by set rlimit
|
||||
RLimits rlimit.RLimits
|
||||
RLimits []rlimit.RLimit
|
||||
|
||||
// Resource limit enforced by tracer
|
||||
Limit types.Limit
|
||||
@ -35,7 +35,7 @@ type Runner struct {
|
||||
Root string
|
||||
|
||||
// Mount syscalls
|
||||
Mounts []*mount.Mount
|
||||
Mounts []mount.SyscallParams
|
||||
|
||||
// hostname & domainname
|
||||
HostName, DomainName string
|
||||
|
||||
Loading…
Reference in New Issue
Block a user