From bc0b7f92f12bbc07033488365c0270c4d75eaf1e Mon Sep 17 00:00:00 2001 From: criyle Date: Fri, 15 May 2020 03:02:04 -0400 Subject: [PATCH] Add MacOS sandbox support --- cmd/runprog/main_darwin.go | 16 +++++++++++++++- pkg/forkexec/fork_child_darwin.go | 18 ++++++++++++++++-- pkg/forkexec/syscall_darwin.go | 10 ++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/cmd/runprog/main_darwin.go b/cmd/runprog/main_darwin.go index c41c184..efe40fb 100644 --- a/cmd/runprog/main_darwin.go +++ b/cmd/runprog/main_darwin.go @@ -3,6 +3,8 @@ package main import ( "flag" + "fmt" + "io/ioutil" "log" "os" "syscall" @@ -17,6 +19,8 @@ var ( timeLimit, realTimeLimit, memoryLimit, outputLimit, stackLimit uint64 inputFileName, outputFileName, errorFileName, workPath string + profilePath string + args []string ) @@ -31,6 +35,7 @@ func main() { flag.StringVar(&outputFileName, "out", "", "Set output file name") flag.StringVar(&errorFileName, "err", "", "Set error file name") flag.StringVar(&workPath, "work-path", "", "Set the work path of the program") + flag.StringVar(&profilePath, "p", "", "sandbox profile") flag.Parse() args = flag.Args() @@ -61,6 +66,15 @@ func start() (*runner.Result, error) { } defer closeFiles(files) + var profile string + if profilePath != "" { + c, err := ioutil.ReadFile(profilePath) + if err != nil { + return nil, fmt.Errorf("profile: %v", err) + } + profile = string(c) + } + // if not defined, then use the original value fds := make([]uintptr, len(files)) for i, f := range files { @@ -89,7 +103,7 @@ func start() (*runner.Result, error) { RLimits: rlims.PrepareRLimit(), Files: fds, WorkDir: workPath, - SandboxProfile: "", + SandboxProfile: profile, SyncFunc: func(pid int) error { mTime = time.Now() return nil diff --git a/pkg/forkexec/fork_child_darwin.go b/pkg/forkexec/fork_child_darwin.go index 8c0be61..66c6b76 100644 --- a/pkg/forkexec/fork_child_darwin.go +++ b/pkg/forkexec/fork_child_darwin.go @@ -9,7 +9,8 @@ import ( //go:norace func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, profile *byte, p [2]int) (r1 uintptr, err1 syscall.Errno) { var ( - err2 syscall.Errno + err2 syscall.Errno + errBuf *byte ) // similar to exec_linux, avoid side effect by shuffling around @@ -93,12 +94,25 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, prof // Set limit for _, rlim := range r.RLimits { - _, _, err1 := rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(rlim.Res), uintptr(unsafe.Pointer(&rlim.Rlim)), 0) + _, _, err1 = rawSyscall(funcPC(libc_setrlimit_trampoline), uintptr(rlim.Res), uintptr(unsafe.Pointer(&rlim.Rlim)), 0) if err1 != 0 { goto childerror } } + // Load sandbox profile + if profile != nil { + r1, _, err1 = rawSyscall(funcPC(libc_sandbox_init_trampoline), uintptr(unsafe.Pointer(profile)), 0, uintptr(unsafe.Pointer(&errBuf))) + if err1 != 0 { + goto childerror + } + if r1 != 0 { + err1 = 253 + goto childerror + } + rawSyscall(funcPC(libc_sandbox_free_error_trampoline), uintptr(unsafe.Pointer(errBuf)), 0, 0) + } + // Sync before exec err2 = 0 r1, _, err1 = rawSyscall(funcPC(libc_write_trampoline), uintptr(pipe), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) diff --git a/pkg/forkexec/syscall_darwin.go b/pkg/forkexec/syscall_darwin.go index abccfc8..319ba4b 100644 --- a/pkg/forkexec/syscall_darwin.go +++ b/pkg/forkexec/syscall_darwin.go @@ -3,8 +3,12 @@ package forkexec import ( "syscall" _ "unsafe" // use go:linkname + + "github.com/criyle/go-sandbox/pkg/darwin" // use sandbox_init ) +var _ = darwin.SandboxInit + //go:linkname funcPC syscall.funcPC func funcPC(f func()) uintptr @@ -47,5 +51,11 @@ func libc_execve_trampoline() //go:linkname libc_exit_trampoline syscall.libc_exit_trampoline func libc_exit_trampoline() +//go:linkname libc_sandbox_init_trampoline github.com/criyle/go-sandbox/pkg/darwin.libc_sandbox_init_trampoline +func libc_sandbox_init_trampoline() + +//go:linkname libc_sandbox_free_error_trampoline github.com/criyle/go-sandbox/pkg/darwin.libc_sandbox_free_error_trampoline +func libc_sandbox_free_error_trampoline() + //go:linkname fcntl syscall.fcntl func fcntl(fd int, cmd int, arg int) (val int, err error)