From f8361a08a0285d0ed203970b8e11fedf0ce82e95 Mon Sep 17 00:00:00 2001 From: criyle Date: Thu, 20 Feb 2025 21:45:03 +0000 Subject: [PATCH] forkexec: only sync when syncFunc exists #13 --- cmd/runprog/main_linux.go | 7 ++++--- pkg/forkexec/fork_child_linux.go | 32 ++++++++++++++++++-------------- pkg/forkexec/fork_linux.go | 21 +++++++++++---------- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/cmd/runprog/main_linux.go b/cmd/runprog/main_linux.go index da154cd..a3c0086 100644 --- a/cmd/runprog/main_linux.go +++ b/cmd/runprog/main_linux.go @@ -224,13 +224,14 @@ func start() (*runner.Result, error) { } } - syncFunc := func(pid int) error { - if cg != nil { + var syncFunc func(pid int) error + if cg != nil { + syncFunc = func(pid int) error { if err := cg.AddProc(pid); err != nil { return err } + return nil } - return nil } if memfile { diff --git a/pkg/forkexec/fork_child_linux.go b/pkg/forkexec/fork_child_linux.go index b3c0521..a73fd7d 100644 --- a/pkg/forkexec/fork_child_linux.go +++ b/pkg/forkexec/fork_child_linux.go @@ -351,14 +351,16 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host // Enable Ptrace & sync with parent (since ptrace_me is a blocking operation) if r.Ptrace && r.Seccomp != nil { { - r1, _, err1 = syscall.RawSyscall(syscall.SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) - if r1 == 0 || err1 != 0 { - childExitError(pipe, LocSyncWrite, err1) - } + if r.SyncFunc != nil { + r1, _, err1 = syscall.RawSyscall(syscall.SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) + if r1 == 0 || err1 != 0 { + childExitError(pipe, LocSyncWrite, err1) + } - r1, _, err1 = syscall.RawSyscall(syscall.SYS_READ, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) - if r1 == 0 || err1 != 0 { - childExitError(pipe, LocSyncRead, err1) + r1, _, err1 = syscall.RawSyscall(syscall.SYS_READ, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) + if r1 == 0 || err1 != 0 { + childExitError(pipe, LocSyncRead, err1) + } } // unshare cgroup namespace @@ -414,14 +416,16 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host // Before exec, sync with parent through pipe (configured as close_on_exec) if !r.Ptrace || r.Seccomp == nil { { - r1, _, err1 = syscall.RawSyscall(syscall.SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) - if r1 == 0 || err1 != 0 { - childExitError(pipe, LocSyncWrite, err1) - } + if r.SyncFunc != nil { + r1, _, err1 = syscall.RawSyscall(syscall.SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) + if r1 == 0 || err1 != 0 { + childExitError(pipe, LocSyncWrite, err1) + } - r1, _, err1 = syscall.RawSyscall(syscall.SYS_READ, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) - if r1 == 0 || err1 != 0 { - childExitError(pipe, LocSyncRead, err1) + r1, _, err1 = syscall.RawSyscall(syscall.SYS_READ, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) + if r1 == 0 || err1 != 0 { + childExitError(pipe, LocSyncRead, err1) + } } // unshare cgroup namespace diff --git a/pkg/forkexec/fork_linux.go b/pkg/forkexec/fork_linux.go index 43fa199..5acf334 100644 --- a/pkg/forkexec/fork_linux.go +++ b/pkg/forkexec/fork_linux.go @@ -65,6 +65,7 @@ func syncWithChild(r *Runner, p [2]int, pid int, err1 syscall.Errno) (int, error err error unshareUser = r.CloneFlags&unix.CLONE_NEWUSER == unix.CLONE_NEWUSER childErr ChildError + n int ) // sync with child @@ -86,24 +87,24 @@ func syncWithChild(r *Runner, p [2]int, pid int, err1 syscall.Errno) (int, error syscall.RawSyscall(syscall.SYS_WRITE, uintptr(p[0]), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2))) } - n, err := readChildErr(p[0], &childErr) - // child returned error code - if (n != int(unsafe.Sizeof(err2)) && n != int(unsafe.Sizeof(childErr))) || childErr.Err != 0 || err != nil { - childErr.Err = handlePipeError(n, childErr.Err) - goto fail - } - // if syncfunc return error, then fail child immediately + // only sync if there is a syncFunc if r.SyncFunc != nil { + n, err = readChildErr(p[0], &childErr) + // child returned error code + if (n != int(unsafe.Sizeof(err2)) && n != int(unsafe.Sizeof(childErr))) || childErr.Err != 0 || err != nil { + childErr.Err = handlePipeError(n, childErr.Err) + goto fail + } if err = r.SyncFunc(int(pid)); err != nil { goto fail } + // otherwise, ack child (err1 == 0) + syscall.RawSyscall(syscall.SYS_WRITE, uintptr(p[0]), uintptr(unsafe.Pointer(&err1)), uintptr(unsafe.Sizeof(err1))) } - // otherwise, ack child (err1 == 0) - syscall.RawSyscall(syscall.SYS_WRITE, uintptr(p[0]), uintptr(unsafe.Pointer(&err1)), uintptr(unsafe.Sizeof(err1))) // if stopped before execve by signal SIGSTOP or PTRACE_ME, then do not wait until execve - if r.Ptrace || r.StopBeforeSeccomp { + if r.StopBeforeSeccomp || (r.Seccomp != nil && r.Ptrace) { // let's wait it in another goroutine to avoid SIGPIPE go func() { readChildErr(p[0], &childErr)