Open bobrik opened 5 years ago
Add to that list gettid
and sched_getaffinity
at a minimum, probably nanosleep
and getpid
. If you're using any of the Golang concurrency primitives you probably hit a sched_yield
or two as well.
Yes, my list is for a tiny program that doesn't do much.
I'm not sure if nanosleep
needs to be explicitly allowed. I followed this example and without whitelisting nanosleep
I can still see it allowed in strace
.
I'm fairly certain Go uses it internally in the runtime for scheduling Goroutines, so while you can probably get away without it for trivial programs, I wouldn't recommend leaving it out.
(I'm also quite certain blacklisting it does block it - I used it extensively as a testcase while developing the bindings. Very easy to call fork off a sleep
and see whether it takes milliseconds or seconds to return)
I have recently built a tool that goes through the execution path of go applications and extract all syscalls it finds. On this source code:
package main
import "fmt"
func main() {
fmt.Println("test")
}
this is what it extracts:
"sched_yield",
"futex",
"write",
"mmap",
"exit_group",
"madvise",
"rt_sigprocmask",
"getpid",
"gettid",
"tgkill",
"rt_sigaction",
"read",
"getpgrp",
"arch_prctl",
here's how to use it:
go install https://github.com/pjbgf/gosystract
gosystract --template='{{- range . }}{{printf "\"%s\",\n" .Name}}{{- end}}' application-path
A default list would certainly be useful since to come up with one isn't trivial.
Just running the program under strace and collecting the observed syscalls isn't sufficient.
In my experience, even running the program with the same input several times in a row gives a different sets of syscalls, e.g. mprotect
and set_robust_list
don't necessarily turn up always.
And then there are non-regular circumstances that lead to syscalls you don't see usually such as restart_syscall
which is executed only if you manage to send a signal that interrupts your program during a syscall.
In can confirm that nanosleep
definitely needs to be whitelisted as it's called a lot, at least if you use Go routines. Not whitelisting it definitely yields a seccomp action.
On the other hand, I haven't seen rt_sigreturn
so far.
Ideally one would have a look at the Go runtime code and grep the syscalls out of it.
Since Go statically links everything (unless you import a module with C bindings), the syscalls in the resulting binary should contain all the syscalls the program and the Go runtime does. And not much else since one should expect that Go eliminates dead runtime code.
I've done this for a medium size Go program of mine (gonzofilter, cf. its whitelist) which does a bit file IO, uses Go routines and does a lot of lexing and parsing:
Get syscall table:
curl -O https://raw.githubusercontent.com/torvalds/linux/v5.6/arch/x86/entry/syscalls/syscall_64.tbl
Get all direct syscalls:
join <(objdump -d gonzofilter -Mintel | grep 'syscall ' -B1 | grep eax | cut -f2 -d, \
| sort -u | awk '{printf("%d\n", strtonum($1));}' | sort -k1,1) \
<(awk '/^[0-9]/ {print $1, $3}' syscall_64.tbl | sort -k1,1) | sort -k1,1 -n > l1
Get all indirect syscalls (i.e. via syscall.Syscall
and syscall.Syscall6
):
join <(objdump -d gonzofilter -Mintel | grep 'call .*Syscall' -B18 \
| grep '\[rsp\]\|Syscall' | grep QWORD | cut -f2 -d, | sort -u \
| awk '{printf("%d\n", strtonum($1));}' | sort -k1,1) \
<(awk '/^[0-9]/ {print $1, $3}' syscall_64.tbl | sort -k1,1) | sort -k1,1 -n > l2
Combined I get this list:
clone
close
epoll_create
epoll_create1
epoll_ctl
epoll_pwait
exit
exit_group
fcntl
fdatasync
flock
fstat
fsync
ftruncate
futex
getpid
gettid
kill
lseek
madvise
mincore
mmap
munmap
nanosleep
openat
pread64
pwrite64
read
readlinkat
rt_sigaction
rt_sigprocmask
sched_getaffinity
sched_yield
setitimer
tgkill
write
When I link against a module with C bindings (such as this libseccomp module), of course, there are some additional syscall originating from the shared libraries (e.g. libc+libpthread+libseccomp).
This is a moving target, meaning any new golang releases and/or Linux kernel releases can add more system calls.
I agree with @kolyshkin, trying to maintain a default list of syscalls is going to be extremely difficult. Maybe someday we could revisit this idea, but at this point in time I think this needs to be a WONTFIX.
Go runtime requires some syscalls for normal operation (like
mmap
for memory allocation).It seems like it's better to provide a list from the library rather than make developers guess.
At least the following are required: