google / gvisor

Application Kernel for Containers
https://gvisor.dev
Apache License 2.0
15.55k stars 1.28k forks source link

EAGAIN on fork, or adhering to cgroup pids.max setting - panics on fork bomb #2490

Open majek opened 4 years ago

majek commented 4 years ago

Related: https://github.com/google/gvisor/issues/2489

According to cgroupsv1, fork might return EAGAIN: https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt

Runsc crashes in such case. To reproduce: (1) Run runsc in a cgroup with pids.max set to low value (256?) (2) Run this inside runsc

root@runsc:~# :(){ :|:& };:
[1] 12

This :(){ :|:& };: is a valid bash command, also known as fork bomb.

Runsc in .boot log shows a not-nice panic:

runtime: failed to create new OS thread (have 53 already; errno=11)
runtime: may need to increase max user processes (ulimit -u)
fatal error: newosproc

runtime stack:
runtime.throw(0xeed0c6, 0x9)
        GOROOT/src/runtime/panic.go:1116 +0x72
runtime.newosproc(0xc0006d8380)
        GOROOT/src/runtime/os_linux.go:161 +0x1ba
runtime.newm1(0xc0006d8380)
        GOROOT/src/runtime/proc.go:1753 +0xdc
runtime.templateThread()
        GOROOT/src/runtime/proc.go:1798 +0x71
runtime.mstart1()
        GOROOT/src/runtime/proc.go:1097 +0xc3
runtime.mstart()
        GOROOT/src/runtime/proc.go:1062 +0x6e

Another error I saw

panic: error initializing first thread: resource temporarily unavailable

goroutine 185 [running]:
gvisor.dev/gvisor/pkg/sentry/platform/ptrace.newSubprocess.func1(0xc000313440, 0xc00051bda0, 0xc00051be00)
        pkg/sentry/platform/ptrace/subprocess.go:179 +0x335
created by gvisor.dev/gvisor/pkg/sentry/platform/ptrace.newSubprocess
        pkg/sentry/platform/ptrace/subprocess.go:159 +0x13b

Runsc should not panic on a fork bomb, or when the user tries to launch too many pids.

fvoznika commented 4 years ago

While we could (and should) fix the second case, the first one happens inside the Go runtime though. gVisor don't have much control over it. When cgroups is supported in gVisor (#190), we could try to prevent panics by limiting the number of PIDs inside the sandbox (or set rlimits). The challenge is to properly account for background goroutines, e.g. netstack, gofer, etc.

majek commented 4 years ago

I see. I frankly don't mind. I just would like to have an ability to ensure the guest can't launch too many pids.

parruda commented 4 years ago

Would setting RLIMIT_NPROC work?

majek commented 4 years ago

@parruda what do you mean? RLIMIT_NPROC inside the gvisor? Is it supported?

parruda commented 4 years ago

I mentioned it because of:

we could try to prevent panics by limiting the number of PIDs inside the sandbox (or set rlimits)

@majek it seems like it is supported. I don't know Go much so you should double check.

I'm working on porting some stuff to run on CloudRun and setrlimit is a limitation.

ihowson commented 3 years ago

https://github.com/google/gvisor/blob/e3fdd1593217894328d5a917bbc356d0a7d145f0/pkg/sentry/syscalls/linux/sys_rlimit.go#L100 suggests that ProcessCount is not enforced.

I can't find any code that uses it for enforcement, though it's likely I have missed something.