mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-11-04 14:49:53 +08:00
forkexec: fix deadlock in go scheduler when syncWithChild
- also fix broken pipe when using fd as executable resolves #2
This commit is contained in:
parent
ca60fcad98
commit
701fed8d1c
4
go.mod
4
go.mod
@ -4,8 +4,8 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/elastic/go-seccomp-bpf v1.2.0
|
github.com/elastic/go-seccomp-bpf v1.2.0
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861
|
||||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/pkg/errors v0.9.1 // indirect
|
require github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
|||||||
8
go.sum
8
go.sum
@ -13,12 +13,12 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 h1:yssD99+7tqHWO5Gwh81phT+67hg+KttniBr6UnEXOY8=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
||||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|||||||
@ -137,6 +137,10 @@ func forkAndExecInChild1(r *Runner, argv0 *byte, argv, env []*byte, workdir, hos
|
|||||||
nextfd++
|
nextfd++
|
||||||
}
|
}
|
||||||
if r.ExecFile > 0 && int(r.ExecFile) < nextfd {
|
if r.ExecFile > 0 && int(r.ExecFile) < nextfd {
|
||||||
|
// Avoid fd rewrite
|
||||||
|
for nextfd == pipe {
|
||||||
|
nextfd++
|
||||||
|
}
|
||||||
_, _, err1 = syscall.RawSyscall(syscall.SYS_DUP3, r.ExecFile, uintptr(nextfd), syscall.O_CLOEXEC)
|
_, _, err1 = syscall.RawSyscall(syscall.SYS_DUP3, r.ExecFile, uintptr(nextfd), syscall.O_CLOEXEC)
|
||||||
if err1 != 0 {
|
if err1 != 0 {
|
||||||
return pipe, LocDup3, 0, err1
|
return pipe, LocDup3, 0, err1
|
||||||
|
|||||||
@ -87,9 +87,9 @@ 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)))
|
syscall.RawSyscall(syscall.SYS_WRITE, uintptr(p[0]), uintptr(unsafe.Pointer(&err2)), uintptr(unsafe.Sizeof(err2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
r1, _, err1 = syscall.RawSyscall(syscall.SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&childErr)), uintptr(unsafe.Sizeof(childErr)))
|
n, err := readChildErr(p[0], &childErr)
|
||||||
// child returned error code
|
// child returned error code
|
||||||
if (r1 != unsafe.Sizeof(err2) && r1 != unsafe.Sizeof(childErr)) || childErr.Err != 0 || err1 != 0 {
|
if (n != int(unsafe.Sizeof(err2)) && n != int(unsafe.Sizeof(childErr))) || childErr.Err != 0 || err != nil {
|
||||||
childErr.Err = handlePipeError(r1, childErr.Err)
|
childErr.Err = handlePipeError(r1, childErr.Err)
|
||||||
goto fail
|
goto fail
|
||||||
}
|
}
|
||||||
@ -107,16 +107,16 @@ func syncWithChild(r *Runner, p [2]int, pid int, err1 syscall.Errno) (int, error
|
|||||||
if r.Ptrace || r.StopBeforeSeccomp {
|
if r.Ptrace || r.StopBeforeSeccomp {
|
||||||
// let's wait it in another goroutine to avoid SIGPIPE
|
// let's wait it in another goroutine to avoid SIGPIPE
|
||||||
go func() {
|
go func() {
|
||||||
syscall.RawSyscall(syscall.SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&childErr)), uintptr(unsafe.Sizeof(childErr)))
|
readChildErr(p[0], &childErr)
|
||||||
unix.Close(p[0])
|
unix.Close(p[0])
|
||||||
}()
|
}()
|
||||||
return int(pid), nil
|
return int(pid), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if read anything mean child failed after sync (close_on_exec so it should not block)
|
// if read anything mean child failed after sync (close_on_exec so it should not block)
|
||||||
r1, _, err1 = syscall.RawSyscall(syscall.SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&childErr)), uintptr(unsafe.Sizeof(childErr)))
|
n, err = readChildErr(p[0], &childErr)
|
||||||
unix.Close(p[0])
|
unix.Close(p[0])
|
||||||
if r1 != 0 || err1 != 0 {
|
if n != 0 || err != nil {
|
||||||
childErr.Err = handlePipeError(r1, childErr.Err)
|
childErr.Err = handlePipeError(r1, childErr.Err)
|
||||||
goto failAfterClose
|
goto failAfterClose
|
||||||
}
|
}
|
||||||
@ -133,6 +133,26 @@ failAfterClose:
|
|||||||
return 0, childErr
|
return 0, childErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readChildErr(fd int, childErr *ChildError) (n int, err error) {
|
||||||
|
for {
|
||||||
|
n, err = readlen(fd, (*byte)(unsafe.Pointer(childErr)), int(unsafe.Sizeof(*childErr)))
|
||||||
|
if err != syscall.EINTR {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://cs.opensource.google/go/go/+/refs/tags/go1.18.1:src/syscall/zsyscall_linux_amd64.go;l=944
|
||||||
|
func readlen(fd int, p *byte, np int) (n int, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(syscall.SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
|
||||||
|
n = int(r0)
|
||||||
|
if e1 != 0 {
|
||||||
|
err = syscall.Errno(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// check pipe error
|
// check pipe error
|
||||||
func handlePipeError(r1 uintptr, errno syscall.Errno) syscall.Errno {
|
func handlePipeError(r1 uintptr, errno syscall.Errno) syscall.Errno {
|
||||||
if r1 >= unsafe.Sizeof(errno) {
|
if r1 >= unsafe.Sizeof(errno) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user