From f0dd44f4664e0da972b248945fb6ba14ca780f19 Mon Sep 17 00:00:00 2001 From: criyle Date: Thu, 20 Feb 2025 22:52:26 -0500 Subject: [PATCH] container: fix cgroup fd forkexec: disabled VFORK for now as it is not working properly #13 --- container/container_exec_linux.go | 2 +- container/environment_linux.go | 2 +- container/host_exec_linux.go | 1 + pkg/forkexec/fork_child_linux.go | 29 ++++++++++++++++------------- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/container/container_exec_linux.go b/container/container_exec_linux.go index f8127a3..8ae9400 100644 --- a/container/container_exec_linux.go +++ b/container/container_exec_linux.go @@ -110,7 +110,7 @@ func (c *containerServer) handleExecve(cmd *execCmd, msg unixsocket.Msg) error { Seccomp: seccomp, CgroupFd: cgroupFd, - UnshareCgroupAfterSync: c.UnshareCgroup && !cmd.SyncAfter, + UnshareCgroupAfterSync: c.UnshareCgroup, } // starts the runner, error is handled same as wait4 to make communication equal pid, err := r.Start() diff --git a/container/environment_linux.go b/container/environment_linux.go index 76c2d57..49871b7 100644 --- a/container/environment_linux.go +++ b/container/environment_linux.go @@ -250,7 +250,7 @@ func (b *Builder) startContainer() (*container, error) { unix.CAP_SYS_ADMIN, unix.CAP_SYS_RESOURCE, }, - Pdeathsig: syscall.SIGTERM, + Pdeathsig: syscall.SIGKILL, }, } if err = r.Start(); err != nil { diff --git a/container/host_exec_linux.go b/container/host_exec_linux.go index 32de90f..56cc419 100644 --- a/container/host_exec_linux.go +++ b/container/host_exec_linux.go @@ -72,6 +72,7 @@ func (c *container) Execve(ctx context.Context, param ExecveParam) runner.Result FdExec: param.ExecFile > 0, CTTY: param.CTTY, SyncAfter: param.SyncAfterExec, + FdCgroup: param.CgroupFD > 0, } cm := cmd{ Cmd: cmdExecve, diff --git a/pkg/forkexec/fork_child_linux.go b/pkg/forkexec/fork_child_linux.go index 090dfb8..d045068 100644 --- a/pkg/forkexec/fork_child_linux.go +++ b/pkg/forkexec/fork_child_linux.go @@ -5,22 +5,32 @@ import ( "syscall" "unsafe" + "github.com/criyle/go-sandbox/pkg/rlimit" "golang.org/x/sys/unix" ) // Reference to src/syscall/exec_linux.go // +//go:noinline //go:norace +//go:nocheckptr func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, hostname, domainname, pivotRoot *byte, p [2]int) (r1 uintptr, err1 syscall.Errno) { var ( - clone3 *cloneArgs + clone3 *cloneArgs + pid uintptr + err2 syscall.Errno + unshareUser = r.CloneFlags&unix.CLONE_NEWUSER == unix.CLONE_NEWUSER + i int + rlim rlimit.RLimit ) + pipe := p[1] + // similar to exec_linux, avoid side effect by shuffling around fd, nextfd := prepareFds(r.Files) flag := r.CloneFlags & UnshareFlags - if r.SyncFunc == nil && !(r.StopBeforeSeccomp || (r.Seccomp != nil && r.Ptrace)) && flag|syscall.CLONE_NEWUSER != syscall.CLONE_NEWUSER { - flag |= syscall.CLONE_VM | syscall.CLONE_VFORK + if r.SyncFunc == nil && !(r.StopBeforeSeccomp || (r.Seccomp != nil && r.Ptrace)) && flag&syscall.CLONE_NEWUSER != syscall.CLONE_NEWUSER { + // flag |= syscall.CLONE_VM | syscall.CLONE_VFORK } // use clone3 if cgroupFd specified @@ -62,13 +72,6 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host afterForkInChild() // Notice: cannot call any GO functions beyond this point - pipe := p[1] - var ( - pid uintptr - err2 syscall.Errno - unshareUser = r.CloneFlags&unix.CLONE_NEWUSER == unix.CLONE_NEWUSER - ) - // Close write end of pipe if _, _, err1 = syscall.RawSyscall(syscall.SYS_CLOSE, uintptr(p[0]), 0, 0); err1 != 0 { childExitError(pipe, LocCloseWrite, err1) @@ -154,7 +157,7 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host r.ExecFile = uintptr(nextfd) nextfd++ } - for i := 0; i < len(fd); i++ { + for i = 0; i < len(fd); i++ { if fd[i] >= 0 && fd[i] < int(i) { // Avoid fd rewrite for nextfd == pipe || (r.ExecFile > 0 && nextfd == int(r.ExecFile)) { @@ -170,7 +173,7 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host } } // Pass 2: fd[i] => i - for i := 0; i < len(fd); i++ { + for i = 0; i < len(fd); i++ { if fd[i] == -1 { syscall.RawSyscall(syscall.SYS_CLOSE, uintptr(i), 0, 0) continue @@ -324,7 +327,7 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host } // Set limit - for i, rlim := range r.RLimits { + for i, rlim = range r.RLimits { // prlimit instead of setrlimit to avoid 32-bit limitation (linux > 3.2) _, _, err1 = syscall.RawSyscall6(syscall.SYS_PRLIMIT64, 0, uintptr(rlim.Res), uintptr(unsafe.Pointer(&rlim.Rlim)), 0, 0, 0) if err1 != 0 {