forkexec: support vfork

(#13)
This commit is contained in:
criyle 2025-02-22 20:03:46 +00:00
parent f9deb2dc1a
commit 396ac9723e
12 changed files with 281 additions and 4 deletions

View File

@ -5,6 +5,7 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/criyle/go-sandbox/pkg/forkexec/vfork"
"github.com/criyle/go-sandbox/pkg/rlimit" "github.com/criyle/go-sandbox/pkg/rlimit"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -30,7 +31,7 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host
flag := r.CloneFlags & UnshareFlags flag := r.CloneFlags & UnshareFlags
if r.SyncFunc == nil && !(r.StopBeforeSeccomp || (r.Seccomp != nil && r.Ptrace)) && flag&syscall.CLONE_NEWUSER != syscall.CLONE_NEWUSER { 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 flag |= syscall.CLONE_VM | syscall.CLONE_VFORK
} }
// use clone3 if cgroupFd specified // use clone3 if cgroupFd specified
@ -54,13 +55,13 @@ func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, host
// UnshareFlags (new namespaces) is activated by clone syscall // UnshareFlags (new namespaces) is activated by clone syscall
if clone3 != nil { if clone3 != nil {
r1, _, err1 = syscall.RawSyscall6(unix.SYS_CLONE3, uintptr(unsafe.Pointer(clone3)), unsafe.Sizeof(*clone3), 0, 0, 0, 0) r1, err1 = vfork.RawVforkSyscall(unix.SYS_CLONE3, uintptr(unsafe.Pointer(clone3)), unsafe.Sizeof(*clone3), 0)
} else { } else {
if runtime.GOARCH == "s390x" { if runtime.GOARCH == "s390x" {
// On Linux/s390, the first two arguments of clone(2) are swapped. // On Linux/s390, the first two arguments of clone(2) are swapped.
r1, _, err1 = syscall.RawSyscall6(syscall.SYS_CLONE, 0, flag, 0, 0, 0, 0) r1, err1 = vfork.RawVforkSyscall(syscall.SYS_CLONE, 0, flag, 0)
} else { } else {
r1, _, err1 = syscall.RawSyscall6(syscall.SYS_CLONE, flag, 0, 0, 0, 0, 0) r1, err1 = vfork.RawVforkSyscall(syscall.SYS_CLONE, flag, 0, 0)
} }
} }
if err1 != 0 || r1 != 0 { if err1 != 0 || r1 != 0 {

View File

@ -0,0 +1,25 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-24
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
POPL SI // preserve return address
INVOKE_SYSCALL
PUSHL SI
CMPL AX, $0xfffff001
JLS ok
MOVL $-1, r1+16(FP)
NEGL AX
MOVL AX, err+20(FP)
RET
ok:
MOVL AX, r1+16(FP)
MOVL $0, err+20(FP)
RET

View File

@ -0,0 +1,28 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
POPQ R12 // preserve return address
SYSCALL
PUSHQ R12
CMPQ AX, $0xfffffffffffff001
JLS ok2
MOVQ $-1, r1+32(FP)
NEGQ AX
MOVQ AX, err+40(FP)
RET
ok2:
MOVQ AX, r1+32(FP)
MOVQ $0, err+40(FP)
RET

View File

@ -0,0 +1,26 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-24
MOVW trap+0(FP), R7 // syscall entry
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
SWI $0
MOVW $0xfffff001, R1
CMP R1, R0
BLS ok
MOVW $-1, R1
MOVW R1, r1+16(FP)
RSB $0, R0, R0
MOVW R0, err+20(FP)
RET
ok:
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, err+20(FP)
RET

View File

@ -0,0 +1,27 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
CMN $4095, R0
BCC ok
MOVD $-1, R4
MOVD R4, r1+32(FP) // r1
NEG R0, R0
MOVD R0, err+40(FP) // errno
RET
ok:
MOVD R0, r1+32(FP) // r1
MOVD ZR, err+40(FP) // errno
RET

View File

@ -0,0 +1,27 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV $0, R7
MOVV $0, R8
MOVV $0, R9
MOVV trap+0(FP), R11 // syscall entry
SYSCALL
MOVW $-4096, R12
BGEU R12, R4, ok
MOVV $-1, R12
MOVV R12, r1+32(FP) // r1
SUBVU R4, R0, R4
MOVV R4, err+40(FP) // errno
RET
ok:
MOVV R4, r1+32(FP) // r1
MOVV R0, err+40(FP) // errno
RET

View File

@ -0,0 +1,27 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (mips64 || mips64le)
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
BEQ R7, ok
MOVV $-1, R1
MOVV R1, r1+32(FP) // r1
MOVV R2, err+40(FP) // errno
RET
ok:
MOVV R2, r1+32(FP) // r1
MOVV R0, err+40(FP) // errno
RET

View File

@ -0,0 +1,24 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (mips || mipsle)
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-24
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
BEQ R7, ok
MOVW $-1, R1
MOVW R1, r1+16(FP) // r1
MOVW R2, err+20(FP) // errno
RET
ok:
MOVW R2, r1+16(FP) // r1
MOVW R0, err+20(FP) // errno
RET

View File

@ -0,0 +1,27 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (ppc64 || ppc64le)
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
BVC ok
MOVD $-1, R4
MOVD R4, r1+32(FP) // r1
MOVD R3, err+40(FP) // errno
RET
ok:
MOVD R3, r1+32(FP) // r1
MOVD R0, err+40(FP) // errno
RET

View File

@ -0,0 +1,27 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV ZERO, A3
MOV ZERO, A4
MOV ZERO, A5
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV $-4096, T0
BLTU T0, A0, err
MOV A0, r1+32(FP) // r1
MOV ZERO, err+40(FP) // errno
RET
err:
MOV $-1, T0
MOV T0, r1+32(FP) // r1
SUB A0, ZERO, A0
MOV A0, err+40(FP) // errno
RET

View File

@ -0,0 +1,26 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
// func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1, err uintptr)
TEXT ·RawVforkSyscall(SB),NOSPLIT|NOFRAME,$0-48
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD $0xfffffffffffff001, R8
CMPUBLT R2, R8, ok2
MOVD $-1, r1+32(FP)
NEG R2, R2
MOVD R2, err+40(FP) // errno
RET
ok2:
MOVD R2, r1+32(FP)
MOVD $0, err+40(FP) // errno
RET

View File

@ -0,0 +1,12 @@
// Package vfork provides the mirror of the un-exported syscall.rawVforkSyscall.
// The assembly code is copied from go1.24 syscall package
package vfork
import "syscall"
// RawVforkSyscall provided the mirrored version from un-exported syscall.rawVforkSyscall
// The go:linkname does not work for assembly function and it was suggested by the go team
// to copy over the assembly functions
//
// See go.dev/issue/71892
func RawVforkSyscall(trap, a1, a2, a3 uintptr) (r1 uintptr, err syscall.Errno)