{"id":37960094,"url":"https://github.com/criyle/go-sandbox","last_synced_at":"2026-01-16T18:03:35.878Z","repository":{"id":45774924,"uuid":"177891667","full_name":"criyle/go-sandbox","owner":"criyle","description":"Sandbox implemented in GO including containers (namespace, cgroup), ptrace, seccomp","archived":false,"fork":false,"pushed_at":"2025-12-20T21:58:39.000Z","size":406,"stargazers_count":237,"open_issues_count":2,"forks_count":36,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-12-22T20:49:22.897Z","etag":null,"topics":["cgroup","cgroups-v2","container","golang","libseccomp","linux","linux-namespace","memfd","namespace","ptrace","rlimit","sandbox","unix-socket","uoj"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/criyle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-03-27T00:50:48.000Z","updated_at":"2025-12-20T21:58:19.000Z","dependencies_parsed_at":"2023-10-15T03:13:35.960Z","dependency_job_id":"26a9ea54-0190-47e8-8e75-faa4f8f8449a","html_url":"https://github.com/criyle/go-sandbox","commit_stats":null,"previous_names":["criyle/go-judger"],"tags_count":90,"template":false,"template_full_name":null,"purl":"pkg:github/criyle/go-sandbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/criyle%2Fgo-sandbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/criyle%2Fgo-sandbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/criyle%2Fgo-sandbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/criyle%2Fgo-sandbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/criyle","download_url":"https://codeload.github.com/criyle/go-sandbox/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/criyle%2Fgo-sandbox/sbom","scorecard":{"id":309115,"data":{"date":"2025-08-11","repo":{"name":"github.com/criyle/go-sandbox","commit":"2d0d63be761850032317f590df5af7027f25f6ad"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.6,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":4,"reason":"4 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 2/26 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T22:49:10.467Z","repository_id":45774924,"created_at":"2025-08-17T22:49:10.467Z","updated_at":"2025-08-17T22:49:10.467Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28480513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cgroup","cgroups-v2","container","golang","libseccomp","linux","linux-namespace","memfd","namespace","ptrace","rlimit","sandbox","unix-socket","uoj"],"created_at":"2026-01-16T18:03:35.281Z","updated_at":"2026-01-16T18:03:35.870Z","avatar_url":"https://github.com/criyle.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-sandbox\n\n[![GoDoc](https://godoc.org/github.com/criyle/go-sandbox?status.svg)](https://godoc.org/github.com/criyle/go-sandbox) [![Go Report Card](https://goreportcard.com/badge/github.com/criyle/go-sandbox)](https://goreportcard.com/report/github.com/criyle/go-sandbox) [![Release](https://img.shields.io/github/v/tag/criyle/go-sandbox)](https://github.com/criyle/go-sandbox/releases/latest)\n\nOriginal goal was to replica [uoj-judger/run_program](https://github.com/vfleaking/uoj) in GO language using [libseccomp](https://github.com/pkg/seccomp/libseccomp-golang). As technology grows, it also implements new technologies including Linux namespace and cgroup.\n\nThe idea of rootfs and interval CPU usage checking comes from [syzoj/judge-v3](https://github.com/syzoj/judge-v3) and the pooled pre-forked container comes from [vijos/jd4](https://github.com/vijos/jd4).\n\nIf you are looking for sandbox implementation via REST / gRPC API, please check [go-judge](https://github.com/criyle/go-judge).\n\nNotice: Only works on Linux since ptrace, unshare, cgroup are available only on Linux\n\n## Build \u0026 Install\n\n- install latest go compiler from [golang/download](https://golang.org/dl/)\n- download repository: `git clone githuc.com/criyle/go-sandbox`\n- build: `go build ./cmd/runprog` \n- or install directly: `go install github.com/criyle/go-sandbox/cmd/runprog@latest`\n\n## Technologies\n\n### libseccomp + ptrace (improved UOJ sandbox)\n\n1. Restricted computing resource by POSIX rlimit: Time \u0026 Memory (Stack) \u0026 Output\n2. Restricted syscall access (by libseccomp \u0026 ptrace)\n3. Restricted file access (read \u0026 write \u0026 access \u0026 exec). Evaluated by UOJ FileSet\n\nImprovements:\n\n1. Precise resource limits (s -\u003e ms, mb -\u003e kb)\n2. More architectures (arm32, arm64)\n3. Allow multiple traced programs in different threads\n4. Allow pipes as input / output files\n\nDefault file access syscall check:\n\n- check file read / write: `open`, `openat`\n- check file read: `readlink`, `readlinkat`\n- check file write: `unlink`, `unlinkat`, `chmod`, `rename`\n- check file access: `stat`, `lstat`, `access`, `faccessat`\n- check file exec: `execve`, `execveat`\n\n### linux namespace + cgroup\n\n1. Unshare \u0026 bind mount rootfs based on hostfs (eliminated ptrace)\n2. Use Linux Control Groups to limit \u0026 acct CPU \u0026 memory (eliminated wait4.rusage)\n3. Container tech with execveat memfd, sethostname, setdomainname\n\n### prefork containers\n\nUtilize the linux namespace + cgroup but create container in advance to reduce the duplicated effort of creating mount points. See Pre-forked container protocol and environment for design details.\n\nOn kernel \u003e= 5.7 with cgroup v2, the new `clone3(CLONE_INTO_CGROUP)` with `vfork` is available to reduce the resource consumption of create new address spaces as well.\n\n## Design\n\n### Result Status\n\n- Normal (no error)\n- Program Error\n  - Resource Limit Exceeded\n    - Time\n    - Memory\n    - Output\n  - Unauthorized Access\n    - Disallowed Syscall\n  - Runtime Error\n    - Signalled\n      - `SIGXCPU` / `SIGKILL` are treated as TimeLimitExceeded by rlimit or caller kill\n      - `SIGXFSZ` is treated as OutputLimitExceeded by rlimit\n      - `SIGSYS` is treaded as Disallowed Syscall by seccomp\n      - Potential Runtime error are: `SIGSEGV` (segment fault)\n    - Nonzero Exit Status\n- Program Runner Error\n\n### Result Structure\n\n``` go\ntype Result struct {\n    Status            // result status\n    ExitStatus int    // exit status (signal number if signalled)\n    Error      string // potential detailed error message (for program runner error)\n\n    Time   time.Duration // used user CPU time  (underlying type int64 in ns)\n    Memory Size          // used user memory    (underlying type uint64 in bytes)\n    // metrics for the program runner\n    SetUpTime   time.Duration\n    RunningTime time.Duration\n}\n```\n\n### Runner Interface\n\nConfigured runner to run the program. `Context` is used to cancel (control time limit exceeded event; should not be nil).\n\n``` go\ntype Runner interface {\n    Run(context.Context) \u003c-chan runner.Result\n}\n```\n\n### Pre-forked Container Protocol\n\n1. Pre-fork container to run programs inside\n2. Unix socket to pass fd inside / outside\n\nContainer / Host Communication Protocol (single thread):\n\n- ping (alive check):\n  - reply: pong\n- conf (set configuration):\n  - reply pong\n- open (open files in given mode inside container):\n  - send: []OpenCmd\n  - reply: \"success\", file fds / \"error\"\n- delete (unlink file / rmdir dir inside container):\n  - send: path\n  - reply: \"finished\" / \"error\"\n- reset (clean up container for later use (clear workdir / tmp)):\n  - send:\n  - reply: \"success\"\n- execve: (execute file inside container):\n  - send: argv, env, rLimits, fds\n  - reply:\n    - success: \"success\", pid\n    - failed: \"failed\"\n  - send (success): \"init_finished\" (as cmd)\n    - reply: \"finished\" / send: \"kill\" (as cmd)\n    - send: \"kill\" (as cmd) / reply: \"finished\"\n  - reply:\n\nAny socket related error will cause the container exit (with all process inside container)\n\n### Pre-forked Container Environment\n\nContainer restricted environment is accessed though RPC interface defined by above protocol\n\nProvides:\n\n- File access\n  - Open: create / access files\n  - Delete: remove file\n- Management\n  - Ping: alive check\n  - Reset: remove temporary files\n  - Destroy: destroy the container environment\n- Run program\n  - Execve: execute program with given parameters\n\n``` go\ntype Environment interface {\n    Ping() error\n    Open([]OpenCmd) ([]*os.File, error)\n    Delete(p string) error\n    Reset() error\n    Execve(context.Context, ExecveParam) \u003c-chan runner.Result\n    Destroy() error\n}\n```\n\n## Packages (/pkg)\n\n- seccomp: provides seccomp type definition\n  - libseccomp: provides utility function that wrappers libseccomp\n- forkexec: fork-exec provides mount, unshare, ptrace, seccomp, capset before exec\n- memfd: read regular file and creates a sealed memfd for its contents\n- unixsocket: send / recv oob msg from a unix socket\n- cgroup: creates cgroup directories and collects resource usage / limits\n- mount: provides utility function that wrappers mount syscall\n- rlimit: provides utility function that defines rlimit syscall\n- pipe: provides wrapper to collect all written content through pipe\n\n## Packages\n\n- cmd/runprog/config: defines arch \u0026 language specified trace condition for ptrace runner from UOJ\n- container: creates pre-forked container to run programs inside\n- runner: interface to run program\n  - ptrace: wrapper to call forkexec and ptracer\n    - filehandler: an example implementation of UOJ file set\n  - unshare: wrapper to call forkexec and unshared namespaces\n- ptracer: ptrace tracer and provides syscall trap filter context\n\n## Executable\n\n- runprog: safely run program by unshare / ptrace / pre-forked containers\n\n## Configurations\n\n- config/config.go: all configs toward running specs (similar to UOJ)\n\n## Kernel Versions\n\n- 6.1: `pids.peak` in cgroup v2\n- 5.19: `memory.peak` in cgroup v2\n- 5.7: `clone3` with `CLONE_INTO_CGROUP`\n- 5.3: `clone3`\n- 4.15: cgroup v2 (also need support in the Linux distribution)\n- 4.14: SECCOMP_RET_KILL_PROCESS \n- 4.6: CLONE_NEWCGROUP\n- 3.19: execveat()\n- 3.17: seccomp, memfd_create\n- 3.10: CentOS 7\n- 3.8: CLONE_NEWUSER without CAP_SYS_ADMIN, CAP_SETUID, CAP_SETGID\n- 3.5: prctl(PR_SET_NO_NEW_PRIVS)\n- 2.6.36: prlimit64\n\n## Benchmarks\n\n### ForkExec\n\n```bash\n$ go test -bench . -benchtime 10s\ngoos: linux\ngoarch: amd64\npkg: github.com/criyle/go-sandbox/pkg/forkexec\nBenchmarkSimpleFork-4              \t   12409\t    996096 ns/op\nBenchmarkUnsharePid-4              \t   10000\t   1065168 ns/op\nBenchmarkUnshareUser-4             \t   10000\t   1061770 ns/op\nBenchmarkUnshareUts-4              \t   10000\t   1056558 ns/op\nBenchmarkUnshareCgroup-4           \t   10000\t   1049446 ns/op\nBenchmarkUnshareIpc-4              \t     709\t  16114052 ns/op\nBenchmarkUnshareMount-4            \t     745\t  16207754 ns/op\nBenchmarkUnshareNet-4              \t    3643\t   3492924 ns/op\nBenchmarkFastUnshareMountPivot-4   \t     612\t  20967318 ns/op\nBenchmarkUnshareAll-4              \t     837\t  14047995 ns/op\nBenchmarkUnshareMountPivot-4       \t     488\t  24198331 ns/op\nPASS\nok  \tgithub.com/criyle/go-sandbox/pkg/forkexec\t147.186s\n```\n\n### Container\n\n```bash\n$ go test -bench . -benchtime 10s\ngoos: linux\ngoarch: amd64\npkg: github.com/criyle/go-sandbox/container\nBenchmarkContainer-4   \t    5907\t   2062070 ns/op\nPASS\nok  \tgithub.com/criyle/go-sandbox/container\t21.763s\n```\n\n### Cgroup\n\n```bash\n$ go test -bench . -benchtime 10s\ngoos: linux\ngoarch: amd64\npkg: github.com/criyle/go-sandbox/pkg/cgroup\nBenchmarkCgroup-4   \t   50283\t    245094 ns/op\nPASS\nok  \tgithub.com/criyle/go-sandbox/pkg/cgroup\t14.744s\n```\n\n### Socket\n\nBlocking:\n\n```bash\n$ go test -bench . -benchtime 10s\ngoos: linux\ngoarch: amd64\npkg: github.com/criyle/go-sandbox/pkg/unixsocket\ncpu: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz\nBenchmarkBaseline-8             12170148              1048 ns/op\nBenchmarkGoroutine-8             2658846              4910 ns/op\nBenchmarkChannel-8               8454133              1431 ns/op\nBenchmarkChannelBuffed-8         8767264              1357 ns/op\nBenchmarkChannelBuffed4-8        9670935              1230 ns/op\nBenchmarkEmptyGoroutine-8       34927512               342.8 ns/op\nPASS\nok      github.com/criyle/go-sandbox/pkg/unixsocket     83.669s\n```\n\nNon-block:\n\n```bash\n$ go test -bench . -benchtime 10s\ngoos: linux\ngoarch: amd64\npkg: github.com/criyle/go-sandbox/pkg/unixsocket\ncpu: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz\nBenchmarkBaseline-8             11609772              1001 ns/op\nBenchmarkGoroutine-8             2470767              4788 ns/op\nBenchmarkChannel-8               8488646              1427 ns/op\nBenchmarkChannelBuffed-8         8876050              1345 ns/op\nBenchmarkChannelBuffed4-8        9813187              1212 ns/op\nBenchmarkEmptyGoroutine-8       34852828               342.2 ns/op\nPASS\nok      github.com/criyle/go-sandbox/pkg/unixsocket     81.679s\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcriyle%2Fgo-sandbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcriyle%2Fgo-sandbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcriyle%2Fgo-sandbox/lists"}