{"id":13684406,"url":"https://github.com/xfernando/go2seccomp","last_synced_at":"2026-01-12T01:58:09.222Z","repository":{"id":144201788,"uuid":"120469111","full_name":"xfernando/go2seccomp","owner":"xfernando","description":"Generate seccomp profiles from go binaries","archived":false,"fork":false,"pushed_at":"2018-05-08T15:58:37.000Z","size":33,"stargazers_count":136,"open_issues_count":0,"forks_count":11,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-12T05:37:22.876Z","etag":null,"topics":["containers","go","seccomp","security"],"latest_commit_sha":null,"homepage":null,"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/xfernando.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}},"created_at":"2018-02-06T14:22:45.000Z","updated_at":"2024-07-26T08:45:26.000Z","dependencies_parsed_at":"2023-06-18T04:46:25.232Z","dependency_job_id":null,"html_url":"https://github.com/xfernando/go2seccomp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xfernando%2Fgo2seccomp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xfernando%2Fgo2seccomp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xfernando%2Fgo2seccomp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xfernando%2Fgo2seccomp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xfernando","download_url":"https://codeload.github.com/xfernando/go2seccomp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251777779,"owners_count":21642224,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["containers","go","seccomp","security"],"created_at":"2024-08-02T14:00:33.199Z","updated_at":"2026-01-12T01:58:09.213Z","avatar_url":"https://github.com/xfernando.png","language":"Go","funding_links":[],"categories":["文章"],"sub_categories":[],"readme":"# go2seccomp\n\n`go2seccomp` analyzes compiled go binaries and generates a seccomp profile that blocks all syscalls, except the ones\nused by the binary. The profile can then be used when running the binary in a container using docker, rkt, or any runtime\nthat supports seccomp to further reduce the container's attack surface.\n\nThis tool aims to help make the process of creating seccomp profiles for go programs easier, and can also help\ndevelopers see when changes increase or decrease the scope of what their programs can do with relation to syscalls.\n\n## Installation\n\n`go get -u github.com/xfernando/go2seccomp`\n\n## Usage\n\n`go2seccomp /path/to/binary /path/to/profile.json`\n\n## Examples\n\nRunning `go2seccomp` on a simple hello world application like this one:\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n        fmt.Println(\"Hello World!\")\n}\n```\n\nyields this profile:\n\n```json\n {\n     \"defaultAction\": \"SCMP_ACT_ERRNO\",\n     \"architectures\": [\n         \"SCMP_ARCH_X86_64\"\n     ],\n     \"syscalls\": [\n         {\n             \"names\": [\n                 \"arch_prctl\",\n                 \"brk\",\n                 \"clone\",\n                 \"close\",\n                 \"epoll_create\",\n                 \"epoll_create1\",\n                 \"epoll_ctl\",\n                 \"epoll_wait\",\n                 \"execve\",\n                 \"exit\",\n                 \"exit_group\",\n                 \"fcntl\",\n                 \"futex\",\n                 \"getpid\",\n                 \"gettid\",\n                 \"kill\",\n                 \"madvise\",\n                 \"mincore\",\n                 \"mmap\",\n                 \"munmap\",\n                 \"open\",\n                 \"pselect6\",\n                 \"read\",\n                 \"readlinkat\",\n                 \"rt_sigaction\",\n                 \"rt_sigprocmask\",\n                 \"rt_sigreturn\",\n                 \"sched_getaffinity\",\n                 \"sched_yield\",\n                 \"setitimer\",\n                 \"sigaltstack\",\n                 \"stat\",\n                 \"tkill\",\n                 \"write\"\n             ],\n             \"action\": \"SCMP_ACT_ALLOW\"\n         }\n     ]\n }\n```\n\nWith the generated profile we can then start a docker container like this (assuming you built an image for the code above\nwith the tag `helloworld`):\n\n```bash\ndocker run --security-opt=\"no-new-privileges\" --security-opt=\"seccomp=profile.json\" helloworld\n```\n\nThere's a script on [examples/helloworld](./examples/helloworld) called `build-and-run.sh` that takes this hello world example,\nbuilds the binary, generates the seccomp profile, builds the docker image and runs the image with the generated profile:\n\nRunning `go2seccomp` on the `kubectl` 1.9.0 binary yields the following profile:\n\n```json\n{\n    \"defaultAction\": \"SCMP_ACT_ERRNO\",\n    \"architectures\": [\n        \"SCMP_ARCH_X86_64\"\n    ],\n    \"syscalls\": [\n        {\n            \"names\": [\n                \"accept\",\n                \"accept4\",\n                \"arch_prctl\",\n                \"bind\",\n                \"brk\",\n                \"chdir\",\n                \"chroot\",\n                \"clone\",\n                \"close\",\n                \"connect\",\n                \"dup\",\n                \"dup2\",\n                \"epoll_create\",\n                \"epoll_create1\",\n                \"epoll_ctl\",\n                \"epoll_wait\",\n                \"execve\",\n                \"exit\",\n                \"exit_group\",\n                \"fchdir\",\n                \"fchmod\",\n                \"fchmodat\",\n                \"fchown\",\n                \"fcntl\",\n                \"fstat\",\n                \"fsync\",\n                \"ftruncate\",\n                \"futex\",\n                \"getcwd\",\n                \"getdents64\",\n                \"getgid\",\n                \"getpeername\",\n                \"getpid\",\n                \"getppid\",\n                \"getrandom\",\n                \"getsockname\",\n                \"getsockopt\",\n                \"gettid\",\n                \"getuid\",\n                \"ioctl\",\n                \"kill\",\n                \"listen\",\n                \"lseek\",\n                \"lstat\",\n                \"madvise\",\n                \"mincore\",\n                \"mkdirat\",\n                \"mmap\",\n                \"mount\",\n                \"munmap\",\n                \"open\",\n                \"openat\",\n                \"pipe\",\n                \"pipe2\",\n                \"prctl\",\n                \"pread64\",\n                \"pselect6\",\n                \"ptrace\",\n                \"pwrite64\",\n                \"read\",\n                \"readlinkat\",\n                \"recvfrom\",\n                \"recvmsg\",\n                \"renameat\",\n                \"rt_sigaction\",\n                \"rt_sigprocmask\",\n                \"rt_sigreturn\",\n                \"sched_getaffinity\",\n                \"sched_yield\",\n                \"sendfile\",\n                \"sendmsg\",\n                \"sendto\",\n                \"setgid\",\n                \"setgroups\",\n                \"setitimer\",\n                \"setpgid\",\n                \"setsid\",\n                \"setsockopt\",\n                \"setuid\",\n                \"shutdown\",\n                \"sigaltstack\",\n                \"socket\",\n                \"stat\",\n                \"symlinkat\",\n                \"tkill\",\n                \"unlinkat\",\n                \"unshare\",\n                \"wait4\",\n                \"waitid\",\n                \"write\",\n                \"writev\"\n            ],\n            \"action\": \"SCMP_ACT_ALLOW\"\n        }\n    ]\n}\n```\n\n## How it works\n\n`go2seccomp` uses`go tool objdump` to decompile the binary. With the decompiled binary we search for occurences of any of the following:\n\n* `CALL syscall.Syscall(SB)`\n* `CALL syscall.Syscall6(SB)`\n* `CALL syscall.RawSyscall(SB)`\n* `CALL syscall.RawSyscall6(SB)`\n\nThese are calls to functions of the same name on the [syscall](https://golang.org/pkg/syscall/) package, which are used to\nprovide access to the underlying syscalls using constants with the syscall ID.\n\nAfter finding an occurrence of one of those calls, `go2seccomp` searches the previous instructions looking for the `MOVQ` instruction\nthat puts the syscall ID at the address pointed by the stack pointer (`SP`) register.\n\nAs an example, let's look at the code for the `GetCwd` func of the `syscall` package. Line [152](https://github.com/golang/go/blob/104445e3140f4468839db49a25cb0182f7923174/src/syscall/zsyscall_linux_amd64.go#L152) is where\nthe call to the `Syscall` func is made, shown below.\n\n```go\nr0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)\n```\n\nIt passes the `SYS_GETCWD` constant, which has the value 79. Below we have the dissasembled code for this line.\n\n```asm\n  zsyscall_linux_amd64.go:152   0x47b234    48c704244f000000    MOVQ $0x4f, 0(SP)\n  zsyscall_linux_amd64.go:152   0x47b23c    48894c2408          MOVQ CX, 0x8(SP)\n  zsyscall_linux_amd64.go:152   0x47b241    4889442410          MOVQ AX, 0x10(SP)\n  zsyscall_linux_amd64.go:152   0x47b246    48c744241800000000  MOVQ $0x0, 0x18(SP)\n  zsyscall_linux_amd64.go:152   0x47b24f    e81c340000          CALL syscall.Syscall(SB)\n```\n\nThe value the `MOVQ` instruction is putting on the address pointed by the `SP` register is 0x4F, which is 79, the ID\nof the `getcwd` syscall.\n\nWe collect all syscall IDs using this method and generate a seccomp profile json as output.\n\n### Go Runtime syscalls\n\nGo's `runtime` package doesn't use the functions on the `syscall` package. Instead, it has a lot of assembly code that\nuses syscalls directly. The file [sys_linux_amd64.s](https://github.com/golang/go/blob/master/src/runtime/sys_linux_amd64.s) contains most of those.\nThe first version of `go2seccomp` didn't take those into account, so a lot of syscalls needed were missing, but are now properly accounted for.\n\nSince it now analyzes actual `SYSCALL` calls, this removed the limitations that only those syscalls made through the `syscall` package\nwould be discovered. Now even syscalls made in C code through `cgo` should be discovered when analyzing static builds.\n\n### Default syscalls\n\nWhen I tried running containers with profiles `go2seccomp` generated they didn't start with different error messages at times (even the basic helloworld).\nAfter some digging, I found this [issue](https://github.com/moby/moby/issues/22252) on the moby project, where I found that some syscalls\nneed to be enabled on the seccomp profile because docker needs them to start the container, even if they're not needed for the binary the container runs.\n\nThe syscalls that need to be enabled by default are:\n\n* `execve`\n* `futex`\n* `stat`\n\n## Limitations\n\nThere are some limitations in go2seccomp:\n\n* If the syscall ID passed to the syscall functions are defined at runtime, they won't be detected\n  * Though a warning will be displayed when we find a syscall whose ID can't be parsed\n* If you use go plugins, syscalls from the plugins probably won't be detected\n\nMore details about limitations can be seen at @jessfraz [keynote at FOSDEM](https://www.youtube.com/watch?v=7mzbIOtcIaQ)\naround 30 minutes in.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxfernando%2Fgo2seccomp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxfernando%2Fgo2seccomp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxfernando%2Fgo2seccomp/lists"}