Yeuoly hai 1 ano
pai
achega
52d75b3596

+ 1 - 0
go.mod

@@ -13,6 +13,7 @@ require (
 	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-playground/validator/v10 v10.17.0 // indirect
 	github.com/goccy/go-json v0.10.2 // indirect
+	github.com/google/uuid v1.6.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.6 // indirect
 	github.com/leodido/go-urn v1.3.0 // indirect

+ 2 - 0
go.sum

@@ -28,6 +28,8 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=

+ 37 - 0
internal/core/runner/init.go

@@ -0,0 +1,37 @@
+package runner
+
+import (
+	"os/exec"
+	"strconv"
+	"strings"
+
+	"github.com/langgenius/dify-sandbox/internal/static"
+	"github.com/langgenius/dify-sandbox/internal/utils/log"
+)
+
+func init() {
+	// create sandbox user
+	user := static.SANDBOX_USER
+	uid := static.SANDBOX_USER_UID
+
+	// check if user exists
+	_, err := exec.Command("id", user).Output()
+	if err != nil {
+		// create user
+		output, err := exec.Command("bash", "-c", "useradd -u "+strconv.Itoa(uid)+" "+user).Output()
+		if err != nil {
+			log.Panic("failed to create user: %v, %v", err, string(output))
+		}
+	}
+
+	// get gid of sandbox user and setgid
+	gid, err := exec.Command("id", "-g", static.SANDBOX_USER).Output()
+	if err != nil {
+		log.Panic("failed to get gid of user: %v", err)
+	}
+
+	static.SANDBOX_GROUP_ID, err = strconv.Atoi(strings.TrimSpace(string(gid)))
+	if err != nil {
+		log.Panic("failed to convert gid: %v", err)
+	}
+}

+ 24 - 0
internal/core/runner/python/path.go

@@ -0,0 +1,24 @@
+package python
+
+var (
+	PYTHON_RUNNER_PATH = []string{
+		"/usr/bin/python3",
+		"/usr/bin/python3.10",
+		"/usr/lib/python3/dist-packages",
+		"/usr/lib/python3.10",
+		"/usr/bin/echo",
+		// libc
+		"/lib/x86_64-linux-gnu/libc.so.6",
+		"/lib/x86_64-linux-gnu/libm.so.6",
+		"/lib/x86_64-linux-gnu/libexpat.so.1",
+		"/lib/x86_64-linux-gnu/libz.so.1",
+		"/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
+		"/lib/x86_64-linux-gnu/libexpat.so.1.8.7",
+		"/lib/x86_64-linux-gnu/libz.so.1.2.11",
+		"/lib64/ld-linux-x86-64.so.2",
+		// libpthread
+		"/lib/x86_64-linux-gnu/libpthread.so.0",
+		// libdl
+		"/lib/x86_64-linux-gnu/libdl.so.2",
+	}
+)

+ 30 - 0
internal/core/runner/python/prescript.py

@@ -0,0 +1,30 @@
+import os
+import uuid
+import shutil
+
+def create_sandbox_and_execute(paths, closures):
+    tmp_dir = os.path.join("/tmp", "sandbox-" + str(uuid.uuid4()))
+    os.makedirs(tmp_dir, mode=0o755)
+    
+    try:
+        for file_path in paths:
+            target_path = os.path.join(tmp_dir, file_path)
+            if os.path.isdir(file_path):
+                os.makedirs(target_path, mode=0o755)
+            else:
+                os.makedirs(os.path.dirname(target_path), mode=0o755, exist_ok=True)
+                shutil.copy(file_path, target_path)
+        
+        original_root = os.open("/", os.O_RDONLY)
+        os.chroot(tmp_dir)
+        os.chdir("/")
+        
+        try:
+            closures()
+        finally:
+            os.fchdir(original_root)
+            os.chroot(".")
+    finally:
+        shutil.rmtree(tmp_dir)
+
+print(123)

+ 6 - 1
internal/core/runner/python/python.go

@@ -1,7 +1,9 @@
 package python
 
 import (
+	_ "embed"
 	"fmt"
+	"syscall"
 	"time"
 
 	"github.com/langgenius/dify-sandbox/internal/core/runner"
@@ -12,9 +14,12 @@ type PythonRunner struct {
 	runner.SeccompRunner
 }
 
+//go:embed prescript.py
+var python_sandbox_fs []byte
+
 func (p *PythonRunner) Run(code string, timeout time.Duration, stdin chan []byte) (<-chan []byte, <-chan []byte, error) {
 	err := p.WithSeccomp(func() error {
-		fmt.Println("Hello World")
+		syscall.Exec("/usr/bin/python3", []string{"/usr/bin/python3", "./internal/core/runner/python/prescript.py"}, nil)
 		return nil
 	})
 	if err != nil {

+ 19 - 4
internal/core/runner/seccomp.go

@@ -23,7 +23,7 @@ func (s *SeccompRunner) WithSeccomp(closures func() error) error {
 	defer ctx.Release()
 
 	for call := range static.ALLOW_SYSCALLS {
-		err = ctx.AddRule(sg.ScmpSyscall(call), sg.ActAllow)
+		err = ctx.AddRule(sg.ScmpSyscall(static.ALLOW_SYSCALLS[call]), sg.ActAllow)
 		if err != nil {
 			return err
 		}
@@ -45,7 +45,6 @@ func (s *SeccompRunner) WithSeccomp(closures func() error) error {
 	if err != nil {
 		return err
 	}
-
 	// load bpf
 	sock_filters := make([]syscall.SockFilter, n/8)
 	bytesBuffer := bytes.NewBuffer(data)
@@ -90,11 +89,13 @@ func (s *SeccompRunner) WithSeccomp(closures func() error) error {
 
 		defer syscall.Close(int(stdout_writer))
 		defer syscall.Close(int(stderr_writer))
+		defer syscall.Exit(0)
 
 		bpf := syscall.SockFprog{
 			Len:    uint16(len(sock_filters)),
 			Filter: &sock_filters[0],
 		}
+
 		_, _, err2 := syscall.RawSyscall6(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, 2, uintptr(unsafe.Pointer(&bpf)), 0, 0, 0)
 		if err2 != 0 {
 			response := fmt.Sprintf("prctl failed: %d\n", err2)
@@ -102,6 +103,20 @@ func (s *SeccompRunner) WithSeccomp(closures func() error) error {
 			return nil
 		}
 
+		_, _, err2 = syscall.RawSyscall(syscall.SYS_SETGID, uintptr(static.SANDBOX_GROUP_ID), 0, 0)
+		if err2 != 0 {
+			response := fmt.Sprintf("setgid failed: %v\n", err2)
+			_, _ = syscall.Write(int(stderr_writer), []byte(response))
+			return nil
+		}
+
+		_, _, err2 = syscall.RawSyscall(syscall.SYS_SETUID, uintptr(static.SANDBOX_USER_UID), 0, 0)
+		if err2 != 0 {
+			response := fmt.Sprintf("setuid failed: %v\n", err2)
+			_, _ = syscall.Write(int(stderr_writer), []byte(response))
+			return nil
+		}
+
 		err := closures()
 		if err != nil {
 			response := fmt.Sprintf("%v\n", err)
@@ -121,12 +136,12 @@ func (s *SeccompRunner) WithSeccomp(closures func() error) error {
 
 		// read from stderr pipe
 		data := make([]byte, 4096)
-		n, err := syscall.Read(int(stderr_reader), data)
+		_, err := syscall.Read(int(stderr_reader), data)
 		if err != nil {
 			return err
 		}
 
-		fmt.Println(string(data[:n]))
+		fmt.Println(string(data))
 	}
 
 	return nil

+ 26 - 1
internal/static/syscalls.go

@@ -1,5 +1,30 @@
 package static
 
+import "syscall"
+
+const (
+	SYS_GETRANDOM = 318
+	SYS_RSEQ      = 334
+)
+
 var ALLOW_SYSCALLS = []int{
-	0, 1,
+	// file io
+	syscall.SYS_READ, syscall.SYS_WRITE, syscall.SYS_OPEN, syscall.SYS_OPENAT, syscall.SYS_CLOSE,
+	syscall.SYS_PREAD64, syscall.SYS_PWRITE64, syscall.SYS_ACCESS, syscall.SYS_NEWFSTATAT, syscall.SYS_SET_TID_ADDRESS, syscall.SYS_SET_ROBUST_LIST, syscall.SYS_PRLIMIT64,
+	SYS_RSEQ, SYS_GETRANDOM,
+	syscall.SYS_LSEEK, syscall.SYS_IOCTL, syscall.SYS_GETDENTS, syscall.SYS_GETDENTS64, syscall.SYS_FUTEX, syscall.SYS_READLINK, syscall.SYS_SYSINFO, syscall.SYS_FCNTL,
+	syscall.SYS_DUP,
+	// memory
+	syscall.SYS_MMAP, syscall.SYS_BRK, syscall.SYS_MPROTECT, syscall.SYS_MUNMAP,
+	// user/group
+	syscall.SYS_GETUID, syscall.SYS_GETEUID, syscall.SYS_GETGID, syscall.SYS_SETUID, syscall.SYS_SETGID, syscall.SYS_GETEGID,
+	// process
+	syscall.SYS_GETPID, syscall.SYS_GETPPID, syscall.SYS_GETTID,
+	syscall.SYS_CLONE, syscall.SYS_FORK, syscall.SYS_VFORK, syscall.SYS_EXECVE, syscall.SYS_EXIT, syscall.SYS_EXIT_GROUP,
+	syscall.SYS_WAIT4, syscall.SYS_WAITID,
+	syscall.SYS_KILL, syscall.SYS_TKILL, syscall.SYS_TGKILL, syscall.SYS_RT_SIGQUEUEINFO, syscall.SYS_RT_SIGPROCMASK, syscall.SYS_RT_SIGRETURN, syscall.SYS_RT_SIGACTION,
+	// time
+	syscall.SYS_CLOCK_GETTIME, syscall.SYS_GETTIMEOFDAY, syscall.SYS_TIME, syscall.SYS_NANOSLEEP,
+
+	syscall.SYS_ARCH_PRCTL,
 }

+ 6 - 0
internal/static/user.go

@@ -0,0 +1,6 @@
+package static
+
+const SANDBOX_USER = "sandbox"
+const SANDBOX_USER_UID = 65537
+
+var SANDBOX_GROUP_ID = 0